home *** CD-ROM | disk | FTP | other *** search
- /*
- WASTE Demo Project:
- File Handling
-
- Copyright © 1993-1997 Marco Piovanelli
- All Rights Reserved
-
- C port by John C. Daub
- */
-
-
- #ifndef __WEDEMOAPP__
- #include "WEDemoIntf.h"
- #endif
-
- #ifndef __FOLDERS__
- #include <Folders.h>
- #endif
-
- #define kFileNotOpened -1
-
- OSErr ReadTextFile ( const FSSpec * pFileSpec, WEReference we )
- {
- SInt16 dataForkRefNum = kFileNotOpened;
- SInt16 resForkRefNum = kFileNotOpened;
- Handle hText = nil;
- Handle hStyles = nil;
- Handle hSoup = nil;
- Handle hFontTable = nil;
- Size textSize;
- Boolean wasChanged = false;
- OSErr err;
-
- // open the data fork with read-only permission
- if ((err = FSpOpenDF(pFileSpec, fsRdPerm, &dataForkRefNum)) != noErr)
- goto cleanup;
-
- // get data fork size
- if ((err = GetEOF(dataForkRefNum, &textSize)) != noErr)
- goto cleanup;
-
- // set the position in the file from where to start reading
- if ((err = SetFPos(dataForkRefNum, fsFromStart, 0L)) != noErr)
- goto cleanup;
-
- // try to allocate a handle that large, use temporary memory if available
- if ((err = NewHandleTemp(textSize, &hText)) != noErr)
- goto cleanup;
-
- // read in the text
- HLock(hText);
- err = FSRead(dataForkRefNum, &textSize, *hText);
- HUnlock(hText);
- if (err != noErr)
- goto cleanup;
-
- // see if the file has a resource fork
- // FSpOpenResFile will return -1 if it fails
- if ( ( resForkRefNum = FSpOpenResFile( pFileSpec, fsRdPerm ) ) != kFileNotOpened )
- {
- // look for a style scrap resource (get the first one; the resource ID doesn't matter)
- if ((hStyles = Get1IndResource(kTypeStyles, 1)) != nil)
- {
- DetachResource(hStyles);
- }
-
- // look for a soup resource as well
- if ((hSoup = Get1IndResource(kTypeSoup, 1)) != nil)
- {
- DetachResource(hSoup);
- }
-
- // finally, look for a font table resource
- if ((hFontTable = Get1IndResource(kTypeFontTable, 1)) != nil)
- {
- DetachResource(hFontTable);
- }
- }
-
- // if both a style scrap and a font table were found,
- // re-map font IDs in the style scrap
- if ((hStyles != nil) && (hFontTable != nil))
- {
- if ((WEUpdateFontTable(hFontTable, nil, &wasChanged) == noErr) && wasChanged)
- {
- WEUpdateStyleScrap((StScrpHandle) hStyles, hFontTable);
- }
- }
-
- // insert the text into the WE record
- HLock(hText);
- if ((err = WEInsert(*hText, textSize, (StScrpHandle) hStyles, hSoup, we)) != noErr)
- goto cleanup;
-
- // set the insertion point at the beginning of the text
- WESetSelection(0, 0, we);
-
- // reset the WE instance modification count
- WEResetModCount( we );
-
- cleanup:
- // display an alert box if anything went wrong
- if (err != noErr)
- {
- ErrorAlert( err );
- }
-
- ForgetHandle(&hText);
- ForgetHandle(&hStyles);
- ForgetHandle(&hSoup);
- ForgetHandle(&hFontTable);
-
- if ( dataForkRefNum != kFileNotOpened )
- {
- FSClose(dataForkRefNum);
- dataForkRefNum = kFileNotOpened;
- }
-
- if ( resForkRefNum != kFileNotOpened )
- {
- CloseResFile(resForkRefNum);
- resForkRefNum = kFileNotOpened;
- }
-
- return err;
- }
-
- // I added a bunch of other functionality to WriteTextFile(), mostly to show how to use
- // temp files, check for locked files, etc. ( all along Apple's recommended way of
- // doing things. - JCD
-
- OSErr WriteTextFile ( const FSSpec * pFileSpec, WEReference we )
- {
- FInfo fileInfo ;
- Size textSize ;
- Boolean replacing ;
- SInt16 dataForkRefNum = kFileNotOpened ;
- SInt16 resForkRefNum = kFileNotOpened ;
- Handle hText = nil ;
- Handle hStyles = nil ;
- Handle hSoup = nil ;
- Handle hFontTable = nil;
- UInt32 theTime ;
- Str255 tempFileName ;
- FSSpec tempFileSpec ;
- SInt16 tempVRef ; // volume reference # for the temp file
- SInt32 tempDirID ; // directory ID of the temp file
- OSErr err ;
-
- // will we be replacing an existing file?
- err = FSpGetFInfo( pFileSpec, &fileInfo ) ;
- if ( err == noErr )
- {
- replacing = true;
- }
- else if ( err == fnfErr )
- {
- replacing = false;
- }
- else
- {
- goto cleanup;
- }
-
- // originally, Marco had it so that if the file already existed (replacing == true)
- // then just can the original file and move along. for the scope of this demo, that
- // really is ok, but generally speaking, not the Apple-recommended way of doing things.
- // since we know we're under (at least) System 7 (due to WASTE's need of it), we know
- // we can use temporary files, so let us do so!
-
- // also, Marco didn't check for locked files (technically, if a file is locked from
- // the Finder, you shouldn't be able to modify it). let's check for that.
-
- // if the file currently exists (meaning it was saved at some time in the past, be it
- // 5 minutes ago, or 5 days ago), there is a chance that it could be locked (from the
- // Finder's "Get Info" window (or otherwise). If the file is locked, you cannot
- // save changes. Therefore, if 'replacing' is true, we have to throw up a message
- // saying that we can't do this, then exit.
-
- if ( replacing )
- {
- if ( ( err = FSpCheckObjectLock ( pFileSpec ) ) != noErr )
- {
- goto cleanup ;
- }
-
- // create the temporary file name. the name doesn't have to make sense, just
- // be unique
-
- GetDateTime ( & theTime ) ;
- NumToString ( theTime, tempFileName ) ;
-
- // find the temporary items folder on the file's volume; create it if necessary
- // it is important that the temp folder (and the temp file) and the "original" target
- // file be on the same volume; if not, FSpExchangeFiles will return diffVolErr (-1303)
- // and won't work
-
- if ( ( err = FindFolder ( pFileSpec -> vRefNum, kTemporaryFolderType, kCreateFolder, & tempVRef, & tempDirID ) ) != noErr )
- {
- goto cleanup ;
- }
-
- // make an FSSpec for the temp file
- err = FSMakeFSSpec ( tempVRef, tempDirID, tempFileName, & tempFileSpec ) ;
- if ( (err != noErr) && (err != fnfErr ) )
- {
- goto cleanup ;
- }
- }
-
- // create a new file. if we're replacing, make a temp file. if it's a
- // new file from the onset, just create the file
-
- // should we allow people to choose the file to create? i.e. create a TEXT
- // file or a ttro file? if you'd like to do this, you'll want to find this
- // info out when calling CustomPutFile() and pass that info to this function
-
- if ( replacing )
- {
- FSpCreateResFile( &tempFileSpec, sigWASTEDemo, kTypeText, smSystemScript );
- }
- else
- {
- FSpCreateResFile( pFileSpec, sigWASTEDemo, kTypeText, smSystemScript );
- }
-
- if ((err = ResError()) != noErr)
- goto cleanup;
-
- // if replacing an old file, copy the old file information
- if ( replacing )
- {
- if ( ( err = FSpSetFInfo( &tempFileSpec, &fileInfo ) ) != noErr )
- {
- goto cleanup;
- }
- }
-
- // open the data fork for writing
- if ( replacing )
- {
- err = FSpOpenDF( &tempFileSpec, fsRdWrPerm, &dataForkRefNum );
- }
- else
- {
- err = FSpOpenDF( pFileSpec, fsRdWrPerm, &dataForkRefNum );
- }
-
- if ( err != noErr )
- {
- goto cleanup;
- }
-
- // set the end-of-file
- if ( ( err = SetEOF( dataForkRefNum, 0 ) ) != noErr )
- {
- goto cleanup;
- }
-
- // set the position in the file to write from
- if ( ( err = SetFPos( dataForkRefNum, fsFromStart, 0 ) ) != noErr )
- {
- goto cleanup;
- }
-
- // get the text handle from the WE instance
- // WEGetText returns the original handle, not a copy, so don't dispose of it!!
- hText = WEGetText( we );
- textSize = GetHandleSize( hText );
-
- // write the text
- HLock( hText );
- err = FSWrite( dataForkRefNum, &textSize, *hText );
- HUnlock( hText );
-
- if ( err != noErr )
- {
- goto cleanup;
- }
-
- // open the resource file for writing
- if ( replacing )
- {
- resForkRefNum = FSpOpenResFile( &tempFileSpec, fsRdWrPerm );
- }
- else
- {
- resForkRefNum = FSpOpenResFile( pFileSpec, fsRdWrPerm );
- }
-
- if ( ( err = ResError ( ) ) != noErr )
- {
- goto cleanup;
- }
-
- // allocate temporary handles to hold the style scrap, the soup
- // and the font table
- // try tapping temporary memory since WECopyRange() could get huge
- if ( ( err = NewHandleTemp ( 0, & hStyles ) ) != noErr )
- {
- goto cleanup;
- }
- if ( ( err = NewHandleTemp ( 0, & hSoup ) ) != noErr )
- {
- goto cleanup;
- }
- if ( ( err = NewHandleTemp ( 0, & hFontTable ) ) != noErr )
- {
- goto cleanup ;
- }
-
- // create the style scrap and the soup
- if ( ( err = WECopyRange ( 0, LONG_MAX, nil, ( StScrpHandle ) hStyles, hSoup, we ) ) != noErr )
- {
- goto cleanup ;
- }
-
- // create the font table
- if ( ( err = WEBuildFontTable ( hFontTable, nil, we ) ) != noErr )
- {
- goto cleanup ;
- }
-
- // make them resource handles
- AddResource ( hStyles, kTypeStyles, 128, "\p" ) ;
- if ( ( err = ResError ( ) ) != noErr )
- {
- goto cleanup ;
- }
- AddResource ( hSoup, kTypeSoup, 128, "\p" ) ;
- if ( ( err = ResError ( ) ) != noErr )
- {
- goto cleanup ;
- }
- AddResource ( hFontTable, kTypeFontTable, 128, "\p" ) ;
- if ( ( err = ResError ( ) ) != noErr )
- {
- goto cleanup ;
- }
-
- // write them to the resource file
- ChangedResource ( hStyles ) ;
- WriteResource ( hStyles ) ;
- if ( ( err = ResError ( ) ) != noErr )
- {
- goto cleanup ;
- }
- ChangedResource ( hSoup ) ;
- WriteResource ( hSoup ) ;
- if ( ( err = ResError ( ) ) != noErr )
- {
- goto cleanup ;
- }
- ChangedResource ( hFontTable ) ;
- WriteResource ( hFontTable ) ;
- if ( ( err = ResError ( ) ) != noErr )
- {
- goto cleanup ;
- }
-
- // "clean" this document by resetting the WE instance modification count
- WEResetModCount ( we ) ;
-
- err = noErr;
-
- cleanup:
- // display an alert box if anything went wrong
- if (err != noErr)
- {
- ErrorAlert( err );
- }
-
- // remember, don't dispose the hText handle!
- ForgetResource ( & hStyles ) ;
- ForgetResource ( & hSoup ) ;
- ForgetResource ( & hFontTable ) ;
-
- if ( dataForkRefNum != kFileNotOpened )
- {
- FSClose( dataForkRefNum ) ;
- dataForkRefNum = kFileNotOpened ;
- }
-
- if ( resForkRefNum != kFileNotOpened )
- {
- CloseResFile( resForkRefNum ) ;
- resForkRefNum = kFileNotOpened ;
- }
-
- if ( replacing )
- {
- // update the disk with any unwritten data
-
- FlushVol( nil, tempFileSpec.vRefNum );
-
- // since we were replacing an existing file, let's now swap the original
- // and the temp file. let's hear it for safe saves.
-
- if ( ( err = FSpExchangeFiles( &tempFileSpec, pFileSpec ) ) != noErr )
- {
- // handle the error
- return err;
- }
-
- // can the temp file since we don't need it anymore
-
- err = FSpDelete( &tempFileSpec );
- if ( err != noErr )
- {
- // handle the error
-
- return err;
- }
- }
-
- // and update the disk with any unwritten data
- FlushVol( nil, pFileSpec->vRefNum );
-
- return err;
- }
-
-
- /* The following 2 functions (CheckObjectLock and FSpCheckObjectLock) were taken
- from MoreFiles 1.2.1, a code sample from Apple's DTS. Here's some info from
- the MoreFiles readme:
-
- A collection of File Manager and related routines
-
- by Jim Luther, Apple Macintosh Developer Technical Support
- with significant code contributions by Nitin Ganatra, Apple Macintosh Developer
- Technical Support
- MoreFile Reference is by Eric Soldan
- Copyright © 1992-1994 Apple Computer, Inc.
- All rights reserved.
-
- Frankly, this is one amazing repository of all sorts of file-related things. I'd
- check it out if you can. (should be, as of this writing, on ftp.info.apple.com
- in like the /Apple.Support.Services/Developer_Support/ or something like that).
-
- thanx to Alex Rosen for answering my post on comp.sys.mac.programmer.help and pointing
- out MoreFiles to me.
-
- WHAT DO THEY DO? Oh duh...i should tell you huh?
-
- Both functions do the same thing: check to see if the object is locked
- (in this case, the object is a file). This is using in WriteTextFile()
- to prevent overwriting/deleting locked files.
-
- The only difference between these 2 functions are the arguments passed.
- the first takes a vRefNum, dirID and a file name, the second takes an FSSpec
- and then just calls the first based on the FSSpec (just makes for slighly
- neater/readable code)
- */
-
- pascal OSErr CheckObjectLock(SInt16 vRefNum, SInt32 dirID, StringPtr name)
- {
- CInfoPBRec pb;
- OSErr error;
-
- pb.hFileInfo.ioNamePtr = name;
- pb.hFileInfo.ioVRefNum = vRefNum;
- pb.hFileInfo.ioDirID = dirID;
- pb.hFileInfo.ioFDirIndex = 0; // use ioNamePtr and ioDirID
- error = PBGetCatInfoSync(&pb);
-
- if ( error == noErr )
- {
- // check locked bit
- if ( (pb.hFileInfo.ioFlAttrib & 0x01) != 0 )
- error = fLckdErr;
- }
- return ( error );
- }
-
- /*****************************************************************************/
-
- pascal OSErr FSpCheckObjectLock(const FSSpec *spec)
- {
- return ( CheckObjectLock(spec->vRefNum, spec->parID, (StringPtr) spec->name) );
- }
-
-