SetIndString.c

/*
    File:       SetIndString.c
 
    Contains:   I have been reviewing your question on how to set the contents of STR# resources
                from your program.
 
                As it turns out, there is no Toolbox call to do this, mostly because resources are
                not meant to store data which changes frequently.  I have a solution to your
                problem, but it comes with a warning: PLEASE DON'T CHANGE ANY OF YOUR APPLICATIONS
                RESOURCES WHILE RUNNING.  Doing so will make it impossible for your program to run
                off of a fileserver or locked volume.
 
                That out of the way the format of an STR# resource is:
 
                2 bytes       number of strings
                -------------------------------
                1 byte        length of 1st str
                (variable)    1st string data
                -------------------------------
                1 byte        length of nth str
                (variable)    nth string data
                ...
                ...
 
                Note that the indexes into the strings are not at set positions, but instead are
                relative to the lengths of the previous strings.
 
                Finally, here's a C function, SetIndString() which takes the same parameters as
                GetIndString().  This call does the opposite, namely, it sets a particular STR#
                string to the passed in string:
                
    Written by:     
 
    Copyright:  Copyright © 1984-1999 by Apple Computer, Inc., All Rights Reserved.
 
                You may incorporate this Apple sample source code into your program(s) without
                restriction. This Apple sample source code has been provided "AS IS" and the
                responsibility for its operation is yours. You are not permitted to redistribute
                this Apple sample source code as "Apple sample source code" after having made
                changes. If you're going to re-distribute the source, we require that you make
                it clear in the source that the code was descended from Apple sample source
                code, but that you've made changes.
 
    Change History (most recent first):
                8/9/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
                
 
*/
 
OSErr SetIndString(StringPtr theStr,short resID,short strIndex)
{
   Handle theRes;               /* handle pointing to STR# resource */
   short numStrings;            /* number of strings in STR# */
   short ourString;             /* counter to index up to strIndex */
   char *resStr;                /* string pointer to STR# string to replace */
   long oldSize;                /* size of STR# resource before call */
   long newSize;                /* size of STR# resource after call */
   unsigned long offset;        /* resource offset to str to replace*/
 
   /* make sure index is in bounds */
 
   if (resID < 1)
   return -1;
 
   /* make sure resource exists */
 
   theRes = GetResource('STR#',resID);
   if (ResError()!=noErr)
   return ResError();
   if (!theRes || !(*theRes))
   return resNotFound;
 
   HLock(theRes);
   HNoPurge(theRes);
 
   /* get # of strings in STR# */
 
   BlockMove(*theRes,&numStrings,sizeof(short));
   if (strIndex > numStrings)
   return resNotFound;
 
   /* get a pointer to the string to replace */
 
   offset = sizeof(short);
   resStr = (char *) *theRes + sizeof(short);
   for (ourString=1; ourString<strIndex; ourString++) {
   offset += 1+resStr[0];
   resStr += 1+resStr[0];
   }
 
   /* grow/shrink resource handle to make room for new string */
 
   oldSize = GetHandleSize(theRes);
   newSize = oldSize - resStr[0] + theStr[0];
   HUnlock(theRes);
   SetHandleSize(theRes,newSize);
   if (MemError()!=noErr) {
   ReleaseResource(theRes);
   return -1;
   }
   HLock(theRes);
   resStr = *theRes + offset;
 
   /* move old data forward/backward to make room */
 
   BlockMove(resStr+resStr[0]+1, resStr+theStr[0]+1, oldSize-offset-resStr[0]-1
 
   /* move new data in */
 
   BlockMove(theStr,resStr,theStr[0]+1);
 
   /* write resource out */
 
   ChangedResource(theRes);
   WriteResource(theRes);
   HPurge(theRes);
   ReleaseResource(theRes);
 
   return ResError();
}
 
----------