clntxres.cpp
Upload User: zhongxx05
Upload Date: 2007-06-06
Package Size: 33641k
Code Size: 34k
Category:

Symbian

Development Platform:

C/C++

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