clntxres.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:35k
源码类别:

Symbian

开发平台:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Source last modified: $Id: clntxres.cpp,v 1.9.20.1 2004/07/09 02:09:16 hubbe Exp $
  3.  * 
  4.  * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
  5.  * 
  6.  * The contents of this file, and the files included with this file,
  7.  * are subject to the current version of the RealNetworks Public
  8.  * Source License (the "RPSL") available at
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed
  10.  * the file under the current version of the RealNetworks Community
  11.  * Source License (the "RCSL") available at
  12.  * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
  13.  * will apply. You may also obtain the license terms directly from
  14.  * RealNetworks.  You may not use this file except in compliance with
  15.  * the RPSL or, if you have a valid RCSL with RealNetworks applicable
  16.  * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
  17.  * the rights, obligations and limitations governing use of the
  18.  * contents of the file.
  19.  * 
  20.  * Alternatively, the contents of this file may be used under the
  21.  * terms of the GNU General Public License Version 2 or later (the
  22.  * "GPL") in which case the provisions of the GPL are applicable
  23.  * instead of those above. If you wish to allow use of your version of
  24.  * this file only under the terms of the GPL, and not to allow others
  25.  * to use your version of this file under the terms of either the RPSL
  26.  * or RCSL, indicate your decision by deleting the provisions above
  27.  * and replace them with the notice and other provisions required by
  28.  * the GPL. If you do not delete the provisions above, a recipient may
  29.  * use your version of this file under the terms of any one of the
  30.  * RPSL, the RCSL or the GPL.
  31.  * 
  32.  * This file is part of the Helix DNA Technology. RealNetworks is the
  33.  * developer of the Original Code and owns the copyrights in the
  34.  * portions it created.
  35.  * 
  36.  * This file, and the files included with this file, is distributed
  37.  * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
  38.  * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
  39.  * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
  40.  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
  41.  * ENJOYMENT OR NON-INFRINGEMENT.
  42.  * 
  43.  * Technology Compatibility Kit Test Suite(s) Location:
  44.  *    http://www.helixcommunity.org/content/tck
  45.  * 
  46.  * Contributor(s):
  47.  * 
  48.  * ***** END LICENSE BLOCK ***** */
  49. #include "hxresult.h"
  50. #include "hxassert.h"
  51. #include "hxheap.h"
  52. #include "hxslist.h"
  53. #include "netbyte.h"
  54. #include "hxstrutl.h"
  55. #include "hxver.h"
  56. #include "clntxres.ver"
  57. #include "clntxres.h"
  58. #include "hxmarsh.h"
  59. #include "hlxclib/string.h"
  60. #include "hlxclib/stdlib.h"
  61. #ifdef _MACINTOSH
  62. #pragma export on
  63. #endif
  64. #ifdef _AIX
  65. #include "dllpath.h"
  66. ENABLE_MULTILOAD_DLLACCESS_PATHS(Pnxres);
  67. #endif
  68. STDAPI HXCreateInstance(IUnknown**  /*OUT*/ ppIUnknown);
  69. #ifdef _MACINTOSH
  70. #pragma export off
  71. #endif
  72. #include "hxheap.h"
  73. #ifdef _DEBUG
  74. #undef HX_THIS_FILE
  75. static const char HX_THIS_FILE[] = __FILE__;
  76. #endif
  77. /*
  78.  * PNCreateInstance
  79.  * -----------------
  80.  * Entry point into this resource manager.
  81.  * 
  82.  * input:
  83.  * IUnknown** ppIUnknown - Pointer to mem where we store pointer to new ob.
  84.  *
  85.  * output:
  86.  * STDAPI
  87.  * 
  88.  */
  89. STDAPI 
  90. HXCreateInstance
  91. (
  92.     IUnknown**  /*OUT*/ ppIUnknown
  93. )
  94. {
  95.     *ppIUnknown = (IUnknown*)(IHXPlugin*)new CHXXResFile;
  96.     if (*ppIUnknown != NULL) 
  97.     {
  98. (*ppIUnknown)->AddRef();
  99. return HXR_OK;
  100.     }
  101.     // Out of memory...
  102.     return HXR_OUTOFMEMORY;
  103. }
  104. STDAPI ENTRYPOINT(CanUnload2)(void)
  105. {
  106.     return (CHXBaseCountingObject::ObjectsActive() > 0 ? HXR_FAIL : HXR_OK );
  107. }
  108. /*
  109.  * QueryInterface
  110.  * --------------
  111.  * Used to get interfaces supported by us.
  112.  *
  113.  * input:
  114.  * REFIID riid - Id of interface.
  115.  * void **ppvObj - Place to copy interface pointer.
  116.  *
  117.  */
  118. STDMETHODIMP 
  119. CHXXResFile::QueryInterface
  120. (
  121.     REFIID riid, 
  122.     void** ppvObj
  123. )
  124. {
  125.     QInterfaceList qiList[] =
  126.         {
  127.             { GET_IIDHANDLE(IID_IHXXResFile), (IHXXResFile*)this },
  128.             { GET_IIDHANDLE(IID_IHXPlugin), (IHXPlugin*)this },
  129.             { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IHXXResFile*)this },
  130.         };
  131.     
  132.     return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
  133. }
  134. /* 
  135.  * AddRef
  136.  * ------
  137.  * Increments the ref count by one.
  138.  *
  139.  * input:
  140.  * void
  141.  *
  142.  * output:
  143.  * ULONG32 - The count.
  144.  *
  145.  */
  146. STDMETHODIMP_ (ULONG32) 
  147. CHXXResFile::AddRef
  148. (
  149.     void
  150. )
  151. {
  152.     return InterlockedIncrement(&m_lRefCount);
  153. }
  154. /*
  155.  * Release
  156.  * -------
  157.  * Decrements the ref count by one, deleting 
  158.  * self if count reaches zero.
  159.  *
  160.  * input:
  161.  * void
  162.  * 
  163.  * output:
  164.  * ULONG32 - Current ref count.
  165.  *
  166.  */
  167. STDMETHODIMP_(ULONG32) 
  168. CHXXResFile::Release
  169. (
  170.     void
  171. )
  172. {
  173.     // Decrement, return count if possible.
  174.     if (InterlockedDecrement(&m_lRefCount) > 0) return m_lRefCount; 
  175.     // Else, delete self.
  176.     delete this;
  177.     return 0;
  178. }
  179. // IHXPlugin methods
  180. /************************************************************************
  181.  *  Method:
  182.  *    IHXPlugin::InitPlugin
  183.  *  Purpose:
  184.  *    Initializes the plugin for use. This interface must always be
  185.  *    called before any other method is called. This is primarily needed 
  186.  *    so that the plugin can have access to the context for creation of
  187.  *    IHXBuffers and IMalloc.
  188.  */
  189. STDMETHODIMP CHXXResFile::InitPlugin(IUnknown* /*IN*/ pContext)
  190. {
  191.     m_pContext = pContext;
  192.     m_pContext->AddRef();
  193.     m_pContext->QueryInterface(IID_IHXCommonClassFactory,
  194.     (void**)&m_pCommonClassFactory);
  195.     return HXR_OK;
  196. }
  197. const char* const CHXXResFile::zm_pName     = "PNXRes";
  198. const char* const CHXXResFile::zm_pDescription     = "External Resource File Reader";
  199. const char* const CHXXResFile::zm_pCopyright     = HXVER_COPYRIGHT;
  200. const char* const CHXXResFile::zm_pMoreInfoURL     = HXVER_MOREINFO;
  201. /************************************************************************
  202.  *  Method:
  203.  *    IHXPlugin::GetPluginInfo
  204.  *  Purpose:
  205.  *    Returns the basic information about this plugin. Including:
  206.  *
  207.  *    bLoadMultiple whether or not this plugin DLL can be loaded
  208.  * multiple times. All File Formats must set
  209.  * this value to TRUE.
  210.  *    pDescription which is used in about UIs (can be NULL)
  211.  *    pCopyright which is used in about UIs (can be NULL)
  212.  *    pMoreInfoURL which is used in about UIs (can be NULL)
  213.  */
  214. STDMETHODIMP CHXXResFile::GetPluginInfo
  215. (
  216.     REF(BOOL)        /*OUT*/ bLoadMultiple,
  217.     REF(const char*) /*OUT*/ pDescription,
  218.     REF(const char*) /*OUT*/ pCopyright,
  219.     REF(const char*) /*OUT*/ pMoreInfoURL,
  220.     REF(ULONG32)     /*OUT*/ ulVersionNumber
  221. )
  222. {
  223.     bLoadMultiple = TRUE;   // Must be true for file formats.
  224.     pDescription    = zm_pDescription;
  225.     pCopyright     = zm_pCopyright;
  226.     pMoreInfoURL    = zm_pMoreInfoURL;
  227.     ulVersionNumber = TARVER_ULONG32_VERSION;
  228.     return HXR_OK;
  229. }
  230. CHXXResFile::CHXXResFile():
  231.     mCacheList(NULL)
  232.     ,mCachePos(0)
  233.     ,mLanguageId(0x0409)    // default US English
  234.     ,mMaxCachedData(kDefaultCacheLimit)
  235.     ,mLoadedCache(NULL)
  236.     ,m_lRefCount(0)
  237.     ,m_pCommonClassFactory(NULL)
  238.     ,m_pContext(NULL)
  239.     ,m_nCodePage(0)
  240.     ,m_nResFileRef(0)
  241. {
  242. }
  243. CHXXResFile::~CHXXResFile()
  244. {
  245.     KillCache();
  246.     if (mCacheList)
  247.     {
  248. delete mCacheList;
  249. mCacheList=NULL;
  250.     }
  251.     if (mLoadedCache)
  252.     {
  253. delete mLoadedCache;
  254. mLoadedCache=NULL;
  255.     }
  256.     HX_RELEASE(m_pCommonClassFactory);
  257.     HX_RELEASE(m_pContext);
  258. }
  259. //
  260. // Open the specified file and read in all the data about where resources
  261. //  are stored in the file.
  262. //
  263. STDMETHODIMP_(HX_RESULT)
  264. CHXXResFile::Open(const char*  path)
  265. {    
  266.     HX_RESULT rc = CHXPeff::open(path);
  267.     
  268.     if (rc != HXR_OK) 
  269.     {
  270. return rc;
  271.     }
  272.     //
  273.     // Read the data in the file header, and determine where to start reading from in the file.
  274.     //
  275.     if(HXR_OK != FindResourceData())
  276.     {
  277. return HXR_RESOURCE_NODATA;
  278.     }
  279.     
  280.     CacheResourceEntries();
  281.     return rc;
  282. }
  283. //
  284. // Close the file.
  285. //
  286. STDMETHODIMP_(HX_RESULT)
  287. CHXXResFile::Close()
  288. {
  289.     CHXPeff::close();
  290.     FlushCache();
  291.     return HXR_OK;
  292. }
  293. //
  294. // Allow the resources to be accessed by type, and ID.
  295. //
  296. STDMETHODIMP_(HX_RESULT)
  297. CHXXResFile::GetResource   (ULONG32 type, ULONG32  ID,  IHXXResource** resource)
  298. {
  299.     XResCacheEntry* entry = NULL;
  300.     HX_RESULT rc = HXR_OK;
  301.     char* buffer = NULL;
  302.     HX_RESULT err;
  303.     CHXXResource*  newresource;
  304.     UCHAR* data;
  305.     ULONG32  readsize;
  306.     UCHAR* tempdata;
  307.     
  308.     HX_ASSERT(resource);
  309.     
  310.     if (!resource)
  311.     {
  312. return HXR_INVALID_PARAMETER;
  313.     }
  314.  
  315. #ifdef _MACINTOSH
  316.     INT16 nSavedResFile = 0;
  317.     // if loading from resource fork, set current res file.
  318.     if (m_nResFileRef)
  319.     {
  320.      nSavedResFile = ::CurResFile();
  321.      ::UseResFile(m_nResFileRef);
  322.     }
  323. #endif
  324.     rc = FindInCache(type, ID, &entry);
  325.     if (rc != HXR_OK)
  326.     {
  327. err = HXR_RESOURCE_NOT_FOUND;
  328. goto Cleanup;
  329.     }
  330.     if (!mLoadedCache)
  331.     {
  332. mLoadedCache = new CHXSimpleList();
  333.     }
  334.     HX_ASSERT(mLoadedCache);
  335.     if (!mLoadedCache)
  336.     {
  337. err = HXR_OUTOFMEMORY;
  338. goto Cleanup;
  339.     }
  340.     
  341.     //
  342.     // We can't continue if the requested resource wasn't in the cache.
  343.     //
  344.     if (!entry)
  345.     {
  346. err = HXR_FAIL;
  347. goto Cleanup;
  348.     }
  349.     
  350.     //
  351.     // Okay new we need a buffer
  352.     //
  353.     
  354.     buffer = new char[entry->size];
  355.     
  356.     if (!buffer)
  357.     {
  358.         err = HXR_OUTOFMEMORY;
  359. goto Cleanup;
  360.     }
  361.     
  362.     newresource = 
  363. new CHXXResource(buffer, entry->size, entry->id,
  364. entry->type, entry->language,this);
  365.     
  366.     if (!newresource)
  367.     {
  368. delete [] buffer;
  369. err = HXR_OUTOFMEMORY;
  370. goto Cleanup;
  371.     }
  372.     *resource = newresource;
  373.     newresource->AddRef();
  374.     //
  375.     // Okay now check to see if the data for the resource was already cached.
  376.     //
  377.     // If the data was cached already then return the pointer to the data already in memory.
  378.     //
  379.     if (entry->cached == TRUE)
  380.     {
  381. if (entry->cached_data == NULL)
  382. {
  383.     err = HXR_RESOURCE_NODATA;
  384.     goto Cleanup;
  385. }
  386. //
  387. // BUFFER
  388. //
  389. memcpy(buffer, entry->cached_data, entry->size); /* Flawfinder: ignore */
  390. err = HXR_OK;
  391. goto Cleanup;
  392.     }
  393.     
  394.     //
  395.     // If we got here, we need to load the resource from the file.
  396.     //
  397.     if (!entry->location)
  398.     {
  399. delete newresource;
  400. err = HXR_RESOURCE_NODATA;
  401. goto Cleanup;
  402.     }
  403.     //
  404.     // Seek to the resource's physical location in the file.
  405.     //
  406.     rc = mFile->Seek(entry->location, 0);
  407.     if (rc != HXR_OK)
  408.     {
  409.         delete newresource;
  410.         err = rc;
  411. goto Cleanup;
  412.     }
  413.     //
  414.     // Allocate a buffer to load the data into.
  415.     //
  416.     data = new UCHAR[entry->size];
  417.     HX_ASSERT(data);
  418.     if (!data)
  419.     {
  420.         delete newresource;
  421.         err = HXR_OUTOFMEMORY;
  422. goto Cleanup;
  423.     }
  424.     //
  425.     // Okay read in the data.
  426.     //
  427.     readsize = mFile->Read((char*)data, entry->size);
  428.     if (readsize != entry->size)
  429.     {
  430. delete newresource;
  431. err = HXR_AT_END;
  432. goto Cleanup;
  433.     }
  434.     
  435.     //
  436.     // Copy in the end of resource marker.
  437.     //
  438.     // This is used in certain resources to detect the end of the resource data.
  439.     // This makes it easy for us to just pass around one ptr, instead of having to 
  440.     // otherwise pass the length around to the processing functions.
  441.     //
  442.     
  443.     tempdata = data;
  444.     
  445.     tempdata = data + entry->size;
  446.     tempdata -= sizeof(kEndOfResourceMarker);
  447.     if(TestBigEndian())
  448.     {
  449. putlong(tempdata,kEndOfResourceMarker);
  450.     }
  451.     else
  452.     {
  453. (*(ULONG32*)tempdata)=kEndOfResourceMarker;
  454.     }
  455.     //
  456.     // Trim the Cached Data now so we don't delete the data we loaded
  457.     // for the cached entry.
  458.     //
  459.     TrimCachedData(entry->size);
  460.     //
  461.     // Setup the cached entry.
  462.     // Setup the data that we return.
  463.     //
  464.     entry->cached = TRUE;
  465.     entry->cached_data = data;
  466.     
  467.     mLoadedCache->AddHead(entry);
  468.     memcpy(buffer, data, entry->size); /* Flawfinder: ignore */
  469.     err = HXR_OK;
  470.     
  471. Cleanup:
  472.     //
  473.     // Okay we got here, no errors.
  474.     //
  475. #ifdef _MACINTOSH
  476.     if (nSavedResFile)
  477.     {
  478.      ::UseResFile(nSavedResFile);
  479.     }
  480. #endif
  481.     return err;
  482. }
  483. //
  484. // HIGH LEVEL FUNCTIONS
  485. //
  486. //
  487. // Return a 'C' string from the given ID.
  488. //
  489. #define STRINGTABLEMASK 0xFFF0
  490. #define STRINGENTRYMASK 0x000F
  491. STDMETHODIMP_(IHXXResource*)
  492. CHXXResFile::GetString   (ULONG32 ID)
  493. {
  494.     HX_ASSERT(this);
  495.     UINT16  wID = (UINT16)ID;
  496.     
  497.     UINT16  StringTableID = wID & STRINGTABLEMASK;
  498.     StringTableID = StringTableID >> 4;
  499.     StringTableID++;
  500.     UINT16  StringEntryID = wID & STRINGENTRYMASK;
  501.     //
  502.     // Okay now after determining the string ID, we must
  503.     // actually load the data.
  504.     //
  505.     char* StringTable = NULL; 
  506.     char* ResultString = NULL;
  507.     char* tempstring = NULL;
  508.     IHXXResource* OriginalStringTable = NULL;
  509.     IHXXResource* result = NULL;
  510.     ULONG32 bufferlength = 0;
  511.     HX_RESULT rc = HXR_OK;
  512.     UINT16 counter = 0;
  513.     UINT16 len = 0;
  514.     rc = GetResource(HX_RT_STRING,StringTableID,&OriginalStringTable);
  515.     
  516.     if (rc != HXR_OK)
  517.     {
  518. goto CleanUp;
  519.     }
  520.     
  521.     HX_ASSERT(OriginalStringTable);
  522.     StringTable=(char*)OriginalStringTable->ResourceData();
  523.     
  524.     //
  525.     // Okay now we have the String Table resource data. Let's parse it.
  526.     //
  527.     while (counter < StringEntryID)
  528.     {
  529. UINT16  len = *((UINT16*)StringTable);
  530. ReverseWORD(len);
  531. //
  532. // Jump past the length word.
  533. //
  534. StringTable += 2;
  535. HX_ASSERT(StringTable);
  536. //
  537. // Jump ahead len * 2
  538. //
  539. StringTable += (2 * len);
  540. HX_ASSERT(StringTable);
  541. counter++;
  542.     }
  543.     //
  544.     // Okay we should now be at the string we wnat.
  545.     //
  546.     
  547.     len = *((UINT16*)StringTable);
  548.     ReverseWORD(len);
  549.     
  550.     if (!len)
  551.     {
  552. goto CleanUp;
  553.     }
  554.     
  555.     StringTable += 2;
  556.     //
  557.     // Make buffer for holoding the string, add 2 bytes to make it long enough for two 's
  558.     //
  559.     ResultString = new char[(len * 2) + 2];
  560.     HX_ASSERT(ResultString);
  561.     if (!ResultString)
  562.     {
  563.         return NULL;
  564.     }
  565.     memset(ResultString, 0, (len * 2) + 2);
  566.     memcpy(ResultString, StringTable, (len * 2)); /* Flawfinder: ignore */
  567.     //
  568.     // Okay turn the string into a normal ASCII string.
  569.     //
  570.     tempstring = new char[ (len+1) * 2];
  571.     HX_ASSERT(tempstring);
  572.     if (!tempstring)
  573.     {
  574.         goto CleanUp;
  575.     }
  576. #ifdef _WIN32
  577.     WideCharToMultiByte(GetCodePage(),  0, (unsigned short*)ResultString, len+1, tempstring, (len+1) * 2, "", 0);
  578. #else
  579.     if (HXR_OK != ProcessFromUnicode((const char*)ResultString, len * 2, 
  580.     tempstring, len * 2))
  581.     {
  582. delete [] ResultString;
  583. ResultString=NULL;
  584. delete [] tempstring;
  585. tempstring=NULL;
  586. goto CleanUp;
  587.     }
  588. #endif
  589.     //
  590.     // Here we return the string that was output from the ProcessFromUnicode function.
  591.     //
  592.     delete [] ResultString;
  593.     ResultString = tempstring;
  594.     //
  595.     //      We return it as an IHXXResource so that deletion happens correctly.
  596.     //
  597.     result = new CHXXResource(ResultString, strlen(ResultString)+1,
  598.     ID, HX_RT_STRING, OriginalStringTable->Language(), this);
  599.     
  600.     HX_ASSERT(result);
  601.     
  602.     if (result)
  603.     {
  604. result->AddRef();
  605.     }
  606.     
  607.     if (!result)
  608.     {
  609. delete [] ResultString;
  610.     }
  611. CleanUp:
  612.     
  613.     if (OriginalStringTable)
  614.     {
  615. OriginalStringTable->Release();
  616. OriginalStringTable=NULL;
  617. StringTable=NULL;
  618.     }
  619.     return result;
  620. }
  621. STDMETHODIMP_(IHXXResource*)
  622. CHXXResFile::GetVersionInfo()
  623. {
  624.     IHXXResource* pRes = NULL;
  625.     GetResource(HX_RT_VERSION, 1, &pRes);
  626.     return pRes;
  627. }
  628. //
  629. // Return a "BITMAP" from the given ID.
  630. //
  631. STDMETHODIMP_(IHXXResource*)
  632. CHXXResFile::GetBitmap   (ULONG32 ID)
  633. {
  634.     IHXXResource* result = NULL;
  635.     
  636.     HX_RESULT rc = GetResource(HX_RT_BITMAP, ID, &result);
  637.     
  638.     return result;
  639. }
  640. //
  641. // Return a "DIALOG" from the given ID.
  642. //
  643. STDMETHODIMP_(IHXXResource*)
  644. CHXXResFile::GetDialog   (ULONG32 ID)
  645. {
  646.     IHXXResource* result = NULL;
  647.     HX_RESULT rc = GetResource(HX_RT_DIALOG, ID, &result);
  648.     
  649.     return result;
  650. }
  651. //
  652. // This function removes extra resource data chunks, that are loaded
  653. // when a resource is loaded.
  654. //
  655. STDMETHODIMP_(HX_RESULT)
  656. CHXXResFile::FlushCache(void)
  657. {
  658.     if (!mCacheList) 
  659.     {
  660.         return HXR_OK;
  661.     }
  662.     //
  663.     // Scan all entries looking for the matching type, and id. 
  664.     //
  665.     XResCacheEntry*  curEntry = NULL;
  666.     
  667.     LISTPOSITION  listpos = mCacheList->GetHeadPosition();
  668.     
  669.     while (listpos)
  670.     {
  671.         curEntry=(XResCacheEntry*) mCacheList->GetNext(listpos);
  672. if (curEntry->cached_data)
  673. {
  674.     delete [] curEntry->cached_data;
  675.     curEntry->cached_data = NULL;
  676.     curEntry->cached = FALSE;
  677. }
  678.     }
  679.     /*
  680.        This fixes a bug causing an infinite loop in the TrimCacheData
  681.     */
  682.     if (mLoadedCache)
  683.     {
  684. listpos = mLoadedCache->GetHeadPosition();
  685.     
  686. while (listpos)
  687. {
  688.     curEntry = (XResCacheEntry*)mLoadedCache->GetAt(listpos);
  689.     curEntry->cached_data = NULL;
  690.     curEntry->cached = FALSE;
  691.     mLoadedCache->RemoveAt(listpos);
  692.     listpos = mLoadedCache->GetHeadPosition();
  693. }
  694.     }
  695.     return HXR_OK;
  696. }
  697. //
  698. // Sets the amount of memory that can be filled with cached resource data.
  699. //
  700. STDMETHODIMP_(HX_RESULT)
  701. CHXXResFile::SetCacheLimit(ULONG32 MaxCachedData)  
  702.     mMaxCachedData=MaxCachedData; 
  703.     return HXR_OK;
  704. };
  705. //
  706. // Sets the Language ID of resources to be loaded.
  707. //
  708. STDMETHODIMP_(HX_RESULT) 
  709. CHXXResFile::SetLanguage(ULONG32 id)
  710. {
  711.     //
  712.     // Eventually check a list and determine if the language is valid.
  713.     //
  714.     mLanguageId=id;
  715.     return HXR_OK;
  716. }
  717. STDMETHODIMP
  718. CHXXResFile::UseResourceFile(INT16 nResourceFileRef)
  719. {
  720.     m_nResFileRef = nResourceFileRef;
  721.     return HXR_OK;
  722. }
  723. //
  724. //
  725. //
  726. // SUPPORT METHODS
  727. //
  728. //
  729. HX_RESULT CHXXResFile::FindResourceData()
  730. {
  731.     HX_RESULT rc = HXR_OK;
  732.     ULONG32 size;
  733.     ULONG32 pos;
  734.     HX_IMAGE_SECTION_HEADER sectionheader;
  735.     rc = GetSectionHeaderNamed(".rsrc", sectionheader);
  736.     if (rc != HXR_OK)
  737.     {
  738.         return rc;
  739.     }
  740.     mResSectionVirtualAddress = sectionheader.VirtualAddress;
  741.     //
  742.     // This actually moves us to the data portion of the section.
  743.     //
  744.     rc = FindSectionNamed(".rsrc",size,pos);
  745.     
  746.     if (rc != HXR_OK) 
  747.     {
  748. return rc;
  749.     }
  750.     
  751.     //
  752.     // Save the location of the ResourceData for a later time.
  753.     //
  754.     mResourceDataPosition = pos;
  755.     return HXR_OK;
  756. }
  757. //
  758. // This function searches the resource tree, and caches the resource data.
  759. // This helps later, we basically just do a search of this cache and save
  760. // moocho time, instead of reading through the resource tree again.
  761. //
  762. // Also if the resource had already been loaded, it's data may have been cached already
  763. // So we check this later, and return the cached data as well, instead of going back to 
  764. // disk.
  765. //
  766. HX_RESULT CHXXResFile::CacheResourceEntries(void)
  767. {
  768.     if (mCacheList)
  769.     {
  770. KillCache();
  771. delete mCacheList;
  772. mCacheList = NULL;
  773.     }
  774.     if (mLoadedCache)
  775.     {
  776. delete mLoadedCache;
  777. mLoadedCache = NULL;
  778.     }
  779.     mCacheList = new CHXSimpleList();
  780.     if (mCacheList == NULL)
  781.     {
  782. return HXR_OUTOFMEMORY;
  783.     }
  784.     HX_RESULT rc = HXR_OK;
  785.     rc = ReadResourceHeader();
  786.     if (rc != HXR_OK)
  787.     {
  788. return rc;
  789.     }
  790.     rc = ReadInAllResources();
  791.     if (rc != HXR_OK)
  792.     {
  793. return rc;
  794.     }
  795.     return HXR_OK;
  796. }
  797. HX_RESULT CHXXResFile::ReadResourceHeader(void)
  798. {
  799.     return GetResourceDirEntry(mResourceHeader);
  800. }
  801. //
  802. // This function is what actually does the resource reading.
  803. // Currently named resources are not being supported.
  804. //
  805. HX_RESULT CHXXResFile::ReadInAllResources(void)
  806. {
  807.     // Skip ahead over the named resources.
  808.     mFile->Seek(8*mResourceHeader.NumberOfNamedEntries,1);
  809.     // Now read each of the tree branches for the entries left.
  810.     ULONG32  count=mResourceHeader.NumberOfIdEntries;
  811.     ULONG32  counter=0;
  812.     for (counter=1; counter <= count; counter++)
  813.     {
  814. HX_IMAGE_RESOURCE_DIRECTORY_ENTRY    type;
  815. HX_IMAGE_RESOURCE_DIRECTORY_ENTRY    id;
  816. HX_IMAGE_RESOURCE_DIRECTORY_ENTRY    language;
  817. HX_IMAGE_RESOURCE_DATA_ENTRY    data;
  818. ULONG32     curtoplevelpos;
  819. ULONG32     rootpos;
  820. //
  821. // Get the top level directory entries. It is synonymous with type.
  822. //
  823. rootpos = mFile->Tell();
  824. GetResourceEntry(type);
  825. curtoplevelpos = mFile->Tell();
  826. type.OffsetToData = type.OffsetToData ^ 0x80000000;
  827. mFile->Seek(type.OffsetToData+mResourceDataPosition, 0);
  828. //
  829. // Get teh second level directory.  It is synonymous with ID.
  830. //
  831. ULONG32 idoffset = mFile->Tell();
  832. HX_IMAGE_RESOURCE_DIRECTORY  dir_id;
  833. GetResourceDirEntry(dir_id);
  834. //
  835. // scan all the entries in the id directory.
  836. //
  837. for (ULONG32 id_counter = 1; 
  838.     id_counter <= dir_id.NumberOfIdEntries; 
  839.     id_counter++)
  840. {
  841.     GetResourceEntry(id);
  842.     ULONG32  curIdPos = mFile->Tell();
  843.     
  844.     id.OffsetToData = id.OffsetToData ^ 0x80000000;
  845.     mFile->Seek(id.OffsetToData+mResourceDataPosition, 0);
  846.     //
  847.     // Scan all the language entries for the given id.
  848.     //
  849.     HX_IMAGE_RESOURCE_DIRECTORY   dir_language;
  850.     GetResourceDirEntry(dir_language);
  851.     for (ULONG32   lang_counter = 1; 
  852. lang_counter <= dir_language.NumberOfIdEntries; 
  853. lang_counter++)
  854.     {
  855. GetResourceEntry(language);
  856. ULONG32  curLangPos = mFile->Tell();
  857. mFile->Seek(language.OffsetToData+mResourceDataPosition, 0);
  858. //
  859. // Get the Data attributes for this file.
  860. //
  861. ReadDWord(data.OffsetToData);
  862. ReadDWord(data.Size);
  863. ReadDWord(data.CodePage);
  864. ReadDWord(data.Reserved);
  865. //
  866. // The data offset is VIRTUAL. 
  867. // However it is relative to the VIRTUAL address of the section 
  868. // we are currently in.  This adjusts for that, giving us the physical location of the resource.
  869. //
  870. data.OffsetToData -= mResSectionVirtualAddress;
  871. //
  872. // Okay cache the data. 
  873. //
  874. XResCacheEntry*  newentry = new XResCacheEntry;
  875. HX_ASSERT_VALID_PTR(newentry);
  876. if (!newentry)
  877. {
  878.          return HXR_OUTOFMEMORY;
  879. }
  880. memset(newentry, 0, sizeof(XResCacheEntry));
  881. newentry->type     = type.Name;
  882. newentry->id     = id.Name;
  883. newentry->language  = language.Name;
  884. newentry->size     = data.Size + sizeof(kEndOfResourceMarker);
  885. newentry->location  = data.OffsetToData + mResourceDataPosition;
  886. //
  887. // Add the entry to the cache for later.
  888. //
  889. mCacheList->AddTail(newentry);
  890. //
  891. // Seek back to the next language directory entry.
  892. //
  893. mFile->Seek(curLangPos,0);
  894.     }
  895.     //
  896.     // Seek back to the next ID directory entry
  897.     //
  898.     
  899.     mFile->Seek(curIdPos,0);
  900. }
  901. //
  902. // Reset to the position in the file where the next resource branch starts.
  903. //
  904. mFile->Seek(curtoplevelpos,0);
  905.     }
  906.     return HXR_OK;
  907. }
  908. HX_RESULT CHXXResFile::GetResourceEntry(HX_IMAGE_RESOURCE_DIRECTORY_ENTRY& h)
  909. {
  910.     IF_ERROR_RETURN(ReadDWord(h.Name));
  911.     IF_ERROR_RETURN(ReadDWord(h.OffsetToData));
  912.     return HXR_OK;
  913. }
  914. HX_RESULT CHXXResFile::GetResourceDirEntry(HX_IMAGE_RESOURCE_DIRECTORY&      h)
  915. {
  916.     IF_ERROR_RETURN(ReadDWord(h.Characteristics));
  917.     IF_ERROR_RETURN(ReadDWord(h.TimeDateStamp));
  918.     IF_ERROR_RETURN(ReadWord(h.MajorVersion));
  919.     IF_ERROR_RETURN(ReadWord(h.MinorVersion));
  920.     IF_ERROR_RETURN(ReadWord(h.NumberOfNamedEntries));
  921.     IF_ERROR_RETURN(ReadWord(h.NumberOfIdEntries));
  922.     return HXR_OK;
  923. }
  924. HX_RESULT CHXXResFile::FindInCache(ULONG32  type,   ULONG32 ID,  XResCacheEntry** ppEntry)
  925. {
  926.     if (!mCacheList) 
  927.     {
  928.         return HXR_OK;
  929.     }
  930.     HX_ASSERT(ppEntry);
  931.     //
  932.     // Scan all entries looking for the matching type, and id. 
  933.     //
  934.     
  935.     XResCacheEntry*  curEntry = NULL;
  936.     
  937.     LISTPOSITION  listpos = mCacheList->GetHeadPosition();
  938.     
  939.     while (listpos)
  940.     {
  941. curEntry=(XResCacheEntry*) mCacheList->GetNext(listpos);
  942. if (curEntry->type == type && 
  943.     curEntry->id == ID && 
  944.     curEntry->language == mLanguageId)
  945. {
  946.     *ppEntry=curEntry;
  947.     return HXR_OK;
  948. }
  949.     }
  950.     
  951.     if (curEntry->type == type && 
  952. curEntry->id == ID && 
  953. curEntry->language == mLanguageId)
  954.     {
  955. *ppEntry=curEntry;
  956. return HXR_OK;
  957.     }
  958.     return HXR_RESOURCE_NOT_CACHED;
  959. }
  960. STDMETHODIMP
  961. CHXXResFile::GetFirstResourceLanguage(REF(UINT32) ulLangID)
  962. {
  963.     HX_RESULT rc = HXR_FAIL;
  964.     if(mCacheList)
  965.     {
  966. mCachePos = mCacheList->GetHeadPosition();
  967. if(mCachePos)
  968. {
  969.     XResCacheEntry* pEntry = (XResCacheEntry*)mCacheList->
  970.     GetNext(mCachePos);
  971.     if(pEntry)
  972.     {
  973. ulLangID = pEntry->language;
  974.     }
  975.     rc = HXR_OK;
  976. }
  977.     }
  978.     return rc;
  979. }
  980. STDMETHODIMP
  981. CHXXResFile::GetNextResourceLanguage(REF(UINT32) ulLangID)
  982. {
  983.     HX_RESULT rc = HXR_FAIL;
  984.     if(mCacheList &&
  985. mCachePos)
  986.     {
  987. XResCacheEntry* pEntry = (XResCacheEntry*)mCacheList->
  988.     GetNext(mCachePos);
  989. if(pEntry)
  990. {
  991.     ulLangID = pEntry->language;
  992. }
  993. rc = HXR_OK;
  994.     }
  995.     return rc;
  996. }
  997. const int SIZEOF_VS_VERSION_KEY = 32; // (strlen("VS_VERSION_INFO") + 1) * 2
  998. const int SIZEOF_FILE_INFO_KEY  = 30; // (strlen("StringFileInfo") + 1) * 2
  999. static UINT32
  1000. GetPadding(BYTE* pOrigin, BYTE* pCur)
  1001. {
  1002.     // return number of bytes of padding needed
  1003.     // to align pCur on a 32-bit boundary
  1004.     HX_ASSERT(pCur >= pOrigin);
  1005.     UINT32 ulOffset = pCur - pOrigin;
  1006.     return ulOffset % 4;
  1007. }
  1008. BYTE*
  1009. CHXXResFile::GetResInfo(BYTE* pData, UINT16& uResInfoLen, 
  1010. UINT16& uResInfoType, CHXString& key)
  1011. {
  1012.     // parses a res info struct and returns the
  1013.     // offset to the 'Children' or 'Value' member
  1014.     BYTE* pStart = pData;
  1015.     uResInfoLen = *((UINT16*)pData); pData += sizeof(UINT16);
  1016.     ReverseWORD(uResInfoLen);
  1017.     UINT16 ulValueLen = *((UINT16*)pData); pData += sizeof(UINT16);
  1018.     ReverseWORD(ulValueLen);
  1019.     uResInfoType = *((UINT16*)pData); pData += sizeof(UINT16);
  1020.     ReverseWORD(uResInfoType);
  1021.     UINT32 ulStringMemLen = StringMemLength((const char*)pData);
  1022.     char* pAsciiString = new char[ulStringMemLen];
  1023.     ProcessFromUnicode((const char*)pData, (UINT16)ulStringMemLen, 
  1024. pAsciiString, (UINT16)ulStringMemLen);
  1025.     key = pAsciiString;
  1026.     delete[] pAsciiString;
  1027.     pData += ulStringMemLen;
  1028.     pData += GetPadding(pStart, pData);
  1029.     return pData;
  1030. }
  1031. STDMETHODIMP_(BOOL)
  1032. CHXXResFile::IncludesShortName(const char* pShortName)
  1033. {
  1034.     // walk through the resource VERSION information
  1035.     // to find the string key 'ShortName', then
  1036.     // see if pShortName is contained in those values
  1037.     BOOL bFound = FALSE;
  1038.     IHXXResource* pRes = GetVersionInfo();
  1039.     if(pRes)
  1040.     {
  1041. BYTE* pData = (BYTE*)pRes->ResourceData();
  1042. BYTE* pStart = pData;
  1043. // walk through VS_VERSION_INFO 
  1044. UINT16 vsInfoLen = *((UINT16*)pData); pData += sizeof(UINT16);
  1045. ReverseWORD(vsInfoLen);
  1046. UINT16 vsInfoValueLen = *((UINT16*)pData); pData += sizeof(UINT16);
  1047. ReverseWORD(vsInfoValueLen);
  1048. pData += sizeof(UINT16);    // skip type
  1049. pData += SIZEOF_VS_VERSION_KEY;
  1050. pData += GetPadding(pStart, pData);
  1051. pData += vsInfoValueLen;    // skip over VS_FIXEDFILEINFO
  1052. pData += GetPadding(pStart, pData);
  1053. CHXString keyStr;
  1054. UINT16 uResInfoLen = 0;
  1055. UINT16 uResInfoType = 0;
  1056. BYTE* pEndOfData = pStart + vsInfoLen;
  1057. while(pData < pEndOfData &&
  1058.       !bFound)
  1059. {
  1060.     // find 'StringFileInfo'
  1061.     pData = GetResInfo(pData, uResInfoLen, uResInfoType, keyStr);
  1062.     if(strcasecmp((const char*)keyStr, "StringFileInfo") == 0)
  1063.     {
  1064. BYTE* pDataEnd = pData + uResInfoLen;
  1065. // get string table
  1066. pData = GetResInfo(pData, uResInfoLen, uResInfoType, keyStr);
  1067. while(pData < pDataEnd &&
  1068.     !bFound)
  1069. {
  1070.     // get string name/value pairs
  1071.     pData = GetResInfo(pData, uResInfoLen, uResInfoType, keyStr);
  1072.     // pData now points to a UNICODE value
  1073.     UINT32 ulStringMemLen = StringMemLength((const char*)pData);
  1074.     char* pAsciiString = new char[ulStringMemLen];
  1075.     ProcessFromUnicode((const char*)pData, (UINT16)ulStringMemLen, 
  1076. pAsciiString, (UINT16)ulStringMemLen);
  1077.     if(strcasecmp((const char*)keyStr, "ShortName") == 0)
  1078.     {
  1079. if(strstr(pAsciiString, pShortName))
  1080. {
  1081.     bFound = TRUE;
  1082. }
  1083.     }
  1084.     delete[] pAsciiString;
  1085.     pData += ulStringMemLen;
  1086.     pData += GetPadding(pStart, pData);
  1087. }
  1088.     }
  1089. }
  1090. HX_RELEASE(pRes);
  1091.     }
  1092. #if defined (_MACINTOSH) || defined (_UNIX) /* version resource type not supported */
  1093.     bFound = TRUE;
  1094. #endif
  1095.     return bFound;    // not implemented yet...
  1096. }
  1097. //
  1098. // This function dumps the entire contents of the cache.
  1099. //
  1100. HX_RESULT CHXXResFile::KillCache(void)
  1101. {
  1102.     if (!mCacheList) 
  1103.     {
  1104.         return HXR_OK;
  1105.     }
  1106.     //
  1107.     // Scan all entries killing off any cached data.
  1108.     //
  1109.     XResCacheEntry*  curEntry = NULL;
  1110.     LISTPOSITION listpos = mCacheList->GetHeadPosition();
  1111.     
  1112.     while (listpos)
  1113.     {
  1114. curEntry = (XResCacheEntry*)mCacheList->GetAt(listpos);
  1115. if (curEntry->cached == TRUE)
  1116. {
  1117.     HX_ASSERT(curEntry->cached_data);
  1118.     if (curEntry->cached_data != NULL)
  1119.     {
  1120. delete [] curEntry->cached_data;
  1121. curEntry->cached_data = NULL;
  1122.     }
  1123. }
  1124. mCacheList->RemoveAt(listpos);
  1125. delete curEntry;
  1126. listpos = mCacheList->GetHeadPosition();
  1127.     }
  1128.     return HXR_OK;
  1129. }
  1130. HX_RESULT CHXXResFile::TrimCachedData(ULONG32 needed)
  1131. {
  1132.     if (needed > mMaxCachedData)
  1133.     {
  1134. FlushCache();
  1135. return HXR_OK;
  1136.     }
  1137.     if (mLoadedCache->GetCount()==0) 
  1138.     {
  1139. return HXR_OK;
  1140.     }
  1141.     LISTPOSITION listpos = mLoadedCache->GetHeadPosition();
  1142.     ULONG32 totalcached = 0;
  1143.     XResCacheEntry*                     curEntry;
  1144.     while (listpos)
  1145.     {
  1146. curEntry = (XResCacheEntry*)mLoadedCache->GetNext(listpos);
  1147. totalcached += curEntry->size;
  1148.     }
  1149.     
  1150.     // never get out of this loop
  1151.     while (mLoadedCache->GetCount() && 
  1152.     needed + totalcached > mMaxCachedData)
  1153.     {
  1154. //
  1155. // Find the largest thing and trash it.
  1156. //
  1157. LISTPOSITION savepos=NULL;
  1158. ULONG32 largestItem = 0;
  1159. listpos = mLoadedCache->GetHeadPosition();
  1160. while (listpos)
  1161. {
  1162.     curEntry = (XResCacheEntry*)mLoadedCache->GetAt(listpos);
  1163.     if (curEntry->size > largestItem)
  1164.     {
  1165. savepos = listpos;
  1166. largestItem = curEntry->size;
  1167.     }
  1168.     mLoadedCache->GetNext(listpos);
  1169. }
  1170. HX_ASSERT( savepos );
  1171. curEntry = (XResCacheEntry*)mLoadedCache->GetAt(savepos);
  1172.     HX_ASSERT(curEntry->cached && curEntry->cached_data);
  1173. delete [] curEntry->cached_data;
  1174. curEntry->cached_data = NULL;
  1175. curEntry->cached = FALSE;
  1176. totalcached -= curEntry->size;
  1177. mLoadedCache->RemoveAt(savepos);
  1178.     }
  1179.     return HXR_OK;
  1180. }
  1181. UINT32
  1182. CHXXResFile::GetCodePage()
  1183. {
  1184.     if(!m_nCodePage)
  1185.     {
  1186. m_nCodePage = 1252; // Default code page.
  1187. IHXXResource* pRes = GetVersionInfo();
  1188. if(pRes)
  1189. {
  1190.     BYTE* pData = (BYTE*)pRes->ResourceData();
  1191.     BYTE* pStart = pData;
  1192.     
  1193.     // walk through VS_VERSION_INFO 
  1194.     UINT16 vsInfoLen = *((UINT16*)pData); pData += sizeof(UINT16);
  1195.     ReverseWORD(vsInfoLen);
  1196.     UINT16 vsInfoValueLen = *((UINT16*)pData); pData += sizeof(UINT16);
  1197.     ReverseWORD(vsInfoValueLen);
  1198.     pData += sizeof(UINT16);    // skip type
  1199.     pData += SIZEOF_VS_VERSION_KEY;
  1200.     pData += GetPadding(pStart, pData);
  1201.     pData += vsInfoValueLen;    // skip over VS_FIXEDFILEINFO
  1202.     pData += GetPadding(pStart, pData);
  1203.     CHXString keyStr;
  1204.     UINT16 uResInfoLen = 0;
  1205.     UINT16 uResInfoType = 0;
  1206.     BYTE* pEndOfData = pStart + vsInfoLen;
  1207.     while(pData < pEndOfData)
  1208.     {
  1209. // find 'StringFileInfo'
  1210. pData = GetResInfo(pData, uResInfoLen, uResInfoType, keyStr);
  1211. if(strcasecmp((const char*)keyStr, "StringFileInfo") == 0)
  1212. {
  1213.     // get string table
  1214.     pData = GetResInfo(pData, uResInfoLen, uResInfoType, keyStr);
  1215.     if(keyStr.GetLength() == 8)
  1216.     {
  1217. m_nCodePage = strtoul(keyStr.Right(4), NULL, 16);
  1218. break;
  1219.     }
  1220. }
  1221.     }
  1222. }
  1223. HX_RELEASE(pRes);
  1224.     }
  1225.     return m_nCodePage;
  1226. }
  1227. //
  1228. //
  1229. // CHXXResource methods
  1230. //
  1231. // This object is returned from a call to CHXXResFile::GetResource
  1232. //
  1233. #ifdef _MACINTOSH
  1234. #pragma mark -
  1235. #pragma mark ***CHXXResource Entries***
  1236. #pragma mark -
  1237. #endif
  1238. CHXXResource::CHXXResource (void* data,
  1239.     ULONG32 datalength, 
  1240.     ULONG32 ID, 
  1241.     ULONG32 Type, 
  1242.     ULONG32 Language,
  1243.     IHXXResFile*  file)
  1244. {
  1245.     HX_ASSERT(data);
  1246.     HX_ASSERT(file);
  1247.     
  1248.     m_lRefCount = 0;
  1249.     mResFile = file;
  1250.     mResData = data;
  1251.     mID = ID;
  1252.     mType = Type;
  1253.     mLength = datalength;
  1254.     mLanguage = Language;
  1255.     mResFile->AddRef();
  1256. }
  1257. CHXXResource::~CHXXResource()
  1258. {
  1259.     if (mResData)
  1260.     {
  1261. delete [] mResData;
  1262. mResData = NULL;
  1263.     }
  1264.     
  1265.     if (mResFile)
  1266.     {
  1267. mResFile->Release();
  1268.     }
  1269. }
  1270. /*
  1271.  * QueryInterface
  1272.  * --------------
  1273.  * Used to get interfaces supported by us.
  1274.  *
  1275.  * input:
  1276.  * REFIID riid - Id of interface.
  1277.  * void **ppvObj - Place to copy interface pointer.
  1278.  *
  1279.  */
  1280. STDMETHODIMP 
  1281. CHXXResource::QueryInterface
  1282. (
  1283.     REFIID riid, 
  1284.     void** ppvObj
  1285. )
  1286. {
  1287.     QInterfaceList qiList[] =
  1288.         {
  1289.             { GET_IIDHANDLE(IID_IHXXResource), (IHXXResource*)this },
  1290.             { GET_IIDHANDLE(IID_IHXXResFile), (IHXXResFile*)mResFile },
  1291.             { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IHXXResource*)this },
  1292.         };
  1293.     
  1294.     return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
  1295. }
  1296. /* 
  1297.  * AddRef
  1298.  * ------
  1299.  * Increments the ref count by one.
  1300.  *
  1301.  * input:
  1302.  * void
  1303.  *
  1304.  * output:
  1305.  * ULONG32 - The count.
  1306.  *
  1307.  */
  1308. STDMETHODIMP_ (ULONG32) 
  1309. CHXXResource::AddRef
  1310. (
  1311.     void
  1312. )
  1313. {
  1314.     return InterlockedIncrement(&m_lRefCount);
  1315. }
  1316. /*
  1317.  * Release
  1318.  * -------
  1319.  * Decrements the ref count by one, deleting 
  1320.  * self if count reaches zero.
  1321.  *
  1322.  * input:
  1323.  * void
  1324.  * 
  1325.  * output:
  1326.  * ULONG32 - Current ref count.
  1327.  *
  1328.  */
  1329. STDMETHODIMP_(ULONG32) 
  1330. CHXXResource::Release
  1331. (
  1332.     void
  1333. )
  1334. {
  1335.     // Decrement, return count if possible.
  1336.     if (InterlockedDecrement(&m_lRefCount) > 0) return m_lRefCount; 
  1337.     // Else, delete self.
  1338.     delete this;
  1339.     return 0;
  1340. }
  1341. //
  1342. // Functions for determining information from a loaded resource.
  1343. //
  1344. STDMETHODIMP_(ULONG32) CHXXResource::ID (void)
  1345. {
  1346.     return mID;
  1347. }
  1348. STDMETHODIMP_(ULONG32) CHXXResource::Type (void)
  1349. {
  1350.     return mType;
  1351. }
  1352. STDMETHODIMP_(ULONG32) CHXXResource::Length (void)
  1353. {
  1354.     return mLength;
  1355. }
  1356. STDMETHODIMP_(ULONG32) CHXXResource::Language (void)
  1357. {
  1358.     return mLanguage;
  1359. }
  1360. STDMETHODIMP_(IHXXResFile*) CHXXResource::ResFile (void)
  1361. {
  1362.     IHXXResFile* result = NULL;
  1363.     QueryInterface(IID_IHXXResFile, (void**)&result);
  1364.     return result;
  1365. }
  1366. //
  1367. // Data accessors
  1368. //
  1369. STDMETHODIMP_(void*) CHXXResource::ResourceData (void)
  1370. {
  1371.     return mResData;
  1372. }