Back to index

lightning-sunbird  0.9+nobinonly
nsAppleSingleEncoder.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code, released
00016  * March 31, 1998.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1999
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Samir Gehani <sgehani@netscape.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 
00041 #ifndef _NS_APPLESINGLEENCODER_H_
00042        #include "nsAppleSingleEncoder.h"
00043 #endif
00044  
00045 #include <Files.h>
00046 #include <OSUtils.h>
00047 #include "nsAppleSingleDecoder.h" /* AppleSingle struct definitions */
00048 #include "MoreFilesExtras.h"
00049 #include "IterateDirectory.h"
00050 
00051 nsAppleSingleEncoder::nsAppleSingleEncoder()
00052 {
00053        mInFile = NULL;
00054        mOutFile = NULL;
00055 }
00056 
00057 nsAppleSingleEncoder::~nsAppleSingleEncoder()
00058 {
00059 }
00060 
00061 Boolean
00062 nsAppleSingleEncoder::HasResourceFork(FSSpecPtr aFile)
00063 {
00064        OSErr  err = noErr;
00065        Boolean bHasResFork = false;
00066        short  refnum;
00067        long   bytes2Read = 1;
00068        char   buf[2];
00069        
00070        err = FSpOpenRF(aFile, fsRdPerm, &refnum);
00071        if (err == noErr)
00072        {
00073               err = FSRead(refnum, &bytes2Read, &buf[0]);
00074               if (err == noErr)    /* err==eofErr if all OK but no res fork */
00075                      bHasResFork = true;
00076        }
00077        
00078        FSClose(refnum);
00079        
00080        return bHasResFork;
00081 }
00082 
00083 OSErr
00084 nsAppleSingleEncoder::Encode(FSSpecPtr aFile)
00085 {
00086        OSErr         err = noErr;
00087        FSSpec        transient, exists;
00088        
00089        // handle init in lieu of overloading 
00090        if (!mOutFile || !mInFile)
00091        {
00092               mInFile = aFile;
00093               mOutFile = aFile;
00094        }
00095        
00096        // param check
00097        if (!mInFile)
00098               return paramErr;
00099               
00100        // stomp old temp file
00101        mTransient = &transient;
00102        err = FSMakeFSSpec(  mInFile->vRefNum, mInFile->parID, kTransientName, 
00103                                           mTransient);
00104        if (err == noErr) 
00105               FSpDelete(mTransient);
00106               
00107        // write to transient file 
00108        ERR_CHECK( WriteHeader() );
00109        ERR_CHECK( WriteEntryDescs() );
00110        ERR_CHECK( WriteEntries() );
00111        
00112        // rename transient file to out file      
00113        err = FSMakeFSSpec( mOutFile->vRefNum, mOutFile->parID, mOutFile->name,
00114                                           &exists );
00115        if (err == noErr)
00116               FSpDelete(mOutFile);
00117        FSpRename(mTransient, mOutFile->name);
00118 
00119        return err;
00120 }
00121 
00122 OSErr
00123 nsAppleSingleEncoder::Encode(FSSpecPtr aInFile, FSSpecPtr aOutFile)
00124 {
00125        OSErr err = noErr;
00126        
00127        // param check
00128        if (!aInFile || !aOutFile)
00129               return paramErr;
00130               
00131        mInFile = aInFile;
00132        mOutFile = aOutFile;
00133        
00134        err = Encode(NULL);
00135 
00136        return err;
00137 }
00138 
00139 pascal void
00140 EncodeDirIterateFilter(const CInfoPBRec * const cpbPtr, Boolean *quitFlag, void *yourDataPtr)
00141 {      
00142        OSErr                              err = noErr;
00143        FSSpec                                    currFSp;
00144        nsAppleSingleEncoder*       thisObj = NULL;
00145        Boolean                                   isDir = false;
00146        long                               dummy;
00147        
00148        // param check
00149        if (!yourDataPtr || !cpbPtr || !quitFlag)
00150               return;
00151        
00152        *quitFlag = false;
00153               
00154        // extract 'this' -- an nsAppleSingleEncoder instance
00155        thisObj = (nsAppleSingleEncoder*) yourDataPtr;
00156        thisObj->ReInit();
00157        
00158        // make an FSSpec from the CInfoPBRec*
00159        err = FSMakeFSSpec(cpbPtr->hFileInfo.ioVRefNum, cpbPtr->hFileInfo.ioFlParID, 
00160                                           cpbPtr->hFileInfo.ioNamePtr, &currFSp);
00161        if (err == noErr)
00162        {
00163               FSpGetDirectoryID(&currFSp, &dummy, &isDir);
00164               
00165               // if current FSSpec is file
00166               if (!isDir)
00167               {
00168                      // if file has res fork
00169                      if (nsAppleSingleEncoder::HasResourceFork(&currFSp))
00170                      {
00171                             // encode file
00172                             thisObj->Encode(&currFSp);
00173                      }
00174               }
00175               else
00176               {
00177                      // else if current FSSpec is folder ignore
00178                      // XXX never reached?
00179                      return;
00180               }
00181        }
00182 }
00183 
00184 OSErr
00185 nsAppleSingleEncoder::EncodeFolder(FSSpecPtr aFolder)
00186 {
00187        OSErr  err = noErr;
00188        long   dummy;
00189        Boolean       isDir = false;
00190        
00191        // check that FSSpec is folder
00192        if (aFolder)
00193        {
00194               FSpGetDirectoryID(aFolder, &dummy, &isDir);
00195               if (!isDir)
00196                      return dirNFErr;
00197        }
00198        
00199        // recursively enumerate contents of folder (maxLevels=0 means recurse all)
00200        FSpIterateDirectory(aFolder, 0, EncodeDirIterateFilter, (void*)this);
00201                      
00202        return err;
00203 }
00204 
00205 void
00206 nsAppleSingleEncoder::ReInit()
00207 {
00208        mInFile = NULL;
00209        mOutFile = NULL;
00210 }
00211 
00212 OSErr
00213 nsAppleSingleEncoder::WriteHeader()
00214 {
00215        OSErr         err = noErr;
00216        ASHeader      hdr;
00217        int                  i;
00218        long          bytes2Wr;
00219        
00220        // init header info
00221        hdr.magicNum = kAppleSingleMagicNum; 
00222        hdr.versionNum = kAppleSingleVerNum;
00223        for (i=0; i<16; i++)
00224               hdr.filler[i] = 0;
00225        hdr.numEntries = kNumASEntries;           
00226               /*
00227               ** Entries:
00228               **
00229               ** 1> Real name
00230               ** 2> Finder info
00231               ** 3> File dates
00232               ** 4> Resource fork
00233               ** 5> Data fork
00234               ** 6> Mac info
00235               */
00236        
00237        bytes2Wr = sizeof(ASHeader);
00238        ERR_CHECK( FSpCreate(mTransient, 'MOZZ', '????', 0) );
00239        ERR_CHECK( FSpOpenDF(mTransient, fsRdWrPerm, &mTransRefNum) );
00240        // ERR_CHECK( SetFPos(mTransRefNum, fsFromStart, 0) ); // XXX revisit
00241        ERR_CHECK( FSWrite(mTransRefNum, &bytes2Wr, &hdr) );
00242        if (bytes2Wr != sizeof(ASHeader))
00243               err = -1;
00244               
00245        return err;
00246 }
00247 
00248 OSErr
00249 nsAppleSingleEncoder::WriteEntryDescs()
00250 {
00251        OSErr         err = noErr;
00252        long          offset = sizeof(ASHeader), bytes2Wr = kNumASEntries*sizeof(ASEntry);
00253        ASEntry       entries[kNumASEntries];
00254        int           i;
00255        CInfoPBRec    pb;
00256        
00257        ERR_CHECK( FSpGetCatInfo(&pb, mInFile) );
00258        
00259        // real name
00260        entries[0].entryOffset = sizeof(ASHeader) + (sizeof(ASEntry) * kNumASEntries);
00261        entries[0].entryID = AS_REALNAME;
00262        entries[0].entryLength = pb.hFileInfo.ioNamePtr[0];
00263               
00264        // finder info
00265        entries[1].entryID = AS_FINDERINFO;
00266        entries[1].entryLength = sizeof(FInfo) + sizeof(FXInfo);
00267               
00268        // file dates
00269        entries[2].entryID = AS_FILEDATES;
00270        entries[2].entryLength = sizeof(ASFileDates);
00271               
00272        // resource fork
00273        entries[3].entryID = AS_RESOURCE;
00274        entries[3].entryLength = pb.hFileInfo.ioFlRLgLen;
00275 
00276        // data fork
00277        entries[4].entryID = AS_DATA;
00278        entries[4].entryLength = pb.hFileInfo.ioFlLgLen;
00279        
00280        // mac info
00281        entries[5].entryID = AS_MACINFO;
00282        entries[5].entryLength = sizeof(ASMacInfo);
00283        
00284        for (i=1; i<kNumASEntries; i++) /* start at 1, not 0 */
00285        {
00286               entries[i].entryOffset = entries[i-1].entryOffset + entries[i-1].entryLength;
00287        }
00288        
00289        // ERR_CHECK( SetFPos(mTransRefNum, fsFromStart, sizeof(ASHeader)) ); // revisit
00290        ERR_CHECK( FSWrite(mTransRefNum, &bytes2Wr, &entries[0]) );
00291        if (bytes2Wr != (kNumASEntries * sizeof(ASEntry)))
00292               err = -1;
00293               
00294        return err;
00295 }
00296 
00297 OSErr
00298 nsAppleSingleEncoder::WriteEntries()
00299 {
00300        OSErr                err = noErr;
00301        long                 bytes2Wr;
00302        DateTimeRec          currTime;
00303        ASFileDates          asDates;
00304        unsigned long currSecs;
00305        ASMacInfo            asMacInfo;
00306        int                         i;
00307        CInfoPBRec           pb;
00308        char                 name[32];
00309        
00310        FSpGetCatInfo(&pb, mInFile);
00311        
00312        // real name
00313        bytes2Wr = pb.hFileInfo.ioNamePtr[0];
00314        strncpy(name, (char*)(pb.hFileInfo.ioNamePtr+1), bytes2Wr);
00315        ERR_CHECK( FSWrite(mTransRefNum, &bytes2Wr, name) );
00316        FSpGetCatInfo(&pb, mInFile); // XXX refresh after write
00317        if (bytes2Wr != pb.hFileInfo.ioNamePtr[0])
00318        {
00319               err = -1;
00320               goto cleanup;
00321        }
00322               
00323        // finder info
00324        bytes2Wr = sizeof(FInfo);
00325        ERR_CHECK( FSWrite(mTransRefNum, &bytes2Wr, &pb.hFileInfo.ioFlFndrInfo) );
00326        FSpGetCatInfo(&pb, mInFile); // XXX refresh after write
00327        if (bytes2Wr != sizeof(FInfo))
00328        {
00329               err = -1;
00330               goto cleanup;
00331        }
00332        
00333        bytes2Wr = sizeof(FXInfo);
00334        ERR_CHECK( FSWrite(mTransRefNum, &bytes2Wr, &pb.hFileInfo.ioFlXFndrInfo) );
00335        FSpGetCatInfo(&pb, mInFile); // XXX refresh after write 
00336        if (bytes2Wr != sizeof(FXInfo))
00337        {
00338               err = -1;
00339               goto cleanup;
00340        }
00341               
00342        // file dates
00343        GetTime(&currTime);
00344        DateToSeconds(&currTime, &currSecs);
00345        FSpGetCatInfo(&pb, mInFile); // XXX refresh after sys calls
00346        asDates.create = pb.hFileInfo.ioFlCrDat + kConvertTime;
00347        asDates.modify = pb.hFileInfo.ioFlMdDat + kConvertTime;
00348        asDates.backup = pb.hFileInfo.ioFlBkDat + kConvertTime;
00349        asDates.access = currSecs + kConvertTime;
00350        bytes2Wr = sizeof(ASFileDates);
00351        ERR_CHECK( FSWrite(mTransRefNum, &bytes2Wr, &asDates) );
00352        FSpGetCatInfo(&pb, mInFile); // XXX refresh after write
00353        if (bytes2Wr != sizeof(ASFileDates))
00354        {
00355               err = -1;
00356               goto cleanup;
00357        }
00358               
00359        // resource fork
00360        ERR_CHECK( WriteResourceFork() );
00361        
00362        // data fork
00363        ERR_CHECK( WriteDataFork() );
00364        
00365        // mac info   
00366        for (i=0; i<3; i++)
00367               asMacInfo.filler[i];
00368        FSpGetCatInfo(&pb, mInFile); // XXX refresh
00369        asMacInfo.ioFlAttrib = pb.hFileInfo.ioFlAttrib;
00370        bytes2Wr = sizeof(ASMacInfo);
00371        ERR_CHECK( FSWrite(mTransRefNum, &bytes2Wr, &asMacInfo) );
00372        if (bytes2Wr != sizeof(ASMacInfo))
00373        {
00374               err = -1;
00375               goto cleanup;
00376        }
00377        
00378 cleanup:
00379        FSClose(mTransRefNum);
00380        
00381        return err;
00382 }
00383 
00384 #define BUFSIZE 8192
00385 
00386 OSErr
00387 nsAppleSingleEncoder::WriteResourceFork()
00388 {
00389        OSErr         err = noErr;
00390        short         refnum;
00391        long          bytes2Rd, bytes2Wr;
00392        char          buf[BUFSIZE];
00393        
00394        // open infile's resource fork
00395        ERR_CHECK( FSpOpenRF(mInFile, fsRdPerm, &refnum) );
00396        
00397        while (err != eofErr)
00398        {
00399               // keep reading chunks till infile's eof encountered
00400               bytes2Rd = BUFSIZE;
00401               err = FSRead(refnum, &bytes2Rd, buf);
00402               if (bytes2Rd <= 0)
00403                      goto cleanup;
00404               if (err == noErr || err == eofErr)
00405               {             
00406                      // keep writing 
00407                      bytes2Wr = bytes2Rd;
00408                      err = FSWrite(mTransRefNum, &bytes2Wr, buf);
00409                      if (err != noErr || bytes2Wr != bytes2Rd)
00410                             goto cleanup;
00411               }      
00412        }
00413               
00414 cleanup:
00415        // close infile
00416        FSClose(refnum);
00417               
00418        // eof is OK so translate          
00419        if (err == eofErr)
00420               err = noErr;
00421 
00422        return err;
00423 }
00424 
00425 OSErr
00426 nsAppleSingleEncoder::WriteDataFork()
00427 {
00428        OSErr         err = noErr;
00429        short         refnum;
00430        long          bytes2Rd, bytes2Wr;
00431        char          buf[BUFSIZE];
00432        
00433        // open infile's data fork
00434        ERR_CHECK( FSpOpenDF(mInFile, fsRdPerm, &refnum) );
00435        
00436        while (err != eofErr)
00437        {
00438               // keep reading chunks till infile's eof encountered
00439               bytes2Rd = BUFSIZE;
00440               err = FSRead(refnum, &bytes2Rd, buf);
00441               if (bytes2Rd <= 0)
00442                      goto cleanup;
00443               if (err == noErr || err == eofErr)
00444               {             
00445                      // keep writing 
00446                      bytes2Wr = bytes2Rd;
00447                      err = FSWrite(mTransRefNum, &bytes2Wr, buf);
00448                      if (err != noErr || bytes2Wr != bytes2Rd)
00449                             goto cleanup;
00450               }      
00451        }
00452               
00453 cleanup:
00454        // close infile
00455        FSClose(refnum);
00456        
00457        // eof is OK so translate          
00458        if (err == eofErr)
00459               err = noErr;
00460        
00461        return err;
00462 }
00463 
00464 OSErr
00465 nsAppleSingleEncoder::FSpGetCatInfo(CInfoPBRec *pb, FSSpecPtr aFile)
00466 {
00467        OSErr err = noErr;
00468        Str31 name;
00469        
00470        nsAppleSingleDecoder::PLstrncpy(name, aFile->name, aFile->name[0]);
00471        name[0] = aFile->name[0]; // XXX paranoia
00472 
00473        pb->hFileInfo.ioNamePtr = name;
00474        pb->hFileInfo.ioVRefNum = aFile->vRefNum;
00475        pb->hFileInfo.ioDirID = aFile->parID;
00476        pb->hFileInfo.ioFDirIndex = 0; // use ioNamePtr and ioDirID 
00477        ERR_CHECK( PBGetCatInfoSync(pb) );
00478 
00479        return err;
00480 }