Back to index

lightning-sunbird  0.9+nobinonly
nsAppleSingleDecoder.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_APPLESINGLEDECODER_H_
00042   #include "nsAppleSingleDecoder.h"
00043 #endif
00044 
00045 #include "MoreFilesX.h"
00046 
00047 #ifdef STANDALONE_ASD
00048 #include <iostream>
00049 using namespace std;
00050 #undef MOZILLA_CLIENT
00051 #endif
00052 
00053 #ifdef MOZILLA_CLIENT
00054   #include "nsISupportsUtils.h"
00055 #endif
00056 
00057 /*----------------------------------------------------------------------*
00058  *   Constructors/Destructor
00059  *----------------------------------------------------------------------*/
00060 #ifdef MOZILLA_CLIENT
00061   MOZ_DECL_CTOR_COUNTER(nsAppleSingleDecoder)
00062 #endif
00063 
00064 nsAppleSingleDecoder::nsAppleSingleDecoder(const FSRef *inRef, FSRef *outRef)
00065 : mInRef(NULL), 
00066   mOutRef(NULL),
00067   mInRefNum(0),
00068   mRenameReqd(false)
00069 {
00070 #ifdef MOZILLA_CLIENT
00071     MOZ_COUNT_CTOR(nsAppleSingleDecoder);
00072 #endif
00073 
00074   if (inRef && outRef)
00075   {
00076     /* merely point to FSRefs, not own 'em */
00077     mInRef = inRef;
00078     mOutRef = outRef;
00079   }
00080 }
00081 
00082 nsAppleSingleDecoder::nsAppleSingleDecoder()
00083 : mInRef(NULL), 
00084   mOutRef(NULL),
00085   mInRefNum(0),
00086   mRenameReqd(false)
00087 {
00088 #ifdef MOZILLA_CLIENT
00089   MOZ_COUNT_CTOR(nsAppleSingleDecoder);
00090 #endif
00091 }
00092 
00093 nsAppleSingleDecoder::~nsAppleSingleDecoder()
00094 {
00095   /* not freeing FSRefs since we don't own 'em */
00096 
00097 #ifdef MOZILLA_CLIENT
00098   MOZ_COUNT_DTOR(nsAppleSingleDecoder);
00099 #endif
00100 }
00101 
00102 #pragma mark -
00103 
00104 /*----------------------------------------------------------------------*
00105  *   Public methods
00106  *----------------------------------------------------------------------*/
00107 OSErr
00108 nsAppleSingleDecoder::Decode()
00109 {
00110   OSErr         err = noErr;
00111   ASHeader      header;
00112   UInt32        bytesRead = sizeof(header);
00113   HFSUniStr255  nameInRef;
00114    
00115   // param check
00116   if (!mInRef || !mOutRef)
00117     return paramErr;
00118      
00119   // check for existence (and get leaf name for later renaming of decoded file)
00120   err = FSGetCatalogInfo(mInRef, kFSCatInfoNone, NULL, &nameInRef, NULL, NULL);
00121   if (err == fnfErr)
00122     return err;
00123     
00124   HFSUniStr255 dataForkName;
00125   MAC_ERR_CHECK(FSGetDataForkName( &dataForkName ));
00126   MAC_ERR_CHECK(FSOpenFork( mInRef, dataForkName.length, dataForkName.unicode, 
00127     fsRdPerm, &mInRefNum ));
00128   MAC_ERR_CHECK(FSRead( mInRefNum, (long *)&bytesRead, &header ));
00129   
00130   if ( (bytesRead != sizeof(header)) ||
00131      (header.magicNum != APPLESINGLE_MAGIC) ||
00132      (header.versionNum != APPLESINGLE_VERSION) ||
00133      (header.numEntries == 0) ) // empty file?
00134      return -1;
00135   
00136   // create the outSpec which we'll rename correctly later
00137   FSRef parentRef;
00138   MAC_ERR_CHECK(FSGetParentRef( mInRef, &parentRef ));
00139   MAC_ERR_CHECK(FSMakeUnique( &parentRef, mOutRef ));
00140   MAC_ERR_CHECK(FSCreateFork( mOutRef, dataForkName.length, 
00141     dataForkName.unicode ));
00142   
00143   /* Loop through the entries, processing each.
00144   ** Set the time/date stamps last, because otherwise they'll 
00145   ** be destroyed  when we write.
00146   */  
00147   {
00148     Boolean hasDateEntry = false;
00149     ASEntry dateEntry;
00150     long offset;
00151     ASEntry entry;
00152     
00153     for ( int i=0; i < header.numEntries; i++ )
00154     {  
00155       offset = sizeof( ASHeader ) + sizeof( ASEntry ) * i;
00156       MAC_ERR_CHECK(SetFPos( mInRefNum, fsFromStart, offset ));
00157       
00158       bytesRead = sizeof(entry);
00159       MAC_ERR_CHECK(FSRead( mInRefNum, (long *) &bytesRead, &entry ));
00160       if (bytesRead != sizeof(entry))
00161         return -1;
00162         
00163        if ( entry.entryID == AS_FILEDATES )
00164        {
00165          hasDateEntry = true;
00166          dateEntry = entry;
00167        }
00168        else
00169          MAC_ERR_CHECK(ProcessASEntry( entry ));
00170     }
00171     if ( hasDateEntry )
00172       MAC_ERR_CHECK(ProcessASEntry( dateEntry ));
00173   }
00174   
00175   // close the inSpec
00176   FSClose( mInRefNum );
00177   
00178   // rename if need be
00179   if (mRenameReqd)
00180   {
00181     // delete encoded version of target file
00182     MAC_ERR_CHECK(FSDeleteObject( mInRef ));
00183     MAC_ERR_CHECK(FSRenameUnicode( mOutRef, nameInRef.length, 
00184       nameInRef.unicode, kTextEncodingUnknown, mOutRef ));
00185     mRenameReqd = false; 
00186   }
00187 
00188   return err;
00189 }
00190 
00191 OSErr
00192 nsAppleSingleDecoder::Decode(const FSRef *inRef, FSRef *outRef)
00193 {
00194   OSErr   err = noErr;
00195   
00196   // param check
00197   if (inRef && outRef)
00198   {
00199     mInRef = inRef;    // reinit
00200     mOutRef = outRef;
00201     mRenameReqd = false; 
00202   }
00203   else
00204     return paramErr;
00205     
00206   err = Decode();
00207   
00208   return err;
00209 }
00210 
00211 Boolean 
00212 DecodeDirIterateFilter(Boolean containerChanged, ItemCount currentLevel,
00213   const FSCatalogInfo *catalogInfo, const FSRef *ref, 
00214   const FSSpec *spec, const HFSUniStr255 *name, void *yourDataPtr)
00215 {  
00216   FSRef                   outRef;
00217   nsAppleSingleDecoder   *thisObj;
00218   Boolean                 isDir;
00219   
00220   // param check
00221   if (!yourDataPtr || !ref)
00222     return false;
00223     
00224   // extract 'this' -- an nsAppleSingleDecoder instance
00225   thisObj = (nsAppleSingleDecoder*) yourDataPtr;
00226   
00227   isDir = nsAppleSingleDecoder::IsDirectory(ref);
00228   
00229   // if current FSRef is file
00230   if (!isDir)
00231   {
00232     // if file is in AppleSingle format
00233     if (nsAppleSingleDecoder::IsAppleSingleFile(ref))
00234     {
00235       // decode file
00236       thisObj->Decode(ref, &outRef);
00237     }
00238   }
00239 
00240   // else current FSRef is folder 
00241   else
00242   {
00243     thisObj->DecodeFolder(ref);
00244   }
00245 
00246   return false; // always continue iteration
00247 }
00248 
00249 OSErr 
00250 nsAppleSingleDecoder::DecodeFolder(const FSRef *aFolder)
00251 {
00252   OSErr  err;
00253   Boolean  isDir = false;
00254   
00255   // check that FSSpec is folder
00256   if (aFolder)
00257   {
00258     isDir = IsDirectory((const FSRef *) aFolder);
00259     if (!isDir)
00260       return dirNFErr;
00261   }
00262   
00263   // recursively enumerate contents of folder 
00264   // (maxLevels=0 means recurse all)
00265   err = FSIterateContainer(aFolder, 0, kFSCatInfoNone, false, 
00266     false, DecodeDirIterateFilter, (void*)this);
00267       
00268   // XXX do we really want to return err?
00269   return err;
00270 }
00271 
00272 Boolean
00273 nsAppleSingleDecoder::IsAppleSingleFile(const FSRef *inRef)
00274 {
00275   OSErr   err;
00276   SInt16  inRefNum;
00277   UInt32  magic;
00278   long    bytesRead = sizeof(magic);
00279   
00280   // param checks
00281   if (!inRef)
00282     return false;
00283     
00284   // check for existence
00285   err = FSGetCatalogInfo(inRef, kFSCatInfoNone, NULL, NULL, NULL, NULL);
00286   if (err!=noErr)
00287     return false;
00288   
00289   // open and read the magic number len bytes  
00290   HFSUniStr255 dataForkName;
00291   err = FSGetDataForkName( &dataForkName );
00292   if (err!=noErr)
00293     return false;
00294 
00295   err = FSOpenFork( inRef, dataForkName.length, dataForkName.unicode, 
00296           fsRdPerm, &inRefNum );
00297   if (err!=noErr)
00298     return false;
00299 
00300   err = FSRead( inRefNum, &bytesRead, &magic );
00301   if (err!=noErr)
00302     return false;
00303     
00304   FSClose(inRefNum);
00305   if (bytesRead != sizeof(magic))
00306     return false;
00307 
00308   // check if bytes read match magic number  
00309   return (magic == APPLESINGLE_MAGIC);
00310 }
00311 
00312 #pragma mark -
00313 
00314 /*----------------------------------------------------------------------*
00315  *   Private methods
00316  *----------------------------------------------------------------------*/
00317 OSErr
00318 nsAppleSingleDecoder::ProcessASEntry(ASEntry inEntry)
00319 {
00320   switch (inEntry.entryID)
00321   {
00322     case AS_DATA:
00323       return ProcessDataFork( inEntry );
00324       break;
00325     case AS_RESOURCE:
00326       return ProcessResourceFork( inEntry );
00327       break;
00328     case AS_REALNAME:
00329       ProcessRealName( inEntry );
00330       break;
00331     case AS_FILEDATES:
00332       return ProcessFileDates( inEntry );
00333       break;
00334     case AS_FINDERINFO:
00335       return ProcessFinderInfo( inEntry );
00336       break;
00337     case AS_MACINFO:
00338     case AS_COMMENT:
00339     case AS_ICONBW:
00340     case AS_ICONCOLOR:
00341     case AS_PRODOSINFO:
00342     case AS_MSDOSINFO:
00343     case AS_AFPNAME:
00344     case AS_AFPINFO:
00345     case AS_AFPDIRID:
00346     default:
00347       return 0;
00348   }
00349   return 0;
00350 }
00351 
00352 OSErr
00353 nsAppleSingleDecoder::ProcessDataFork(ASEntry inEntry)
00354 {
00355   OSErr  err = noErr;
00356   SInt16  refNum;
00357   
00358   /* Setup the files */
00359   HFSUniStr255 dataForkName;
00360   err = FSGetDataForkName( &dataForkName );
00361   if (err != noErr) 
00362     return err;
00363 
00364   err = FSOpenFork( mOutRef, dataForkName.length, dataForkName.unicode, 
00365           fsWrPerm, &refNum );
00366 
00367   if ( err == noErr )
00368     err = EntryToMacFile( inEntry, refNum );
00369   
00370   FSClose( refNum );
00371   return err;
00372 }
00373 
00374 OSErr
00375 nsAppleSingleDecoder::ProcessResourceFork(ASEntry inEntry)
00376 {
00377   OSErr  err = noErr;
00378   SInt16  refNum;
00379     
00380   HFSUniStr255 rsrcForkName;
00381   err = FSGetResourceForkName( &rsrcForkName );
00382   if (err != noErr) 
00383     return err;
00384 
00385   err = FSOpenFork( mOutRef, rsrcForkName.length, rsrcForkName.unicode, 
00386           fsWrPerm, &refNum );
00387 
00388   if ( err == noErr )
00389     err = EntryToMacFile( inEntry, refNum );
00390   
00391   FSClose( refNum );
00392   return err;
00393 }
00394 
00395 OSErr
00396 nsAppleSingleDecoder::ProcessRealName(ASEntry inEntry)
00397 {
00398   OSErr         err = noErr;
00399   Str255        newName;
00400   HFSUniStr255  newNameUni;
00401   UInt32        bytesRead;
00402   FSRef         parentOfOutRef;
00403   
00404   MAC_ERR_CHECK(SetFPos(mInRefNum, fsFromStart, inEntry.entryOffset));
00405   
00406   bytesRead = inEntry.entryLength;
00407   MAC_ERR_CHECK(FSRead(mInRefNum, (long *) &bytesRead, &newName[1]));
00408   if (bytesRead != inEntry.entryLength)
00409     return -1;
00410     
00411   newName[0] = inEntry.entryLength;
00412   MAC_ERR_CHECK(FSGetParentRef(mOutRef, &parentOfOutRef));
00413   MAC_ERR_CHECK(HFSNameGetUnicodeName(newName, kTextEncodingUnknown, 
00414     &newNameUni));
00415   err = FSRenameUnicode(mOutRef, newNameUni.length, newNameUni.unicode, 
00416           kTextEncodingUnknown, mOutRef);
00417   if (err == dupFNErr)
00418   {
00419     HFSUniStr255 inRefName;
00420     MAC_ERR_CHECK(FSGetCatalogInfo(mInRef, kFSCatInfoNone, NULL, &inRefName, 
00421       NULL, NULL));
00422 
00423     // if we are trying to rename temp decode file to src name, rename later
00424     if (nsAppleSingleDecoder::UCstrcmp(&newNameUni, &inRefName))
00425     {
00426       mRenameReqd = true;
00427       return noErr;
00428     }
00429     
00430     // otherwise replace file in the way
00431     FSRef inTheWayRef;
00432 
00433     // delete file in the way
00434     MAC_ERR_CHECK(FSMakeFSRefUnicode( &parentOfOutRef, newNameUni.length, 
00435       newNameUni.unicode, kTextEncodingUnknown, &inTheWayRef ));
00436     MAC_ERR_CHECK(FSDeleteObject( &inTheWayRef ));
00437 
00438     // rename decoded file to ``newName''
00439     MAC_ERR_CHECK(FSRenameUnicode( mOutRef, newNameUni.length, 
00440       newNameUni.unicode, kTextEncodingUnknown, mOutRef ));
00441   }
00442 
00443   return err;
00444 }
00445 
00446 OSErr
00447 nsAppleSingleDecoder::ProcessFileDates(ASEntry inEntry)
00448 {
00449   OSErr         err = noErr;
00450   ASFileDates   dates;
00451   UInt32        bytesRead;
00452   FSCatalogInfo catInfo;
00453 
00454   if ( inEntry.entryLength != sizeof(dates) )  
00455     return -1;
00456   
00457   MAC_ERR_CHECK(SetFPos(mInRefNum, fsFromStart, inEntry.entryOffset));
00458   
00459   bytesRead = inEntry.entryLength;
00460   MAC_ERR_CHECK(FSRead(mInRefNum, (long *) &bytesRead, &dates));
00461   if (bytesRead != inEntry.entryLength)
00462     return -1;
00463     
00464 #define YR_2000_SECONDS 3029529600
00465   LocalDateTime local = (LocalDateTime) {0, 0, 0};
00466 
00467   // set creation date
00468   local.lowSeconds = dates.create + YR_2000_SECONDS;
00469   ConvertLocalToUTCDateTime(&local, &catInfo.createDate);
00470 
00471   // set content modification date
00472   local.lowSeconds = dates.modify + YR_2000_SECONDS;
00473   ConvertLocalToUTCDateTime(&local, &catInfo.contentModDate);
00474 
00475   // set last access date
00476   local.lowSeconds = dates.access + YR_2000_SECONDS;
00477   ConvertLocalToUTCDateTime(&local, &catInfo.accessDate);
00478 
00479   // set backup date
00480   local.lowSeconds = dates.backup + YR_2000_SECONDS;
00481   ConvertLocalToUTCDateTime(&local, &catInfo.backupDate);
00482 
00483   // set attribute modification date
00484   GetUTCDateTime(&catInfo.attributeModDate, kUTCDefaultOptions);  
00485 
00486   MAC_ERR_CHECK(FSSetCatalogInfo(mOutRef, 
00487     kFSCatInfoCreateDate |
00488     kFSCatInfoContentMod |
00489     kFSCatInfoAttrMod    |
00490     kFSCatInfoAccessDate |
00491     kFSCatInfoBackupDate,
00492     &catInfo));
00493 
00494   return err;
00495 }
00496 
00497 OSErr
00498 nsAppleSingleDecoder::ProcessFinderInfo(ASEntry inEntry)
00499 {
00500   OSErr         err = noErr;
00501   ASFinderInfo  info;
00502   UInt32        bytesRead;
00503   FSCatalogInfo catInfo;
00504   
00505   if (inEntry.entryLength != sizeof( ASFinderInfo ))
00506     return -1;
00507 
00508   MAC_ERR_CHECK(SetFPos(mInRefNum, fsFromStart, inEntry.entryOffset));
00509 
00510   bytesRead = sizeof(info);
00511   MAC_ERR_CHECK(FSRead(mInRefNum, (long *) &bytesRead, &info));
00512   if (bytesRead != inEntry.entryLength)
00513     return -1;
00514     
00515   MAC_ERR_CHECK(FSGetCatalogInfo(mOutRef, kFSCatInfoGettableInfo, &catInfo, 
00516     NULL, NULL, NULL));
00517 
00518   BlockMoveData((const void *) &info.ioFlFndrInfo, 
00519     (void *) &catInfo.finderInfo, sizeof(FInfo));
00520   BlockMoveData((const void *) &info.ioFlXFndrInfo, 
00521     (void *) &catInfo.extFinderInfo, sizeof(FXInfo));
00522 
00523   MAC_ERR_CHECK(FSSetCatalogInfo(mOutRef, 
00524     kFSCatInfoFinderInfo |
00525     kFSCatInfoFinderXInfo,
00526     &catInfo));
00527     
00528   return err;
00529 }
00530 
00531 OSErr
00532 nsAppleSingleDecoder::EntryToMacFile(ASEntry inEntry, UInt16 inTargetSpecRefNum)
00533 {
00534 #define BUFFER_SIZE 8192
00535 
00536   OSErr  err = noErr;
00537   char   buffer[BUFFER_SIZE];
00538   UInt32 totalRead = 0, bytesRead, bytesToWrite;
00539 
00540   MAC_ERR_CHECK(SetFPos( mInRefNum, fsFromStart, inEntry.entryOffset ));
00541 
00542   while ( totalRead < inEntry.entryLength )
00543   {
00544 // Should we yield in here?
00545     bytesRead = BUFFER_SIZE;
00546     err = FSRead( mInRefNum, (long *) &bytesRead, buffer );
00547     if (err!=noErr && err!=eofErr)
00548       return err;
00549       
00550     if ( bytesRead <= 0 )
00551       return -1;
00552     bytesToWrite = totalRead + bytesRead > inEntry.entryLength ? 
00553                   inEntry.entryLength - totalRead :
00554                   bytesRead;
00555 
00556     totalRead += bytesRead;
00557     MAC_ERR_CHECK(FSWrite(inTargetSpecRefNum, (long *) &bytesToWrite, 
00558       buffer));
00559   }  
00560   
00561   return err;
00562 }
00563 
00564 #pragma mark -
00565 
00566 Boolean 
00567 nsAppleSingleDecoder::IsDirectory(const FSRef *inRef)
00568 {
00569   OSErr err;
00570   Boolean isDir;
00571 
00572   if (!inRef)
00573     return false;
00574 
00575   err = FSGetFinderInfo(inRef, NULL, NULL, &isDir);
00576   if (err != noErr)
00577     return false;
00578   
00579   return isDir;
00580 }
00581 
00582 OSErr
00583 nsAppleSingleDecoder::FSMakeUnique(const FSRef *inParentRef, FSRef *outRef)
00584 {
00585 /*
00586 ** This function has descended from Apple Sample Code, but we have
00587 ** made changes.  Specifically, this function descends from the 
00588 ** GenerateUniqueHFSUniStr() function in MoreFilesX.c, version 1.0.1.
00589 */
00590 
00591   OSErr         result = noErr;
00592   long          i, startSeed = 0x4a696d4c; /* a fine unlikely filename */
00593   FSRefParam    pb;
00594   unsigned char hexStr[17] = "0123456789ABCDEF";
00595   HFSUniStr255  uniqueName;
00596   
00597   /* set up the parameter block */
00598   pb.name = uniqueName.unicode;
00599   pb.nameLength = 8;  /* always 8 characters */
00600   pb.textEncodingHint = kTextEncodingUnknown;
00601   pb.newRef = outRef;
00602   pb.ref = inParentRef;
00603 
00604   /* loop until we get fnfErr with a filename in both directories */
00605   result = noErr;
00606   while ( fnfErr != result )
00607   {
00608     /* convert startSeed to 8 character Unicode string */
00609     uniqueName.length = 8;
00610     for ( i = 0; i < 8; ++i )
00611     {
00612       uniqueName.unicode[i] = hexStr[((startSeed >> ((7-i)*4)) & 0xf)];
00613     }
00614     
00615     result = PBMakeFSRefUnicodeSync(&pb);
00616     if ( fnfErr == result )
00617     {
00618       OSErr err;
00619       MAC_ERR_CHECK(FSCreateFileUnicode(inParentRef, uniqueName.length,
00620         uniqueName.unicode, kFSCatInfoNone, NULL, outRef, NULL));
00621 
00622       return noErr;
00623     }
00624     else if ( noErr != result)
00625     {
00626       /* exit if anything other than noErr or fnfErr */
00627       return result;
00628     }
00629     
00630     /* increment seed for next pass through loop */
00631     ++(startSeed);
00632   }
00633   
00634   return result;
00635 }    
00636 
00637 /*----------------------------------------------------------------------*
00638  *   Utilities
00639  *----------------------------------------------------------------------*/
00640 Boolean
00641 nsAppleSingleDecoder::UCstrcmp(const HFSUniStr255 *str1, 
00642                                const HFSUniStr255 *str2)
00643 {
00644   OSStatus          status;
00645   Boolean           bEqual; 
00646 
00647   status = UCCompareTextDefault(kUCCollateStandardOptions, str1->unicode, 
00648                                  str1->length, str2->unicode, str2->length, 
00649                                  &bEqual, NULL);
00650   if (status != noErr)
00651     return false;
00652 
00653   return bEqual;
00654 }
00655 
00656 #ifdef STANDALONE_ASD
00657 int
00658 main(int argc, char **argv)
00659 {
00660   OSErr err;
00661   FSRef encoded, decoded;
00662   nsAppleSingleDecoder *decoder = new nsAppleSingleDecoder;
00663   Boolean isDir;
00664 
00665   if (argc < 2)
00666   {
00667     cout << "usage: " << argv[0] << " <file/folder>" << endl
00668          << "\t\tAppleSingle encoded file path" << endl 
00669          << "\t\tor" << endl
00670          << "\t\tfolder path containing AppleSingle encoded files." << endl;
00671     exit(-1);
00672   }
00673 
00674   err = FSPathMakeRef((const UInt8 *)argv[1], &encoded, &isDir);
00675   if (err != noErr)
00676     return 1;
00677 
00678   // handle AppleSingle encoded files
00679   if (!isDir)
00680   {
00681     Boolean isEncoded = nsAppleSingleDecoder::IsAppleSingleFile(&encoded);
00682     cout << "IsAppleSingleFile returned: " << (isEncoded ? "true" : "false")
00683          << endl;
00684 
00685     if (isEncoded)
00686     {
00687       err = decoder->Decode(&encoded, &decoded);
00688       cout << "Decode returned: " << err << endl;
00689     }
00690   }
00691 
00692   // handle folders containing AppleSingle encoded files
00693   else
00694   {
00695     err = decoder->DecodeFolder(&encoded);
00696     cout << "DecodeFolder returned: " << err << endl;
00697   }
00698 
00699   // verify out file (n/a for folders)
00700   if (!isDir)
00701   {
00702     err = FSGetCatalogInfo(&decoded, kFSCatInfoNone, NULL, NULL, NULL, NULL);
00703     if (err == noErr)
00704     {
00705       cout << "Decoded file appears to exist" << endl;
00706       char path[1024];
00707       FSRefMakePath(&decoded, (UInt8 *)path, 1024);
00708       cout << "Decoded file path: " << path << endl;
00709     }
00710     else
00711       cout << "Decoded file doesn't appear to exist: " << err << endl;
00712   }
00713 
00714   return 0;
00715 }
00716 #endif /* STANDALONE_ASD */