Source release of Wolfenstein 3D Classic Platinum for iOS, 1.2
authorTravis Bradshaw <travis.bradshaw@idsoftware.com>
Tue, 31 Jan 2012 22:57:34 +0000 (16:57 -0600)
committerTravis Bradshaw <travis.bradshaw@idsoftware.com>
Tue, 31 Jan 2012 22:57:34 +0000 (16:57 -0600)
45 files changed:
wolf3d/code/env/common.h
wolf3d/code/env/fileio.c
wolf3d/code/env/files.c
wolf3d/code/env/filesystem.h
wolf3d/code/env/sound.c
wolf3d/code/env/sound_sfx_id.c
wolf3d/code/env/texture_manager.c
wolf3d/code/iphone/EAGLView.h
wolf3d/code/iphone/EAGLView.m
wolf3d/code/iphone/FSCopyObject.c [new file with mode: 0644]
wolf3d/code/iphone/FSCopyObject.h [new file with mode: 0644]
wolf3d/code/iphone/GenLinkedList.c [new file with mode: 0644]
wolf3d/code/iphone/GenLinkedList.h [new file with mode: 0644]
wolf3d/code/iphone/Info.plist
wolf3d/code/iphone/arialGlyphRects.h [new file with mode: 0644]
wolf3d/code/iphone/default.png
wolf3d/code/iphone/gles_glue.c
wolf3d/code/iphone/hud.c
wolf3d/code/iphone/iphone_alerts.h [new file with mode: 0644]
wolf3d/code/iphone/iphone_alerts.m [new file with mode: 0644]
wolf3d/code/iphone/iphone_downloadSOD.m [new file with mode: 0644]
wolf3d/code/iphone/iphone_downloadUserMap.m [new file with mode: 0644]
wolf3d/code/iphone/iphone_loop.c
wolf3d/code/iphone/iphone_main.c
wolf3d/code/iphone/iphone_mapselector.c [new file with mode: 0644]
wolf3d/code/iphone/iphone_menus.c
wolf3d/code/iphone/iphone_wolf.h
wolf3d/code/iphone/wolf3d.xcodeproj/greghodges.mode1v3 [new file with mode: 0644]
wolf3d/code/iphone/wolf3d.xcodeproj/greghodges.pbxuser [new file with mode: 0644]
wolf3d/code/iphone/wolf3d.xcodeproj/project.pbxproj
wolf3d/code/iphone/wolf3dAppDelegate.h
wolf3d/code/iphone/wolf3dAppDelegate.m
wolf3d/code/iphone/wolf3d_icon.png
wolf3d/code/wolf/wolf_actor_ai.c
wolf3d/code/wolf/wolf_ai_com.c
wolf3d/code/wolf/wolf_client_main.c
wolf3d/code/wolf/wolf_level.c
wolf3d/code/wolf/wolf_local.h
wolf3d/code/wolf/wolf_main.c
wolf3d/code/wolf/wolf_player.c
wolf3d/code/wolf/wolf_player.h
wolf3d/code/wolf/wolf_powerups.c
wolf3d/code/wolf/wolf_pushwalls.c
wolf3d/code/wolf/wolf_renderer.c
wolf3d/code/wolfiphone.h

index ad0d4865e37efc9c19304f14eecd2d3fef43eec7..44f51217bf535f5b7f60ec3975a638ef298323d2 100644 (file)
@@ -181,6 +181,7 @@ extern void Client_Init( void );
 #define        BUTTON_ATTACK           1
 #define        BUTTON_USE                      2
 #define        BUTTON_CHANGE_WEAPON 4
+#define BUTTON_ALTERNATE_ATTACK        8       //gsh
 #define        BUTTON_ANY                      128                     // any key whatsoever
 
 
index 1848e55c118a769179ecc738e3057e79caca14e5..de8917b92a0964d859b39ccb66d6916e2428da6d 100644 (file)
@@ -216,8 +216,6 @@ PUBLIC filehandle_t *FS_OpenFile( const char *filename, W32 FlagsAndAttributes )
                pathBase = iphoneDocDirectory;
                my_snprintf( netpath, sizeof( netpath ), "%s/%s", pathBase, filename );
        } else {
-//             extern char iphoneAppDirectory[1024];
-//             pathBase = iphoneAppDirectory;
                pathBase = FS_Gamedir();
                my_snprintf( netpath, sizeof( netpath ), "%s/%s", pathBase, filename );
        }
@@ -225,7 +223,17 @@ PUBLIC filehandle_t *FS_OpenFile( const char *filename, W32 FlagsAndAttributes )
        // high performance file mapping path, avoiding stdio
        fd = open( netpath, O_RDONLY );
        if ( fd == -1 ) {
-               return NULL;
+//             return NULL; 
+               //if it couldn't be found in that path then check again in the document directory
+               //gsh
+               //pathBase = FS_ForceGamedir(); 
+               extern char iphoneDocDirectory[1024];
+               pathBase = iphoneDocDirectory;
+               my_snprintf( netpath, sizeof( netpath ), "%s/%s", pathBase, filename );
+               fd = open( netpath, O_RDONLY );
+               if ( fd == -1 ) {  //okay, couldn't find it there either... return null
+                       return NULL;
+               }
        }
        fstat( fd, &s );
        
index acd92e21715a8d7f3cfca3c7b6498f3fa31a65cd..cb9fba44f5e7184fc9391ecfb99703e5645d56e3 100644 (file)
@@ -60,7 +60,7 @@
 
 
 PRIVATE char fs_gamedir[ MAX_OSPATH ];
-
+//PRIVATE char fs_soddir[ MAX_OSPATH ]; //gsh
 
 
 /*
@@ -77,8 +77,24 @@ PRIVATE char fs_gamedir[ MAX_OSPATH ];
 */
 PUBLIC char *FS_Gamedir( void )
 {
+       /*
+       //gsh... this is a trick to load in where the iphoneDocDirectory is
+       if (currentMap.episode >= 6)
+       {
+//             sprintf( fs_soddir, "%s/SODbase", iphoneDocDirectory );  //if you're downloading the SOD data
+               sprintf( fs_soddir, "%s/", iphoneDocDirectory );  //if you're only downloading the spear maps
+               return fs_soddir;
+       }*/
+       
        return fs_gamedir;
 }
+/*
+//gsh this is so that we can force a non-SOD folder
+//it's only getting used in the FSOpenFile() of fileio.c
+PUBLIC char *FS_ForceGamedir( void )
+{
+       return fs_gamedir;
+}*/
 
 
 /*
index 59bde7717c3e06ed94de1d742b7043cdead85500..b158fec49e0979700611355e3900400eb58e4cd5 100644 (file)
@@ -45,6 +45,7 @@
 
 extern void    FS_InitFilesystem(void);
 extern char    *FS_Gamedir(void);
+//extern char *FS_ForceGamedir(void); //gsh
 
 
 
index 7ed3524898c1f48c16ee9b06d831ac10b2265726..bd7ecc2ce7a4c88a6784cf2754c9fd24209f2d1a 100644 (file)
@@ -690,7 +690,7 @@ PRIVATE void Sound_Register( void )
 {
        
        s_initSound = Cvar_Get( "s_initSound", "1", CVAR_INIT );        
-       s_masterVolume  = Cvar_Get( "s_masterVolume", "1.0", CVAR_ARCHIVE );
+       s_masterVolume  = Cvar_Get( "s_masterVolume", "0.3", CVAR_ARCHIVE ); //gsh changed this from "1.0" to "0.3" for the volume hack... otherwise it's too loud
        s_sfxVolume             = Cvar_Get( "s_sfxVolume", "1.0", CVAR_ARCHIVE );
        s_musicVolume   = Cvar_Get( "s_musicVolume", "1.0", CVAR_ARCHIVE );
        s_minDistance   = Cvar_Get( "s_minDistance", "0.0", CVAR_ARCHIVE );
index 4c8d11b503aed7f92faa05c8657baf8edc29370a..617552925032b962bb876e17d7abc73c40bf30d8 100644 (file)
@@ -248,33 +248,57 @@ PUBLIC void Sound_BeginRegistration( void )
        s_registering = true;
 }
 
+
 PUBLIC sfx_t *Sound_RegisterSound( const char *name )
 {
        sfx_t   *sfx;
+       bool isSpearSound = false;
 
        if( ! sound_initialized )
        {
                return NULL;
        }
-
-       if( g_version->value == 1 )
+       
+       if( g_version->value == SPEAROFDESTINY  && currentMap.episode >= 6 && strncmp(name, "iphone", 6) && currentMap.episode < 9)//added the episode & iphone check... gsh
        {
+               isSpearSound = true;
+               
                char tempname[ 256 ];
-
                my_snprintf( tempname, sizeof( tempname ), "sod%s", name );
-
                sfx = Sound_FindSound( tempname );
+       
+               //gsh
+               //Com_Printf("Finding Sound: %s\n", tempname);          
        }
        else
        {
                sfx = Sound_FindSound( name );
+               
+               //gsh
+               //Com_Printf("Finding Sound: %s\n", name);
        }
-
+/*
+       //original
        if( ! s_registering )
        {
                Sound_LoadSound( sfx );
        }
-
+*/
+       //gsh
+       if( ! s_registering )
+       {
+               //if it couldn't be found and we tried finding it in sod
+               //then it might exist in wolf3d
+               if( !Sound_LoadSound( sfx ) && isSpearSound)
+               {
+                       sfx = Sound_FindSound( name );          
+                       //Com_Printf("Finding Sound Again: %s\n", name);
+                       
+                       if( ! s_registering )
+                               Sound_LoadSound( sfx );  //try loading again
+               }
+       }
+       
        return sfx;
 }
 
index 18c16a8fb365674b03374abc30fabc2f51c4af7a..d960d1d89b96ac6df53718ccc1f8a352cd4a1d47 100644 (file)
@@ -464,14 +464,14 @@ PUBLIC texture_t *TM_FindTexture( const char *name, texturetype_t type )
        {
                return r_notexture;
        }
-       
+
        // Check for file extension
        len = strlen( name );
        if( len < 5 )
        {
                return r_notexture;
        }
-
+       
        // look for it in the texture cache
        for( i = 0, tex = ttextures; i < numttextures; ++i, ++tex )
        {
@@ -490,7 +490,8 @@ PUBLIC texture_t *TM_FindTexture( const char *name, texturetype_t type )
                return r_notexture;
        }
 
-//     Com_Printf( "Loading texture: %s\n", name );
+       //gsh
+       //Com_Printf( "Loading texture: %s\n", name );
        
        // look for the pre-digested 5551 version
        strcpy( digested, name );
@@ -514,7 +515,6 @@ PUBLIC texture_t *TM_FindTexture( const char *name, texturetype_t type )
                        { GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG, GL_UNSIGNED_BYTE, 2 },
                };
                
-               
                picHeader_t *ph = (picHeader_t *)fh->filedata;
                
                int noMips = 0;
@@ -606,7 +606,7 @@ PUBLIC texture_t *TM_FindTexture( const char *name, texturetype_t type )
                if ( fh == NULL ) {
                        Com_Printf( "Failed to find texture %s\n", name );
                        return r_notexture;
-               }
+               } //else {   //added the else...gsh
                jpgSize = FS_GetFileSize( fh );
                jpgData = fh->ptrStart;
                
@@ -616,13 +616,48 @@ PUBLIC texture_t *TM_FindTexture( const char *name, texturetype_t type )
                if ( ! data ) {
                        free( jpgData );
                        return r_notexture; 
-               }
+               } //else {   //added the else
                tex = TM_LoadTexture( name, data, width, height, type, bytes );
                MM_FREE( data );
                tex->maxS = tex->maxT = 1.0f;
                return tex;
+               
+               
+       }
+       
+       /*
+       Com_Printf("Trying to find texture made it to the end\n");
+       
+       //gsh.. couldn't find it... try doing it again, but looking in a new location
+       if (spritelocation == SODSPRITESDIRNAME && spritelocation != WL6SPRITESDIRNAME)
+       {
+               //need to remove the 'sod'
+               if (strncmp(spritelocation, name, strlen(spritelocation)) == 0)
+               {
+                       char buffer[64];
+                       char tempName[64];
+                       int offset = strlen(spritelocation) + 1;
+                       for (int i = 0; i < strlen(name) - offset; ++i)
+                       {
+                               buffer[i] = name[i+offset];
+                       }
+                       buffer[i] = '\0'; //just in case
+                       
+                       spritelocation = WL6SPRITESDIRNAME;
+                       
+                       //TODO: 
+                       my_snprintf(tempName, sizeof(tempName), "%s/%s", spritelocation, buffer);
+                       
+                       Com_Printf("tempName: %s\n", tempName);
+                       Com_Printf("buffer: %s\n", buffer);
+                       
+                       spritelocation = SODSPRITESDIRNAME;  //return to sodsprites
+                       tex = TM_FindTexture( tempName, type);
+                       return tex;
+               }
        }
 
+       return r_notexture;*/
        return NULL;
 }
 
index 80e888168de534571e7b1f4583ad664771168020..dd2c39a9e494870a07f67446af334a3130bc41a9 100644 (file)
 #import <OpenGLES/ES1/gl.h>
 #import <OpenGLES/ES1/glext.h>
 
+
+
+#ifdef VOLUMEHACK
+#import <MediaPlayer/MPVolumeView.h>
+#endif
+
 /*
 This class wraps the CAEAGLLayer from CoreAnimation into a convenient UIView subclass.
 The view content is basically an EAGL surface you render your OpenGL scene into.
@@ -49,6 +56,14 @@ Note that setting the view non-opaque will only work if the EAGL surface has an
     NSTimer *animationTimer;
        NSTimeInterval animationInterval;
        
+       //gsh... an attempt at hacking the volume button
+#ifdef VOLUMEHACK
+       MPVolumeView *volumeView;
+       UISlider *volumeViewSlider;
+       float lastFramesVolume;
+#endif 
+//     NSThread *pLoadThread;
+       
 }
 
 @property NSTimeInterval animationInterval;
index 13cb97ff3b6459b8d531440b8098ff2a47b2ee94..7fde3ecbd9f22f2ac30b09953408b566412046bb 100644 (file)
 
 #include "wolfiphone.h"
 
+
+
+//gsh
+//#define NOTIFYLISTEN  //uncomment to receive notifications
+
 struct AVSystemControllerPrivate;
 
 @interface AVSystemController : NSObject
@@ -144,6 +149,40 @@ EAGLView *eaglview;
                ((void(*)(int))eglSwapInterval)( 2 );
        }
 #endif
+
+#ifdef VOLUMEHACK
+       //-------------------
+       // Volume Button Hack
+       //gsh
+       // Note: MediaPlayer framework required for this trick
+       //create a MPVolumeView to hack the volume button
+       CGRect frame = CGRectMake(0, -30, 180, 10);  //put this thing offscreen
+       volumeView = [[[MPVolumeView alloc] initWithFrame:frame] autorelease];
+       [volumeView sizeToFit];
+       [self addSubview:volumeView];
+       
+       // Find the volume view slider 
+       for (UIView *view in [volumeView subviews]){
+               if ([[[view class] description] isEqualToString:@"MPVolumeSlider"]) {
+                       volumeViewSlider = (UISlider *)view;
+               }
+       }
+       
+       //listen for volume changes
+       [[NSNotificationCenter defaultCenter] addObserver:self 
+                                                                                        selector:@selector(volumeListener:) 
+                                                                                                name:@"AVSystemController_SystemVolumeDidChangeNotification" 
+                                                                                          object:nil];
+       
+       //---------------------
+#endif
+       
+#ifdef NOTIFYLISTEN    //gsh
+       //this is a general purpose listener
+       [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationListener:)
+                                                                                                name:nil
+                                                                                          object:nil];
+#endif
        
        // with swapinterval, we want to update as fast as possible
        float   interval = 1.0 / 30.0f;
@@ -155,7 +194,14 @@ EAGLView *eaglview;
     return self;
 }
 
+//gsh
+- (void)viewDidLoad {
+
+       Com_Printf("\n---------------\nviewDidLoad() called\n---------------\n\n");
+}
+
 - (void)drawView {
+               
        [ (wolf3dAppDelegate *)[UIApplication sharedApplication].delegate restartAccelerometerIfNeeded];
        
 #if 0  
@@ -175,11 +221,28 @@ EAGLView *eaglview;
                }
        }
 #endif 
+       
+#ifdef VOLUMEHACK
        //------------------
+       // volume hack
+
+       
+       //check for volume adjustments   gsh
+       if ( menuState == IPM_CONTROLS)
+       {
+               if (lastFramesVolume != s_masterVolume->value)
+               {
+                       lastFramesVolume = s_masterVolume->value;
+                       [volumeViewSlider setValue:lastFramesVolume animated:NO];
+                       [volumeViewSlider _commitVolumeChange];
+               }
+       }
+#endif
        
        iphoneFrame();  // swapBuffers() will be called from here
 }
 
+
 - (void)swapBuffers {
 //    glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
        loggedTimes[iphoneFrameNum&(MAX_LOGGED_TIMES-1)].beforeSwap = Sys_Milliseconds();
@@ -215,7 +278,11 @@ EAGLView *eaglview;
 - (void) handleTouches:(NSSet*)touches withEvent:(UIEvent*)event {
        int touchCount = 0;
        int points[16];
-       static int previousTouchCount;
+       static int previousTouchCount = 0;
+       
+       //gsh
+       if (previousTouchCount == 0)
+               isTouchMoving = 0;
        
        NSSet *t = [event allTouches];
     for (UITouch *myTouch in t)
@@ -232,10 +299,12 @@ EAGLView *eaglview;
         }
         if (myTouch.phase == UITouchPhaseMoved) {
             // touch moved handler
+                       //gsh, use this for swipe events in the scrolling menus
+                       isTouchMoving = 1;
         }
         if (myTouch.phase == UITouchPhaseEnded) {
                        touchCount--;
-        }
+               }
     }
        
        // toggle the console with four touches
@@ -281,11 +350,62 @@ EAGLView *eaglview;
        [self handleTouches:touches withEvent:event];
 }
 
-
 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
        [self handleTouches:touches withEvent:event];
 }
 
+// gsh
+#ifdef NOTIFYLISTEN
+- (void) notificationListener:(NSNotification *)notify
+{
+       Com_Printf("notificationListener: %s\n", [notify.name UTF8String]);
+//NSString
+       
+       if ([notify.name isEqualToString:@"CPDistributedMessagingCenterServerDidTerminateNotification"] && menuState == IPM_STOREKIT)
+       {
+               iphoneMessageBox("Apple Store Failed", "Connection to app store has terminated.  Please try again later.");
+               menuState = IPM_MAIN;
+       }
+       //sometimes after requrestProductData() is called we get these notifications
+       //and the storekit no longer responds (making it appear as a crash)
+       /*      
+notificationListener: CPDistributedMessagingCenterServerDidTerminateNotification
+notificationListener: SKNotificationRequestFinished
+notificationListener: SKNotificationTransactionsRefreshed
+notificationListener: CPDistributedMessagingCenterServerDidTerminateNotification
+*/     
+}
+#endif
+
+#ifdef VOLUMEHACK
+//-------------------
+// Volume Button Hack
+// gsh
+// currently this is problematic...
+// it's slow if the user holds the volume button
+// let's see if inlining this with the normal game loop is faster
+// than listening for the event... it's not
+// Note:  MediaPlayer framework required for this trick
+//-------------------
+- (void) volumeListener:(NSNotification *)notify
+{
+       //TODO: provide left/right click attacks
+       if (volumeViewSlider.value < s_masterVolume->value)
+       {
+       
+               [volumeViewSlider setValue:s_masterVolume->value animated:NO];//volumeSetting animated:NO];
+               [volumeViewSlider _commitVolumeChange];  //again, ignoring compiler warning complaints
+                                                                                               //this might have a warning because it's currently undocumented?
+               Cvar_Set("volumeFireDown", "1");
+       }
+       else if (volumeViewSlider.value > s_masterVolume->value)//volumeSetting)
+       {
+               [volumeViewSlider setValue:s_masterVolume->value animated:NO];//volumeSetting animated:NO];
+               [volumeViewSlider _commitVolumeChange];  //again, ignoring compiler warning complaints
+               Cvar_Set("volumeFireUp", "1");
+       }
+}
+#endif
 
 
 @end
diff --git a/wolf3d/code/iphone/FSCopyObject.c b/wolf3d/code/iphone/FSCopyObject.c
new file mode 100644 (file)
index 0000000..d4580be
--- /dev/null
@@ -0,0 +1,1986 @@
+/*
+       File:           FSCopyObject.c
+       
+       Contains:       A Copy/Delete Files/Folders engine which uses HFS+ API's.
+                               This code takes some tricks/techniques from MoreFilesX and
+                               MPFileCopy, wraps them all up into an easy to use API, and
+                               adds a bunch of features.  It will run on Mac OS 9.1 through 
+                               9.2.x and 10.1.x and up (Classic, Carbon and Mach-O)
+
+       Disclaimer:     IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+                               ("Apple") in consideration of your agreement to the following terms, and your
+                               use, installation, modification or redistribution of this Apple software
+                               constitutes acceptance of these terms.  If you do not agree with these terms,
+                               please do not use, install, modify or redistribute this Apple software.
+
+                               In consideration of your agreement to abide by the following terms, and subject
+                               to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
+                               copyrights in this original Apple software (the "Apple Software"), to use,
+                               reproduce, modify and redistribute the Apple Software, with or without
+                               modifications, in source and/or binary forms; provided that if you redistribute
+                               the Apple Software in its entirety and without modifications, you must retain
+                               this notice and the following text and disclaimers in all such redistributions of
+                               the Apple Software.  Neither the name, trademarks, service marks or logos of
+                               Apple Computer, Inc. may be used to endorse or promote products derived from the
+                               Apple Software without specific prior written permission from Apple.  Except as
+                               expressly stated in this notice, no other rights or licenses, express or implied,
+                               are granted by Apple herein, including but not limited to any patent rights that
+                               may be infringed by your derivative works or by other works in which the Apple
+                               Software may be incorporated.
+
+                               The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+                               WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+                               WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+                               PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+                               COMBINATION WITH YOUR PRODUCTS.
+
+                               IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+                               CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+                               GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+                               ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+                               OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+                               (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+                               ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+       Copyright © 2002-2004 Apple Computer, Inc., All Rights Reserved
+*/
+
+#include "FSCopyObject.h"
+#include "GenLinkedList.h"
+#if !TARGET_API_MAC_OSX
+#include <UnicodeConverter.h>
+#endif
+#include <stddef.h>
+#include <string.h>
+
+#pragma mark ----- Tunable Parameters -----
+
+/* The following constants control the behavior of the copy engine. */
+
+enum {         /* BufferSizeForVolSpeed */
+/*     kDefaultCopyBufferSize  =   2L * 1024 * 1024,*/                 /* 2MB,   Fast but not very responsive. */
+       kDefaultCopyBufferSize  = 256L * 1024,                                  /* 256kB, Slower but can still use machine. */
+       kMaximumCopyBufferSize  =   2L * 1024 * 1024,
+       kMinimumCopyBufferSize  = 1024
+};
+
+enum {         /* CheckForDestInsideSrc */
+       errFSDestInsideSource   = -1234
+};
+
+enum {         
+                       /* for use with PBHGetDirAccess in IsDropBox */
+       kPrivilegesMask                 = kioACAccessUserWriteMask | kioACAccessUserReadMask | kioACAccessUserSearchMask,
+
+                       /* for use with FSGetCatalogInfo and FSPermissionInfo->mode                     */
+                       /* from sys/stat.h...  note -- sys/stat.h definitions are in octal      */
+                       /*                                                                                                                                      */
+                       /* You can use these values to adjust the users/groups permissions      */
+                       /* on a file/folder with FSSetCatalogInfo and extracting the            */
+                       /* kFSCatInfoPermissions field.  See code below for examples            */
+       kRWXUserAccessMask              = 0x01C0,
+       kReadAccessUser                 = 0x0100,
+       kWriteAccessUser                = 0x0080,
+       kExecuteAccessUser              = 0x0040,
+
+       kRWXGroupAccessMask             = 0x0038,
+       kReadAccessGroup                = 0x0020,
+       kWriteAccessGroup               = 0x0010,
+       kExecuteAccessGroup             = 0x0008,
+
+       kRWXOtherAccessMask             = 0x0007,
+       kReadAccessOther                = 0x0004,
+       kWriteAccessOther               = 0x0002,
+       kExecuteAccessOther             = 0x0001,
+
+       kDropFolderValue                = kWriteAccessOther | kExecuteAccessOther
+};
+
+#define        kNumObjects                     80
+
+#define VolHasCopyFile(volParms)       (((volParms)->vMAttrib & (1L << bHasCopyFile)) != 0)
+
+#pragma mark ----- Struct Definitions -----
+
+       /* The CopyParams data structure holds the copy buffer used     */
+       /* when copying the forks over, as well as special case         */
+       /* info on the destination                                                                      */
+struct CopyParams {
+       void                               *copyBuffer;
+       ByteCount                               copyBufferSize;
+       Boolean                         copyingToDropFolder;
+       Boolean                                 copyingToLocalVolume;
+       Boolean                                 volHasCopyFile;
+       DupeAction                              dupeAction;
+};
+typedef struct CopyParams CopyParams;
+
+       /* The FilterParams data structure holds the date and info              */
+       /* that the caller wants passed into the Filter Proc, as well   */
+       /* as the Filter Proc Pointer itself                                                    */
+struct FilterParams {
+       FSCatalogInfoBitmap             whichInfo;
+       CopyObjectFilterProcPtr filterProcPtr;
+       Boolean                                 containerChanged;
+       Boolean                                 wantSpec;
+       Boolean                                 wantName;
+       void                               *yourDataPtr;
+};
+typedef struct FilterParams FilterParams;
+
+       /* The ForkTracker data structure holds information about a specific fork,      */
+       /* specifically the name and the refnum.  We use this to build a list of        */
+       /* all the forks before we start copying them.  We need to do this because      */
+       /* if we're copying into a drop folder, we must open all the forks before       */
+       /* we start copying data into any of them.                                                                      */
+       /* Plus it's a convenient way to keep track of all the forks...                         */
+struct ForkTracker {
+       HFSUniStr255                    forkName;
+       SInt64                                  forkSize;
+       SInt16                          forkDestRefNum;
+};
+typedef struct ForkTracker ForkTracker;
+typedef ForkTracker *ForkTrackerPtr;
+
+       /* The FolderListData data structure holds FSRefs to the source and                     */
+       /* coorisponding destination folder, as well as which level its on                      */
+       /* for use in ProcessFolderList.                                                                                        */ 
+struct FolderListData
+{
+       FSRef                                   sourceDirRef;
+       FSRef                                   destDirRef;
+       UInt32                                  level;
+};
+typedef struct FolderListData FolderListData;
+
+       /* The FSCopyFolderGlobals data structure holds the information needed to       */
+       /* copy a directory                                                                                                                     */
+struct FSCopyFolderGlobals
+{
+       FSRef                              *sourceDirRef;
+       FSRef                              *destDirRef;
+
+       FSCatalogInfo              *catInfoList;
+       FSRef                              *srcRefList;
+       HFSUniStr255               *nameList;
+       
+       GenLinkedList                   folderList;
+       GenIteratorPtr                  folderListIter;
+       
+       CopyParams                         *copyParams;
+       FilterParams               *filterParams;
+       Boolean                                 containerChanged;
+       
+       ItemCount                               maxLevels;
+       ItemCount                               currentLevel;
+};
+typedef struct FSCopyFolderGlobals FSCopyFolderGlobals;
+
+       /* The FSDeleteObjectGlobals data structure holds information needed to */
+       /* recursively delete a directory                                                                               */
+struct FSDeleteObjectGlobals
+{
+       FSCatalogInfo                   catalogInfo;            /* FSCatalogInfo                                */
+       ItemCount                               actualObjects;          /* number of objects returned   */
+       OSErr                                   result;                         /* result                                               */
+};
+typedef struct FSDeleteObjectGlobals FSDeleteObjectGlobals;
+
+#pragma mark ----- Local Prototypes -----
+
+static OSErr   FSCopyObjectPreflight ( const FSRef                     *source,
+                                                                               const FSRef                     *destDir,
+                                                                               const DupeAction         dupeAction,
+                                                                               FSCatalogInfo           *sourceCatInfo,
+                                                                               CopyParams                      *copyParams,            /* can be NULL */
+                                                                               HFSUniStr255            *newObjectName,
+                                                                               FSRef                           *deleteMeRef,
+                                                                               Boolean                         *isReplacing,
+                                                                               Boolean                         *isDirectory );
+
+static OSErr   FSCopyFile                        (     const FSRef                     *source,
+                                                                               const FSRef                     *destDir,
+                                                                               const FSCatalogInfo     *sourceCatInfo,
+                                                                               const HFSUniStr255      *newFileName,
+                                                                               CopyParams                      *copyParams,
+                                                                               FilterParams            *filterParams,
+                                                                               FSRef                           *newFileRef,            /* can be NULL */
+                                                                               FSSpec                          *newFileSpec );         /* can be NULL */
+                                                               
+static OSErr   CopyFile                          (     const FSRef                     *source,
+                                                                               FSCatalogInfo           *sourceCatInfo,
+                                                                               const FSRef                     *destDir,
+                                                                               const HFSUniStr255      *destName,                      /* can be NULL */
+                                                                               CopyParams                      *copyParams,
+                                                                               FSRef                           *newRef,                        /* can be NULL */
+                                                                               FSSpec                          *newSpec );                     /* can be NULL */
+                                                               
+static OSErr   FSUsePBHCopyFile          (     const FSRef                     *srcFileRef,
+                                                                               const FSRef             *dstDirectoryRef,
+                                                                               const HFSUniStr255      *destName,                      /* can be NULL (no rename during copy) */
+                                                                               TextEncoding            textEncodingHint,
+                                                                               FSRef                           *newRef,                        /* can be NULL */
+                                                                               FSSpec                          *newSpec );                     /* can be NULL */
+                                                                                       
+static OSErr   DoCopyFile                        (     const FSRef             *source,
+                                                                               FSCatalogInfo           *sourceCatInfo,
+                                                                               const FSRef                     *destDir,
+                                                                               const HFSUniStr255      *destName,
+                                                                               CopyParams                      *params, 
+                                                                               FSRef                           *newRef,                        /* can be NULL */
+                                                                               FSSpec                          *newSpec );                     /* can be NULL */
+
+static OSErr   FSCopyFolder              (     const FSRef                     *source,
+                                                                               const FSRef                     *destDir,
+                                                                               const FSCatalogInfo     *sourceCatInfo,
+                                                                               const HFSUniStr255      *newFoldName,
+                                                                               CopyParams                      *copyParams,
+                                                                               FilterParams            *filterParams,
+                                                                               ItemCount                        maxLevels,
+                                                                               FSRef                           *outDirRef,                     /* can be NULL */
+                                                                               FSSpec                          *outDirSpec );          /* can be NULL */
+
+static OSErr   ProcessFolderList         (     FSCopyFolderGlobals *folderGlobals );
+
+static OSErr   CopyFolder                        (     FSCopyFolderGlobals     *folderGlobals );
+
+static OSErr   CheckForDestInsideSrc ( const FSRef                     *source,
+                                                                               const FSRef                     *destDir );
+
+static OSErr   CopyForks                         (     const FSRef                     *source,
+                                                                               const FSRef                     *dest,
+                                                                               CopyParams                      *params );
+
+static OSErr   CopyForksToDisk           (     const FSRef                     *source,
+                                                                               const FSRef                     *dest,
+                                                                               CopyParams                      *params );
+                                                                               
+static OSErr   CopyForksToDropBox        (     const FSRef                     *source,
+                                                                               const FSRef                     *dest,
+                                                                               CopyParams                      *params );
+
+static OSErr   OpenAllForks              (     const FSRef                     *dest,
+                                                                               GenLinkedList           *forkList );
+
+static OSErr   WriteFork                         (     const SInt16            srcRefNum,
+                                                                               const SInt16            destRefNum,
+                                                                               const CopyParams        *params,
+                                                                               const SInt64            forkSize );
+
+static UInt32  CalcBufferSizeForVol  ( const GetVolParmsInfoBuffer *volParms,
+                                                                               UInt32                          volParmsSize );
+
+static UInt32  BufferSizeForVolSpeed ( UInt32                          volumeBytesPerSecond );
+
+static OSErr   FSDeleteFolder            (     const FSRef                     *container );
+
+static void            FSDeleteFolderLevel       (     const FSRef                     *container,
+                                                                               FSDeleteObjectGlobals *theGlobals );
+
+static OSErr   IsDropBox                         (     const FSRef                     *source,
+                                                                               Boolean                         *isDropBox );
+
+static OSErr   GetMagicBusyCreateDate( UTCDateTime                     *date );
+
+static OSErr   FSGetVRefNum              (     const FSRef                     *ref,
+                                                                               FSVolumeRefNum          *vRefNum );
+
+static OSErr   FSGetVolParms             (     FSVolumeRefNum            volRefNum,
+                                                                               UInt32                            bufferSize,
+                                                                               GetVolParmsInfoBuffer*volParmsInfo,
+                                                                               UInt32                           *actualInfoSize );     /*      Can Be NULL     */
+
+static OSErr   UniStrToPStr              (     const HFSUniStr255      *uniStr,
+                                                                               TextEncoding             textEncodingHint,
+                                                                               Boolean                          isVolumeName,
+                                                                               Str255                           pStr );
+
+static OSErr   FSMakeFSRef                       (     FSVolumeRefNum           volRefNum,
+                                                                               SInt32                           dirID,
+                                                                               ConstStr255Param         name,
+                                                                               FSRef                           *ref );
+                                               
+static OSErr   SetupDestination          (     const FSRef                     *destDir,
+                                                                               const DupeAction         dupeAction,
+                                                                               HFSUniStr255            *sourceName,
+                                                                               FSRef                           *deleteMeRef,
+                                                                               Boolean                         *isReplacing);
+
+static OSErr   GetUniqueName             (     const FSRef                     *destDir,
+                                                                               HFSUniStr255            *sourceName );
+
+static OSErr   GetObjectName             (     const FSRef                     *sourceRef,
+                                                                               HFSUniStr255            *sourceName,
+                                                                               TextEncoding            *sourceEncoding );
+                                                                       
+static OSErr   CreateFolder              (     const FSRef                     *sourceRef,
+                                                                               const FSRef                     *destDirRef,
+                                                                               const FSCatalogInfo     *catalogInfo,
+                                                                               const HFSUniStr255      *folderName,
+                                                                               CopyParams                      *params,
+                                                                               FSRef                           *newFSRefPtr,
+                                                                               FSSpec                          *newFSSpecPtr );
+
+static OSErr   DoCreateFolder            (     const FSRef                     *sourceRef,
+                                                                               const FSRef                     *destDirRef,
+                                                                               const FSCatalogInfo     *catalogInfo,
+                                                                               const HFSUniStr255      *folderName,
+                                                                               CopyParams                      *params,
+                                                                               FSRef                           *newFSRefPtr,
+                                                                               FSSpec                          *newFSSpecPtr);
+
+static pascal void MyDisposeDataProc  (        void                            *pData );
+
+static pascal void MyCloseForkProc       (     void                            *pData );
+
+/*****************************************************************************/
+/*****************************************************************************/
+/*****************************************************************************/
+
+#pragma mark ----- Copy Objects -----
+
+       /* This routine acts as the top level of the copy engine.       */ 
+OSErr FSCopyObject(    const FSRef                             *source,
+                                       const FSRef                             *destDir,
+                                       ItemCount                               maxLevels,
+                                       FSCatalogInfoBitmap             whichInfo,
+                                       DupeAction                              dupeAction,
+                                       const HFSUniStr255              *newObjectName, /* can be NULL */
+                                       Boolean                                 wantFSSpec,
+                                       Boolean                                 wantName,
+                                       CopyObjectFilterProcPtr filterProcPtr,  /* can be NULL */
+                                       void                                    *yourDataPtr,   /* can be NULL */
+                                       FSRef                                   *newObjectRef,  /* can be NULL */
+                                       FSSpec                                  *newObjectSpec) /* can be NULL */
+{
+       CopyParams      copyParams;
+       FilterParams    filterParams;
+       FSCatalogInfo   sourceCatInfo;
+       HFSUniStr255    sourceName,
+                                       tmpObjectName;
+       FSRef                   tmpObjectRef,
+                                       deleteMeRef;
+       Boolean                 isDirectory,
+                                       isReplacing = false;
+       OSErr                   err = ( source != NULL && destDir != NULL ) ? noErr : paramErr;
+
+               /* Zero out these two FSRefs in case an error occurs before or  */
+               /* inside FSCopyObjectPreflight.  Paranoia mainly...                    */
+       BlockZero( &deleteMeRef,        sizeof( FSRef ) );
+       BlockZero( &tmpObjectRef,       sizeof( FSRef ) );
+
+               /* setup filterParams */
+       filterParams.whichInfo          = whichInfo;
+       filterParams.filterProcPtr      = filterProcPtr;
+       filterParams.wantSpec           = ( filterProcPtr && wantFSSpec );      /* only get this info if        */
+       filterParams.wantName           = ( filterProcPtr && wantName );        /* a filterProc is provied      */
+       filterParams.yourDataPtr        = yourDataPtr;
+       
+               /* Get and store away the name of the source object */
+               /* and setup the initial name of the new object         */
+       if( err == noErr )
+               err = GetObjectName( source, &sourceName, NULL );
+       if( err == noErr )
+               tmpObjectName = (newObjectName != NULL) ? *newObjectName : sourceName;
+
+       if( err == noErr )              /* preflight/prep the destination and our internal variables */
+               err = FSCopyObjectPreflight( source, destDir, dupeAction, &sourceCatInfo, &copyParams, &tmpObjectName, &deleteMeRef, &isReplacing, &isDirectory );
+               
+                                                       /* now that we have some info, lets print it */
+       if( err == noErr )
+       {
+               dwarning(( "%s -- err: %d, maxLevels: %u, whichInfo: %08x,\n", __FUNCTION__, err, (unsigned int)maxLevels, (int)whichInfo ));
+               dwarning(( "\t\t\t\tdupeAction: %s, wantSpec: %s, wantName: %s,\n", ((dupeAction == kDupeActionReplace) ? "replace" : ((dupeAction == kDupeActionRename) ? "rename" : "standard")), (filterParams.wantSpec)?"yes":"no", (filterParams.wantName)?"yes":"no" ));
+               dwarning(( "\t\t\t\tfilterProcPtr: 0x%08x, yourDataPtr: 0x%08x,\n", (unsigned int)filterProcPtr, (unsigned int)yourDataPtr ));
+               dwarning(( "\t\t\t\tnewObjectRef: 0x%08x, newObjectSpec: 0x%08x,\n", (unsigned int)newObjectRef, (unsigned int)newObjectSpec ));
+               dwarning(( "\t\t\t\tcopyBufferSize: %dkB, isDirectory: %s, isLocal: %s,\n", (int)copyParams.copyBufferSize/1024, (isDirectory)?"yes":"no", (copyParams.copyingToLocalVolume)?"yes":"no" ));
+               dwarning(( "\t\t\t\tisDropBox: %s, PBHCopyFileSync supported: %s\n\n", (copyParams.copyingToDropFolder)?"yes":"no", (copyParams.volHasCopyFile)?"yes":"no" ));
+       }
+               
+       if( err == noErr )              /* now copy the file/folder... */
+       {               /* is it a folder? */
+               if ( isDirectory )
+               {               /* yes */
+                       err = CheckForDestInsideSrc(source, destDir);                   
+                       if( err == noErr )
+                               err = FSCopyFolder( source, destDir, &sourceCatInfo, &tmpObjectName, &copyParams, &filterParams, maxLevels, &tmpObjectRef, newObjectSpec );
+               }
+               else    /* no */
+                       err = FSCopyFile(source, destDir, &sourceCatInfo, &tmpObjectName, &copyParams, &filterParams, &tmpObjectRef, newObjectSpec);
+       }
+       
+               /* if an object existed in the destination with the same name as        */
+               /* the source and the caller wants to replace it, we had renamed it     */
+               /* to ".DeleteMe" earlier.  If no errors, we delete it, else delete     */
+               /* the one we just created and rename the origenal back to its          */
+               /* origenal name.                                                                                                       */
+               /*                                                                                                                                      */
+               /* This is done mainly to cover the case of the source being in the     */
+               /* destination directory when kDupeActionReplace is selected            */
+               /* (3188701)                                                                                                            */
+       if( copyParams.dupeAction == kDupeActionReplace && isReplacing == true )
+       {
+               dwarning(("%s -- Cleaning up, this might take a moment.  err : %d\n", __FUNCTION__, err));
+       
+               if( err == noErr )
+                       err = FSDeleteObjects( &deleteMeRef );
+               else    
+               {               /* not much we can do if the delete or rename fails, we need to preserve        */
+                               /* the origenal error code that got us here.                                                            */
+                               /*                                                                                                                                                      */
+                               /* If an error occurs before or inside SetupDestination, newFileRef and         */
+                               /* deleteMeRef will be invalid so the delete and rename will simply fail        */
+                               /* leaving the source and destination unchanged                                                         */
+                       myverify_noerr( FSDeleteObjects( &tmpObjectRef ) );
+                       myverify_noerr( FSRenameUnicode( &deleteMeRef, sourceName.length, sourceName.unicode, sourceCatInfo.textEncodingHint, NULL ) );
+               }
+       }
+       
+       if( err == noErr && newObjectRef != NULL )
+               *newObjectRef = tmpObjectRef;
+
+               /* Clean up for space and safety...  Who me? */
+       if( copyParams.copyBuffer != NULL )
+               DisposePtr((char*)copyParams.copyBuffer);
+               
+       mycheck_noerr( err );   
+       
+       return err;
+}                               
+
+/*****************************************************************************/
+
+       /* Does a little preflighting (as the name suggests) to figure out the optimal  */
+       /* buffer size, if its a drop box, on a remote volume etc                                               */
+static OSErr FSCopyObjectPreflight(    const FSRef                     *source,
+                                                                       const FSRef                     *destDir,
+                                                                       const DupeAction        dupeAction,
+                                                                       FSCatalogInfo           *sourceCatInfo,
+                                                                       CopyParams              *copyParams,
+                                                                       HFSUniStr255            *newObjectName,
+                                                                       FSRef                           *deleteMeRef,
+                                                                       Boolean                         *isReplacing,
+                                                                       Boolean                         *isDirectory)
+{
+       GetVolParmsInfoBuffer   srcVolParms,
+                                                       destVolParms;
+       UInt32                                  srcVolParmsSize = 0,
+                                                       destVolParmsSize = 0;
+       FSVolumeRefNum                  srcVRefNum,
+                                                       destVRefNum;
+       OSErr                                   err = ( source            != NULL && destDir     != NULL &&
+                                                                       sourceCatInfo != NULL && copyParams      != NULL &&
+                                                                       newObjectName != NULL && deleteMeRef != NULL &&
+                                                                       isDirectory       != NULL ) ? noErr : paramErr;
+
+       BlockZero( copyParams, sizeof( CopyParams ) );
+
+       copyParams->dupeAction = dupeAction;
+
+       if( err == noErr )              /* Get the info we will need later about the source object      */
+               err = FSGetCatalogInfo( source, kFSCatInfoSettableInfo, sourceCatInfo, NULL, NULL, NULL );              
+       if( err == noErr )              /* get the source's vRefNum                                                                     */
+               err = FSGetVRefNum( source, &srcVRefNum );
+       if( err == noErr )              /* get the source's volParams                                                           */
+               err = FSGetVolParms( srcVRefNum,  sizeof(GetVolParmsInfoBuffer), &srcVolParms, &srcVolParmsSize );                      
+       if( err == noErr )              /* get the destination's vRefNum                                                        */
+               err = FSGetVRefNum( destDir, &destVRefNum );
+       if( err == noErr )
+       {
+                                                       /* Calculate the optimal copy buffer size for the src vol       */
+               copyParams->copyBufferSize = CalcBufferSizeForVol( &srcVolParms, srcVolParmsSize );
+       
+                                                       /* if src and dest on different volumes, get its vol parms      */
+                                                       /* and calculate its optimal buffer size                                        */
+                                                       /* else destVolParms = srcVolParms                                                      */
+               if( srcVRefNum != destVRefNum )
+               {
+                       err = FSGetVolParms( destVRefNum, sizeof(GetVolParmsInfoBuffer), &destVolParms, &destVolParmsSize );
+                       if( err == noErr )
+                       {
+                               ByteCount tmpBufferSize = CalcBufferSizeForVol( &destVolParms, destVolParmsSize );
+                               if( tmpBufferSize < copyParams->copyBufferSize )
+                                       copyParams->copyBufferSize = tmpBufferSize;                             
+                       }
+               }
+               else 
+                       destVolParms = srcVolParms;
+       }
+       if( err == noErr )
+               err = ((copyParams->copyBuffer = NewPtr( copyParams->copyBufferSize )) != NULL ) ? noErr : MemError();
+
+               /* figure out if source is a file or folder                     */
+               /*                        if it is on a local volume,                   */
+               /*                        if destination is a drop box                  */
+               /*                        if source and dest are on same server */
+               /*                        and if it supports PBHCopyFile                */
+       if( err == noErr )              /* is the destination a Drop Box        */
+               err = IsDropBox( destDir, &copyParams->copyingToDropFolder );
+       if( err == noErr )
+       {
+                       /* Is it a directory                                                                    */
+               *isDirectory = ((sourceCatInfo->nodeFlags & kFSNodeIsDirectoryMask) != 0);
+                       /* destVolParms.vMServerAdr is non-zero for remote volumes      */
+               copyParams->copyingToLocalVolume = (destVolParms.vMServerAdr == 0);
+               if( !copyParams->copyingToLocalVolume )
+               {
+                               /* If the destination is on a remote volume, and source and dest are on         */
+                               /* the same server, then it might support PBHCopyFileSync                                       */
+                               /* If not, then PBHCopyFileSync won't work                                                                      */
+
+                               /* figure out if the volumes support PBHCopyFileSync                                            */
+                       copyParams->volHasCopyFile = ( err == noErr && destVolParms.vMServerAdr == srcVolParms.vMServerAdr ) ?
+                                                                                  VolHasCopyFile(&srcVolParms) : false;
+               }       
+       }
+       
+       if( err == noErr )
+               err = SetupDestination( destDir, copyParams->dupeAction, newObjectName, deleteMeRef, isReplacing );
+               
+       return err;
+}
+
+#pragma mark ----- Copy Files -----
+
+/*****************************************************************************/
+
+static OSErr FSCopyFile(       const FSRef                     *source,
+                                                       const FSRef                     *destDir,
+                                                       const FSCatalogInfo     *sourceCatInfo,
+                                                       const HFSUniStr255      *newFileName,
+                                                       CopyParams                      *copyParams,
+                                                       FilterParams            *filterParams,
+                                                       FSRef                           *outFileRef,
+                                                       FSSpec                          *outFileSpec )
+{
+       FSCatalogInfo   catInfo = *sourceCatInfo;
+       FSRef                   newFileRef;
+       FSSpec                  newFileSpec;
+       OSErr                   err = ( source != NULL && destDir != NULL &&
+                                                       copyParams != NULL && filterParams != NULL ) ? noErr : paramErr;
+       
+                                                       /* If you would like a Pre-Copy filter (i.e to weed out objects */
+                                                       /* you don't want to copy) you should add it here                               */
+       
+       if( err == noErr )              /* copy the file over */
+               err = CopyFile( source, &catInfo, destDir, newFileName, copyParams, &newFileRef, (filterParams->wantSpec || outFileSpec) ? &newFileSpec : NULL );
+
+               /* Call the IterateFilterProc _after_ the new file was created even if an error occured.        */
+               /* Note: if an error occured above, the FSRef and other info might not be valid                         */
+       if( filterParams->filterProcPtr != NULL )
+       {
+                       /* get the extra info the user wanted on the new file that we don't have */
+               if( err == noErr && (filterParams->whichInfo & ~kFSCatInfoSettableInfo) != kFSCatInfoNone )
+                       err = FSGetCatalogInfo( &newFileRef, filterParams->whichInfo & ~kFSCatInfoSettableInfo, &catInfo, NULL, NULL, NULL );   
+
+               err = CallCopyObjectFilterProc( filterParams->filterProcPtr, false, 0, err, &catInfo, &newFileRef, 
+                                                                               (filterParams->wantSpec) ? &newFileSpec : NULL,
+                                                                               (filterParams->wantName) ? newFileName : NULL,
+                                                                               filterParams->yourDataPtr);
+       }
+       
+       if( err == noErr )
+       {       
+               if( outFileRef != NULL )
+                       *outFileRef             = newFileRef;
+               if( outFileSpec != NULL )
+                       *outFileSpec    = newFileSpec;
+       }
+               
+       mycheck_noerr(err);
+
+       return err;
+}
+
+/*****************************************************************************/
+
+static OSErr CopyFile( const FSRef                     *source,
+                                               FSCatalogInfo           *sourceCatInfo,
+                                               const FSRef                     *destDir,
+                                               const HFSUniStr255      *destName,              /* can be NULL */
+                                               CopyParams                      *params,
+                                               FSRef                           *newFile,               /* can be NULL */
+                                               FSSpec                          *newSpec )              /* can be NULL */
+{
+       OSErr           err = paramErr;
+       
+               /* Clear the "inited" bit so that the Finder positions the icon for us. */
+       ((FInfo *)(sourceCatInfo->finderInfo))->fdFlags &= ~kHasBeenInited;
+
+               /* if the volumes support PBHCopyFileSync, try to use it                        */
+       if( params->volHasCopyFile == true )
+               err = FSUsePBHCopyFile( source, destDir, destName, kTextEncodingUnknown, newFile, newSpec );
+                       
+                                                       /* if PBHCopyFile didn't work or not supported, */
+       if( err != noErr )              /* then try old school file transfer                    */
+               err = DoCopyFile( source, sourceCatInfo, destDir, destName, params, newFile, newSpec );         
+
+       mycheck_noerr(err);
+
+       return err;
+}
+
+/*****************************************************************************/
+
+       /* Wrapper function for PBHCopyFileSync */
+static OSErr FSUsePBHCopyFile( const FSRef                     *srcFileRef,
+                                                               const FSRef                     *dstDirectoryRef,
+                                                               const HFSUniStr255      *destName,                      /* can be NULL */
+                                                               TextEncoding            textEncodingHint,
+                                                               FSRef                           *newRef,                        /* can be NULL */
+                                                               FSSpec                          *newSpec)                       /* can be NULL */
+{
+       FSSpec                                  srcFileSpec;
+       FSCatalogInfo                   catalogInfo;
+       HParamBlockRec                  pb;
+       Str255                                  hfsName;
+       OSErr                                   err = ( srcFileRef != NULL && dstDirectoryRef != NULL ) ? noErr : paramErr;
+       
+       if( err == noErr )              /* get FSSpec of source FSRef */
+               err = FSGetCatalogInfo(srcFileRef, kFSCatInfoNone, NULL, NULL, &srcFileSpec, NULL);
+       if( err == noErr )              /* get the destination vRefNum and nodeID (nodeID is the dirID) */
+               err = FSGetCatalogInfo(dstDirectoryRef, kFSCatInfoVolume | kFSCatInfoNodeID, &catalogInfo, NULL, NULL, NULL);
+       if( err == noErr )              /* gather all the info needed */
+       {
+               pb.copyParam.ioVRefNum          = srcFileSpec.vRefNum;
+               pb.copyParam.ioDirID            = srcFileSpec.parID;
+               pb.copyParam.ioNamePtr          = (StringPtr)srcFileSpec.name;
+               pb.copyParam.ioDstVRefNum       = catalogInfo.volume;
+               pb.copyParam.ioNewDirID         = (long)catalogInfo.nodeID;
+               pb.copyParam.ioNewName          = NULL;
+               if( destName != NULL )
+                       err = UniStrToPStr( destName, textEncodingHint, false, hfsName );
+               pb.copyParam.ioCopyName         = ( destName != NULL && err == noErr ) ? hfsName : NULL;
+       }
+       if( err == noErr )                      /* tell the server to copy the object */
+               err = PBHCopyFileSync(&pb);
+       
+       if( err == noErr )
+       {
+               if( newSpec != NULL )   /* caller wants an FSSpec, so make it */                
+                       myverify_noerr(FSMakeFSSpec( pb.copyParam.ioDstVRefNum, pb.copyParam.ioNewDirID, pb.copyParam.ioCopyName, newSpec));
+               if( newRef != NULL )    /* caller wants an FSRef, so make it */
+                       myverify_noerr(FSMakeFSRef( pb.copyParam.ioDstVRefNum, pb.copyParam.ioNewDirID, pb.copyParam.ioCopyName, newRef));
+       }
+       
+       if( err != paramErr )           /* returning paramErr is ok, it means PBHCopyFileSync was not supported */
+               mycheck_noerr(err);
+
+       return err;
+}
+
+/*****************************************************************************/
+
+       /* Copies a file referenced by source to the directory referenced by    */
+       /* destDir.  destName is the name the file we are going to copy to the  */
+       /* destination.  sourceCatInfo is the catalog info of the file, which   */
+       /* is passed in as an optimization (we could get it by doing a                  */
+       /* FSGetCatalogInfo but the caller has already done that so we might as */
+       /* well take advantage of that).                                                                                */
+       /*                                                                                                                                              */
+static OSErr DoCopyFile(const FSRef                    *source,
+                                               FSCatalogInfo           *sourceCatInfo,
+                                               const FSRef                     *destDir,
+                                               const HFSUniStr255      *destName,
+                                               CopyParams                      *params,
+                                               FSRef                           *newRef,
+                                               FSSpec                          *newSpec )
+{
+       FSRef                           dest;
+       FSSpec                          tmpSpec;
+       FSPermissionInfo        originalPermissions;
+       OSType                          originalFileType = 'xxxx';
+       UInt16                          originalNodeFlags = kFSCatInfoNone;
+       Boolean                         getSpec;
+       OSErr                           err = noErr;
+
+               /* If we're copying to a drop folder, we won't be able to reset this            */
+               /* information once the copy is done, so we don't mess it up in                         */
+               /* the first place.  We still clear the locked bit though; items dropped        */
+               /* into a drop folder always become unlocked.                                                           */
+       if (!params->copyingToDropFolder)
+       {
+                       /* Remember to clear the file's type, so the Finder doesn't                             */
+                       /* look at the file until we're done.                                                                   */
+               originalFileType = ((FInfo *) &sourceCatInfo->finderInfo)->fdType;
+               ((FInfo *) &sourceCatInfo->finderInfo)->fdType = kFirstMagicBusyFiletype;
+
+                       /* Remember and clear the file's locked status, so that we can                  */
+                       /* actually write the forks we're about to create.                                              */
+               originalNodeFlags = sourceCatInfo->nodeFlags;
+       }
+       sourceCatInfo->nodeFlags &= ~kFSNodeLockedMask;
+       
+               /* figure out if we should get the FSSpec to the new file or not                        */
+               /* If the caller asked for it, or if we need it for symlinks                            */
+       getSpec = ( ( newSpec != NULL ) || ( !params->copyingToDropFolder && originalFileType == 'slnk' && ((FInfo *) &sourceCatInfo->finderInfo)->fdCreator == 'rhap' ) );
+       
+               /* we need to have user level read/write/execute access to the file we are      */
+               /* going to create otherwise FSCreateFileUnicode will return                            */
+               /* -5000 (afpAccessDenied), and the FSRef returned will be invalid, yet         */
+               /* the file is created (size 0k)... bug?                                                                        */
+       originalPermissions = *((FSPermissionInfo*)sourceCatInfo->permissions);
+       ((FSPermissionInfo*)sourceCatInfo->permissions)->mode |= kRWXUserAccessMask;
+       
+               /* Classic only supports 9.1 and higher, so we don't have to worry                      */
+               /* about 2397324                                                                                                                        */
+       if( err == noErr )
+               err = FSCreateFileUnicode(destDir, destName->length, destName->unicode, kFSCatInfoSettableInfo, sourceCatInfo, &dest, ( getSpec ) ? &tmpSpec : NULL );
+       if( err == noErr )      /* Copy the forks over to the new file                                          */
+               err = CopyForks(source, &dest, params);
+
+               /* Restore the original file type, creation and modification dates,                     */
+               /* locked status and permissions.                                                                                       */
+               /* This is one of the places where we need to handle drop                                       */
+               /* folders as a special case because this FSSetCatalogInfo will fail for        */
+               /* an item in a drop folder, so we don't even attempt it.                                       */
+       if (err == noErr && !params->copyingToDropFolder)
+       {
+               ((FInfo *) &sourceCatInfo->finderInfo)->fdType = originalFileType;
+               sourceCatInfo->nodeFlags  = originalNodeFlags;
+               *((FSPermissionInfo*)sourceCatInfo->permissions) = originalPermissions;
+
+                       /* 2796751, FSSetCatalogInfo returns -36 when setting the Finder Info   */
+                       /* for a symlink.  To workaround this, when the file is a                               */
+                       /* symlink (slnk/rhap) we will finish the copy in two steps. First              */
+                       /* setting everything but the Finder Info on the file, then calling             */
+                       /* FSpSetFInfo to set the Finder Info for the file. I would rather use  */
+                       /* an FSRef function to set the Finder Info, but FSSetCatalogInfo is    */
+                       /* the only one...  catch-22...                                                                                 */
+                       /*                                                                                                                                              */
+                       /* The Carbon File Manager always sets the type/creator of a symlink to */
+                       /* slnk/rhap if the file is a symlink we do the two step, if it isn't   */
+                       /* we use FSSetCatalogInfo to do all the work.                                                  */
+               if ((originalFileType == 'slnk') && (((FInfo *) &sourceCatInfo->finderInfo)->fdCreator == 'rhap'))
+               {                                                               /* Its a symlink                                                        */
+                                                                               /* set all the info, except the Finder info     */
+                       err = FSSetCatalogInfo(&dest, kFSCatInfoNodeFlags | kFSCatInfoPermissions, sourceCatInfo);
+                       if ( err == noErr )                     /* set the Finder Info to that file                     */
+                               err = FSpSetFInfo( &tmpSpec, ((FInfo *) &sourceCatInfo->finderInfo) );
+               }
+               else                                                    /* its a regular file                                           */
+                       err = FSSetCatalogInfo(&dest, kFSCatInfoNodeFlags | kFSCatInfoFinderInfo | kFSCatInfoPermissions, sourceCatInfo);
+       }
+       
+               /* If we created the file and the copy failed, try to clean up by                       */
+               /* deleting the file we created.  We do this because, while it's                        */
+               /* possible for the copy to fail halfway through and the File Manager           */
+               /* doesn't really clean up that well in that case, we *really* don't want       */
+               /* any half-created files being left around.                                                            */
+               /* if the file already existed, we don't want to delete it                                      */
+       if( err == noErr || err == dupFNErr )
+       {                       /* if everything was fine, then return the new file Spec/Ref            */
+               if( newRef != NULL )
+                       *newRef = dest;
+               if( newSpec != NULL )
+                       *newSpec = tmpSpec;
+       }
+       else    
+               myverify_noerr( FSDeleteObjects(&dest) );
+
+       mycheck_noerr(err);
+
+       return err;
+}
+
+/*****************************************************************************/
+
+#pragma mark ----- Copy Folders -----
+
+static OSErr FSCopyFolder(     const FSRef                     *source,
+                                                       const FSRef                     *destDir,
+                                                       const FSCatalogInfo     *sourceCatInfo,
+                                                       const HFSUniStr255      *newObjectName,
+                                                       CopyParams                      *copyParams, 
+                                                       FilterParams            *filterParams,
+                                                       ItemCount                       maxLevels,
+                                                       FSRef                           *outDirRef,
+                                                       FSSpec                          *outDirSpec )
+{
+       FSCopyFolderGlobals     folderGlobals;
+       FolderListData          *tmpListData            = NULL;
+       FSCatalogInfo           catInfo = *sourceCatInfo;
+       FSRef                           newDirRef;
+       FSSpec                          newDirSpec;
+       OSErr                           err;
+
+                                                       /* setup folder globals */
+       folderGlobals.catInfoList               = (FSCatalogInfo*)      NewPtr( sizeof( FSCatalogInfo ) * kNumObjects );
+       folderGlobals.srcRefList                = (FSRef*)                      NewPtr( sizeof( FSRef )                 * kNumObjects );
+       folderGlobals.nameList                  = (HFSUniStr255*)       NewPtr( sizeof( HFSUniStr255 )  * kNumObjects );
+       folderGlobals.folderListIter    = NULL;
+       folderGlobals.copyParams                = copyParams;
+       folderGlobals.filterParams              = filterParams;
+       folderGlobals.maxLevels                 = maxLevels;
+       folderGlobals.currentLevel              = 0;
+
+                                                       /* if any of the NewPtr calls failed, we MUST bail */
+       err                                                             = ( folderGlobals.catInfoList   != NULL &&
+                                                                               folderGlobals.srcRefList        != NULL &&
+                                                                               folderGlobals.nameList          != NULL ) ? noErr : memFullErr;
+
+                                                       /* init the linked list we will use to keep track of the folders */
+       InitLinkedList( &folderGlobals.folderList, MyDisposeDataProc );
+
+       if( err == noErr && !copyParams->copyingToDropFolder )
+               err = GetMagicBusyCreateDate( &catInfo.createDate );
+       if( err == noErr )              /* create the directory */
+               err = DoCreateFolder( source, destDir, &catInfo, newObjectName, folderGlobals.copyParams, &newDirRef, (filterParams->wantSpec || outDirSpec ) ? &newDirSpec : NULL );
+       
+               /* Note: if an error occured above, the FSRef and other info might not be valid */
+       if( filterParams->filterProcPtr != NULL )
+       {
+                       /* get the info the user wanted about the source directory we don't have */
+               if( err == noErr && (filterParams->whichInfo & ~kFSCatInfoSettableInfo) != kFSCatInfoNone )
+                       err = FSGetCatalogInfo(&newDirRef, filterParams->whichInfo & ~kFSCatInfoSettableInfo, &catInfo, NULL, NULL, NULL);
+
+               err = CallCopyObjectFilterProc(filterParams->filterProcPtr, false, folderGlobals.currentLevel,
+                                                                          err, &catInfo, &newDirRef,
+                                                                          ( filterParams->wantSpec ) ? &newDirSpec : NULL,
+                                                                          ( filterParams->wantName ) ? newObjectName : NULL,
+                                                                            filterParams->yourDataPtr);
+       }
+       if( err == noErr )              /* create the memory for this folder */
+               err = ( ( tmpListData = (FolderListData*) NewPtr( sizeof( FolderListData ) ) ) != NULL ) ? noErr : MemError();
+       if( err == noErr )
+       {               /* setup the folder info */
+               tmpListData->sourceDirRef       = *source;
+               tmpListData->destDirRef         = newDirRef;
+               tmpListData->level                      = folderGlobals.currentLevel;
+                       /* add this folder to the list to give ProcessFolderList something to chew on */
+               err = AddToTail( &folderGlobals.folderList, tmpListData );
+               if( err == noErr )                      /* tmpListData added successfully       */
+                       err = ProcessFolderList( &folderGlobals );
+               else                                            /* error occured, so dispose of memory */
+                       DisposePtr( (char*) tmpListData );
+       }
+       
+       dwarning(("\n%s -- %u folders were found\n", __FUNCTION__, (unsigned int)GetNumberOfItems( &folderGlobals.folderList ) ));
+       
+               /* when we're done destroy the list and free up any memory we allocated */
+       DestroyList( &folderGlobals.folderList );
+
+               /* now that the copy is complete, we can set things back to normal      */
+               /* for the directory we just created.                                                           */
+               /* We have to do this only for the top directory of the copy            */
+               /* all subdirectories were created all at once                                          */
+       if( err == noErr && !folderGlobals.copyParams->copyingToDropFolder )
+               err = FSSetCatalogInfo( &newDirRef, kFSCatInfoCreateDate | kFSCatInfoPermissions, sourceCatInfo );
+                                       
+               /* Copy went as planned, and caller wants an FSRef/FSSpec to the new directory */               
+       if( err == noErr )
+       {
+               if( outDirRef != NULL)
+                       *outDirRef = newDirRef;
+               if( outDirSpec != NULL )
+                       *outDirSpec = newDirSpec;
+       }
+
+               /* clean up for space and safety, who me? */
+       if( folderGlobals.catInfoList )
+               DisposePtr( (char*) folderGlobals.catInfoList );
+       if( folderGlobals.srcRefList )
+               DisposePtr( (char*) folderGlobals.srcRefList );
+       if( folderGlobals.nameList )
+               DisposePtr( (char*) folderGlobals.nameList );
+
+       mycheck_noerr(err);     
+
+       return ( err );
+}
+
+/*****************************************************************************/
+
+       /* We now store a list of all the folders/subfolders we encounter in the source */
+       /* Each node in the list contains an FSRef to the source, an FSRef to the               */
+       /* mirror folder in the destination, and the level in the source that folder    */
+       /* is on.  This is done so that we can use FSGetCatalogInfoBulk to its full             */
+       /* potential (getting items in bulk).  We copy the source one folder at a time. */
+       /* Copying over the contents of each folder before we continue on to the next   */
+       /* folder in the list.  This allows us to use the File Manager's own caching    */
+       /* system to our advantage.                                                                                                             */
+static OSErr ProcessFolderList( FSCopyFolderGlobals *folderGlobals )
+{
+       FolderListData          *folderListData;
+       OSErr                           err = noErr;
+       
+               /* iterate through the list of folders and copy over each one individually      */
+       for( InitIterator( &folderGlobals->folderList, &folderGlobals->folderListIter ); folderGlobals->folderListIter != NULL && err == noErr; Next( &folderGlobals->folderListIter ) )
+       {
+                       /* Get the data for this folder */
+               folderListData = (FolderListData*) GetData( folderGlobals->folderListIter );
+               if( folderListData != NULL )
+               {
+                       #if DEBUG && !TARGET_API_MAC_OS8
+                       {
+                               char    path[1024];
+                               myverify_noerr(FSRefMakePath( &(folderListData->sourceDirRef),  (unsigned char*)path, 1024 ));
+                               dwarning(("\n\n%s -- Copying contents of\n\t%s\n", __FUNCTION__, path));
+                               myverify_noerr(FSRefMakePath( &(folderListData->destDirRef),    (unsigned char*)path, 1024 ));
+                               dwarning(("\t\tto\n\t%s\n", path));
+                       }       
+                       #endif
+                       
+                               /* stuff the data into our globals */
+                       folderGlobals->sourceDirRef     = &(folderListData->sourceDirRef);
+                       folderGlobals->destDirRef       = &(folderListData->destDirRef);
+                       folderGlobals->currentLevel = folderListData->level;
+                       
+                               /* Copy over this folder and add any subfolders to our list of folders  */
+                               /* so they will get processed later                                                                             */
+                       err = CopyFolder( folderGlobals );
+               }
+       }
+       
+       return err;
+}
+
+/*****************************************************************************/
+
+       /* Copy the contents of the source into the destination.  If any subfolders */
+       /* are found, add them to a local list of folders during the loop stage         */
+       /* Once the copy is done, insert the local list into the global list right      */
+       /* after the current position in the list.  This is done so we don't jump       */
+       /* all over the disk getting the different folders to copy                                      */
+static OSErr CopyFolder( FSCopyFolderGlobals *folderGlobals )
+{
+       GenLinkedList   tmpList;
+       FolderListData  *tmpListData = NULL;
+       FilterParams    *filterPtr = folderGlobals->filterParams;
+       FSIterator              iterator;
+       FSRef                   newRef;
+       FSSpec                  newSpec;
+       UInt32                  actualObjects;
+       OSErr                   err,
+                                       junkErr;
+       int                             i;
+
+               /* Init the local list */
+       InitLinkedList( &tmpList, MyDisposeDataProc);
+
+       err = FSOpenIterator( folderGlobals->sourceDirRef, kFSIterateFlat, &iterator );
+       if( err == noErr )
+       {
+               do
+               {
+                               /* grab a bunch of objects (kNumObjects) from this folder and copy them over */
+                       err = FSGetCatalogInfoBulk( iterator, kNumObjects, &actualObjects, &filterPtr->containerChanged,
+                                                                               kFSCatInfoSettableInfo, folderGlobals->catInfoList, folderGlobals->srcRefList,
+                                                                               NULL, folderGlobals->nameList );
+                       if( ( err == noErr || err == errFSNoMoreItems ) &&
+                               ( actualObjects != 0 ) )
+                       {                       
+                               dwarning(("%s -- actualObjects retrieved from FSGetCatalogInfoBulk: %u\n",__FUNCTION__, (unsigned int)actualObjects ));
+                       
+                                       /* iterate over the objects actually returned */
+                               for( i = 0; i < actualObjects; i++ )
+                               {
+                                               /* Any errors in here will be passed to the filter proc                         */
+                                               /* we don't want an error in here to prematurely cancel the copy        */
+
+                                               /* If you would like a Pre-Copy filter (i.e to weed out objects         */
+                                               /* you don't want to copy) you should add it here                                       */
+
+                                               /* Is the new object a directory?       */                              
+                                       if( ( folderGlobals->catInfoList[i].nodeFlags & kFSNodeIsDirectoryMask ) != 0 )
+                                       {               /* yes */
+                                               junkErr = CreateFolder( &folderGlobals->srcRefList[i], folderGlobals->destDirRef,
+                                                                                               &folderGlobals->catInfoList[i], &folderGlobals->nameList[i],
+                                                                                               folderGlobals->copyParams, &newRef, (filterPtr->wantSpec) ? &newSpec : NULL );
+                                                       /* If maxLevels is zero, we aren't checking levels                              */
+                                                       /* If currentLevel+1 < maxLevels, add this folder to the list   */
+                                               if( folderGlobals->maxLevels == 0 || (folderGlobals->currentLevel + 1) < folderGlobals->maxLevels )
+                                               {
+                                                       if( junkErr == noErr )          /* Create memory for folder list data   */
+                                                               junkErr = ( ( tmpListData = (FolderListData*) NewPtr( sizeof( FolderListData ) ) ) != NULL ) ? noErr : MemError();
+                                                       if( junkErr == noErr )
+                                                       {                                                       /* Setup the folder list data                   */
+                                                               tmpListData->sourceDirRef       = folderGlobals->srcRefList[i];
+                                                               tmpListData->destDirRef         = newRef;
+                                                               tmpListData->level                      = folderGlobals->currentLevel + 1;
+                                                               
+                                                                                                               /* Add it to the local list                             */
+                                                               junkErr = AddToTail( &tmpList, tmpListData );
+                                                       }
+                                                               /* If an error occured and memory was created, we need to dispose of it */
+                                                               /* since it was not added to the list                                                                   */
+                                                       if( junkErr != noErr && tmpListData != NULL )
+                                                               DisposePtr( (char*) tmpListData );
+                                               }
+                                       }
+                                       else
+                                       {               /* no */
+                                               junkErr = CopyFile(     &folderGlobals->srcRefList[i], &folderGlobals->catInfoList[i], 
+                                                                                       folderGlobals->destDirRef, &folderGlobals->nameList[i], 
+                                                                                       folderGlobals->copyParams, &newRef, ( filterPtr->wantSpec ) ? &newSpec : NULL );
+                                       }
+                                       
+                                               /* Note: if an error occured above, the FSRef and other info might not be valid */
+                                       if( filterPtr->filterProcPtr != NULL )
+                                       {
+                                               if( junkErr == noErr && (filterPtr->whichInfo & ~kFSCatInfoSettableInfo) != kFSCatInfoNone )    /* get the extra info about the new object that the user wanted that we don't already have */
+                                                       junkErr = FSGetCatalogInfo( &newRef, filterPtr->whichInfo & ~kFSCatInfoSettableInfo, &folderGlobals->catInfoList[i], NULL, NULL, NULL );
+
+                                               err = CallCopyObjectFilterProc( filterPtr->filterProcPtr, filterPtr->containerChanged,
+                                                                                                               folderGlobals->currentLevel, junkErr,
+                                                                                                               &folderGlobals->catInfoList[i], &newRef,
+                                                                                                               ( filterPtr->wantSpec ) ? &newSpec : NULL,
+                                                                                                               ( filterPtr->wantName ) ? &folderGlobals->nameList[i] : NULL,
+                                                                                                               filterPtr->yourDataPtr);
+                                       }
+                               }
+                       }
+               }while( err == noErr );
+       
+                       /* errFSNoMoreItems is OK - it only means we hit the end of this level */
+                       /* afpAccessDenied is OK too - it only means we cannot see inside the directory */
+               if( err == errFSNoMoreItems || err == afpAccessDenied )
+                       err = noErr;
+
+                       /* Insert the local list of folders from the current folder into our global list.  Even */
+                       /* if no items were added to the local list (due to error, or empty folder), InsertList */
+                       /* handles it correctly.  We add the local list even if an error occurred.  It will get */
+                       /* disposed of when the global list is destroyed.  Doesn't hurt to have a couple extra  */
+                       /* steps when we're going to bail anyways.                                                                                              */
+               InsertList( &folderGlobals->folderList, &tmpList, folderGlobals->folderListIter );      
+                       
+                       /* Close the FSIterator (closing an open iterator should never fail) */
+               (void) FSCloseIterator(iterator);
+       }
+
+       mycheck_noerr( err );   
+       
+       return err;
+}
+
+/*****************************************************************************/
+
+       /* Determines whether the destination directory is equal to the source  */
+       /* item, or whether it's nested inside the source item.  Returns a              */
+       /* errFSDestInsideSource if that's the case.  We do this to prevent             */
+       /* endless recursion while copying.                                                                             */
+       /*                                                                                                                                              */
+static OSErr CheckForDestInsideSrc(    const FSRef     *source,
+                                                                       const FSRef     *destDir)
+{
+       FSRef                   thisDir = *destDir;
+       FSCatalogInfo   thisDirInfo;
+       Boolean                 done = false;
+       OSErr                   err;
+       
+       do
+       {
+               err = FSCompareFSRefs(source, &thisDir);
+               if (err == noErr)
+                       err = errFSDestInsideSource;
+               else if (err == diffVolErr)
+               {
+                       err = noErr;
+                       done = true;
+               } 
+               else if (err == errFSRefsDifferent)
+               {
+                       /* This is somewhat tricky.  We can ask for the parent of thisDir       */
+                       /* by setting the parentRef parameter to FSGetCatalogInfo but, if       */
+                       /* thisDir is the volume's FSRef, this will give us back junk.          */
+                       /* So we also ask for the parent's dir ID to be returned in the         */
+                       /* FSCatalogInfo record, and then check that against the node           */
+                       /* ID of the root's parent (ie 1).  If we match that, we've made        */
+                       /* it to the top of the hierarchy without hitting source, so            */
+                       /* we leave with no error.                                                                                      */
+                       
+                       err = FSGetCatalogInfo(&thisDir, kFSCatInfoParentDirID, &thisDirInfo, NULL, NULL, &thisDir);
+                       if( ( err == noErr ) && ( thisDirInfo.parentDirID == fsRtParID ) )
+                               done = true;
+               }
+       } while ( err == noErr && ! done );
+       
+       mycheck_noerr( err );   
+
+       return err;
+}
+
+/*****************************************************************************/
+
+#pragma mark ----- Copy Forks -----
+
+       /* This is where the majority of the work is done.  I special cased             */
+       /* DropBoxes in order to use FSIterateForks to its full potential for   */
+       /* the more common case (read/write permissions).  It also simplifies   */
+       /* the code to have it seperate.                                                                                */
+static OSErr CopyForks(        const FSRef             *source,
+                                               const FSRef             *dest,
+                                               CopyParams              *params)
+{
+       OSErr                   err;
+
+       err = ( !params->copyingToDropFolder ) ?        CopyForksToDisk         ( source, dest, params ) :
+                                                                                               CopyForksToDropBox      ( source, dest, params );
+
+       mycheck_noerr( err );   
+
+       return err;
+}
+
+       /* Open each fork individually and copy them over to the destination                            */
+static OSErr CopyForksToDisk(  const FSRef     *source,
+                                                               const FSRef     *dest,
+                                                               CopyParams      *params )
+{
+       HFSUniStr255    forkName;
+       CatPositionRec  iterator;
+       SInt64                  forkSize;
+       SInt16                  srcRefNum,
+                                       destRefNum;
+       OSErr                   err;
+       
+               /* need to initialize the iterator before using it */
+       iterator.initialize = 0;
+       
+       do
+       {
+               err = FSIterateForks( source, &iterator, &forkName, &forkSize, NULL );
+
+                       /* Create the fork.  Note: Data and Resource forks are automatically            */
+                       /* created when the file is created.  FSCreateFork returns noErr for them       */
+                       /* We also want to create the fork even if there is no data to preserve         */
+                       /* empty forks                                                                                                                          */
+               if( err == noErr )
+                       err = FSCreateFork( dest, forkName.length, forkName.unicode );
+
+                       /* Mac OS 9.0 has a bug (in the AppleShare external file system,                        */
+                       /* I think) [2410374] that causes FSCreateFork to return an errFSForkExists     */
+                       /* error even though the fork is empty.  The following code swallows            */
+                       /* the error (which is harmless) in that case.                                                          */
+               if( err == errFSForkExists && !params->copyingToLocalVolume )
+                       err = noErr;
+
+                       /* The remainder of this code only applies if there is actual data                      */
+                       /* in the source fork.                                                                                                          */
+
+               if( err == noErr && forkSize > 0 )
+               {
+                       destRefNum = srcRefNum = 0;
+                       
+                                                                       /* Open the destination fork    */
+                       err = FSOpenFork(dest, forkName.length, forkName.unicode, fsWrPerm, &destRefNum);
+                       if( err == noErr )              /* Open the source fork                 */
+                               err = FSOpenFork(source, forkName.length, forkName.unicode, fsRdPerm, &srcRefNum);
+                       if( err == noErr )              /* Write the fork to disk               */
+                               err = WriteFork( srcRefNum, destRefNum, params, forkSize );
+
+                       if( destRefNum  != 0 )  /* Close the destination fork   */
+                               myverify_noerr( FSCloseFork( destRefNum ) );
+                       if( srcRefNum   != 0 )  /* Close the source fork                */
+                               myverify_noerr( FSCloseFork( srcRefNum ) );
+               }                                       
+       }
+       while( err == noErr );
+       
+       if( err == errFSNoMoreItems )
+               err = noErr;
+
+       mycheck_noerr( err );
+               
+       return err;
+}
+
+       /* If we're copying to a DropBox, we have to handle the copy process a little           */
+       /* differently then when we are copying to a regular folder.                                            */
+static OSErr CopyForksToDropBox(       const FSRef             *source,
+                                                                       const FSRef             *dest,
+                                                                       CopyParams              *params )
+{
+       GenLinkedList   forkList;
+       GenIteratorPtr  pIter;
+       ForkTrackerPtr  forkPtr;
+       SInt16                  srcRefNum;
+       OSErr                   err;
+
+       InitLinkedList( &forkList, MyCloseForkProc );
+       
+               /* If we're copying into a drop folder, open up all of those forks.     */
+               /* We have to do this because once we've started writing to a fork      */
+               /* in a drop folder, we can't open any more forks.                                      */
+       err = OpenAllForks( dest, &forkList );
+               
+               /* Copy each fork over to the destination                                                       */
+       for( InitIterator( &forkList, &pIter ); pIter != NULL && err == noErr; Next( &pIter ) )
+       {
+               srcRefNum       = 0;
+               forkPtr         = GetData( pIter );
+                                                               /* Open the source fork         */
+               err = FSOpenFork(source, forkPtr->forkName.length, forkPtr->forkName.unicode, fsRdPerm, &srcRefNum);
+               if( err == noErr )              /* Write the data over          */
+                       err = WriteFork( srcRefNum, forkPtr->forkDestRefNum, params, forkPtr->forkSize );
+
+               if( srcRefNum   != 0 )  /* Close the source fork        */
+                       myverify_noerr( FSCloseFork( srcRefNum ) );
+       }
+               /* we're done, so destroy the list even if an error occured                             */
+               /* the DisposeDataProc will close any open forks                                                */
+       DestroyList( &forkList );
+
+       mycheck_noerr( err );
+
+       return err;
+}
+
+/*****************************************************************************/
+
+       /* Create and open all the forks in the destination file.  We need to do this when              */
+       /* we're copying into a drop folder, where you must open all the forks before starting  */
+       /* to write to any of them.                                                                                                                             */
+       /*                                                                                                                                                                              */
+       /* IMPORTANT:  If it fails, this routine won't close forks that opened successfully.    */
+       /*              Make sure that the DisposeDataProc for the forkList closed any open forks               */
+       /*              Or you close each one manually before destroying the list                                               */
+static OSErr OpenAllForks(     const FSRef             *dest,
+                                                       GenLinkedList   *forkList )
+{
+       ForkTrackerPtr  forkPtr;
+       HFSUniStr255    forkName;
+       CatPositionRec  iterator;
+       SInt64                  forkSize;
+       OSErr                   err = ( dest != NULL && forkList != NULL ) ? noErr : paramErr;
+       
+               /* need to initialize the iterator before using it */
+       iterator.initialize = 0;
+       
+               /* Iterate over the list of forks       */
+       while( err == noErr )
+       {
+               forkPtr = NULL; /* init forkPtr */
+               
+               err = FSIterateForks( dest, &iterator, &forkName, &forkSize, NULL );
+               if( err == noErr )
+                       err = ( forkPtr = (ForkTrackerPtr) NewPtr( sizeof( ForkTracker ) ) ) != NULL ? noErr : MemError();
+               if( err == noErr )
+               {
+                       forkPtr->forkName               = forkName;
+                       forkPtr->forkSize               = forkSize;
+                       forkPtr->forkDestRefNum = 0;
+
+                               /* Create the fork.  Note: Data and Resource forks are automatically            */
+                               /* created when the file is created.  FSCreateFork returns noErr for them       */
+                               /* We also want to create the fork even if there is no data to preserve         */
+                               /* empty forks                                                                                                                          */
+                       err = FSCreateFork( dest, forkName.length, forkName.unicode );
+
+                               /* Swallow afpAccessDenied because this operation causes the external file      */
+                               /* system compatibility shim in Mac OS 9 to generate a GetCatInfo request       */
+                               /* to the AppleShare external file system, which in turn causes an AFP          */
+                               /* GetFileDirParms request on the wire, which the AFP server bounces with       */
+                               /* afpAccessDenied because the file is in a drop folder.  As there's no         */
+                               /* native support for non-classic forks in current AFP, there's no way I        */
+                               /* can decide how I should handle this in a non-test case.  So I just           */
+                               /* swallow the error and hope that when native AFP support arrives, the         */
+                               /* right thing will happen.                                                                                                     */
+                       if( err == afpAccessDenied )
+                               err = noErr;
+                               
+                               /* only open the fork if the fork has some data                                                         */
+                       if( err == noErr && forkPtr->forkSize > 0 )
+                               err = FSOpenFork( dest, forkPtr->forkName.length, forkPtr->forkName.unicode, fsWrPerm, &forkPtr->forkDestRefNum );
+
+                               /* if everything is ok, add this fork to the list                                                       */
+                       if( err == noErr )
+                               err = AddToTail( forkList, forkPtr );
+               }
+               if( err != noErr && forkPtr != NULL )
+                       DisposePtr( (char*) forkPtr );
+       }
+
+       if( err == errFSNoMoreItems )
+               err = noErr;
+
+       mycheck_noerr( err );   
+
+       return err;
+}
+
+/*****************************************************************************/
+
+       /* Writes the fork from the source, references by srcRefNum, to the destination fork    */
+       /* references by destRefNum                                                                                                                             */
+static OSErr WriteFork(        const SInt16            srcRefNum,
+                                               const SInt16            destRefNum,
+                                               const CopyParams        *params,
+                                               const SInt64            forkSize )
+{
+       UInt64                  bytesRemaining;
+       UInt64                  bytesToReadThisTime;
+       UInt64                  bytesToWriteThisTime;
+       OSErr                   err;
+       
+
+               /* Here we create space for the entire fork on the destination volume.                          */      
+               /* FSAllocateFork has the right semantics on both traditional Mac OS                            */
+               /* and Mac OS X.  On traditional Mac OS it will allocate space for the                          */
+               /* file in one hit without any other special action.  On Mac OS X,                                      */
+               /* FSAllocateFork is preferable to FSSetForkSize because it prevents                            */
+               /* the system from zero filling the bytes that were added to the end                            */
+               /* of the fork (which would be waste because we're about to write over                          */
+               /* those bytes anyway.                                                                                                                          */
+       err = FSAllocateFork(destRefNum, kFSAllocNoRoundUpMask, fsFromStart, 0, forkSize, NULL);
+
+               /* Copy the file from the source to the destination in chunks of                                        */
+               /* no more than params->copyBufferSize bytes.  This is fairly                                           */
+               /* boring code except for the bytesToReadThisTime/bytesToWriteThisTime                          */
+               /* distinction.  On the last chunk, we round bytesToWriteThisTime                                       */
+               /* up to the next 512 byte boundary and then, after we exit the loop,                           */
+               /* we set the file's EOF back to the real location (if the fork size                            */
+               /* is not a multiple of 512 bytes).                                                                                                     */
+               /*                                                                                                                                                                      */
+               /* This technique works around a 'bug' in the traditional Mac OS File Manager,          */
+               /* where the File Manager will put the last 512-byte block of a large write into        */
+               /* the cache (even if we specifically request no caching) if that block is not          */
+               /* full. If the block goes into the cache it will eventually have to be                         */
+               /* flushed, which causes sub-optimal disk performance.                                                          */
+               /*                                                                                                                                                                      */
+               /* This is only done if the destination volume is local.  For a network                         */
+               /* volume, it's better to just write the last bytes directly.                                           */
+               /*                                                                                                                                                                      */
+               /* This is extreme over-optimization given the other limits of this                                     */
+               /* sample, but I will hopefully get to the other limits eventually.                                     */
+       bytesRemaining = forkSize;
+       while( err == noErr && bytesRemaining != 0 )
+       {
+               if( bytesRemaining > params->copyBufferSize )
+               {
+                       bytesToReadThisTime  =  params->copyBufferSize;
+                       bytesToWriteThisTime =  bytesToReadThisTime;
+               }
+               else 
+               {
+                       bytesToReadThisTime  =  bytesRemaining;
+                       bytesToWriteThisTime =  ( params->copyingToLocalVolume )                  ?
+                                                                       ( (bytesRemaining + 0x01FF ) & ~0x01FF ) : bytesRemaining;
+               }
+               
+               err = FSReadFork( srcRefNum, fsAtMark + noCacheMask, 0, bytesToReadThisTime, params->copyBuffer, NULL );
+               if( err == noErr )
+                       err = FSWriteFork( destRefNum, fsAtMark + noCacheMask, 0, bytesToWriteThisTime, params->copyBuffer, NULL );
+               if( err == noErr )
+                       bytesRemaining -= bytesToReadThisTime;
+       }
+       
+       if (err == noErr && params->copyingToLocalVolume && ( forkSize & 0x01FF ) != 0 )
+               err = FSSetForkSize( destRefNum, fsFromStart, forkSize );
+
+       return err;
+}
+
+/*****************************************************************************/
+
+#pragma mark ----- Calculate Buffer Size -----
+
+       /* This routine calculates the appropriate buffer size for                              */
+       /* the given volParms.  It's a simple composition of FSGetVolParms              */
+       /* BufferSizeForVolSpeed.                                                                                               */
+static UInt32 CalcBufferSizeForVol(const GetVolParmsInfoBuffer *volParms, UInt32 volParmsSize)
+{
+       UInt32  volumeBytesPerSecond = 0;
+
+       /* Version 1 of the GetVolParmsInfoBuffer included the vMAttrib         */
+       /* field, so we don't really need to test actualSize.  A noErr          */
+       /* result indicates that we have the info we need.  This is                     */
+       /* just a paranoia check.                                                                                       */
+       
+       mycheck(volParmsSize >= offsetof(GetVolParmsInfoBuffer, vMVolumeGrade));
+
+       /* On the other hand, vMVolumeGrade was not introduced until            */
+       /* version 2 of the GetVolParmsInfoBuffer, so we have to explicitly     */
+       /* test whether we got a useful value.                                                          */
+       
+       if( ( volParmsSize >= offsetof(GetVolParmsInfoBuffer, vMForeignPrivID) ) &&
+               ( volParms->vMVolumeGrade <= 0 ) ) 
+       {
+               volumeBytesPerSecond = -volParms->vMVolumeGrade;
+       }
+
+       return BufferSizeForVolSpeed(volumeBytesPerSecond);
+}
+
+/*****************************************************************************/
+
+       /* Calculate an appropriate copy buffer size based on the volumes               */
+       /* rated speed.  Our target is to use a buffer that takes 0.25                  */
+       /* seconds to fill.  This is necessary because the volume might be              */
+       /* mounted over a very slow link (like ARA), and if we do a 256 KB              */
+       /* read over an ARA link we'll block the File Manager queue for                 */
+       /* so long that other clients (who might have innocently just                   */
+       /* called PBGetCatInfoSync) will block for a noticeable amount of time. */
+       /*                                                                                                                                              */
+       /* Note that volumeBytesPerSecond might be 0, in which case we assume   */
+       /* some default value.                                                                                                  */
+static UInt32 BufferSizeForVolSpeed(UInt32 volumeBytesPerSecond)
+{
+       ByteCount bufferSize;
+       
+       if (volumeBytesPerSecond == 0)
+               bufferSize = kDefaultCopyBufferSize;
+       else
+       {       /* We want to issue a single read that takes 0.25 of a second,  */
+               /* so devide the bytes per second by 4.                                                 */
+               bufferSize = volumeBytesPerSecond / 4;
+       }
+       
+               /* Round bufferSize down to 512 byte boundary. */
+       bufferSize &= ~0x01FF;
+       
+               /* Clip to sensible limits. */
+       if (bufferSize < kMinimumCopyBufferSize)
+               bufferSize = kMinimumCopyBufferSize;
+       else if (bufferSize > kMaximumCopyBufferSize)
+               bufferSize = kMaximumCopyBufferSize;
+               
+       return bufferSize;
+}
+
+/*****************************************************************************/
+
+#pragma mark ----- Delete Objects -----
+
+OSErr FSDeleteObjects( const FSRef *source )
+{
+       FSCatalogInfo   catalogInfo;
+       OSErr                   err = ( source != NULL ) ? noErr : paramErr;
+       
+       #if DEBUG && !TARGET_API_MAC_OS8
+       if( err == noErr )
+       {
+               char    path[1024];
+               myverify_noerr(FSRefMakePath( source,   (unsigned char*)path, 1024 ));
+               dwarning(("\n%s -- Deleting %s\n", __FUNCTION__, path));
+       }       
+       #endif
+
+               /* get nodeFlags for container */
+       if( err == noErr )
+               err = FSGetCatalogInfo(source, kFSCatInfoNodeFlags, &catalogInfo, NULL, NULL,NULL);
+       if( err == noErr && (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) != 0 )
+       {               /* its a directory, so delete its contents before we delete it */
+               err = FSDeleteFolder(source);
+       }
+       if( err == noErr && (catalogInfo.nodeFlags & kFSNodeLockedMask) != 0 )  /* is object locked? */
+       {               /* then attempt to unlock the object (ignore err since FSDeleteObject will set it correctly) */
+               catalogInfo.nodeFlags &= ~kFSNodeLockedMask;
+               (void) FSSetCatalogInfo(source, kFSCatInfoNodeFlags, &catalogInfo);
+       }               
+       if( err == noErr )      /* delete the object (if it was a directory it is now empty, so we can delete it) */
+               err = FSDeleteObject(source);
+
+       mycheck_noerr( err );
+       
+       return ( err );
+}
+
+/*****************************************************************************/
+
+#pragma mark ----- Delete Folders -----
+
+static OSErr FSDeleteFolder( const FSRef *container )
+{
+       FSDeleteObjectGlobals   theGlobals;
+       
+       theGlobals.result = ( container != NULL ) ? noErr : paramErr;
+       
+               /* delete container's contents */
+       if( theGlobals.result == noErr )
+               FSDeleteFolderLevel(container, &theGlobals);
+       
+       mycheck_noerr( theGlobals.result );
+       
+       return ( theGlobals.result );
+}
+
+/*****************************************************************************/
+
+static void FSDeleteFolderLevel(const FSRef                            *container,
+                                                               FSDeleteObjectGlobals   *theGlobals )
+{
+       FSIterator                                      iterator;
+       FSRef                                           itemToDelete;
+       UInt16                                          nodeFlags;
+
+               /* Open FSIterator for flat access and give delete optimization hint */
+       theGlobals->result = FSOpenIterator(container, kFSIterateFlat + kFSIterateDelete, &iterator);
+       if ( theGlobals->result == noErr )
+       {
+               do      /* delete the contents of the directory */
+               {
+                               /* get 1 item to delete */
+                       theGlobals->result = FSGetCatalogInfoBulk(      iterator, 1, &theGlobals->actualObjects,
+                                                                                                               NULL, kFSCatInfoNodeFlags, &theGlobals->catalogInfo,
+                                                                                                               &itemToDelete, NULL, NULL);
+                       if ( (theGlobals->result == noErr) && (theGlobals->actualObjects == 1) )
+                       {
+                                       /* save node flags in local in case we have to recurse */
+                               nodeFlags = theGlobals->catalogInfo.nodeFlags;
+                               
+                                       /* is it a directory? */
+                               if ( (nodeFlags & kFSNodeIsDirectoryMask) != 0 )
+                               {       /* yes -- delete its contents before attempting to delete it */ 
+                                       FSDeleteFolderLevel(&itemToDelete, theGlobals);
+                               }
+                               if ( theGlobals->result == noErr)                       /* are we still OK to delete? */
+                               {       
+                                       if ( (nodeFlags & kFSNodeLockedMask) != 0 )     /* is item locked? */
+                                       {               /* then attempt to unlock it (ignore result since FSDeleteObject will set it correctly) */
+                                               theGlobals->catalogInfo.nodeFlags = nodeFlags & ~kFSNodeLockedMask;
+                                               (void) FSSetCatalogInfo(&itemToDelete, kFSCatInfoNodeFlags, &theGlobals->catalogInfo);
+                                       }
+                                               /* delete the item */
+                                       theGlobals->result = FSDeleteObject(&itemToDelete);
+                               }
+                       }
+               } while ( theGlobals->result == noErr );
+                       
+                       /* we found the end of the items normally, so return noErr */
+               if ( theGlobals->result == errFSNoMoreItems )
+                       theGlobals->result = noErr;
+                       
+                       /* close the FSIterator (closing an open iterator should never fail) */
+               myverify_noerr(FSCloseIterator(iterator));
+       }
+
+       mycheck_noerr( theGlobals->result );
+       
+       return;
+}
+
+/*****************************************************************************/
+
+#pragma mark ----- Utilities -----
+
+       /* Figures out if the given directory is a drop box or not              */
+       /* if it is, the Copy Engine will behave slightly differently   */
+static OSErr IsDropBox(        const FSRef* source,
+                                               Boolean *isDropBox )
+{
+       FSCatalogInfo                   tmpCatInfo;
+       FSSpec                                  sourceSpec;
+       Boolean                                 isDrop = false;
+       OSErr                                   err;
+       
+               /* get info about the destination, and an FSSpec to it for PBHGetDirAccess */
+       err = FSGetCatalogInfo(source, kFSCatInfoNodeFlags | kFSCatInfoPermissions, &tmpCatInfo, NULL, &sourceSpec, NULL);
+       if( err == noErr )      /* make sure the source is a directory */
+               err = ((tmpCatInfo.nodeFlags & kFSNodeIsDirectoryMask) != 0) ? noErr : errFSNotAFolder;
+       if( err == noErr )
+       {
+               HParamBlockRec  hPB;
+
+               BlockZero( &hPB, sizeof( HParamBlockRec ) );
+
+               hPB.accessParam.ioNamePtr               = sourceSpec.name;
+               hPB.accessParam.ioVRefNum               = sourceSpec.vRefNum;
+               hPB.accessParam.ioDirID                 = sourceSpec.parID;
+               
+                       /* This is the official way (reads: the way X Finder does it) to figure */
+                       /* out the current users access privileges to a given directory                 */
+               err = PBHGetDirAccessSync(&hPB);
+               if( err == noErr )      /* its a drop folder if the current user only has write access */
+                       isDrop = (hPB.accessParam.ioACAccess & kPrivilegesMask) == kioACAccessUserWriteMask;
+               else if ( err == paramErr )
+               {
+                       /* There is a bug (2908703) in the Classic File System (not OS 9.x or Carbon)   */
+                       /* on 10.1.x where PBHGetDirAccessSync sometimes returns paramErr even when the */
+                       /* data passed in is correct.  This is a workaround/hack for that problem,              */
+                       /* but is not as accurate.                                                                                                              */
+                       /* Basically, if "Everyone" has only Write/Search access then its a drop folder */
+                       /* that is the most common case when its a drop folder                                                  */
+                       FSPermissionInfo *tmpPerm = (FSPermissionInfo *)tmpCatInfo.permissions;
+                       isDrop = ((tmpPerm->mode & kRWXOtherAccessMask) == kDropFolderValue);
+                       err = noErr;
+               }
+       }
+
+       *isDropBox = isDrop;
+
+       mycheck_noerr( err );
+       
+       return err;
+}
+
+/*****************************************************************************/
+
+       /* The copy engine is going to set the item's creation date                     */
+       /* to kMagicBusyCreationDate while it's copying the item.                       */
+       /* But kMagicBusyCreationDate is an old-style 32-bit date/time,         */
+       /* while the HFS Plus APIs use the new 64-bit date/time.  So            */
+       /* we have to call a happy UTC utilities routine to convert from        */
+       /* the local time kMagicBusyCreationDate to a UTCDateTime                       */
+       /* gMagicBusyCreationDate, which the File Manager will store            */
+       /* on disk and which the Finder we read back using the old                      */
+       /* APIs, whereupon the File Manager will convert it back                        */
+       /* to local time (and hopefully get the kMagicBusyCreationDate          */
+       /* back!).                                                                                                                      */
+static OSErr GetMagicBusyCreateDate( UTCDateTime *date )
+{
+       static  UTCDateTime     magicDate       = { 0, 0xDEADBEEF, 0 };
+                       OSErr           err             = ( date != NULL ) ? noErr : paramErr;
+       
+       if( err == noErr && magicDate.lowSeconds == 0xDEADBEEF )
+               err = ConvertLocalTimeToUTC( kMagicBusyCreationDate, &magicDate.lowSeconds );
+       if( err == noErr )
+               *date = magicDate;
+               
+       mycheck_noerr( err );   
+
+       return err;             
+}
+
+/*****************************************************************************/
+
+static OSErr FSGetVRefNum(     const FSRef             *ref,
+                                                       FSVolumeRefNum  *vRefNum)
+{
+       FSCatalogInfo   catalogInfo;
+       OSErr                   err = ( ref != NULL && vRefNum != NULL ) ? noErr : paramErr;
+
+       if( err == noErr )      /* get the volume refNum from the FSRef */
+               err = FSGetCatalogInfo(ref, kFSCatInfoVolume, &catalogInfo, NULL, NULL, NULL);
+       if( err == noErr )
+               *vRefNum = catalogInfo.volume;
+               
+       mycheck_noerr( err );
+
+       return err;
+}
+
+/*****************************************************************************/ 
+
+static OSErr FSGetVolParms(    FSVolumeRefNum                  volRefNum,
+                                                       UInt32                                  bufferSize,
+                                                       GetVolParmsInfoBuffer   *volParmsInfo,
+                                                       UInt32                                  *actualInfoSize)                /*      Can Be NULL     */
+{
+       HParamBlockRec  pb;
+       OSErr                   err = ( volParmsInfo != NULL ) ? noErr : paramErr;
+               
+       if( err == noErr )
+       {
+               pb.ioParam.ioNamePtr = NULL;
+               pb.ioParam.ioVRefNum = volRefNum;
+               pb.ioParam.ioBuffer = (Ptr)volParmsInfo;
+               pb.ioParam.ioReqCount = (SInt32)bufferSize;
+               err = PBHGetVolParmsSync(&pb);
+       }
+               /* return number of bytes the file system returned in volParmsInfo buffer */
+       if( err == noErr && actualInfoSize != NULL)
+               *actualInfoSize = (UInt32)pb.ioParam.ioActCount;
+
+       mycheck_noerr( err );   
+
+       return ( err );
+}
+
+/*****************************************************************************/
+
+/* Converts a unicode string to a PString                                                                              */
+/* If your code is only for OS X, you can use CFString functions to do all this */
+/* Since this sample code supports OS 9.1 -> OS X, I have to do this the               */
+/* old fashioned way.                                                                                                                  */
+static OSErr UniStrToPStr(     const HFSUniStr255      *uniStr,
+                                                       TextEncoding             textEncodingHint,
+                                                       Boolean                          isVolumeName,
+                                                       Str255                           pStr )
+{
+       UnicodeMapping          uMapping;
+       UnicodeToTextInfo       utInfo;
+       ByteCount                       unicodeByteLength = 0;
+       ByteCount                       unicodeBytesConverted;
+       ByteCount                       actualPascalBytes;
+       OSErr                           err = (uniStr != NULL && pStr != NULL) ? noErr : paramErr;
+
+               /* make sure output is valid in case we get errors or there's nothing to convert */
+       pStr[0] = 0;
+
+       if( err == noErr )
+               unicodeByteLength = uniStr->length * sizeof(UniChar); /* length can be zero, which is fine */
+       if( err == noErr && unicodeByteLength != 0 )
+       {
+                       /* if textEncodingHint is kTextEncodingUnknown, get a "default" textEncodingHint */
+               if ( kTextEncodingUnknown == textEncodingHint )
+               {
+                       ScriptCode                      script;
+                       RegionCode                      region;
+                       
+                       script = (ScriptCode)GetScriptManagerVariable(smSysScript);
+                       region = (RegionCode)GetScriptManagerVariable(smRegionCode);
+                       err = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare, 
+                                                                                                       region, NULL, &textEncodingHint );
+                       if ( err == paramErr )
+                       {               /* ok, ignore the region and try again */
+                               err = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare,
+                                                                                                               kTextRegionDontCare, NULL, 
+                                                                                                               &textEncodingHint );
+                       }
+                       if ( err != noErr )                     /* ok... try something */
+                               textEncodingHint = kTextEncodingMacRoman;               
+               }
+               
+               uMapping.unicodeEncoding        = CreateTextEncoding(   kTextEncodingUnicodeV2_0,
+                                                                                                                       kUnicodeCanonicalDecompVariant, 
+                                                                                                                       kUnicode16BitFormat);
+               uMapping.otherEncoding          = GetTextEncodingBase(textEncodingHint);
+               uMapping.mappingVersion         = kUnicodeUseHFSPlusMapping;
+       
+               err = CreateUnicodeToTextInfo(&uMapping, &utInfo);
+               if( err == noErr )
+               {
+                       err = ConvertFromUnicodeToText( utInfo, unicodeByteLength, uniStr->unicode, kUnicodeLooseMappingsMask,
+                                                                                               0, NULL, 0, NULL,       /* offsetCounts & offsetArrays */
+                                                                                               isVolumeName ? kHFSMaxVolumeNameChars : kHFSPlusMaxFileNameChars,
+                                                                                               &unicodeBytesConverted, &actualPascalBytes, &pStr[1]);
+               }
+               if( err == noErr )
+                       pStr[0] = actualPascalBytes;
+               
+                       /* verify the result in debug builds -- there's really not anything you can do if it fails */
+               myverify_noerr(DisposeUnicodeToTextInfo(&utInfo));                              
+       }
+       
+       mycheck_noerr( err );
+       
+       return ( err ); 
+}
+
+/*****************************************************************************/
+
+       /* Yeah I know there is FSpMakeFSRef, but this way I don't have to      */
+       /* actually have an FSSpec created to make the FSRef, and this is       */
+       /* what FSpMakeFSRef does anyways                                                                       */
+static OSErr FSMakeFSRef(      FSVolumeRefNum          volRefNum,
+                                                       SInt32                          dirID,
+                                                       ConstStr255Param        name,
+                                                       FSRef                           *ref )
+{
+       FSRefParam      pb;
+       OSErr           err = ( ref != NULL ) ? noErr : paramErr;
+       
+       if( err == noErr )
+       {
+               pb.ioVRefNum = volRefNum;
+               pb.ioDirID = dirID;
+               pb.ioNamePtr = (StringPtr)name;
+               pb.newRef = ref;
+               err = PBMakeFSRefSync(&pb);
+       }
+       
+       mycheck_noerr( err );   
+               
+       return ( err );
+}
+
+/*****************************************************************************/
+
+       /* This checks the destination to see if an object of the same name as the source       */
+       /* exists or not.  If it does we have to special handle the DupeActions                         */
+       /*                                                                                                                                                                      */
+       /* If kDupeActionReplace we move aside the object by renameing it to ".DeleteMe"        */
+       /* so that it will be invisible (X only), and give a suggestion on what to do with      */
+       /* it if for some unknown reason it survives the copy and the user finds it.  This      */
+       /* rename is mainly done to handle the case where the source is in the destination      */
+       /* and the user wants to replace.  Basically keeping the source around throughout       */
+       /* the copy, deleting it afterwards.  Its also done cause its a good idea not to        */
+       /* dispose of the existing object in case the copy fails                                                        */
+       /*                                                                                                                                                                      */
+       /* If kDupeActionRename, we create a unique name for the new object and pass            */
+       /* it back to the caller                                                                                                                        */
+static OSErr SetupDestination( const FSRef                     *destDir,
+                                                               const DupeAction        dupeAction,
+                                                               HFSUniStr255            *sourceName,
+                                                               FSRef                           *deleteMeRef,
+                                                               Boolean                         *isReplacing )
+{
+       FSRef   tmpRef;
+       OSErr   err;
+
+               /* check if an object of the same name already exists in the destination */
+       err = FSMakeFSRefUnicode( destDir, sourceName->length, sourceName->unicode, kTextEncodingUnknown, &tmpRef );
+       if( err == noErr )
+       {                                                                                                       /* if the user wants to replace the existing            */
+                                                                                                               /* object, rename it to .DeleteMe first.  Delete it     */
+               if( dupeAction == kDupeActionReplace )                  /* only after copying the new one successfully          */
+               {
+                       err = FSRenameUnicode( &tmpRef, 9, (UniChar*)"\0.\0D\0e\0l\0e\0t\0e\0M\0e", kTextEncodingMacRoman, deleteMeRef );
+                       *isReplacing = ( err == noErr ) ? true : false;
+               }
+               else if( dupeAction == kDupeActionRename )              /* if the user wants to just rename it                          */
+                       err = GetUniqueName( destDir, sourceName );     /* then we get a unique name for the new object         */
+       }
+       else if ( err == fnfErr )                                                       /* if no object exists then                                                     */
+               err = noErr;                                                                    /* continue with no error                                                       */
+       
+       return err;
+}
+
+/*****************************************************************************/
+
+       /* Given a directory and a name, GetUniqueName will check if an object  */
+       /* with the same name already exists, and if it does it will create             */
+       /* a new, unique name for and return it.                                                                */
+       /* it simply appends a number to the end of the name.  It is not                */
+       /* fool proof, and it is limited...  I'll take care of that in a                */
+       /* later release                                                                                                                */
+       /* If anyone has any suggestions/better techniques I would love to hear */
+       /* about them                                                                                                                   */
+static OSErr GetUniqueName(    const FSRef             *destDir,
+                                                       HFSUniStr255    *sourceName )
+{
+       HFSUniStr255    tmpName = *sourceName;
+       FSRef                   tmpRef;
+       unsigned char   hexStr[17] = "123456789";       /* yeah, only 9...  I'm lazy, sosumi */
+       long                    count = 0;
+       int                             index;
+       OSErr                   err;    
+
+               /* find the dot, if there is one */
+       for( index = tmpName.length; index >= 0 && tmpName.unicode[index] != (UniChar) '.'; index-- ) { /* Do Nothing */ }              
+       
+       if( index <= 0) /* no dot or first char is a dot (invisible file), so append to end of name */
+               index = tmpName.length;
+       else                    /* shift the extension up two spots to make room for our digits */
+               BlockMoveData( tmpName.unicode + index, tmpName.unicode + index + 2, (tmpName.length - index) * 2 );
+               
+               /* add the space to the name */
+       tmpName.unicode[ index ] = (UniChar)' ';
+               /* we're adding two characters to the name */
+       tmpName.length += 2;
+
+       do {    /* add the digit to the name */
+               tmpName.unicode[ index + 1 ] = hexStr[count];
+                       /* check if the file with this new name already exists */
+               err = FSMakeFSRefUnicode( destDir, tmpName.length, tmpName.unicode, kTextEncodingUnknown, &tmpRef );
+               count++;
+       } while( err == noErr && count < 10 );
+
+       if( err == fnfErr )
+       {
+               err = noErr;
+               *sourceName = tmpName;
+       }
+       
+       return err;
+}
+
+/*****************************************************************************/
+
+static OSErr GetObjectName( const FSRef                        *sourceRef,
+                                                       HFSUniStr255            *sourceName,            /* can be NULL */
+                                                       TextEncoding            *sourceEncoding )       /* can be NULL */
+{
+       FSCatalogInfo           catInfo;
+       FSCatalogInfoBitmap     whichInfo = (sourceEncoding != NULL) ? kFSCatInfoTextEncoding : kFSCatInfoNone;
+       OSErr                           err;
+       
+       err = FSGetCatalogInfo( sourceRef, whichInfo, &catInfo, sourceName, NULL, NULL );
+       if( err == noErr && sourceEncoding != NULL )
+               *sourceEncoding = catInfo.textEncodingHint;
+       
+       return err;
+}
+
+/*****************************************************************************/
+
+static OSErr CreateFolder(     const FSRef                     *sourceRef,
+                                                       const FSRef                     *destDirRef,
+                                                       const FSCatalogInfo     *catalogInfo,
+                                                       const HFSUniStr255      *folderName,
+                                                       CopyParams                      *params,
+                                                       FSRef                           *newFSRefPtr,
+                                                       FSSpec                          *newFSSpecPtr )
+{
+       FSCatalogInfo           tmpCatInfo;
+       FSPermissionInfo        origPermissions;
+       OSErr                           err = ( sourceRef != NULL && destDirRef != NULL && catalogInfo != NULL &&
+                                                               folderName != NULL && newFSRefPtr != NULL ) ? noErr : paramErr;
+
+       if( err == noErr )
+       {               /* store away the catInfo, create date and permissions on the orig folder */
+               tmpCatInfo = *catalogInfo;
+               origPermissions = *((FSPermissionInfo*)catalogInfo->permissions);
+       }
+       if( err == noErr )                      /* create the new folder */
+               err = DoCreateFolder( sourceRef, destDirRef, &tmpCatInfo, folderName, params, newFSRefPtr, newFSSpecPtr ); 
+       if( err == noErr && !params->copyingToDropFolder )
+       {                       /* if its not a drop box, set the permissions on the new folder */
+               *((FSPermissionInfo*)tmpCatInfo.permissions)    = origPermissions;
+               err = FSSetCatalogInfo( newFSRefPtr, kFSCatInfoPermissions, &tmpCatInfo );
+       }
+       
+       mycheck_noerr( err );
+       
+       return err;
+}
+
+/*****************************************************************************/
+
+static OSErr DoCreateFolder(const FSRef                        *sourceRef,
+                                                       const FSRef                     *destDirRef,
+                                                       const FSCatalogInfo     *catalogInfo,
+                                                       const HFSUniStr255      *folderName,
+                                                       CopyParams                      *params,
+                                                       FSRef                           *newFSRefPtr,
+                                                       FSSpec                          *newFSSpecPtr)
+{
+       FSCatalogInfo   catInfo = *catalogInfo;
+       OSErr                   err;
+       
+               /* Clear the "inited" bit so that the Finder positions the icon for us. */
+       ((FInfo *)(catInfo.finderInfo))->fdFlags &= ~kHasBeenInited;
+               
+               /* we need to have user level read/write/execute access to the folder we are going to create,   */
+               /* otherwise FSCreateDirectoryUnicode will return -5000 (afpAccessDenied),                                              */
+               /* and the FSRef returned will be invalid, yet the folder is created...  bug?                                   */
+       ((FSPermissionInfo*) catInfo.permissions)->mode |= kRWXUserAccessMask;
+       
+       err = FSCreateDirectoryUnicode( destDirRef, folderName->length,
+                                                                       folderName->unicode, kFSCatInfoSettableInfo,
+                                                                       &catInfo, newFSRefPtr,
+                                                                       newFSSpecPtr, NULL);
+                                                                       
+               /* With the new APIs, folders can have forks as well as files.  Before  */
+               /* we start copying items in the folder, we     must copy over the forks        */
+               /* Currently, MacOS doesn't support any file systems that have forks in */
+               /* folders, but the API supports it so (for possible future                             */
+               /* compatability) I kept this in here.                                                                  */
+       if( err == noErr )
+               err = CopyForks( sourceRef, newFSRefPtr, params );
+       
+       mycheck_noerr( err );
+
+       return err;
+}
+
+/*****************************************************************************/
+
+       /* This is the DisposeDataProc that is used by the GenLinkedList in FSCopyFolder        */
+       /* Simply disposes of the data we created and returns                                                           */
+static pascal void MyDisposeDataProc( void *pData )
+{
+       if( pData != NULL )
+               DisposePtr( (char*) pData );
+}
+
+/*****************************************************************************/
+
+       /* This is the DisposeDataProc that is used by the GenLinkedList in CopyItemForks       */
+       /* Simply closes the resource fork (if opened, != 0) and disposes of the memory         */
+static pascal void MyCloseForkProc( void *pData )
+{
+       SInt16          refNum;
+
+       if( pData == NULL )
+               return;
+               
+       refNum = ((ForkTrackerPtr)pData)->forkDestRefNum;
+       if( refNum != 0 )
+               myverify_noerr( FSCloseFork( refNum ) );        /* the fork was opened, so close it */
+       
+       DisposePtr( (char*) pData );    
+}
diff --git a/wolf3d/code/iphone/FSCopyObject.h b/wolf3d/code/iphone/FSCopyObject.h
new file mode 100644 (file)
index 0000000..3189f00
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+       File:           FSCopyObject.h
+       
+       Contains:       A Copy/Delete Files/Folders engine which uses the HFS+ API's
+
+       Disclaimer:     IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+                               ("Apple") in consideration of your agreement to the following terms, and your
+                               use, installation, modification or redistribution of this Apple software
+                               constitutes acceptance of these terms.  If you do not agree with these terms,
+                               please do not use, install, modify or redistribute this Apple software.
+
+                               In consideration of your agreement to abide by the following terms, and subject
+                               to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
+                               copyrights in this original Apple software (the "Apple Software"), to use,
+                               reproduce, modify and redistribute the Apple Software, with or without
+                               modifications, in source and/or binary forms; provided that if you redistribute
+                               the Apple Software in its entirety and without modifications, you must retain
+                               this notice and the following text and disclaimers in all such redistributions of
+                               the Apple Software.  Neither the name, trademarks, service marks or logos of
+                               Apple Computer, Inc. may be used to endorse or promote products derived from the
+                               Apple Software without specific prior written permission from Apple.  Except as
+                               expressly stated in this notice, no other rights or licenses, express or implied,
+                               are granted by Apple herein, including but not limited to any patent rights that
+                               may be infringed by your derivative works or by other works in which the Apple
+                               Software may be incorporated.
+
+                               The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+                               WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+                               WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+                               PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+                               COMBINATION WITH YOUR PRODUCTS.
+
+                               IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+                               CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+                               GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+                               ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+                               OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+                               (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+                               ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+       Copyright © 2002-2004 Apple Computer, Inc., All Rights Reserved
+*/
+
+
+#ifndef __FSCOPYOBJECT_H__
+#define __FSCOPYOBJECT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if TARGET_API_MAC_OSX || defined( __APPLE_CC__ )
+#include       <CoreServices/CoreServices.h>
+#endif
+
+#define DEBUG  1       /* set to zero if you don't want debug spew */
+
+#if DEBUG
+       #include <stdio.h>
+
+       #define QuoteExceptionString(x) #x
+
+       #define dwarning(s)                                     do { printf s; fflush(stderr); } while( 0 )                                     
+
+       #define mycheck_noerr( error )                                                                                          \
+               do {                                                                                                                                    \
+                       if( (OSErr) error != noErr ) {                                                                          \
+                  dwarning((QuoteExceptionString(error) " != noErr in File: %s, Function: %s, Line: %d, Error: %d\n",  \
+                                                                         __FILE__, __FUNCTION__, __LINE__, (OSErr) error));            \
+                }                                                                                                                                      \
+               } while( false )
+
+       #define mycheck( assertion )                                                                                            \
+               do {                                                                                                                                    \
+                       if( ! assertion ) {                                                                                                     \
+                  dwarning((QuoteExceptionString(assertion) " failed in File: %s, Function: %s, Line: %d\n",   \
+                                                                         __FILE__, __FUNCTION__, __LINE__));   \
+                       }                                                                                                                                       \
+               } while( false )
+
+    #define myverify(assertion)                        mycheck(assertion)
+    #define myverify_noerr(assertion)  mycheck_noerr( (assertion) )
+#else
+    #define    dwarning(s)
+    
+       #define mycheck(assertion)
+       #define mycheck_noerr(err)
+    #define myverify(assertion)                        do { (void) (assertion); } while (0)
+    #define myverify_noerr(assertion)  myverify(assertion)    
+#endif
+
+/*
+       This code takes some tricks/techniques from MoreFilesX (by Jim Luther) and
+       MPFileCopy (by Quinn), wraps them all up into an easy to use API, and adds a bunch of
+       features and bug fixes.  It will run on Mac OS 9.1 through 9.2.x and 10.1.x
+       and up (Classic, Carbon and Mach-O)
+*/
+
+       /* Different options that FSCopyObject can take during a copy */
+typedef        UInt32                          DupeAction;
+enum {
+       kDupeActionStandard,    /* will do the copy with no frills */
+       kDupeActionReplace,             /* will delete the existing object and then copy over the new one */
+       kDupeActionRename               /* will rename the new object if an object of the same name exists */
+};
+
+/*****************************************************************************/
+
+#pragma mark CopyObjectFilterProcPtr
+
+/*
+       This is the prototype for the CallCopyObjectFilterProc function which
+       is called once for each file and directory found by FSCopyObject.
+       The CallCopyObjectFilterProc can use the read-only data it receives for
+       whatever it wants.
+
+       The result of the CallCopyObjectFilterProc function indicates if
+       the copy should be stopped.  To stop the copy, return an error; to continue
+       the copy, return noErr.
+
+       The yourDataPtr parameter can point to whatever data structure you might
+       want to access from within the CallCopyObjectFilterProc.
+       
+       Note: If an error had occured during the copy of the current object
+       (currentOSErr != noErr) the FSRef etc might not be valid
+
+       containerChanged        --> Set to true if the container's contents changed
+                                                       during iteration.
+       currentLevel            --> The current recursion level into the container.
+                                                       1 = the container, 2 = the container's immediate
+                                                       subdirectories, etc.
+       currentOSErr            --> The current error code, shows the results of the
+                                                       copy of the current object (ref)
+       catalogInfo                     --> The catalog information for the current object.
+                                                       Only the fields requested by the whichInfo
+                                                       parameter passed to FSIterateContainer are valid.
+       ref                                     --> The FSRef to the current object.
+       spec                            --> The FSSpec to the current object if the wantFSSpec
+                                                       parameter passed to FSCopyObject is true.
+       name                            --> The name of the current object if the wantName
+                                                       parameter passed to FSCopyObject is true.
+       yourDataPtr                     --> An optional pointer to whatever data structure you
+                                                       might want to access from within the
+                                                       CallCopyObjectFilterProc.
+       result                          <-- To continue the copy, return noErr
+       
+       __________
+
+       Also see:       FSCopyObject
+*/
+
+typedef CALLBACK_API( OSErr , CopyObjectFilterProcPtr ) (
+       Boolean containerChanged,
+       ItemCount currentLevel,
+       OSErr currentOSErr,
+       const FSCatalogInfo *catalogInfo,
+       const FSRef *ref,
+       const FSSpec *spec,
+       const HFSUniStr255 *name,
+       void *yourDataPtr);
+
+
+/*****************************************************************************/
+
+#pragma mark CallCopyObjectFilterProc
+
+#define CallCopyObjectFilterProc(userRoutine, containerChanged, currentLevel, currentOSErr, catalogInfo, ref, spec, name, yourDataPtr) \
+       (*(userRoutine))((containerChanged), (currentLevel), (currentOSErr), (catalogInfo), (ref), (spec), (name), (yourDataPtr))
+
+/*****************************************************************************/
+
+#pragma mark FSCopyObject
+
+/*
+       The FSCopyObject function takes a source object (can be a file or directory)
+       and copies it (and its contents if it's a directory) to the new destination
+       directory.
+       
+       It will call your CopyObjectFilterProcPtr once for each object copied
+
+       The maxLevels parameter is only used when the object is a directory,
+       ignored otherwise.
+       It lets you control how deep the recursion goes.
+       If maxLevels is 1, FSCopyObject only scans the specified directory;
+       if maxLevels is 2, FSCopyObject scans the specified directory and
+       one subdirectory below the specified directory; etc. Set maxLevels to
+       zero to scan all levels.
+
+       The yourDataPtr parameter can point to whatever data structure you might
+       want to access from within your CopyObjectFilterProcPtr.
+
+       source                          --> The FSRef to the object you want to copy
+       destDir                         --> The FSRef to the directory you wish to copy source to
+       maxLevels                       --> Maximum number of directory levels to scan or
+                                                       zero to scan all directory levels, ignored if the
+                                                       object is a file
+       whichInfo                       --> The fields of the FSCatalogInfo you wish passed
+                                                       to you in your CopyObjectFilterProc
+       dupeAction                      --> The action to take if an object of the same name exists
+                                                       in the destination
+       newName                         --> The name you want the new object to have.  If you pass
+                                                       in NULL, the source object name will be used. 
+       wantFSSpec                      --> Set to true if you want the FSSpec to each
+                                                       object passed to your CopyObjectFilterProc.
+       wantName                        --> Set to true if you want the name of each
+                                                       object passed to your CopyObjectFilterProc.
+       filterProcPtr           --> A pointer to the CopyObjectFilterProc you
+                                                       want called once for each object found
+                                                       by FSCopyObject.
+       yourDataPtr                     --> An optional pointer to whatever data structure you
+                                                       might want to access from within the
+                                                       CopyObjectFilterProc.
+       newObjectRef            --> An optional pointer to an FSRef that, on return,
+                                                       references the new object.  If you don't want this
+                                                       info returned, pass in NULL
+       newObjectSpec           --> An optional pointer to an FSSPec that, on return,
+                                                       references the new object.  If you don't want this
+                                                       info returned, pass in NULL
+*/
+
+OSErr FSCopyObject(    const FSRef *source,
+                                       const FSRef *destDir,
+                                       ItemCount maxLevels,
+                                       FSCatalogInfoBitmap whichInfo,
+                                       DupeAction dupeAction,
+                                       const HFSUniStr255 *newName,                    /* can be NULL */
+                                       Boolean wantFSSpec,
+                                       Boolean wantName,
+                                       CopyObjectFilterProcPtr filterProcPtr,  /* can be NULL */
+                                       void *yourDataPtr,                                              /* can be NULL */
+                                       FSRef *newObjectRef,                                    /* can be NULL */
+                                       FSSpec *newObjectSpec);                                 /* can be NULL */
+
+/*****************************************************************************/
+
+#pragma mark FSDeleteObjects
+
+/*
+       The FSDeleteObjects function takes an FSRef to a file or directory
+       and attempts to delete it.  If the object is a directory, all files
+       and subdirectories in the specified directory are deleted. If a
+       locked file or directory is encountered, it is unlocked and then
+       deleted.  After deleting the directory's contents, the directory
+       is deleted. If any unexpected errors are encountered, 
+       FSDeleteContainer quits and returns to the caller.
+       
+       source                          --> FSRef to an object (can be file or directory).
+       
+       __________
+*/
+
+OSErr FSDeleteObjects( const FSRef *source );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
\ No newline at end of file
diff --git a/wolf3d/code/iphone/GenLinkedList.c b/wolf3d/code/iphone/GenLinkedList.c
new file mode 100644 (file)
index 0000000..50a3761
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+       File:           GenLinkedList.c
+       
+       Contains:       Linked List utility routines
+
+       Disclaimer:     IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+                               ("Apple") in consideration of your agreement to the following terms, and your
+                               use, installation, modification or redistribution of this Apple software
+                               constitutes acceptance of these terms.  If you do not agree with these terms,
+                               please do not use, install, modify or redistribute this Apple software.
+
+                               In consideration of your agreement to abide by the following terms, and subject
+                               to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
+                               copyrights in this original Apple software (the "Apple Software"), to use,
+                               reproduce, modify and redistribute the Apple Software, with or without
+                               modifications, in source and/or binary forms; provided that if you redistribute
+                               the Apple Software in its entirety and without modifications, you must retain
+                               this notice and the following text and disclaimers in all such redistributions of
+                               the Apple Software.  Neither the name, trademarks, service marks or logos of
+                               Apple Computer, Inc. may be used to endorse or promote products derived from the
+                               Apple Software without specific prior written permission from Apple.  Except as
+                               expressly stated in this notice, no other rights or licenses, express or implied,
+                               are granted by Apple herein, including but not limited to any patent rights that
+                               may be infringed by your derivative works or by other works in which the Apple
+                               Software may be incorporated.
+
+                               The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+                               WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+                               WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+                               PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+                               COMBINATION WITH YOUR PRODUCTS.
+
+                               IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+                               CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+                               GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+                               ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+                               OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+                               (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+                               ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+       Copyright © 2003-2004 Apple Computer, Inc., All Rights Reserved
+*/
+
+#include "GenLinkedList.h"
+
+#pragma mark --- Data Structures ---
+
+       /* This is the internal data structure for the nodes in the linked list.                */
+       /*                                                                                                                                                              */
+       /* Note: The memory pointed to by pNext is owned by the list and is disposed of */
+       /* in DestroyList.  It should not be disposed of in any other way.                              */
+       /*                                                                                                                                                              */
+       /* Note: The memory pointed to by pData is owned by the caller of the linked    */
+       /* list.  The caller is responsible for disposing of this memory.  This can be  */
+       /* done by simply implementing a DisposeDataProc that will be called on each    */
+       /* node in the list, giving the caller a chance to dispose of any memory                */
+       /* created.  The DisposeDataProc is called from DestroyList                                             */ 
+struct GenNode
+{
+       struct  GenNode                         *pNext; /* Pointer to the next node in the list         */
+                       GenDataPtr                       pData; /* The data for this node, owned by caller      */
+};
+typedef struct GenNode GenNode;
+
+#pragma mark --- List Implementation ---
+
+       /* Initializes the given GenLinkedList to an empty list.  This MUST be                  */
+       /* called before any operations are performed on the list, otherwise bad things */
+       /* will happen.                                                                                                                                 */
+void           InitLinkedList( GenLinkedList *pList, DisposeDataProcPtr disposeProcPtr)
+{
+       if( pList == NULL )
+               return;
+
+       pList->pHead = pList->pTail = NULL;
+       pList->NumberOfItems    = 0;
+       pList->DisposeProcPtr   = disposeProcPtr;
+}
+
+       /* returns the current number of items in the given list.                                               */
+       /* If pList == NULL, it returns 0                                                                                               */
+ItemCount      GetNumberOfItems( GenLinkedList *pList )
+{
+       return (pList) ? pList->NumberOfItems : 0;
+}
+       
+       /* Creates a new node, containing pData, and adds it to the tail of pList.              */
+       /* Note: if an error occurs, pList is unchanged.                                                                */
+OSErr          AddToTail( GenLinkedList *pList, void *pData )
+{
+       OSErr           err                     = paramErr;
+       GenNode         *tmpNode        = NULL;
+       
+       if( pList == NULL || pData == NULL )
+               return err;
+
+               /* create memory for new node, if this fails we _must_ bail     */
+       err = ( ( tmpNode = (GenNode*) NewPtr( sizeof( GenNode ) ) ) != NULL ) ? noErr : MemError();
+       if( err == noErr )
+       {
+               tmpNode->pData = pData;                                                                 /* Setup new node                               */
+               tmpNode->pNext = NULL;
+               
+               if( pList->pTail != NULL )                                                              /* more then one item already   */
+                       ((GenNode*) pList->pTail)->pNext = (void*) tmpNode;     /* so append to tail                    */
+               else
+                       pList->pHead = (void*) tmpNode;                                         /* no items, so adjust head             */
+               
+               pList->pTail                    = (void*) tmpNode;
+               pList->NumberOfItems    += 1;
+       }       
+       
+       return err;
+}
+
+       /* Takes pSrcList and inserts it into pDestList at the location pIter points to.                        */
+       /* The lists must have the same DisposeProcPtr, but the Data can be different.  If pSrcList     */
+       /* is empty, it does nothing and just returns                                                                                           */
+       /*                                                                                                                                                                                      */
+       /* If pIter == NULL, insert pSrcList before the head                                                                            */
+       /* else If pIter == pTail, append pSrcList to the tail                                                                          */
+       /* else insert pSrcList in the middle somewhere                                                                                         */
+       /* On return: pSrcList is cleared and is an empty list.                                                                         */
+       /*            The data that was owned by pSrcList is now owned by pDestList                                     */
+void           InsertList( GenLinkedList *pDestList, GenLinkedList *pSrcList, GenIteratorPtr pIter )
+{
+       if( pDestList           == NULL || pSrcList                     == NULL ||
+               pSrcList->pHead == NULL || pSrcList->pTail      == NULL ||
+               pDestList->DisposeProcPtr != pSrcList->DisposeProcPtr )
+               return;
+               
+       if( pDestList->pHead == NULL && pDestList->pTail == NULL )      /* empty list                                   */
+       {
+               pDestList->pHead = pSrcList->pHead;
+               pDestList->pTail = pSrcList->pTail;
+       }
+       else if( pIter == NULL )                                                                        /* insert before head                   */
+       {                               
+                       /* attach the list      */
+               ((GenNode*)pSrcList->pTail)->pNext = pDestList->pHead;
+                       /* fix up head          */
+               pDestList->pHead = pSrcList->pHead;
+       }
+       else if( pIter == pDestList->pTail )                                            /* append to tail                               */
+       {
+                       /* attach the list      */
+               ((GenNode*)pDestList->pTail)->pNext = pSrcList->pHead;
+                       /* fix up tail          */
+               pDestList->pTail = pSrcList->pTail;
+       }
+       else                                                                                                            /* insert in middle somewhere   */
+       {
+               GenNode *tmpNode = ((GenNode*)pIter)->pNext;
+               ((GenNode*)pIter)->pNext = pSrcList->pHead;
+               ((GenNode*)pSrcList->pTail)->pNext = tmpNode;
+       }
+
+       pDestList->NumberOfItems += pSrcList->NumberOfItems;            /* sync up NumberOfItems                */
+       
+       InitLinkedList( pSrcList, NULL);                                                        /* reset the source list                */
+}
+
+       /* Goes through the list and disposes of any memory we allocated.  Calls the DisposeProcPtr,*/
+       /* if it exists, to give the caller a chance to free up their memory                                            */
+void           DestroyList( GenLinkedList      *pList )
+{
+       GenIteratorPtr  pIter           = NULL,
+                                       pNextIter       = NULL;
+
+       if( pList == NULL )
+               return;
+       
+       for( InitIterator( pList, &pIter ), pNextIter = pIter; pIter != NULL; pIter = pNextIter )
+       {
+               Next( &pNextIter );     /* get the next node before we blow away the link */
+               
+               if( pList->DisposeProcPtr != NULL )
+                       CallDisposeDataProc( pList->DisposeProcPtr, GetData( pIter ) );
+               DisposePtr( (char*) pIter );
+       }
+       
+       InitLinkedList( pList, NULL);           
+}
+
+/*#############################################*/
+/*#############################################*/
+/*#############################################*/
+
+#pragma mark -
+#pragma mark --- Iterator Implementation ---
+
+       /* Initializes pIter to point at the head of pList                                                      */
+       /* This must be called before performing any operations with pIter                      */
+void           InitIterator( GenLinkedList *pList, GenIteratorPtr *pIter )
+{
+       if( pList != NULL && pIter != NULL )
+               *pIter = pList->pHead;
+}
+
+       /* On return, pIter points to the next node in the list.  NULL if its gone      */
+       /* past the end of the list                                                                                                     */
+void           Next( GenIteratorPtr *pIter )
+{
+       if( pIter != NULL )
+               *pIter = ((GenNode*)*pIter)->pNext;
+}
+
+       /* Returns the data of the current node that pIter points to                            */
+GenDataPtr     GetData( GenIteratorPtr pIter )
+{
+       return ( pIter != NULL ) ? ((GenNode*)pIter)->pData : NULL;
+}
diff --git a/wolf3d/code/iphone/GenLinkedList.h b/wolf3d/code/iphone/GenLinkedList.h
new file mode 100644 (file)
index 0000000..c6dd69a
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+       File:           GenLinkedList.h
+       
+       Contains:       Linked List utility routines prototypes
+
+       Disclaimer:     IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+                               ("Apple") in consideration of your agreement to the following terms, and your
+                               use, installation, modification or redistribution of this Apple software
+                               constitutes acceptance of these terms.  If you do not agree with these terms,
+                               please do not use, install, modify or redistribute this Apple software.
+
+                               In consideration of your agreement to abide by the following terms, and subject
+                               to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
+                               copyrights in this original Apple software (the "Apple Software"), to use,
+                               reproduce, modify and redistribute the Apple Software, with or without
+                               modifications, in source and/or binary forms; provided that if you redistribute
+                               the Apple Software in its entirety and without modifications, you must retain
+                               this notice and the following text and disclaimers in all such redistributions of
+                               the Apple Software.  Neither the name, trademarks, service marks or logos of
+                               Apple Computer, Inc. may be used to endorse or promote products derived from the
+                               Apple Software without specific prior written permission from Apple.  Except as
+                               expressly stated in this notice, no other rights or licenses, express or implied,
+                               are granted by Apple herein, including but not limited to any patent rights that
+                               may be infringed by your derivative works or by other works in which the Apple
+                               Software may be incorporated.
+
+                               The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+                               WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+                               WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+                               PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+                               COMBINATION WITH YOUR PRODUCTS.
+
+                               IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+                               CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+                               GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+                               ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+                               OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+                               (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+                               ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+       Copyright © 2003-2004 Apple Computer, Inc., All Rights Reserved
+*/
+
+
+#ifndef __GENLINKEDLIST__
+#define __GENLINKEDLIST__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if TARGET_API_MAC_OSX || defined( __APPLE_CC__ )
+#include       <CoreServices/CoreServices.h>
+#endif
+
+/* This is a quick, simple and generic linked list implementation.  I tried            */
+/* to setup the code so that you could use any linked list implementation you  */
+/* want.  They just    need to support these few functions.                                            */
+
+typedef void*  GenIteratorPtr;
+typedef void*  GenDataPtr;
+
+       /* This is a callback that is called from DestroyList for each node in the      */
+       /* list.  It gives the caller the oportunity to free any memory they might      */
+       /* allocated in each node.                                                                                                      */
+typedef CALLBACK_API( void , DisposeDataProcPtr ) ( GenDataPtr pData );
+
+#define CallDisposeDataProc( userRoutine, pData )      (*(userRoutine))((pData))
+
+struct GenLinkedList
+{
+       GenDataPtr                              pHead;                          /* Pointer to the head of the list                                                      */
+       GenDataPtr                              pTail;                          /* Pointer to the tail of the list                                                      */
+       ItemCount                               NumberOfItems;          /* Number of items in the list (mostly for debugging)           */
+       DisposeDataProcPtr              DisposeProcPtr;         /* rountine called to dispose of caller data, can be NULL       */
+};
+typedef struct GenLinkedList   GenLinkedList;
+
+void           InitLinkedList  ( GenLinkedList *pList, DisposeDataProcPtr disposeProcPtr );
+ItemCount      GetNumberOfItems( GenLinkedList *pList );
+OSErr          AddToTail               ( GenLinkedList *pList, GenDataPtr pData );
+void           InsertList              ( GenLinkedList *pDestList, GenLinkedList *pSrcList, GenIteratorPtr pIter );
+void           DestroyList             ( GenLinkedList *pList );
+
+void           InitIterator    ( GenLinkedList *pList, GenIteratorPtr *pIter );
+void           Next                    ( GenIteratorPtr *pIter );
+GenDataPtr     GetData                 ( GenIteratorPtr pIter );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
\ No newline at end of file
index bc5d079c569a591bb0f037828a1491ce2a524aa7..1835ef86e165704a3f0a027dfe287face0be0ab2 100644 (file)
@@ -7,13 +7,13 @@
        <key>CFBundleDevelopmentRegion</key>
        <string>English</string>
        <key>CFBundleDisplayName</key>
-       <string>${PRODUCT_NAME}</string>
+       <string>${PRODUCT_NAME}+</string>
        <key>CFBundleExecutable</key>
        <string>${EXECUTABLE_NAME}</string>
        <key>CFBundleIconFile</key>
        <string>${PRODUCT_NAME}_icon.png</string>
        <key>CFBundleIdentifier</key>
-       <string>${PROFILE_PREFIX}.${PRODUCT_NAME:identifier}</string>
+       <string>com.idsoftware.${PRODUCT_NAME:identifier}</string>
        <key>CFBundleInfoDictionaryVersion</key>
        <string>6.0</string>
        <key>CFBundleName</key>
        <string>APPL</string>
        <key>CFBundleSignature</key>
        <string>????</string>
-       <key>CFBundleVersion</key>
-       <string>1.1</string>
-       <key>LSRequiresIPhoneOS</key>
-       <true/>
-       <key>NSMainNibFile</key>
-       <string>MainWindow</string>
-       <key>UIInterfaceOrientation</key>
-       <string>UIInterfaceOrientationLandscapeLeft</string>
-       <key>UIStatusBarHidden</key>
-       <true/>
        <key>CFBundleURLTypes</key>
        <array>
                <dict>
                        <key>CFBundleURLName</key>
-                       <string>com.idsoftware.wolf3d</string>
+                       <string>com.idsoftware.wolf3dp</string>
                        <key>CFBundleURLSchemes</key>
                        <array>
-                               <string>wolf3d</string>
+                               <string>wolf3dp</string>
                        </array>
                </dict>
        </array>
+       <key>CFBundleVersion</key>
+       <string>1.2</string>
+       <key>LSRequiresIPhoneOS</key>
+       <true/>
+       <key>NSMainNibFile</key>
+       <string>MainWindow</string>
+       <key>UIInterfaceOrientation</key>
+       <string>UIInterfaceOrientationLandscapeLeft</string>
+       <key>UIPrerenderedIcon</key>
+       <true/>
+       <key>UIStatusBarHidden</key>
+       <true/>
 </dict>
 </plist>
diff --git a/wolf3d/code/iphone/arialGlyphRects.h b/wolf3d/code/iphone/arialGlyphRects.h
new file mode 100644 (file)
index 0000000..7f65fb2
--- /dev/null
@@ -0,0 +1,104 @@
+// generated by fontimg
+//
+
+typedef struct  { unsigned short x0, y0, x1, y1; float xoff, yoff, xadvance; } GlyphRect; 
+
+GlyphRect glyphRects[] = {
+ /* ' ' */ {   2,   2,   2,   2, 0.000000, 0.000000, 7.958042 },
+ /* '!' */ {   6,   2,   9,  22, 2.250000, -20.750000, 7.958042 },
+ /* '"' */ {  14,   2,  21,   9, 1.250000, -20.750000, 10.167832 },
+ /* '#' */ {  26,   2,  41,  23, 0.250000, -21.000000, 15.930070 },
+ /* '$' */ {  46,   2,  59,  27, 1.000000, -22.500000, 15.930070 },
+ /* '%' */ {  64,   2,  86,  24, 1.500000, -21.000000, 25.468531 },
+ /* '&' */ {  92,   2, 109,  23, 1.000000, -21.000000, 19.104895 },
+ /* ''' */ { 114,   2, 117,   9, 1.250000, -20.750000, 5.468532 },
+ /* '(' */ { 122,   2, 129,  29, 1.500000, -21.000000, 9.538462 },
+ /* ')' */ { 134,   2, 141,  29, 1.500000, -21.000000, 9.538462 },
+ /* '*' */ { 146,   2, 155,  11, 0.750000, -21.000000, 11.146853 },
+ /* '+' */ { 160,   2, 173,  15, 1.500000, -17.000000, 16.727272 },
+ /* ',' */ { 178,   2, 181,   9, 2.250000, -3.000000, 7.958042 },
+ /* '-' */ { 186,   2, 194,   4, 0.750000, -8.750000, 9.538462 },
+ /* '.' */ { 198,   2, 201,   5, 2.500000, -3.000000, 7.958042 },
+ /* '/' */ { 206,   2, 214,  23, 0.000000, -21.000000, 7.958042 },
+ /* '0' */ { 218,   2, 231,  23, 1.000000, -20.750000, 15.930070 },
+ /* '1' */ { 236,   2, 243,  22, 3.000000, -20.750000, 15.930070 },
+ /* '2' */ {   2,  34,  15,  54, 0.750000, -20.750000, 15.930070 },
+ /* '3' */ {  20,  34,  33,  55, 1.000000, -20.750000, 15.930070 },
+ /* '4' */ {  38,  34,  52,  54, 0.250000, -20.750000, 15.930070 },
+ /* '5' */ {  58,  34,  72,  54, 1.000000, -20.250000, 15.930070 },
+ /* '6' */ {  76,  34,  89,  55, 1.000000, -20.750000, 15.930070 },
+ /* '7' */ {  94,  34, 107,  54, 1.250000, -20.250000, 15.930070 },
+ /* '8' */ { 112,  34, 125,  55, 1.000000, -20.750000, 15.930070 },
+ /* '9' */ { 130,  34, 143,  55, 1.000000, -20.750000, 15.930070 },
+ /* ':' */ { 148,  34, 151,  49, 2.500000, -15.000000, 7.958042 },
+ /* ';' */ { 156,  34, 159,  53, 2.250000, -15.000000, 7.958042 },
+ /* '<' */ { 164,  34, 177,  48, 1.500000, -17.250000, 16.727272 },
+ /* '=' */ { 182,  34, 195,  42, 1.500000, -14.500000, 16.727272 },
+ /* '>' */ { 200,  34, 213,  48, 1.500000, -17.250000, 16.727272 },
+ /* '?' */ { 218,  34, 231,  55, 1.250000, -21.000000, 15.930070 },
+ /* '@' */ {   2,  60,  28,  87, 1.500000, -21.000000, 29.076923 },
+ /* 'A' */ {  34,  60,  53,  80, -0.250000, -20.750000, 19.104895 },
+ /* 'B' */ {  58,  60,  73,  80, 2.000000, -20.750000, 19.104895 },
+ /* 'C' */ {  78,  60,  96,  81, 1.250000, -21.000000, 20.685314 },
+ /* 'D' */ { 102,  60, 119,  80, 2.000000, -20.750000, 20.685314 },
+ /* 'E' */ { 124,  60, 139,  80, 2.250000, -20.750000, 19.104895 },
+ /* 'F' */ { 144,  60, 158,  80, 2.250000, -20.750000, 17.496504 },
+ /* 'G' */ { 162,  60, 181,  81, 1.500000, -21.000000, 22.279720 },
+ /* 'H' */ { 186,  60, 202,  80, 2.250000, -20.750000, 20.685314 },
+ /* 'I' */ { 208,  60, 211,  80, 2.500000, -20.750000, 7.958042 },
+ /* 'J' */ { 216,  60, 227,  81, 0.750000, -20.750000, 14.321678 },
+ /* 'K' */ { 232,  60, 249,  80, 2.000000, -20.750000, 19.104895 },
+ /* 'L' */ {   2,  92,  15, 112, 2.000000, -20.750000, 15.930070 },
+ /* 'M' */ {  20,  92,  39, 112, 2.000000, -20.750000, 23.860140 },
+ /* 'N' */ {  44,  92,  60, 112, 2.000000, -20.750000, 20.685314 },
+ /* 'O' */ {  66,  92,  85, 113, 1.250000, -21.000000, 22.279720 },
+ /* 'P' */ {  90,  92, 106, 112, 2.000000, -20.750000, 19.104895 },
+ /* 'Q' */ { 110,  92, 130, 114, 1.000000, -21.000000, 22.279720 },
+ /* 'R' */ { 136,  92, 154, 112, 2.250000, -20.750000, 20.685314 },
+ /* 'S' */ { 160,  92, 176, 113, 1.250000, -21.000000, 19.104895 },
+ /* 'T' */ { 182,  92, 198, 112, 0.500000, -20.750000, 17.496504 },
+ /* 'U' */ { 204,  92, 220, 113, 2.250000, -20.750000, 20.685314 },
+ /* 'V' */ { 226,  92, 245, 112, 0.000000, -20.750000, 19.104895 },
+ /* 'W' */ {   2, 120,  28, 140, 0.250000, -20.750000, 27.034966 },
+ /* 'X' */ {  34, 120,  53, 140, 0.000000, -20.750000, 19.104895 },
+ /* 'Y' */ {  58, 120,  77, 140, 0.000000, -20.750000, 19.104895 },
+ /* 'Z' */ {  82, 120,  98, 140, 0.500000, -20.750000, 17.496504 },
+ /* '[' */ { 104, 120, 109, 146, 1.750000, -20.750000, 7.958042 },
+ /* '\' */ { 114, 120, 122, 141, 0.000000, -21.000000, 7.958042 },
+ /* ']' */ { 126, 120, 131, 146, 0.500000, -20.750000, 7.958042 },
+ /* '^' */ { 136, 120, 148, 131, 0.750000, -21.000000, 13.440559 },
+ /* '_' */ { 152, 120, 169, 122, -0.500000, 3.750000, 15.930070 },
+ /* '`' */ { 174, 120, 179, 124, 1.000000, -20.750000, 9.538462 },
+ /* 'a' */ { 184, 120, 197, 135, 1.000000, -15.250000, 15.930070 },
+ /* 'b' */ { 202, 120, 215, 141, 1.750000, -20.750000, 15.930070 },
+ /* 'c' */ { 220, 120, 233, 135, 1.000000, -15.250000, 14.321678 },
+ /* 'd' */ { 238, 120, 251, 141, 0.750000, -20.750000, 15.930070 },
+ /* 'e' */ {   2, 152,  15, 167, 1.000000, -15.250000, 15.930070 },
+ /* 'f' */ {  20, 152,  28, 173, 0.250000, -21.000000, 7.958042 },
+ /* 'g' */ {  34, 152,  47, 173, 0.750000, -15.250000, 15.930070 },
+ /* 'h' */ {  52, 152,  64, 172, 1.750000, -20.750000, 15.930070 },
+ /* 'i' */ {  70, 152,  72, 172, 1.750000, -20.750000, 6.363636 },
+ /* 'j' */ {  78, 152,  84, 179, -1.500000, -20.750000, 6.363636 },
+ /* 'k' */ {  88, 152, 100, 172, 1.750000, -20.750000, 14.321678 },
+ /* 'l' */ { 106, 152, 108, 172, 1.750000, -20.750000, 6.363636 },
+ /* 'm' */ { 114, 152, 134, 167, 1.750000, -15.250000, 23.860140 },
+ /* 'n' */ { 140, 152, 152, 167, 1.750000, -15.250000, 15.930070 },
+ /* 'o' */ { 158, 152, 172, 167, 0.750000, -15.250000, 15.930070 },
+ /* 'p' */ { 178, 152, 191, 173, 1.750000, -15.250000, 15.930070 },
+ /* 'q' */ { 196, 152, 209, 173, 1.000000, -15.250000, 15.930070 },
+ /* 'r' */ { 214, 152, 222, 167, 1.750000, -15.250000, 9.538462 },
+ /* 's' */ { 228, 152, 240, 167, 0.750000, -15.250000, 14.321678 },
+ /* 't' */ { 246, 152, 253, 172, 0.500000, -20.250000, 7.958042 },
+ /* 'u' */ {   2, 184,  14, 199, 1.750000, -15.000000, 15.930070 },
+ /* 'v' */ {  20, 184,  33, 199, 0.250000, -15.000000, 14.321678 },
+ /* 'w' */ {  38, 184,  58, 199, 0.000000, -15.000000, 20.685314 },
+ /* 'x' */ {  64, 184,  78, 199, 0.000000, -15.000000, 14.321678 },
+ /* 'y' */ {  84, 184,  98, 205, 0.250000, -15.000000, 14.321678 },
+ /* 'z' */ { 102, 184, 115, 199, 0.500000, -15.000000, 14.321678 },
+ /* '{' */ { 120, 184, 128, 211, 0.750000, -21.000000, 9.566434 },
+ /* '|' */ { 134, 184, 136, 211, 2.500000, -21.000000, 7.440559 },
+ /* '}' */ { 142, 184, 150, 211, 0.500000, -21.000000, 9.566434 },
+ /* '~' */ { 156, 184, 170, 188, 1.000000, -12.500000, 16.727272 },
+ /* '\7f' */ { 176, 184, 190, 202, 3.500000, -18.000000, 21.482517 }
+};
+
index 93416659df4ad4043ab89b05973802025dacb255..c3505d4ccc61b0e689e540595107e70d556bb80b 100644 (file)
Binary files a/wolf3d/code/iphone/default.png and b/wolf3d/code/iphone/default.png differ
index 08ac8f747152226d7e72917f0b1d03560f487f92..d4d53f9098a3a6a68226365fdc0921368a99250f 100644 (file)
@@ -101,6 +101,14 @@ void pfglVertex2i( GLint x, GLint y ) {
        immediate[ curr_vertex ] = vab;
        curr_vertex++;
 }
+void pfglVertex2f( GLfloat x, GLfloat y ) {
+       assert( curr_vertex < MAX_VERTS );
+       vab.xyz[ 0 ] = (float)x;
+       vab.xyz[ 1 ] = (float)y;
+       vab.xyz[ 2 ] = 0.0f;
+       immediate[ curr_vertex ] = vab;
+       curr_vertex++;
+}
 void pfglColor4ub( GLubyte r, GLubyte g, GLubyte b, GLubyte a ) {
        vab.c[ 0 ] = r;
        vab.c[ 1 ] = g;
index 674e9641ba894fb22b1ac9c805b488191f65d3a6..056a76e64fb97777365549f6668f125e1cdef213 100644 (file)
@@ -224,6 +224,7 @@ void HudEditFrame() {
        
        // solid background color and some UI elements for context
        R_Draw_Fill( 0, 0, 480, 320, gray );    
+       
        iphoneDrawFace();
        iphoneDrawNotifyText();
        
@@ -247,3 +248,336 @@ void HudEditFrame() {
        }
  }
 
+//gsh
+/*
+int boundsLeft = 86;//70;
+int boundsRight = 386;//480-72;
+int boundsAbove = 80-15;//97;
+int boundsUnder = 285-15;//320-15;
+*/
+//------------------
+// ConvertFromImageToScreen
+// This converts a point placed in the screen of the iphone image
+// to the screen coordinates of the actual iphone
+// gsh
+//-------------------
+void ConvertFromImageToScreen(int *x, int *y, rect_t boundsRect)
+{
+       int boundsLeft = boundsRect.x;
+       int boundsRight = boundsRect.x + boundsRect.width;
+       int boundsAbove = boundsRect.y;
+       int boundsUnder = boundsRect.y + boundsRect.height;
+       
+       int valX = *x;//prevTouches[0][0];
+       int valY = *y;//prevTouches[0][1];
+       
+       //int boundsLeft = 64;
+       //int boundsRight = 480-64;
+       int width = boundsRight - boundsLeft;
+       
+       //int boundsAbove = 100;
+       //int boundsUnder = 320-10;
+       int height = boundsUnder - boundsAbove;
+       
+       valX -= boundsLeft;
+       valX = 480*valX/width;
+       
+       valY -= boundsAbove;
+       valY = 320*valY/height;
+       
+       *x = valX;
+       *y = valY;
+}
+
+//------------------
+// ConvertFromScreenToImage
+// This converts a point placed on the screen of the iphone
+// to the coordinates of the screen of the iphone image
+// gsh
+//-------------------
+void ConvertFromScreenToImage(int *x, int *y, rect_t boundsRect)
+{
+       int boundsLeft = boundsRect.x;
+       int boundsRight = boundsRect.x + boundsRect.width;
+       int boundsAbove = boundsRect.y;
+       int boundsUnder = boundsRect.y + boundsRect.height;
+       
+       int valX = *x;//prevTouches[0][0];
+       int valY = *y;//prevTouches[0][1];
+       
+       //int boundsLeft = 64;
+       //int boundsRight = 480-64;
+       int width = boundsRight - boundsLeft;
+       
+       //int boundsAbove = 100;
+       //int boundsUnder = 320-10;
+       int height = boundsUnder - boundsAbove;
+       
+       valX = width*valX/480;
+       valX += boundsLeft;
+       
+       valY = height*valY/320;
+       valY += boundsAbove;
+       
+       *x = valX;
+       *y = valY;
+}
+
+//------------------
+// ScaleFromScreenToImage
+// This converts to the correct scale to draw with
+// gsh
+//-------------------
+void ScaleFromScreenToImage(int *width, int *height, rect_t boundsRect)
+{
+       int boundsLeft = boundsRect.x;
+       int boundsRight = boundsRect.x + boundsRect.width;
+       int boundsAbove = boundsRect.y;
+       int boundsUnder = boundsRect.y + boundsRect.height;
+       
+       int w = *width;
+       int h = *height;
+       
+       //int boundsLeft = 64;
+       //int boundsRight = 480-64;
+       int iW = boundsRight - boundsLeft;
+       
+       //int boundsAbove = 100;
+       //int boundsUnder = 320-10;
+       int iH = boundsUnder - boundsAbove;
+       
+       w = w*iW/480;
+       h = h*iH/320;
+       
+       *width = w;
+       *height = h;
+}
+
+
+/*
+ ==================
+ iphoneHudEditFrame
+ Same as HudEditFrame only different
+ gsh
+ ==================
+ */
+void iphoneHudEditFrame() {
+       int             w;
+       int             x;
+       colour3_t gray = { 32, 32, 32 };
+       
+       int adjustY = 10;
+       
+       rect_t boundsRect = RectMake(86, 80-adjustY, 300, 205);
+       
+       
+       
+       //iphoneSetNotifyText( "Drag the controls" );
+       
+       if ( numTouches == 0 && numPrevTouches == 1 && dragHud ) {
+               // if it was released near the center, make it inactive
+               int x = prevTouches[0][0];
+               int y = prevTouches[0][1];
+               
+               //convert x, y coordinates from iphone_image to screen coordinates
+               ConvertFromImageToScreen( &x, &y, boundsRect);
+               //ConvertFromScreenToImage( &x, &y);
+               
+               if ( x > 120 && x < 360 && y > 80 && y < 240 ) {
+                       dragHud->hudFlags |= HF_DISABLED;                       
+               } else {
+                       // magnet pull a matchable axis if it is close enough
+                       if ( dragHud == &huds.forwardStick ) {
+                               SnapSticks( &huds.sideStick, dragHud );
+                               SnapSticks( &huds.turnStick, dragHud );                         
+                       } 
+                       if ( dragHud == &huds.sideStick ) {
+                               SnapSticks( &huds.forwardStick, dragHud );
+                       } 
+                       if ( dragHud == &huds.turnStick ) {
+                               SnapSticks( &huds.forwardStick, dragHud );
+                       } 
+               }
+               Sound_StartLocalSound( "iphone/baction_01.wav" );
+               dragHud = NULL;
+       }
+       
+       if ( numTouches == 1 && numPrevTouches == 0 ) {
+               // identify the hud being touched for drag
+               int x = touches[0][0];
+               int y = touches[0][1];
+               
+               //convert x, y coordinates from iphone_image to screen coordinates
+               ConvertFromImageToScreen( &x, &y, boundsRect);
+//             ConvertFromScreenToImage( &x, &y);
+               
+               dragHud = NULL;
+               for ( hudPic_t *hud = (hudPic_t *)&huds ; hud != (hudPic_t *)(&huds+1) ; hud++ ) {
+                       if ( x >= hud->x && x - hud->x < hud->width && 
+                               y >= hud->y && y - hud->y < hud->height ) {
+                               dragHud = hud;
+                               //int tempDragX = dragHud->x;
+                               //int tempDragY = dragHud->y;
+                               //ConvertFromImageToScreen(&, <#int * y#>)
+                               dragX = dragHud->x - x;
+                               dragY = dragHud->y - y;
+                               Sound_StartLocalSound( "iphone/bdown_01.wav" );
+                               dragHud->hudFlags &= ~HF_DISABLED;
+                               break;
+                       }
+               }
+       }
+       
+       if ( numTouches == 1 && numPrevTouches == 1 && dragHud ) {
+               // adjust the position of the dragHud
+               int x = touches[0][0];
+               int y = touches[0][1];
+               ConvertFromImageToScreen(&x, &y, boundsRect);
+               
+               dragHud->x = x + dragX;
+               dragHud->y = y + dragY;
+               if ( dragHud->x < 0 ) {
+                       dragHud->x = 0;
+               }
+               if ( dragHud->x > 480 - dragHud->width ) {
+                       dragHud->x = 480 - dragHud->width;
+               }
+               if ( dragHud->y < 0 ) {
+                       dragHud->y = 0;
+               }
+               if ( dragHud->y > 320 - dragHud->height ) {
+                       dragHud->y = 320 - dragHud->height;
+               }
+       }
+       
+       // layout the disabled items in the center
+       w = 0;
+       for ( hudPic_t *hud = (hudPic_t *)&huds ; hud != (hudPic_t *)(&huds+1) ; hud++ ) {
+               if ( hud->hudFlags & HF_DISABLED ) {
+                       w += hud->width;
+               }
+       }
+       x = 240 - w / 2;
+       
+       for ( hudPic_t *hud = (hudPic_t *)&huds ; hud != (hudPic_t *)(&huds+1) ; hud++ ) {
+               if ( hud->hudFlags & HF_DISABLED ) {
+                       hud->x = x;
+                       hud->y = 160-hud->height/2;
+                       x += hud->width;
+               }
+       }
+       
+       // decide where the menu button, map button, and ammo will draw
+       
+       // solid background color and some UI elements for context
+       R_Draw_Fill( 0, 0, 480, 320, gray );    
+       
+       iphoneDrawPic(0, 0, 480, 320, "iphone/submenus_background_image.tga");
+       //iphoneDrawPic(240-108, 0, 217, 50, "iphone/header_advanced.tga");
+       iphoneDrawPic(240-108*9/10, 0, 217*9/10, 50*9/10, "iphone/header_advanced.tga");
+       
+       //gsh
+       iphoneDrawPic(10, 60-adjustY, 462, 250, "iphone/iphone_image.tga");
+//     iphoneDrawPic(0, 320-240, 480, 240, "iphone/iphone_image.tga");
+
+       
+//     iphoneDrawFace();
+//     iphoneDrawNotifyText();
+       
+       
+       // draw the active items at their current locations
+       for ( hudPic_t *hud = (hudPic_t *)&huds ; hud != (hudPic_t *)(&huds+1) ; hud++ ) {  //nice foreach loop!
+               if ( hud->hudFlags & HF_DISABLED ) {
+                       pfglColor3f( 0.5, 0.5, 0.5 );
+               }
+               if ( hud == &huds.ammo ) {
+                       int x = huds.ammo.x + huds.ammo.width / 2;
+                       int y = huds.ammo.y;
+                       int w = 48;
+                       int h = 48;
+                       
+                       ConvertFromScreenToImage(&x, &y, boundsRect);
+                       ScaleFromScreenToImage(&w, &h, boundsRect);
+                       
+                       iphoneDrawNumber( x, y, 99, w, h );
+               } else {
+                       int x = hud->x;
+                       int y = hud->y;
+                       int w = hud->width;
+                       int h = hud->height;
+                       
+                       ConvertFromScreenToImage(&x, &y, boundsRect);
+                       ScaleFromScreenToImage(&w, &h, boundsRect);
+                       
+                       iphoneDrawPicNum( x, y, w, h, hud->glTexNum );
+               }
+               pfglColor3f( 1, 1, 1 );
+       }
+       
+       
+       
+       
+       
+       // draw the back button
+       if ( iphoneDrawPicWithTouch( 0, 0, 64, 36, "iphone/button_back.tga" ) ) {
+               menuState = IPM_CONTROLS;
+               iphoneSetNotifyText( "" );
+       }
+       
+       //x = 64;
+       //if (revLand->value)
+               x = 480-64;
+       // draw the menu button
+       if ( iphoneDrawPicWithTouch( x, 0, 64, 36, "iphone/menu.tga" ) ) {
+       //if ( iphoneDrawPicWithTouch( 64, 0, 64, 36, "iphone/button_menu_yellow.tga" ) ) {
+               menuState = IPM_MAIN;
+               iphoneSetNotifyText( "" );
+       }
+       
+       /*
+       //------------------------------------
+       //Draw volume up/down settings... gsh
+       int width = 64*9/10;
+       int height = 36;//48*9/10;
+
+       int y = 0;
+       y = 0;
+       x = 480-width;
+       if (revLand->value){
+               y = 320-height;
+               x = 0;
+       }
+       
+        //gsh
+       if ((int)volumeFireUpSetting->value) {
+               if (iphoneDrawPicWithTouch( x, y, width, height, "iphone/button_pistol.tga" ))
+                       Cvar_Set("volumeFireUpSetting", "0");
+       }
+       else {
+               if (iphoneDrawPicWithTouch( x, y, width, height, "iphone/button_knife.tga" ))
+                       Cvar_Set("volumeFireUpSetting", "1");
+       }
+               
+       
+        x = 480-width-width-5;
+        if (revLand->value)
+                x = width+5;
+        
+       if ((int)volumeFireDownSetting->value) {
+               if (iphoneDrawPicWithTouch( x, y, width, height, "iphone/button_pistol.tga" ))
+                       Cvar_Set("volumeFireDownSetting", "0");
+       }
+       else {
+               if (iphoneDrawPicWithTouch( x, y, width, height, "iphone/button_knife.tga" ))
+                       Cvar_Set("volumeFireDownSetting", "1");
+       }
+       //-----------------------------------
+       */
+       //draw the instructions
+       //if (revLand->value)
+       //      iphoneDrawText(x+width+20, 300, 16, 16, "Drag the controls to customize");
+       //else
+//             iphoneCenterText(240, 300, "Drag each element of the controls to customize");
+       iphoneCenterArialText(245, 315, 0.8f, "Drag each element of the controls to customize");
+}
+
diff --git a/wolf3d/code/iphone/iphone_alerts.h b/wolf3d/code/iphone/iphone_alerts.h
new file mode 100644 (file)
index 0000000..45227d0
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ *  iphone_alerts.h
+ *  wolf3d
+ *
+ *  Created by Greg Hodges on 7/14/09.
+ *  Copyright 2009 id software. All rights reserved.
+ *
+ *  C wrappers for the UIAlertView.
+ *
+ */
+/*
+ Copyright (C) 2009 Id Software, Inc.
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+
+#ifndef __IPHONE_ALERTS__
+#define __IPHONE_ALERTS__
+
+void iphoneMessageBox(char *title, char *message);
+void iphoneKillMessageBox();
+void iphoneYesNoBox(char *title, char *message);
+
+#endif
\ No newline at end of file
diff --git a/wolf3d/code/iphone/iphone_alerts.m b/wolf3d/code/iphone/iphone_alerts.m
new file mode 100644 (file)
index 0000000..e1a4464
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ *  iphone_alerts.c
+ *  wolf3d
+ *
+ *  Created by Greg Hodges on 7/14/09.
+ *  Copyright 2009 id software. All rights reserved.
+ *
+ */
+/*
+ Copyright (C) 2009 Id Software, Inc.
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+
+#import "iphone_alerts.h"
+#import "wolf3dAppDelegate.h"
+
+
+/*
+ ==================================
+ MessageBox
+ Provides a basic pop-up message box
+ ===================================
+ */
+UIAlertView *alert;
+
+void InitAlert()
+{
+       alert = [[UIAlertView alloc] initWithTitle:@"Title" 
+                                                                          message:@"Message"
+                                                                         delegate:nil 
+                                                        cancelButtonTitle:@"OK" 
+                                                        otherButtonTitles: nil];
+}
+
+
+void iphoneMessageBox(char *title, char *message)
+{
+       //check if alert exists and initialize if it isn't
+       if (!alert)
+       {
+               InitAlert();
+       }
+       
+       NSString *nsTitle = [[NSString alloc] initWithCString:title];
+       NSString *nsMessage = [[NSString alloc] initWithCString:message];
+       
+       alert.title = nsTitle;
+       alert.message = nsMessage;
+       
+       [alert show];
+}
+
+void iphoneKillMessageBox()
+{
+       [alert dismissWithClickedButtonIndex:alert.cancelButtonIndex animated:NO];
+}
+
+#if 1
+/*
+ ==================================
+ YesNoBox
+ Provides a yes/no box.  The
+ appdelegate responds to this
+ through the UIAlerViewDelegate
+ ClickedButton call.
+ ===================================
+ */
+UIAlertView *alertYesNo;
+
+void InitAlertYesNo()
+{
+       alertYesNo = [[UIAlertView alloc] initWithTitle:@"Title" 
+                                                                          message:@"Message"
+                                                                         delegate:(wolf3dAppDelegate *)[UIApplication sharedApplication].delegate//nil 
+                                                        cancelButtonTitle:@"No" 
+                                                        otherButtonTitles:@"Yes", nil];        
+}
+
+void iphoneYesNoBox(char *title, char *message)
+{
+       if (!alertYesNo)
+       {
+               InitAlertYesNo();
+       }
+       
+       NSString *nsTitle = [[NSString alloc] initWithCString:title];
+       NSString *nsMessage = [[NSString alloc] initWithCString:message];
+       
+       alertYesNo.title = nsTitle;
+       alertYesNo.message = nsMessage;
+       
+       [alertYesNo show];
+}
+#endif
diff --git a/wolf3d/code/iphone/iphone_downloadSOD.m b/wolf3d/code/iphone/iphone_downloadSOD.m
new file mode 100644 (file)
index 0000000..0cf94a3
--- /dev/null
@@ -0,0 +1,359 @@
+//
+//  iphone_downloadSOD.m
+//  wolf3d
+//
+//  Created by Greg Hodges on 6/8/09.
+//  Copyright 2009 id software. All rights reserved.
+//
+/*
+ Copyright (C) 2009 Id Software, Inc.
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+
+
+#import "../wolfiphone.h"
+#import "wolf3dAppDelegate.h"
+#import "iphone_alerts.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <unistd.h>
+
+#import <SystemConfiguration/SCNetworkReachability.h>  //this is for testing network availability
+
+//Note: in order to link the zlib library into the build from usr/lib/libz.ylib
+//      the flag -lz was added to the OTHER_LDFLAGS under the build options.
+//      To get there: right click on the wolf3d project.  choose get info.
+//      Click on build and scroll to "Other Link Flags" under "Linking"
+
+
+extern  void  Com_Printf(const char* fmt, ... );
+extern  void  my_snprintf( char *dest, size_t size, const char *format, ... );
+
+#ifdef SPEARSTOREKIT
+extern void PurchaseSOD();
+extern bool isStorekitAvailable;
+#endif
+extern  char  iphoneDocDirectory[1024];
+extern menuState_t menuState;
+
+
+int inf(FILE *source, FILE *dest);
+void zerr(int ret);
+
+
+//this is used for determining if we have the correctly sized data
+const unsigned int DownloadFileSize = 45583; //size of maps
+
+//-----------------------------
+// TestURLConnection
+// Test for internet access
+//-----------------------------
+int TestURLConnection()
+{
+       Com_Printf("Testing URL Connection\n");
+       
+       //We wish to be able to test connectability to both apple and id
+       //because we need to communicate to both in order to complete the Spear of Destiny Transaction
+       
+       char *hostid = "www.idsoftware.com";
+       char *hostApple = "www.apple.com";
+       SCNetworkReachabilityFlags              flags[2];
+    SCNetworkReachabilityRef reachability;
+       BOOL gotFlags[2];
+       
+       reachability = SCNetworkReachabilityCreateWithName(NULL, hostid);
+       gotFlags[0] = SCNetworkReachabilityGetFlags(reachability, &flags[0]);
+       CFRelease(reachability);
+       
+       reachability = SCNetworkReachabilityCreateWithName(NULL, hostApple);
+       gotFlags[1] = SCNetworkReachabilityGetFlags(reachability, &flags[1]);
+       CFRelease(reachability);
+       
+       
+       if (gotFlags[0] && gotFlags[1])
+       {
+               // kSCNetworkReachabilityFlagsReachable indicates that the specified nodename or address can
+               // be reached using the current network configuration.
+               if ((flags[0] & kSCNetworkReachabilityFlagsReachable) && (flags[1] & kSCNetworkReachabilityFlagsReachable))
+               {
+                       Com_Printf("Both Hosts were reached\n");
+                       return 1;
+               }
+       }
+
+       //TODO: alert user they cannot download SOD
+       iphoneMessageBox("Host Server Unavailable", "Check your internet connection and try again later.");
+
+       return 0; 
+}
+
+//-----------------------------
+// OpenURLConnection
+// This connects to a server and downloads the file located there
+//-----------------------------
+void OpenURLConnection( const char *url )
+{
+       Com_Printf( "ConnectURL char *: %s\n", url );
+       
+       //convert url to nsstring
+       NSString *nssURL = [NSString stringWithUTF8String: url];
+       
+       // create the request
+       NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:nssURL]
+                                                                                         cachePolicy:NSURLRequestUseProtocolCachePolicy
+                                                                                 timeoutInterval:60.0];
+       
+       // create the connection with the request
+       // and start loading the data
+       NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest 
+                                                                                                                                  delegate:(wolf3dAppDelegate *)[UIApplication sharedApplication].delegate];
+
+       if (!theConnection)
+       {
+               // inform the user that the download could not be made
+               Com_Printf("Connection failed... no download plausible\n");
+               
+               //inform user
+               iphoneMessageBox("Connection Failed", "The install was unable to download.  Check your internet connection and try again later.");
+               
+               //return to main menu
+               menuState = IPM_MAIN;
+       }
+}
+
+//============================
+// DisplayWrongVersionedOS
+// Display to the user they have the wrong OS version and cannot use storekit
+//=============================
+void DisplayWrongVersionedOS()
+{
+       iphoneMessageBox("Feature Unavailable", "Your device is not updated.  This feature requires OS 3.0 or higher.");
+}
+
+//============================
+// BeginStoreKit
+// This starts the purchasing process of the storekit framework
+//=============================
+#ifdef SPEARSTOREKIT
+void BeginStoreKit()
+{
+       //only start the storekit API if it exists
+       if (isStorekitAvailable)
+       {
+               if (TestURLConnection())  //check URL connection again
+               {
+                       menuState = IPM_STOREKIT;
+                       Com_Printf("BeginStoreKit() called\n");
+                       PurchaseSOD();
+               }
+       }
+       else
+               DisplayWrongVersionedOS();
+}
+#endif
+
+
+//============================
+// DownloadSOD
+// starts the download process of SOD
+// this is called after purchase of the SOD levels is confirmed
+//=============================
+void DownloadSOD()
+{
+       menuState = IPM_DOWNLOADPROGRESS; //change the menu to the download screen
+                                        
+       NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+       NSString *documentsDirectory = [paths objectAtIndex:0];
+               
+       //check if download.tgz already exists and delete if it does
+       //create/open file for saving
+       NSString *fileatpath = [documentsDirectory stringByAppendingString:@"/downloadedfile.tgz"];
+       NSFileHandle *file = [NSFileHandle fileHandleForWritingAtPath:fileatpath];
+       
+       if (file) //file exists... delete it, we do not care to append to a pre-exisiting file
+       {
+               if( remove( [fileatpath UTF8String] ) != 0 )
+                       Com_Printf("Error deleting buffer\n");
+               else
+                       Com_Printf("Deleted buffer\n");
+       }
+       
+       //TODO: change this url to what will eventually be the permanent location
+       OpenURLConnection("http://gregory.hodges.googlepages.com/spearMaps.tgz");
+       
+       //after this the control automatically goes back to the appDelegate where it receives the packets of downloaded information
+}
+
+unsigned int dataAmount = 0;
+unsigned int dataTotalAmount = 0;
+extern unsigned int totalDownloaded;
+//int hasBeenMessaged = 0;
+
+//============================
+// AppendData
+// adds a packet of data directly to file
+//============================
+void AppendDataToFile(NSData* data)
+{
+       NSUInteger length = [data length];
+       
+       dataAmount = (unsigned int)length;
+       dataTotalAmount += dataAmount;
+       totalDownloaded = dataTotalAmount;  //update the download screen with the total downloaded
+
+       //get documents directory
+       NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+       NSString *documentsDirectory = [paths objectAtIndex:0];
+       
+       //create/open file for saving
+       NSString *fileatpath = [documentsDirectory stringByAppendingString:@"/downloadedfile.tgz"];
+       NSFileHandle *file = [NSFileHandle fileHandleForWritingAtPath:fileatpath];
+       
+       if (!file) //file does not exist... create and append file
+       {
+               NSLog(@"open file failed\ncreating file with path: %@\n", fileatpath);
+               [[NSFileManager defaultManager] createFileAtPath:fileatpath
+                                                                                               contents:data
+                                                                                         attributes:nil];
+               return;
+       }
+       
+       //seek to end of file and append data
+       [file seekToEndOfFile];
+       [file writeData:data];
+       [file closeFile];
+}
+
+
+
+//===========================
+// DecompressData
+// Calls into untgz.c to start data inflation
+// this function should not be getting called
+//============================
+void DecompressData()
+{
+       Com_Printf("Starting DecompressData");
+       
+       char    path[1024];
+       my_snprintf(path, sizeof(path), "%s/downloadedfile.tgz", iphoneDocDirectory);
+}
+
+//================================
+// IsSpearPurchased
+// returns 1 if Spear was purchased
+//================================ 
+int IsSpearPurchased()
+{
+       //get documents directory
+       NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+       NSString *documentsDirectory = [paths objectAtIndex:0];
+       
+       //create/open file for saving
+       NSString *fileatpath = [documentsDirectory stringByAppendingString:@"/SpearPurchased.log"];
+       NSFileHandle *file = [NSFileHandle fileHandleForWritingAtPath:fileatpath];
+       
+       if (file)
+               return 1;
+       
+       return 0;
+}
+
+//================================
+// IsSpearInstalled 
+// returns 1 if Spear is installed
+//================================ 
+int IsSpearInstalled()
+{
+       //get documents directory
+       NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+       NSString *documentsDirectory = [paths objectAtIndex:0];
+       
+       //create/open file for saving
+       NSString *fileatpath = [documentsDirectory stringByAppendingString:@"/SpearInstalled.log"];
+       NSFileHandle *file = [NSFileHandle fileHandleForWritingAtPath:fileatpath];
+       
+       if (file)
+               return 1;
+       
+       return 0;
+}
+
+//================================
+// WriteDownloadLog 
+// records that we've finished installing SOD
+// but haven't completed the purchase
+//================================ 
+void WriteInstallLog()
+{
+       char *buffer = "useless data";
+       NSData *data = [[NSData alloc] initWithBytes: (void *)buffer length: strlen(buffer)];
+       
+       //get documents directory
+       NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+       NSString *documentsDirectory = [paths objectAtIndex:0];
+       
+       //create/open file for saving
+       NSString *fileatpath = [documentsDirectory stringByAppendingString:@"/SpearInstalled.log"];
+       NSFileHandle *file = [NSFileHandle fileHandleForWritingAtPath:fileatpath];
+       
+       if (!file) //file does not exist... create and append file
+       {
+               NSLog(@"open file failed\ncreating file with path: %@\n", fileatpath);
+               [[NSFileManager defaultManager] createFileAtPath:fileatpath
+                                                                                               contents:data
+                                                                                         attributes:nil];
+               return;
+       }
+       
+}
+
+//================================
+// FinalizeDownload 
+// Installs the needed files for SOD and
+// removes any unwanted data
+//================================ 
+extern void iphoneWriteConfig();
+void FinalizeDownload()
+{
+       // get the documents directory
+       NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+       NSString *documentsDirectory = [paths objectAtIndex:0];
+       NSString *fileName = [documentsDirectory stringByAppendingString:@"/downloadedfile.tgz"];
+       
+       //inflate the data and store in its appropriate directory
+       DecompressData();
+       
+       //TODO: After inflating data... we should delete the downloadedfile.tgz
+       if( remove( [fileName UTF8String] ) != 0 )
+               Com_Printf( "Error deleting downloadedfile.tgz\n" );
+       else
+               Com_Printf( "downloadedfile.tgz successfully deleted\n" );
+       
+       
+       iphoneKillMessageBox();
+       
+       //write a file that lets wolf3d know that SOD is installed
+       WriteInstallLog();
+
+#ifdef SPEARSTOREKIT
+       //start the storekit
+       BeginStoreKit();
+#endif
+}
diff --git a/wolf3d/code/iphone/iphone_downloadUserMap.m b/wolf3d/code/iphone/iphone_downloadUserMap.m
new file mode 100644 (file)
index 0000000..1b1172b
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ *  iphone_downloadUserMap.c
+ *  wolf3d
+ *
+ *  Created by Greg Hodges on 7/20/09.
+ *  Copyright 2009 id software. All rights reserved.
+ *
+ */
+/*
+ Copyright (C) 2009 Id Software, Inc.
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+
+#import "../wolfiphone.h"
+#import "wolf3dAppDelegate.h"
+#import "iphone_alerts.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <unistd.h>
+
+extern  void  Com_Printf(const char* fmt, ... );
+extern  void  my_snprintf( char *dest, size_t size, const char *format, ... );
+
+extern  char  iphoneDocDirectory[1024];
+extern menuState_t menuState;
+
+
+int inf(FILE *source, FILE *dest);
+void zerr(int ret);
+
+
+char mapName[1024];// = "/";
+
+//this is used for determining if we have the correctly sized data
+const unsigned int DownloadUserFileSize = 4096; //max size of maps?
+
+
+//-----------------------------
+// DownloadURLConnection
+// This connects to a server and downloads the file located there
+//-----------------------------
+void DownloadURLConnection( char *url )
+{
+       Com_Printf( "ConnectURL char *: %s\n", url );
+       
+       int length = strlen(url);
+       if (length <= 4)
+       {
+               iphoneMessageBox("error", "url is not a valid map name.  Maps must end in \".map\"");
+               return;
+       }
+       
+       length = strlen(url);
+       //acquire file name of map
+       int pos = length;
+       while (pos > 0)
+       {
+               --pos;
+               if (url[pos] == '/')
+                       break;
+       }
+       ++pos;
+       strcpy(mapName, url + pos);
+       
+       //-------------------------------------------------
+       //check if this file already exists... if so, delete the old one
+       //get documents directory
+       NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+       NSString *documentsDirectory = [paths objectAtIndex:0];
+       
+       //get maps directory
+       NSString *mapsDirectory = [documentsDirectory stringByAppendingString:@"/usermaps/"];
+               
+       DIR *dp = opendir ([mapsDirectory UTF8String]);
+       if (dp != NULL)
+       {
+               struct dirent *ep;
+               while (ep = readdir (dp))
+               {
+                       //if you find a .DS_Store file... ignore it!
+                       if ( strcmp(ep->d_name, ".DS_Store") == 0 )
+                               continue;
+                       if ( strcmp(ep->d_name, ".") == 0 )
+                               continue;
+                       if ( strcmp(ep->d_name, "..") == 0 )
+                               continue;
+                       
+                       if (strcmp(ep->d_name, mapName) == 0)
+                       {
+                               printf("found a file with name: %s\n", mapName);
+                               printf("overwiting file\n");
+                               //TODO: delete this file
+                               char buffer[2048];
+                               sprintf(buffer, "%s%s", [mapsDirectory UTF8String], mapName);
+                               printf("removing at: %s\n", buffer);
+                               remove(buffer);
+                       }
+               }
+       }
+       //-------------------------------------------------
+       
+       
+       //convert url to nsstring
+       NSString *nssURL = [NSString stringWithUTF8String: url];
+       
+       // create the request
+       NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:nssURL]
+                                                                                         cachePolicy:NSURLRequestUseProtocolCachePolicy
+                                                                                 timeoutInterval:60.0];
+       
+       // create the connection with the request
+       // and start loading the data
+       NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest 
+                                                                                                                                  delegate:(wolf3dAppDelegate *)[UIApplication sharedApplication].delegate];
+       
+       if (!theConnection)
+       {
+               // inform the user that the download could not be made
+               Com_Printf("Connection failed... no download plausible\n");
+               
+               //inform user
+               iphoneMessageBox("Connection Failed", "Can not download.  Check your internet connection, file url and try again later.");
+               
+               //return to main menu
+               menuState = IPM_MAIN;
+       }
+       
+       menuState = IPM_DOWNLOADPROGRESS;
+}
+
+unsigned int userDataAmount = 0;
+unsigned int userDataTotalAmount = 0;
+extern unsigned int totalDownloaded;
+
+//============================
+// AppendData
+// adds a packet of data directly to file
+//============================
+void AppendUserDataToFile(NSData* data)
+{
+       NSUInteger length = [data length];
+       
+       userDataAmount = (unsigned int)length;
+       userDataTotalAmount += userDataAmount;
+       totalDownloaded = userDataTotalAmount;  //update the download screen with the total downloaded
+       
+       //get documents directory
+       NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+       NSString *documentsDirectory = [paths objectAtIndex:0];
+       
+       //get maps directory
+       NSString *mapsDirectory = [documentsDirectory stringByAppendingString:@"/usermaps/"];
+       
+       //check if maps directory exists, if not create maps directory
+       mkdir([mapsDirectory UTF8String], 0755);
+       
+       //create/open file for saving
+       NSString *fileatpath = [mapsDirectory stringByAppendingString:[NSString stringWithUTF8String:mapName]];
+       NSFileHandle *file = [NSFileHandle fileHandleForWritingAtPath:fileatpath];
+       
+       if (!file) //file does not exist... create and append file
+       {
+               NSLog(@"open file failed\ncreating file with path: %@\n", fileatpath);
+               [[NSFileManager defaultManager] createFileAtPath:fileatpath
+                                                                                               contents:data
+                                                                                         attributes:nil];
+               return;
+       }
+       
+       //seek to end of file and append data
+       [file seekToEndOfFile];
+       [file writeData:data];
+       [file closeFile];
+}
+
+//================================
+// FinalizeUserDownload 
+//================================ 
+extern int Level_VerifyMap( const char *levelname );
+extern int iphoneGetUserMapLevelByName(const char *mapName);
+void FinalizeUserDownload()
+{
+       char buffer[1024];
+       sprintf(buffer, "usermaps/%s", mapName);
+
+       //we need to verify that this is a true .map file
+       if (Level_VerifyMap(buffer) == 0)
+       {
+               //it wasn't a valid map.  Inform user and delete
+               iphoneMessageBox("invalid map", "downloaded file is an invalid map");
+               
+               NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+               NSString *documentsDirectory = [paths objectAtIndex:0];
+
+               char buffer2[2048];
+               sprintf(buffer2, "%s/usermaps/%s", [documentsDirectory UTF8String], mapName);
+               remove(buffer2);
+               menuState = IPM_MAIN;
+               return;
+       }
+
+       //start this map immediately!
+       menuState = IPM_EPISODE;
+       iphonePreloadBeforePlay();
+       int level = iphoneGetUserMapLevelByName(mapName);
+       iphoneStartUserMap(10, level, currentMap.skill, mapName);
+}
index fd7570377d7e4d1978e930a744906b1530b06184..266754796f6174485fbb01fa0e7abaebc8838d5b 100644 (file)
@@ -120,8 +120,9 @@ brown plant
 cp 136.5551 ~/dev/iphone/wolf3d/base/sprites/013.5551
  
  */
-
+#include <pthread.h> //gsh
 #include "../wolfiphone.h"
+#include "arialGlyphRects.h" //gsh... cass made a nice fontimage helper.  We might as well use it.
 
 currentMap_t currentMap;
 
@@ -131,12 +132,16 @@ int               iphoneFrameNum;
 int            intermissionTriggerFrame;
 int            slowAIFrame;
 
+//gsh
+int returnButtonFrameNum = 0;
+
 // console mode
 int consoleActive;
 
 // the native iPhone code should set the following each frame:
 int    numTouches;
 int    touches[5][2];  // [0] = x, [1] = y in landscape mode, raster order with y = 0 at top
+int isTouchMoving = 0; //gsh
 float  tilt;           // -1.0 to 1.0
 float  tiltPitch;
 
@@ -150,6 +155,9 @@ int prevTouches[5][2];
 
 texture_t *numberPics[10];
 
+//gsh
+texture_t *arialFontTexture;
+
 char *mugshotnames[ NUM_MUGSHOTS ] =
 {
 "iphone/FACE1APIC.tga",
@@ -181,7 +189,11 @@ char *mugshotnames[ NUM_MUGSHOTS ] =
 "iphone/FACE7CPIC.tga",
 
 "iphone/FACE8APIC.tga",
-"iphone/GOTGATLINGPIC.tga"             
+"iphone/GOTGATLINGPIC.tga",    
+
+"iphone/GODMODEFACE0PIC.tga",
+"iphone/GODMODEFACE1PIC.tga",
+"iphone/GODMODEFACE2PIC.tga",
 };
 
 int damageflash;
@@ -308,6 +320,439 @@ int iphoneCenterText( int x, int y, const char *str ) {
        return l * step;
 }
 
+//gsh
+void iphoneCenterTextWithColor(int x, int y, const char *str, colour4_t color ) {
+       
+       pfglColor4f(color[0], color[1], color[2], color[3]);
+       
+       iphoneCenterText(x, y, str);
+       
+       pfglColor4f(1, 1, 1, 1);
+}
+/*
+ ==================
+ iphoneDrawArialText
+ left justified arial text
+ gsh
+ Returns the width in pixels
+ ==================
+ */
+int iphoneDrawArialText( int x, int y, float scale, const char *str ) {
+       /*
+       int l = strlen( str );
+       int     i;
+       font_t *myfont = myfonts[0];
+       //      int             scale;
+       int             step = 10;
+       
+       //      scale = 16;
+       int left_margin = x;
+        */
+       texture_t *gl;
+       
+       gl = TM_FindTexture( "iphone/arialImageLAL_white-alpha.tga", TT_Pic );
+       if( ! gl ) {
+               Com_Printf( "Can't find pic: %s\n", "iphone/arialImageLAL_white-alpha.tga" );
+               return 0;
+       }
+       
+       R_Bind( gl->texnum );
+       
+               
+//     float   fx = x;
+//     float   fy = y;
+       
+//     int scale = 1;//16;
+//     float scale = 0.9f;
+       
+       pfglBegin( GL_QUADS );
+       
+       while ( *str ) {
+               int i = *str;
+               if ( i >= ' ' && i < 128 ) {
+                       GlyphRect *glyph = &glyphRects[i-32];
+                       
+                       // the glyphRects don't include the shadow outline
+                       float   x0 = ( glyph->x0 - 2 ) / 256.0;
+                       float   y0 = ( glyph->y0 - 2 ) / 256.0;
+                       float   x1 = ( glyph->x1 + 3 ) / 256.0;
+                       float   y1 = ( glyph->y1 + 3 ) / 256.0;
+                       
+                       
+                       float   width = ( x1 - x0 ) * 256 * scale;
+                       float   height = ( y1 - y0 ) * 256 * scale;
+                       
+//                     float   xoff = ( glyph->xoff - 1 ) * scale;
+                       float   yoff = ( glyph->yoff - 1 ) * scale;
+                       
+                       if (i == 'l' || i == 'I' || i == 'h' || i == 'i')
+                               yoff += 1;
+                       
+                       pfglTexCoord2f( x0, y0 );
+//                     pfglVertex2f( fx + xoff, fy + yoff );
+                       pfglVertex2i( x, y + yoff);
+                       
+                       pfglTexCoord2f( x1, y0 );
+//                     pfglVertex2f( fx + xoff + width, fy + yoff );
+                       pfglVertex2i( x+width, y + yoff);
+                       
+                       pfglTexCoord2f( x1, y1);
+//                     pfglVertex2f( fx + xoff + width, fy + yoff + height );
+                       pfglVertex2i( x+width, y+height + yoff );
+                       
+                       pfglTexCoord2f( x0, y1);
+//                     pfglVertex2f( fx + xoff, fy + yoff + height );
+                       pfglVertex2i( x, y+height + yoff);                      
+                       
+                       // with our default texture, the difference is negligable
+//                     fx += glyph->xadvance * scale;
+                       x += glyph->xadvance * scale;
+                       //                      fx += ceil(glyph->xadvance);    // with the outline, ceil is probably the right thing
+               }
+               str++;
+       }
+       
+       pfglEnd();
+       
+       return x;
+}
+/*
+ ==================
+ iphoneCenterArialText
+ center justified arial text
+ gsh
+ Returns the width in pixels
+ ==================
+ */
+int iphoneCenterArialText( int x, int y, float scale, const char *str )
+{
+       const char *strcopy = str;
+       float width = 0;
+       while ( *str )
+       {
+               int i = *str;
+               if ( i >= ' ' && i < 128 ) {
+                       
+                       GlyphRect *glyph = &glyphRects[i-32];
+                       width += glyph->xadvance * scale;
+               }
+               ++str;
+       }
+       
+       return iphoneDrawArialText( x - width/2, y, scale, strcopy );
+}
+/*
+ ==================
+ iphoneDrawArialTextInBox
+ center justified arial text
+ gsh
+ Returns the width in pixels
+ ==================
+ */
+int iphoneDrawArialTextInBox( rect_t paragraph, int lineLength, const char *str, rect_t boxRect ) {
+       int l = strlen( str );
+       int     i;
+       
+       if (paragraph.x > boxRect.x + boxRect.width)
+               return 0;
+       if (paragraph.x + lineLength < boxRect.x)
+               return 0;
+       
+       int x = paragraph.x;
+       int y = paragraph.y;
+//     Com_Printf("y value: %i\n", y);
+//     int width = paragraph.width;   //font width
+//     int height = paragraph.height; //font height
+       
+       const int left_margin = x+5;
+       int             step = 10;
+       
+       texture_t *gl;
+       
+       gl = TM_FindTexture( "iphone/arialImageLAL_white-alpha.tga", TT_Pic );
+       if( ! gl ) {
+               Com_Printf( "Can't find pic: %s\n", "iphone/arialImageLAL_white-alpha.tga" );
+               return 0;
+       }
+       
+       R_Bind( gl->texnum );
+       pfglBegin( GL_QUADS );
+       
+       int lengthOfNextWord = 0;
+       float scale = 0.65f;//0.9f;
+       
+       for ( i = 0 ; i < l ; i++/*, x += step*/ ) { 
+               int m = str[i];
+               GlyphRect *glyph = &glyphRects[m-32];
+               
+               float   x0 = ( glyph->x0 - 2 ) / 256.0;
+               float   y0 = ( glyph->y0 - 2 ) / 256.0;
+               float   x1 = ( glyph->x1 + 3 ) / 256.0;
+               float   y1 = ( glyph->y1 + 3 ) / 256.0;
+               
+               float   width = ( x1 - x0 ) * 256 * scale;
+               float   height = ( y1 - y0 ) * 256 * scale;
+               
+               //                      float   xoff = ( glyph->xoff - 1 ) * scale;
+               float   yoff = ( glyph->yoff - 1 ) * scale;
+               
+               
+               //int   row, col; 
+               //float frow, fcol;
+               int     num = str[i];
+               
+               //check when to new-line
+               if ( num == ' ' ) {
+                       float w = 0;
+                       int n = i + 1;
+                       while ( str[n] != ' ' && str[n] != '\0' && str[n] != '\n') {
+                               //++n;
+                               int m = str[n];
+                               GlyphRect *glyph2 = &glyphRects[m-32];
+                               w += glyph2->xadvance * scale;
+                               ++n;
+                       }
+                       lengthOfNextWord = n - i - 1;
+//                     Com_Printf("length of word: %i\n", n - i - 1);
+//                     Com_Printf("length of word pixels: %f\n",w);
+                       
+                       if ( w + x > lineLength + left_margin ) {
+                               y += 30*scale;
+                               x = left_margin;
+                       }
+                       else
+                               x += 10*scale;
+                       //whil
+                       //x += 10*scale;
+                       continue;
+               }
+               if (num == '\n') {
+                       y += 30*scale;
+                       x = left_margin;
+                       continue;
+               }/*
+               if (x + glyph->xadvance * scale > left_margin + lineLength) {
+                       y += 30*scale;
+                       x = left_margin;// + width;
+               }*/
+               
+               //check rendering boundaries
+               if (x < boxRect.x+10) {
+                       x += glyph->xadvance * scale + 1;
+                       continue;
+               }
+               if (x + glyph->xadvance * scale > boxRect.x + boxRect.width) {
+                       x += glyph->xadvance * scale + 1;
+                       continue;
+               }
+               
+               if (y > boxRect.y + boxRect.height)
+                       break;
+                               
+               pfglTexCoord2f( x0, y0 );
+               pfglVertex2i( x, y + yoff);
+               
+               pfglTexCoord2f( x1, y0 );
+               pfglVertex2i( x+width, y + yoff);
+               
+               pfglTexCoord2f( x1, y1);
+               pfglVertex2i( x+width, y+height + yoff );
+               
+               pfglTexCoord2f( x0, y1);
+               pfglVertex2i( x, y+height + yoff);              
+               
+               x += glyph->xadvance * scale + 1;
+               
+       }
+       
+       pfglEnd();
+       
+       return l * step;
+}
+
+
+
+int iphoneDrawText( int x, int y, int width, int height, const char *str ) {
+       int l = strlen( str );
+       int     i;
+       font_t *myfont = myfonts[0];
+//     int             scale;
+       int             step = 10;
+       
+//     scale = 16;
+       int left_margin = x;
+       
+       R_Bind( myfont->texfont->texnum );
+       //R_Bind(arialFontTexture->texnum );
+       pfglBegin( GL_QUADS );
+       
+       for ( i = 0 ; i < l ; i++, x += step ) { 
+               int     row, col; 
+               float frow, fcol;
+               int     num = str[i];
+               
+               if ( num == ' ' ) {
+                       continue;
+               }
+               if (num == '\n') {
+                       y += height;
+                       x = left_margin;
+               }
+               
+               row = (num >> 4) - 2;
+               col = num & 15;
+               
+               frow = row * myfont->hFrac;
+               fcol = col * myfont->wFrac;
+               
+               pfglTexCoord2f( fcol, frow );                                                   
+               pfglVertex2i( x, y );
+               
+               pfglTexCoord2f( fcol+myfont->wFrac, frow );                                     
+               pfglVertex2i( x+width, y );
+               
+               pfglTexCoord2f( fcol+myfont->wFrac, frow+myfont->hFrac );       
+               pfglVertex2i( x+width, y+height );
+               
+               pfglTexCoord2f( fcol, frow+myfont->hFrac );
+               pfglVertex2i( x, y+height );                    
+       }
+       
+       pfglEnd();
+       
+       return l * step;
+}
+
+/*
+ ==================
+ iphoneDrawTextWithColor
+ gsh
+ ==================
+ */
+void iphoneDrawTextWithColor( rect_t rect, const char *str, float colors[4] ) {
+
+       pfglColor4f(colors[0], colors[1], colors[2], colors[3]);
+       iphoneDrawText(rect.x, rect.y, rect.width, rect.height, str);
+       pfglColor4f(1, 1, 1, 1);
+}
+
+/*
+ ==================
+ iphoneDrawMapName
+ gsh
+ ==================
+ */
+void iphoneDrawMapName( rect_t rect, const char *str ) {
+       
+       rect.y += 25;
+       rect.x += 110;//80;
+       /*
+       float colors[4] =  { 0, 0, 0, 1 };
+       iphoneDrawTextWithColor(RectMake(rect.x+1, rect.y+1, rect.width, rect.height), str, colors);
+       iphoneDrawTextWithColor(RectMake(rect.x+2, rect.y+2, rect.width, rect.height), str, colors);
+       
+       colors[0] = 225.0f/255;
+       colors[1] = 166.0f/255;
+       iphoneDrawTextWithColor(rect, str, colors);
+       */
+       
+       pfglColor4f(0, 0, 0, 1);
+       iphoneDrawArialText(rect.x + 1, rect.y + 1, 0.9f, str);
+       iphoneDrawArialText(rect.x + 2, rect.y + 2, 0.9f, str);
+       pfglColor4f(225.0f/255, 166.0f/255, 0, 1);
+       pfglColor4f(225.0f/255, 242.0f/255, 0, 1);
+       iphoneDrawArialText(rect.x, rect.y, 0.9f, str);
+       pfglColor4f(1, 1, 1, 1);
+}
+
+/*
+ ==================
+ iphoneDrawTextInBox
+ gsh
+ Returns the width in pixels
+ ==================
+ */
+int iphoneDrawTextInBox( rect_t paragraph, int lineLength, const char *str, rect_t boxRect ) {
+       int l = strlen( str );
+       int     i;
+       font_t *myfont = myfonts[0];
+       
+       int x = paragraph.x;
+       int y = paragraph.y;
+       int width = paragraph.width;   //font width
+       int height = paragraph.height; //font height
+       
+       int left_margin = x;
+       int             step = 10;
+       
+       R_Bind( myfont->texfont->texnum );
+       pfglBegin( GL_QUADS );
+       
+       int lengthOfNextWord = 0;
+       
+       for ( i = 0 ; i < l ; i++, x += step ) { 
+               int     row, col; 
+               float frow, fcol;
+               int     num = str[i];
+               
+               //check when to new-line
+               if ( num == ' ' ) {
+                       int n = i+1;
+                       while (str[n] != ' ' && str[n] != '\0' && str[n] != '\n') { 
+                               ++n;
+                       }
+                       lengthOfNextWord = n - i;// - 1;
+                       if (x + lengthOfNextWord*step > left_margin + lineLength) {
+                               y += height;
+                               x = left_margin;
+                       }
+                       continue;
+               }
+               if (num == '\n') {
+                       y += height;
+                       x = left_margin;
+                       continue;
+               }
+               if (x + width > left_margin + lineLength) {
+                       y += height;
+                       x = left_margin + width;
+               }
+               
+               //check rendering boundaries
+               if (x < boxRect.x)
+                       continue;
+               if (x + width > boxRect.x + boxRect.width)
+                       continue;
+               if (y < boxRect.y)
+                       continue;
+               if (y + height > boxRect.y + boxRect.height)
+                       continue;
+               
+               row = (num >> 4) - 2;
+               col = num & 15;
+               
+               frow = row * myfont->hFrac;
+               fcol = col * myfont->wFrac;
+               
+               pfglTexCoord2f( fcol, frow );                                                   
+               pfglVertex2i( x, y );
+               
+               pfglTexCoord2f( fcol+myfont->wFrac, frow );                                     
+               pfglVertex2i( x+width, y );
+               
+               pfglTexCoord2f( fcol+myfont->wFrac, frow+myfont->hFrac );       
+               pfglVertex2i( x+width, y+height );
+               
+               pfglTexCoord2f( fcol, frow+myfont->hFrac );
+               pfglVertex2i( x, y+height );                    
+       }
+       
+       pfglEnd();
+       
+       return l * step;
+}
+
+
 
 /*
  ==================
@@ -358,7 +803,7 @@ int TouchReleased( int x, int y, int w, int h ) {
        }
        
        if ( !downPrev ) {
-               if ( downNow ) {
+               if ( downNow && !isTouchMoving ) {
                        Sound_StartLocalSound( "iphone/bdown_01.wav" );
                }
                // wasn't down the previous frame
@@ -370,14 +815,16 @@ int       TouchReleased( int x, int y, int w, int h ) {
                return 0;
        }
        
-       if ( numTouches == numPrevTouches ) {
+       if ( numTouches == numPrevTouches && !isTouchMoving ) {
                // finger dragged off
                Sound_StartLocalSound( "iphone/baborted_01.wav" );
                return 0;
        }
        
-       // released
-       Sound_StartLocalSound( "iphone/baction_01.wav" );
+       if ( !isTouchMoving ) {  //gsh, added the if !isTouchMoving check
+               // released
+               Sound_StartLocalSound( "iphone/baction_01.wav" );
+       }
        return 1;
 }
 
@@ -652,6 +1099,28 @@ PRIVATE void CreateIphoneUserCmd()
        if ( tiltFire->value > 0 && tiltPitch < tiltFire->value ) {
                cmd->buttons |= BUTTON_ATTACK;
        }
+       
+#ifdef VOLUMHACK
+       //gsh... attempting a left/right click attack
+       if ( volumeFireUp->value ) {
+               
+               if ((int)volumeFireUpSetting->value)
+                       cmd->buttons |= BUTTON_ATTACK;
+               else
+                       cmd->buttons |= BUTTON_ALTERNATE_ATTACK;
+               
+               Cvar_Set("volumeFireUp", "0");
+       }
+       else if ( volumeFireDown->value ) {
+               
+               if ((int)volumeFireDownSetting->value)
+                       cmd->buttons |= BUTTON_ATTACK;
+               else
+                       cmd->buttons |= BUTTON_ALTERNATE_ATTACK;
+               
+               Cvar_Set("volumeFireDown", "0");
+       }
+#endif
 
        // tapping the weapon issues the nextWeapon impulse
        if ( TouchReleased( 240 - 40, 320 - 80 - 64, 80, 64 ) ) {
@@ -680,11 +1149,14 @@ iphoneHighlightPicWhenTouched
 Draw transparent except when touched
 =================
 */
+//gsh TODO: change hud alphas
+//TODO: make this cvar setable and adjustable in settings menu
+//float alphaValueForHudControls = 1;//0.5f;
 void iphoneHighlightPicNumWhenTouched( int x, int y, int w, int h, int glTexNum ) {
        if ( TouchDown( x, y, w, h ) ) {
                pfglColor4f(1,1,1,1);
        } else {
-               pfglColor4f(1,1,1,0.5);
+               pfglColor4f(1,1,1,hudAlpha->value);//0.5);
        }
        iphoneDrawPicNum( x, y, w, h, glTexNum );
        pfglColor4f(1,1,1,1);
@@ -752,6 +1224,7 @@ void iphoneDrawNumber( int x, int y, int number, int charWidth, int charHeight )
        for( i = 0 ; i < length ; i++ ) {
                int digit = string[i] - '0';
                tex = numberPics[digit];
+               
                R_Bind( tex->texnum );
                pfglBegin( GL_QUADS );
                
@@ -828,6 +1301,10 @@ void iphoneDrawFace() {
                                h = 0;
                        }
                        pic = mugshotnames[ 3*((100-h)/16)+Player.faceframe ];
+                       
+                       //gsh
+                       if ((Player.flags & FL_GODMODE))
+                               pic = mugshotnames[ 23+Player.faceframe ];
                }
        }
        else
@@ -901,11 +1378,79 @@ void iphoneDrawNotifyText() {
                }
        }
        
+       --notifyFrameNum; //gsh
+       
+//     pfglColor4f( 1, 1, 1, f );
+       //iphoneCenterText( 240, 5, notifyText );
+//     iphoneDrawArialText( 200, 20, 0.7f, notifyText );  //gsh
+       pfglColor4f( 0, 0, 0, f );
+       iphoneCenterArialText( 240+1, 20+1, 0.8f, notifyText); //gsh
+       iphoneCenterArialText( 240+2, 20+2, 0.8f, notifyText); //gsh
+       iphoneCenterArialText( 240+3, 20+3, 0.8f, notifyText); //gsh
        pfglColor4f( 1, 1, 1, f );
-       iphoneCenterText( 240, 5, notifyText );
+       iphoneCenterArialText( 240, 20, 0.8f, notifyText); //gsh
        pfglColor4f( 1, 1, 1, 1 );
 }
 
+/*
+ ==================
+ iphoneDrawReturnButton
+ Displays a button that allows the player to return to the map screen.
+ But it only displays for a few seconds.
+ ==================
+ */
+void iphoneDrawReturnButton() {
+       
+       if (returnButtonFrameNum <= 0)
+               return;
+               
+       // display for three seconds, then fade over 0.3
+       float f = iphoneFrameNum - returnButtonFrameNum - 80;
+       if ( f < 0 ) {
+               f = 1.0;
+       } else {
+               f = 1.0 - f * 0.1f;
+               if ( f < 0 ) {
+                       returnButtonFrameNum = 0;
+                       return;
+               }
+       }
+       
+       //always be semi-transparent
+       if ( f > 0.5f )
+               f = 0.5f;
+
+       pfglColor4f( 1, 1, 1, f );
+       if (iphoneDrawPicWithTouch( 240-32, 32, 64, 48, "iphone/button_back.tga")) {//int x, int y, int w, int h, const char *pic )) {
+               menuState = IPM_MAPS;
+               returnButtonFrameNum = 0;
+               
+               //if it's a spear map, it needs special attention
+               if (currentMap.episode > 5 && currentMap.episode < 10)
+               {
+                       //get the level number
+                       int levelNum = currentMap.episode*10 + currentMap.map;
+                       
+                       if (levelNum == 78 || (levelNum >= 60 && levelNum < 65)) {
+                               episode->value = 6;
+                       }
+                       else if (levelNum == 79 || (levelNum >= 65 && levelNum < 70)) {
+                               episode->value = 7;
+                       }
+                       else if (levelNum >= 70 && levelNum < 76) {
+                               episode->value = 8;
+                       }
+                       else if (levelNum == 76 || levelNum == 77 || levelNum == 80) {
+                               episode->value = 9;
+                       }
+               }
+       }
+       pfglColor4f( 1, 1, 1, 1 );
+       
+       --returnButtonFrameNum;
+}
+
 void iphoneStartBonusFlash() {
        bonusFrameNum = iphoneFrameNum;
 }
@@ -936,14 +1481,14 @@ void iphoneSetAttackDirection( int dir ) {
                attackDirTime[1] = iphoneFrameNum;
        }
 }
-
+//gsh... note to self:  this is where the controls are drawn
 void iphoneDrawHudControl( hudPic_t *hud ) {
        if ( hud->hudFlags & HF_DISABLED ) {
                return;
        }
        iphoneHighlightPicNumWhenTouched( hud->x, hud->y, hud->width, hud->height, hud->glTexNum );
 }
-
+//gsh... note to self:  this is where menu/map buttons are drawn
 int iphoneDrawHudButton( hudPic_t *hud ) {
        if ( hud->hudFlags & HF_DISABLED ) {
                return 0;
@@ -1007,7 +1552,7 @@ iphoneFrame
 ==================
 */
 void iphoneFrame() {
-       unsigned char blendColor[4];
+       unsigned char blendColor[4] = { 0, 0, 0, 0 };
        
        iphoneFrameNum++;
        loggedTimes[iphoneFrameNum&(MAX_LOGGED_TIMES-1)].enterFrame = Sys_Milliseconds();
@@ -1052,6 +1597,12 @@ void iphoneFrame() {
        //------------------
        // normal gameplay
        //------------------
+       
+       //this is a hack for "Floor 18, Part II: Death's Door"
+       //there's no gold key to leave the first room
+       //so we give it to the player here... gsh
+       if (currentMap.episode == 8 && !(Player.items & ITEM_KEY_1))
+               Player.items |= ITEM_KEY_1;
 
        if( Player.playstate != ex_dead )
        {
@@ -1125,16 +1676,19 @@ void iphoneFrame() {
                blendColor[0] = 255;
                blendColor[1] = 0;
                blendColor[2] = 0;
-               blendColor[3] = deathFadeIntensity;
+               blendColor[3] = deathFadeIntensity; 
                deathFadeIntensity += 2;
                if( deathFadeIntensity >= 240 ) {
                        deathFadeIntensity = 0;
                        PL_NewGame( &Player );
-                       iphoneStartMap( currentMap.episode, currentMap.map, currentMap.skill );
+                       if (currentMap.episode >=9) //gsh
+                               iphoneStartUserMap( currentMap.episode, currentMap.map, currentMap.skill, NULL );
+                       else
+                               iphoneStartMap( currentMap.episode, currentMap.map, currentMap.skill );
                }
        } else {
                iphoneDrawWeapon();
-               if( damageflash ) {
+               if( damageflash ) { 
                        blendColor[0] = 255;
                        blendColor[1] = 0;
                        blendColor[2] = 0;
@@ -1160,6 +1714,9 @@ void iphoneFrame() {
        }
        
        iphoneDrawNotifyText();
+       
+       //gsh
+       iphoneDrawReturnButton();
 
        iphoneDrawMapView();
 
@@ -1180,7 +1737,7 @@ void iphoneFrame() {
        if ( iphoneDrawHudButton( &huds.map ) ) {
                iphoneOpenAutomap();
        }
-               
+
        Client_Screen_DrawConsole();    
 
        ShowTilt();             // debug tool
@@ -1189,4 +1746,20 @@ void iphoneFrame() {
        iphoneSavePrevTouches();
        
        SysIPhoneSwapBuffers(); // do the swapbuffers
+       
 }
+
+void iphoneDrawLoading()
+{
+       Com_Printf("Draw Loading!\n");
+//     unsigned char blendColor[4];
+       
+       iphoneSet2D();
+       
+       //draw stuff here
+       iphoneDrawText(100, 100, 16, 16, "Drawing Loading!");//, <#int y#>, <#int width#>, <#int height#>, <#const char * str#>)
+       
+       SysIPhoneSwapBuffers(); // do the swapbuffers   
+}
+
+
index e4e74617e61385b0f6483fa879cf202346461fdb..b9c69912ed2e9be165306a85e2546fea8ed5f26d 100644 (file)
@@ -29,7 +29,6 @@
 
 #include "../wolfiphone.h"
 
-
 cvar_t *controlScheme;
 cvar_t *sensitivity;
 cvar_t *stickTurnBase;
@@ -42,6 +41,13 @@ cvar_t       *tiltMove;
 cvar_t *tiltDeadBand;
 cvar_t *tiltAverages;
 cvar_t *tiltFire;
+#ifdef VOLUMEHACK
+cvar_t *volumeFireUp; //gsh
+cvar_t *volumeFireDown; //gsh
+cvar_t *volumeFireUpSetting; //gsh
+cvar_t *volumeFireDownSetting; //gsh
+#endif
+cvar_t *hudAlpha; //gsh
 cvar_t *music;
 cvar_t *showTilt;
 cvar_t *showTime;
@@ -56,6 +62,10 @@ cvar_t       *autoFire;
 
 W32    sys_frame_time;
 
+#ifdef STOREKIT
+extern void CheckForStorekitExistence(); //gsh
+#endif
+
 void Sys_Error( const char *format, ... )
 { 
     va_list     argptr;
@@ -101,7 +111,12 @@ void Reset_f() {
 void iphoneStartup() {
        char    *s;
        int             start = Sys_Milliseconds();
-
+       
+#ifdef STOREKIT
+       //check for storekit framework and set appropriate flags... gsh
+       CheckForStorekitExistence();
+#endif
+       
        // temporary 
        const char *systemVersion = SysIPhoneGetOSVersion();
        printf( "systemVersion = %s\n", systemVersion );
@@ -119,6 +134,7 @@ void iphoneStartup() {
        Con_Init();
        FS_InitFilesystem();    
        
+       
        // We need to add the early commands twice, because
        // a basedir or cddir needs to be set before execing
        // config files, but we want other parms to override
@@ -137,9 +153,7 @@ void iphoneStartup() {
        Cvar_Get( "version", s, CVAR_SERVERINFO | CVAR_NOSET );
        
        Con_Init();
-       
        Sound_Init();
-       
        Game_Init();    // game and player init
        
        Cbuf_AddText( "exec config.cfg\n" );
@@ -165,6 +179,13 @@ void iphoneStartup() {
        tiltTurn = Cvar_Get( "tiltTurn", "0", CVAR_ARCHIVE );
        tiltMove = Cvar_Get( "tiltMove", "0", CVAR_ARCHIVE );
        tiltFire = Cvar_Get( "tiltFire", "0", CVAR_ARCHIVE );
+#ifdef VOLUMEHACK
+       volumeFireUp = Cvar_Get( "volumeFireUp", "0", 0 );  //gsh
+       volumeFireDown = Cvar_Get( "volumeFireDown", "0", 0 );  //gsh
+       volumeFireUpSetting = Cvar_Get( "volumeFireUpSetting", "1", CVAR_ARCHIVE );  //gsh      // 1 = primary
+       volumeFireDownSetting = Cvar_Get( "volumeFireDownSetting", "0", CVAR_ARCHIVE );  //gsh  // 0 = secondary
+#endif
+       hudAlpha = Cvar_Get("hudAlpha", "1.0", CVAR_ARCHIVE); //gsh
        music = Cvar_Get( "music", "1", CVAR_ARCHIVE );
        tiltDeadBand = Cvar_Get( "tiltDeadBand", "0.08", CVAR_ARCHIVE );
        tiltAverages = Cvar_Get( "tiltAverages", "3", CVAR_ARCHIVE );
@@ -181,7 +202,8 @@ void iphoneStartup() {
        
        // make sure volume changes and incoming calls draw the right orientation
        SysIPhoneSetUIKitOrientation( revLand->value );
-       
+
+       /*  //if we don't preload the ogg files then we have faster start ups... gsh
        // preload all the ogg FM synth sounds
        Com_Printf( "before ogg preload: %i msec\n", Sys_Milliseconds() - start );
        
@@ -210,7 +232,7 @@ void iphoneStartup() {
        Sound_RegisterSound( "lsfx/078.wav" );
        Sound_RegisterSound( "lsfx/080.wav" );
        Sound_RegisterSound( "lsfx/085.wav" );
-       Sound_RegisterSound( "lsfx/086.wav" );
+       Sound_RegisterSound( "lsfx/086.wav" );*/
        
        // these should get overwritten by LoadTheGame
        memset( &currentMap, 0, sizeof( currentMap ) );