home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Snippets / JPartialResources 1.0.1 / JPartialResources.c next >
Encoding:
C/C++ Source or Header  |  1992-10-10  |  8.3 KB  |  327 lines  |  [TEXT/KAHL]

  1. /*
  2.  * JPartialResources.c
  3.  *
  4.  * Jamie's partial resource calls that work under any system.
  5.  * © Copyright 1992 by Jamie R. McCarthy.  All rights reserved.
  6.  * This code can be both distributed and used freely.
  7.  * Internet: k044477@kzoo.edu            AppleLink: j.mccarthy
  8.  * Telephone:  800-421-4157 or US 616-665-7075 (9:00-5:00 Eastern time)
  9.  * I'm releasing this code with the hope that someone will get something
  10.  * out of it.  Feedback of any sort, even just letting me know that you're
  11.  * using it, is greatly appreciated!
  12.  *
  13.  *
  14.  * "Be aware that having a copy of a resource in memory when you are using
  15.  *  the partial resource routines may cause problems.  If you have modified
  16.  *  the copy in memory and then access the resource on disk using either
  17.  *  the ReadPartialResource or WritePartialResource procedure, you will
  18.  *  lose changes made to the copy in memory."  - IM VI, 13-21
  19.  *
  20.  * By "copy in memory," this refers to having the entire resource loaded in.
  21.  * What it's saying is that ReadPartialResource and WritePartialResource
  22.  * consider themselves free to always purge (and maybe reload) the resource
  23.  * handle.  Incidentally, this code doesn't do that--it read directly from
  24.  * disk--so if you're under system 6, your copy of the resource is safe.
  25.  * (Memory may be moved, however, so if the resource is purgeable, it _may_
  26.  * be purged.)
  27.  *
  28.  *
  29.  * "...there's really no reason to access resources directly."  - IM IV-16.
  30.  *
  31.  * Yeah right.
  32.  *
  33.  */
  34.  
  35.  
  36.  
  37. /******************************/
  38.  
  39. #include "JPartialResources.h"
  40.  
  41. /******************************/
  42.  
  43. #include <GestaltEqu.h>
  44.  
  45. /******************************/
  46.  
  47. #define kUninitializedFlag (42)
  48. Boolean partialResourceCallsAreAvailable = kUninitializedFlag;
  49.  
  50. void determineWhetherPRCallsAreAvailable(void);
  51.  
  52. /******************************/
  53.  
  54. typedef struct {
  55.     unsigned long        offsetToRsrcData;
  56.     unsigned long        offsetToRsrcMap;
  57.     unsigned long        lengthOfRsrcData;
  58.     unsigned long        lengthOfRsrcMap;
  59. } rsrcForkHeader;
  60.  
  61. typedef struct {
  62.     short                    rsrcID;
  63.     short                    offsetToRsrcName;
  64.     unsigned long        rsrcAttrs : 8;
  65.     unsigned long        offsetToRsrcData : 24;
  66.     Handle                rsrcHndl;
  67. } rsrcReference;
  68.  
  69. struct rsrcMap;
  70. typedef struct rsrcMap rsrcMap, *rsrcMapPtr, **rsrcMapHndl;
  71. struct rsrcMap {
  72.     rsrcForkHeader        copyOfRsrcForkHeader;
  73.     rsrcMapHndl            nextRsrcMapHndl;
  74.     short                    fileRefNum;
  75.     short                    fileAttrs;
  76.     unsigned short        offsetToTypeList;
  77.     unsigned short        offsetToNameList;
  78. } ;
  79.  
  80. /******************************/
  81.  
  82.         /*
  83.          * Lower-level internal functions.
  84.          */
  85.         
  86.     /*
  87.      * Just as _HomeResFile returns the refNum of a resource's file,
  88.      * so does getHomeRsrcMap() return a pointer to the resource
  89.      * file's map.  Warning--any calls that may move memory,
  90.      * including system memory, invalidate the pointer!
  91.      */
  92. rsrcMapPtr getHomeRsrcMap(Handle theResource);
  93.  
  94.     /*
  95.      * This uses _RsrcMapEntry and getHomeRsrcMap() to find the
  96.      * offset from the beginning of a resource fork to the start of
  97.      * a resource's reference.
  98.      */
  99. long getRsrcRefOffsetIntoFile(Handle theResource);
  100.  
  101. /******************************/
  102.  
  103.         /*
  104.          * Higher-level internal functions.
  105.          */
  106.         
  107.     /*
  108.      * This uses getRsrcRefOffsetIntoFile() and FSRead() to find
  109.      * the offset from the beginning of a resource fork to the start
  110.      * of a resource's data.  The offset points to the data itself,
  111.      * which is just past the longword that tells its size.  If you
  112.      * happen to want the size too, use _SizeResource.
  113.      */
  114. long getRsrcDataOffsetIntoFile(Handle theResource);
  115.  
  116. long getRsrcFileMark(Handle theResource);
  117. void setRsrcFileMark(Handle theResource, long newMark);
  118.  
  119. /******************************/
  120.  
  121.  
  122.  
  123. void jReadPartialResource(Handle theResource, long offset, void *buffer, long count)
  124. {
  125.     if (partialResourceCallsAreAvailable == kUninitializedFlag) {
  126.         determineWhetherPRCallsAreAvailable();
  127.     }
  128.     
  129.     if (partialResourceCallsAreAvailable) {
  130.         ReadPartialResource(theResource, offset, buffer, count);
  131.     } else {
  132.         
  133.         long theRsrcDataOffset;
  134.         long theRsrcDataLength;
  135.         OSErr theErr;
  136.         long oldMark;
  137.         
  138.         oldMark = getRsrcFileMark(theResource);
  139.         theRsrcDataOffset = getRsrcDataOffsetIntoFile(theResource);
  140.         if (theRsrcDataOffset < 0) return ;
  141.         setRsrcFileMark(theResource, theRsrcDataOffset + offset);
  142.         theErr = FSRead( HomeResFile(theResource), &count, buffer );
  143.         setRsrcFileMark(theResource, oldMark);
  144.         
  145.     }
  146. }
  147.  
  148.  
  149.  
  150. void jWritePartialResource(Handle theResource, long offset, void *buffer, long count)
  151. {
  152.     if (partialResourceCallsAreAvailable == kUninitializedFlag) {
  153.         determineWhetherPRCallsAreAvailable();
  154.     }
  155.     
  156.         /*
  157.          * Disallow writing past the end of the resource;
  158.          * try to increase its size if possible.
  159.          */
  160.     if (SizeResource(theResource) < offset+count) {
  161.         jSetResourceSize(theResource, offset+count);
  162.     }
  163.     
  164.         /*
  165.          * Check to be sure the size was successfully increased
  166.          * before continuing.
  167.          */
  168.     if (SizeResource(theResource) < offset+count) {
  169.         return ;
  170.     }
  171.     
  172.     if (partialResourceCallsAreAvailable) {
  173.         WritePartialResource(theResource, offset, buffer, count);
  174.     } else {
  175.         
  176.         long theRsrcDataOffset;
  177.         OSErr theErr;
  178.         long oldMark;
  179.         
  180.         oldMark = getRsrcFileMark(theResource);
  181.         theRsrcDataOffset = getRsrcDataOffsetIntoFile(theResource);
  182.         if (theRsrcDataOffset < 0) return;
  183.         setRsrcFileMark(theResource, theRsrcDataOffset + offset);
  184.         theErr = FSWrite( HomeResFile(theResource), &count, buffer );
  185.         setRsrcFileMark(theResource, oldMark);
  186.         
  187.     }
  188. }
  189.  
  190.  
  191.  
  192. void jSetResourceSize(Handle theResource, long size)
  193. {
  194.     if (partialResourceCallsAreAvailable == kUninitializedFlag) {
  195.         determineWhetherPRCallsAreAvailable();
  196.     }
  197.     
  198.     if (partialResourceCallsAreAvailable) {
  199.         SetResourceSize(theResource, size);
  200.     } else {
  201.         
  202.         Debugger();
  203.         
  204.     }
  205. }
  206.  
  207.  
  208.  
  209. void determineWhetherPRCallsAreAvailable(void)
  210. {
  211.     if (partialResourceCallsAreAvailable == kUninitializedFlag) {
  212.         OSErr theOSErr;
  213.         long theResponse;
  214.         partialResourceCallsAreAvailable = FALSE;
  215. #define kAppleActuallyImplementedTheResourceMgrAttrSelectorInSystem7_0_x (0)
  216. #if kAppleActuallyImplementedTheResourceMgrAttrSelectorInSystem7_0_x
  217.         theOSErr = Gestalt(gestaltResourceMgrAttr, &theResponse);
  218.         if (theOSErr == noErr) {
  219.             if ( (theResponse & 1L<<gestaltPartialRsrcs) != 0 ) {
  220.                 partialResourceCallsAreAvailable = TRUE;
  221.             }
  222.         }
  223. #else
  224.         theOSErr = Gestalt(gestaltSystemVersion, &theResponse);
  225.         if (theOSErr == noErr) {
  226.             if ( (theResponse & 0x0000FFFF) >= 0x0700 ) {
  227.                 partialResourceCallsAreAvailable = TRUE;
  228.             }
  229.         }
  230. #endif
  231.     }
  232. }
  233.  
  234.  
  235.  
  236. /******************************/
  237.  
  238.  
  239.  
  240. rsrcMapPtr getHomeRsrcMap(Handle theResource)
  241. {
  242.     rsrcMapHndl cMapHndl;
  243.     short theRefNum;
  244.     
  245.     theRefNum = HomeResFile(theResource);
  246.     cMapHndl = (rsrcMapHndl) TopMapHndl;
  247.     
  248.     while ( (**cMapHndl).fileRefNum != theRefNum ) {
  249.         cMapHndl = (**cMapHndl).nextRsrcMapHndl;
  250.         if (cMapHndl == NULL) return NULL;
  251.     }
  252.     
  253.     return *cMapHndl;
  254. }
  255.  
  256.  
  257.  
  258. long getRsrcRefOffsetIntoFile(Handle theResource)
  259. {
  260.     long offsetToRsrcRefFromRsrcMap;
  261.     long offsetToRsrcMapFromStartOfFile;
  262.     
  263.     rsrcMapPtr theRsrcMapPtr;
  264.     
  265.     ASSERT(theResource != NULL);
  266.     
  267.     offsetToRsrcRefFromRsrcMap = RsrcMapEntry(theResource);
  268.     if (offsetToRsrcRefFromRsrcMap == 0) {
  269.             /* ResError contains the error. */
  270.         return -1;
  271.     }
  272.     
  273.     theRsrcMapPtr = getHomeRsrcMap(theResource);
  274.     offsetToRsrcMapFromStartOfFile = theRsrcMapPtr->copyOfRsrcForkHeader.offsetToRsrcMap;
  275.     
  276.     return offsetToRsrcMapFromStartOfFile + offsetToRsrcRefFromRsrcMap;
  277. }
  278.  
  279.  
  280.  
  281. long getRsrcDataOffsetIntoFile(Handle theResource)
  282. {
  283.     rsrcReference theRsrcRef;
  284.     long theOffsetToRsrcRef;
  285.     long theOffsetToRsrcData;
  286.     long oldMark;
  287.     OSErr theErr;
  288.     long nBytesToRead;
  289.     
  290.     theOffsetToRsrcRef = getRsrcRefOffsetIntoFile(theResource);
  291.     
  292.     oldMark = getRsrcFileMark(theResource);
  293.     setRsrcFileMark(theResource, theOffsetToRsrcRef);
  294.     nBytesToRead = sizeof(rsrcReference);
  295.     theErr = FSRead( HomeResFile(theResource), &nBytesToRead, &theRsrcRef);
  296.     setRsrcFileMark(theResource, oldMark);
  297.     
  298.     if (theErr != noErr || nBytesToRead < sizeof(rsrcReference)) {
  299.         return -1;
  300.     }
  301.     
  302.     theOffsetToRsrcData = theRsrcRef.offsetToRsrcData
  303.         + 0x0100            // add in the length of the resource header
  304.         + 4;                // skip over the longword that tells the resource's length
  305.     return theOffsetToRsrcData;
  306. }
  307.  
  308.  
  309.  
  310. long getRsrcFileMark(Handle theResource)
  311. {
  312.     OSErr theErr;
  313.     long theMark;
  314.     ASSERT(theResource != NULL);
  315.     theErr = GetFPos( HomeResFile(theResource), &theMark );
  316.     if (theErr != noErr) theMark = -1;
  317.     return theMark;
  318. }
  319.  
  320.  
  321.  
  322. void setRsrcFileMark(Handle theResource, long newMark)
  323. {
  324.     ASSERT(theResource != NULL);
  325.     /* theOSErr = */ SetFPos( HomeResFile(theResource), fsFromStart, newMark );
  326. }
  327.