Storing Data Stacks inside OSX Bundle

Shari shari at gypsyware.com
Sun Nov 18 09:32:13 EST 2007


I was doing it that way for awhile, storing stacks inside the MacOS 
folder of an OSX bundle.  There are some caveats, but I'll tell you 
how it works.

Right-Click on your application's icon.  A menu will appear.  Select 
"Show Package Contents".

There will be one folder called Contents.  In that folder is a folder 
"MacOS".  This is where you store the stack.  That is also where your 
actual app resides.

First Caveat:  Getting the filepath to the stack.  In your main app 
stack script:

global pathToSaveFile
   put the effective fileName of this stack into pathToSaveFile
   if the platform is "MacOS" then
     repeat 3
       delete the last item of pathToSaveFile
     end repeat
   end if
   put "yourSaveStack.rev" into the last item of pathToSaveFile

This sets you up with a global you can call all thru the program to 
access your save file.

The second caveat is that nowadays, even Macs are getting cranky 
about where their users are allowed to write to.  I just recently 
ended up redoing my whole method of saving data.  If the user cannot 
write to this location, saves will fail.

Here is my alternate solution:

Synopsis:

I name the save stack something other than what I really want it to 
be called, compress it, and store the compressed version in a custom 
property of the main app stack.  Now, it doesn't even exist outside 
the main app stack.  When the user installs the app, it decompresses 
the stack from the custom property, and puts it in a Prefs folder 
someplace writeable on the users computer.  It renames the stack to 
the desired name.  This prevents that awful "Stack in memory, do you 
want to purge?" dialog.

Possible Gotcha:

When your save stack is stored outside the main app folder this way, 
if the user installs an updated version of your app, it will not 
replace the save stack unless you specifically tell it to.  So I 
versioned the stack.  I don't want it to automatically be replaced 
when someone updates, unless I've actually changed that stack.

Full code and instructions to make this all work, along with one final Gotcha:

In a stack with a button with no other purpose but to compress stacks 
and store them as custom properties of other stacks:

on mouseUp

   answer file "Select a stack to store compressed data such as 
yourMainStack.mc"
# yourMainStack.mc has a latestPrefsVersion custom property
   if it is empty then exit to top
   put it into storageStack

   answer file "Select a stack to compress such as prefStack.mc:"
# prefStack.mc has a currentPrefsVersion custom property
   if it is empty then exit to top
   put it into stackToShrink

   put url ("binfile:" & stackToShrink) into s

   set the stackData of stack storageStack to compress(s)
   save stack storageStack

   beep

end mouseUp


If you have multiple stacks that might need to be replaced, you will 
need to version each replaceable stack, I am using custom properties. 
This allows you to independantly replace a stack.  For example, if 
your application is versioned 12, but the prefStack is versioned 10, 
you might not need or want to replace the prefStack.  So you don't 
compare the prefStack version to your main app version, but to the 
prefStack that is compressed inside of your app, assuming someone 
always downloads a completely new app when they upgrade.  Rather than 
decompress the stack and check the version, create a custom property 
in the main app for each replaceable stack, and check against it.

In your startUp routine where you check versions, and replace a stack 
if the compressed custom property is a newer version:

   put the latestPrefsVersion of stack primaryAppStack into newV
   put the currentPrefsVersion of stack prefStack into oldV # UserPrefs
   if oldV is not a number then # for legacy, older stacks weren't versioned
     put 1 into oldV
   end if
   if newV > oldV then
     if "UserPrefs" is in the stacksInUse then
       stop using stack "UserPrefs"
     end if
     if "UserPrefs" is in the openstacks then
       close stack "UserPrefs"
     end if
     delete stack "UserPrefs"
     delete file prefStack
     # if you are using a custom filetype or stackFileType
# set your fileType or stackFileType before decompressing
     put decompress(the stackData of stack yourMainStack.mc) \
         into url ("binfile:" & prefStack)

Final note:  Once I moved the prefStack out of the main application 
folder into a preferences folder somewhere else on the user's 
computer, I encountered another problem that caused me grief.  If I 
edited the stack via "go stack prefStack", I was editing not the 
stack that gets compressed and distributed with the program, but the 
stack that is created in the Preferences folder somewhere.  Now my 
app checks for the environment and loads a stack accordingly.  Only 
if it's a standalone does it launch the prefStack in the Preferences 
folder somewhere, otherwise it launches the prefStack that is in the 
same folder as the app during development.  The one that gets 
compressed into a custom property.





>I saw that someone else was doing this... you can store a "main" 
>stack (which needs to be saved) inside the standalone, splash screen 
>engine stack's bundle... and seems to all work just fine...
>
>This has the obvious advantage of making sure they don't get 
>separated, user just sees a single application file.
>
>any caveats to keep in mind? (besides the obvious one of the data 
>stack getting out  on upgrade)
>
>skts


-- 
WlND0WS and MAClNT0SH shareware games
BIackjack GoId
http://www.gypsyware.com



More information about the use-livecode mailing list