mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
714 lines
18 KiB
C++
714 lines
18 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is Mozilla Communicator client code, released
|
|
* March 31, 1998.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Netscape Communications Corporation.
|
|
* Portions created by the Initial Developer are Copyright (C) 1999
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Samir Gehani <sgehani@netscape.com>
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
#ifndef _NS_APPLESINGLEDECODER_H_
|
|
#include "nsAppleSingleDecoder.h"
|
|
#endif
|
|
|
|
#include "MoreFilesX.h"
|
|
|
|
#ifdef STANDALONE_ASD
|
|
#include <iostream>
|
|
using namespace std;
|
|
#undef MOZILLA_CLIENT
|
|
#endif
|
|
|
|
#ifdef MOZILLA_CLIENT
|
|
#include "nsISupportsUtils.h"
|
|
#endif
|
|
|
|
/*----------------------------------------------------------------------*
|
|
* Constructors/Destructor
|
|
*----------------------------------------------------------------------*/
|
|
|
|
nsAppleSingleDecoder::nsAppleSingleDecoder(const FSRef *inRef, FSRef *outRef)
|
|
: mInRef(NULL),
|
|
mOutRef(NULL),
|
|
mInRefNum(0),
|
|
mRenameReqd(false)
|
|
{
|
|
#ifdef MOZILLA_CLIENT
|
|
MOZ_COUNT_CTOR(nsAppleSingleDecoder);
|
|
#endif
|
|
|
|
if (inRef && outRef)
|
|
{
|
|
/* merely point to FSRefs, not own 'em */
|
|
mInRef = inRef;
|
|
mOutRef = outRef;
|
|
}
|
|
}
|
|
|
|
nsAppleSingleDecoder::nsAppleSingleDecoder()
|
|
: mInRef(NULL),
|
|
mOutRef(NULL),
|
|
mInRefNum(0),
|
|
mRenameReqd(false)
|
|
{
|
|
#ifdef MOZILLA_CLIENT
|
|
MOZ_COUNT_CTOR(nsAppleSingleDecoder);
|
|
#endif
|
|
}
|
|
|
|
nsAppleSingleDecoder::~nsAppleSingleDecoder()
|
|
{
|
|
/* not freeing FSRefs since we don't own 'em */
|
|
|
|
#ifdef MOZILLA_CLIENT
|
|
MOZ_COUNT_DTOR(nsAppleSingleDecoder);
|
|
#endif
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
/*----------------------------------------------------------------------*
|
|
* Public methods
|
|
*----------------------------------------------------------------------*/
|
|
OSErr
|
|
nsAppleSingleDecoder::Decode()
|
|
{
|
|
OSErr err = noErr;
|
|
ASHeader header;
|
|
UInt32 bytesRead = sizeof(header);
|
|
HFSUniStr255 nameInRef;
|
|
|
|
// param check
|
|
if (!mInRef || !mOutRef)
|
|
return paramErr;
|
|
|
|
// check for existence (and get leaf name for later renaming of decoded file)
|
|
err = FSGetCatalogInfo(mInRef, kFSCatInfoNone, NULL, &nameInRef, NULL, NULL);
|
|
if (err == fnfErr)
|
|
return err;
|
|
|
|
HFSUniStr255 dataForkName;
|
|
MAC_ERR_CHECK(FSGetDataForkName( &dataForkName ));
|
|
MAC_ERR_CHECK(FSOpenFork( mInRef, dataForkName.length, dataForkName.unicode,
|
|
fsRdPerm, &mInRefNum ));
|
|
MAC_ERR_CHECK(FSRead( mInRefNum, (long *)&bytesRead, &header ));
|
|
|
|
if ( (bytesRead != sizeof(header)) ||
|
|
(header.magicNum != APPLESINGLE_MAGIC) ||
|
|
(header.versionNum != APPLESINGLE_VERSION) ||
|
|
(header.numEntries == 0) ) // empty file?
|
|
return -1;
|
|
|
|
// create the outSpec which we'll rename correctly later
|
|
FSRef parentRef;
|
|
MAC_ERR_CHECK(FSGetParentRef( mInRef, &parentRef ));
|
|
MAC_ERR_CHECK(FSMakeUnique( &parentRef, mOutRef ));
|
|
MAC_ERR_CHECK(FSCreateFork( mOutRef, dataForkName.length,
|
|
dataForkName.unicode ));
|
|
|
|
/* Loop through the entries, processing each.
|
|
** Set the time/date stamps last, because otherwise they'll
|
|
** be destroyed when we write.
|
|
*/
|
|
{
|
|
Boolean hasDateEntry = false;
|
|
ASEntry dateEntry;
|
|
long offset;
|
|
ASEntry entry;
|
|
|
|
for ( int i=0; i < header.numEntries; i++ )
|
|
{
|
|
offset = sizeof( ASHeader ) + sizeof( ASEntry ) * i;
|
|
MAC_ERR_CHECK(SetFPos( mInRefNum, fsFromStart, offset ));
|
|
|
|
bytesRead = sizeof(entry);
|
|
MAC_ERR_CHECK(FSRead( mInRefNum, (long *) &bytesRead, &entry ));
|
|
if (bytesRead != sizeof(entry))
|
|
return -1;
|
|
|
|
if ( entry.entryID == AS_FILEDATES )
|
|
{
|
|
hasDateEntry = true;
|
|
dateEntry = entry;
|
|
}
|
|
else
|
|
MAC_ERR_CHECK(ProcessASEntry( entry ));
|
|
}
|
|
if ( hasDateEntry )
|
|
MAC_ERR_CHECK(ProcessASEntry( dateEntry ));
|
|
}
|
|
|
|
// close the inSpec
|
|
FSClose( mInRefNum );
|
|
|
|
// rename if need be
|
|
if (mRenameReqd)
|
|
{
|
|
// delete encoded version of target file
|
|
MAC_ERR_CHECK(FSDeleteObject( mInRef ));
|
|
MAC_ERR_CHECK(FSRenameUnicode( mOutRef, nameInRef.length,
|
|
nameInRef.unicode, kTextEncodingUnknown, mOutRef ));
|
|
mRenameReqd = false;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
OSErr
|
|
nsAppleSingleDecoder::Decode(const FSRef *inRef, FSRef *outRef)
|
|
{
|
|
OSErr err = noErr;
|
|
|
|
// param check
|
|
if (inRef && outRef)
|
|
{
|
|
mInRef = inRef; // reinit
|
|
mOutRef = outRef;
|
|
mRenameReqd = false;
|
|
}
|
|
else
|
|
return paramErr;
|
|
|
|
err = Decode();
|
|
|
|
return err;
|
|
}
|
|
|
|
Boolean
|
|
DecodeDirIterateFilter(Boolean containerChanged, ItemCount currentLevel,
|
|
const FSCatalogInfo *catalogInfo, const FSRef *ref,
|
|
const FSSpec *spec, const HFSUniStr255 *name, void *yourDataPtr)
|
|
{
|
|
FSRef outRef;
|
|
nsAppleSingleDecoder *thisObj;
|
|
Boolean isDir;
|
|
|
|
// param check
|
|
if (!yourDataPtr || !ref)
|
|
return false;
|
|
|
|
// extract 'this' -- an nsAppleSingleDecoder instance
|
|
thisObj = (nsAppleSingleDecoder*) yourDataPtr;
|
|
|
|
isDir = nsAppleSingleDecoder::IsDirectory(ref);
|
|
|
|
// if current FSRef is file
|
|
if (!isDir)
|
|
{
|
|
// if file is in AppleSingle format
|
|
if (nsAppleSingleDecoder::IsAppleSingleFile(ref))
|
|
{
|
|
// decode file
|
|
thisObj->Decode(ref, &outRef);
|
|
}
|
|
}
|
|
|
|
// else current FSRef is folder
|
|
else
|
|
{
|
|
thisObj->DecodeFolder(ref);
|
|
}
|
|
|
|
return false; // always continue iteration
|
|
}
|
|
|
|
OSErr
|
|
nsAppleSingleDecoder::DecodeFolder(const FSRef *aFolder)
|
|
{
|
|
OSErr err;
|
|
Boolean isDir = false;
|
|
|
|
// check that FSSpec is folder
|
|
if (aFolder)
|
|
{
|
|
isDir = IsDirectory((const FSRef *) aFolder);
|
|
if (!isDir)
|
|
return dirNFErr;
|
|
}
|
|
|
|
// recursively enumerate contents of folder
|
|
// (maxLevels=0 means recurse all)
|
|
err = FSIterateContainer(aFolder, 0, kFSCatInfoNone, false,
|
|
false, DecodeDirIterateFilter, (void*)this);
|
|
|
|
// XXX do we really want to return err?
|
|
return err;
|
|
}
|
|
|
|
Boolean
|
|
nsAppleSingleDecoder::IsAppleSingleFile(const FSRef *inRef)
|
|
{
|
|
OSErr err;
|
|
SInt16 inRefNum;
|
|
UInt32 magic;
|
|
long bytesRead = sizeof(magic);
|
|
|
|
// param checks
|
|
if (!inRef)
|
|
return false;
|
|
|
|
// check for existence
|
|
err = FSGetCatalogInfo(inRef, kFSCatInfoNone, NULL, NULL, NULL, NULL);
|
|
if (err!=noErr)
|
|
return false;
|
|
|
|
// open and read the magic number len bytes
|
|
HFSUniStr255 dataForkName;
|
|
err = FSGetDataForkName( &dataForkName );
|
|
if (err!=noErr)
|
|
return false;
|
|
|
|
err = FSOpenFork( inRef, dataForkName.length, dataForkName.unicode,
|
|
fsRdPerm, &inRefNum );
|
|
if (err!=noErr)
|
|
return false;
|
|
|
|
err = FSRead( inRefNum, &bytesRead, &magic );
|
|
if (err!=noErr)
|
|
return false;
|
|
|
|
FSClose(inRefNum);
|
|
if (bytesRead != sizeof(magic))
|
|
return false;
|
|
|
|
// check if bytes read match magic number
|
|
return (magic == APPLESINGLE_MAGIC);
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
/*----------------------------------------------------------------------*
|
|
* Private methods
|
|
*----------------------------------------------------------------------*/
|
|
OSErr
|
|
nsAppleSingleDecoder::ProcessASEntry(ASEntry inEntry)
|
|
{
|
|
switch (inEntry.entryID)
|
|
{
|
|
case AS_DATA:
|
|
return ProcessDataFork( inEntry );
|
|
break;
|
|
case AS_RESOURCE:
|
|
return ProcessResourceFork( inEntry );
|
|
break;
|
|
case AS_REALNAME:
|
|
ProcessRealName( inEntry );
|
|
break;
|
|
case AS_FILEDATES:
|
|
return ProcessFileDates( inEntry );
|
|
break;
|
|
case AS_FINDERINFO:
|
|
return ProcessFinderInfo( inEntry );
|
|
break;
|
|
case AS_MACINFO:
|
|
case AS_COMMENT:
|
|
case AS_ICONBW:
|
|
case AS_ICONCOLOR:
|
|
case AS_PRODOSINFO:
|
|
case AS_MSDOSINFO:
|
|
case AS_AFPNAME:
|
|
case AS_AFPINFO:
|
|
case AS_AFPDIRID:
|
|
default:
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
OSErr
|
|
nsAppleSingleDecoder::ProcessDataFork(ASEntry inEntry)
|
|
{
|
|
OSErr err = noErr;
|
|
SInt16 refNum;
|
|
|
|
/* Setup the files */
|
|
HFSUniStr255 dataForkName;
|
|
err = FSGetDataForkName( &dataForkName );
|
|
if (err != noErr)
|
|
return err;
|
|
|
|
err = FSOpenFork( mOutRef, dataForkName.length, dataForkName.unicode,
|
|
fsWrPerm, &refNum );
|
|
|
|
if ( err == noErr )
|
|
err = EntryToMacFile( inEntry, refNum );
|
|
|
|
FSClose( refNum );
|
|
return err;
|
|
}
|
|
|
|
OSErr
|
|
nsAppleSingleDecoder::ProcessResourceFork(ASEntry inEntry)
|
|
{
|
|
OSErr err = noErr;
|
|
SInt16 refNum;
|
|
|
|
HFSUniStr255 rsrcForkName;
|
|
err = FSGetResourceForkName( &rsrcForkName );
|
|
if (err != noErr)
|
|
return err;
|
|
|
|
err = FSOpenFork( mOutRef, rsrcForkName.length, rsrcForkName.unicode,
|
|
fsWrPerm, &refNum );
|
|
|
|
if ( err == noErr )
|
|
err = EntryToMacFile( inEntry, refNum );
|
|
|
|
FSClose( refNum );
|
|
return err;
|
|
}
|
|
|
|
OSErr
|
|
nsAppleSingleDecoder::ProcessRealName(ASEntry inEntry)
|
|
{
|
|
OSErr err = noErr;
|
|
Str255 newName;
|
|
HFSUniStr255 newNameUni;
|
|
UInt32 bytesRead;
|
|
FSRef parentOfOutRef;
|
|
|
|
MAC_ERR_CHECK(SetFPos(mInRefNum, fsFromStart, inEntry.entryOffset));
|
|
|
|
bytesRead = inEntry.entryLength;
|
|
MAC_ERR_CHECK(FSRead(mInRefNum, (long *) &bytesRead, &newName[1]));
|
|
if (bytesRead != inEntry.entryLength)
|
|
return -1;
|
|
|
|
newName[0] = inEntry.entryLength;
|
|
MAC_ERR_CHECK(FSGetParentRef(mOutRef, &parentOfOutRef));
|
|
MAC_ERR_CHECK(HFSNameGetUnicodeName(newName, kTextEncodingUnknown,
|
|
&newNameUni));
|
|
err = FSRenameUnicode(mOutRef, newNameUni.length, newNameUni.unicode,
|
|
kTextEncodingUnknown, mOutRef);
|
|
if (err == dupFNErr)
|
|
{
|
|
HFSUniStr255 inRefName;
|
|
MAC_ERR_CHECK(FSGetCatalogInfo(mInRef, kFSCatInfoNone, NULL, &inRefName,
|
|
NULL, NULL));
|
|
|
|
// if we are trying to rename temp decode file to src name, rename later
|
|
if (nsAppleSingleDecoder::UCstrcmp(&newNameUni, &inRefName))
|
|
{
|
|
mRenameReqd = true;
|
|
return noErr;
|
|
}
|
|
|
|
// otherwise replace file in the way
|
|
FSRef inTheWayRef;
|
|
|
|
// delete file in the way
|
|
MAC_ERR_CHECK(FSMakeFSRefUnicode( &parentOfOutRef, newNameUni.length,
|
|
newNameUni.unicode, kTextEncodingUnknown, &inTheWayRef ));
|
|
MAC_ERR_CHECK(FSDeleteObject( &inTheWayRef ));
|
|
|
|
// rename decoded file to ``newName''
|
|
MAC_ERR_CHECK(FSRenameUnicode( mOutRef, newNameUni.length,
|
|
newNameUni.unicode, kTextEncodingUnknown, mOutRef ));
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
OSErr
|
|
nsAppleSingleDecoder::ProcessFileDates(ASEntry inEntry)
|
|
{
|
|
OSErr err = noErr;
|
|
ASFileDates dates;
|
|
UInt32 bytesRead;
|
|
FSCatalogInfo catInfo;
|
|
|
|
if ( inEntry.entryLength != sizeof(dates) )
|
|
return -1;
|
|
|
|
MAC_ERR_CHECK(SetFPos(mInRefNum, fsFromStart, inEntry.entryOffset));
|
|
|
|
bytesRead = inEntry.entryLength;
|
|
MAC_ERR_CHECK(FSRead(mInRefNum, (long *) &bytesRead, &dates));
|
|
if (bytesRead != inEntry.entryLength)
|
|
return -1;
|
|
|
|
#define YR_2000_SECONDS 3029529600
|
|
LocalDateTime local = (LocalDateTime) {0, 0, 0};
|
|
|
|
// set creation date
|
|
local.lowSeconds = dates.create + YR_2000_SECONDS;
|
|
ConvertLocalToUTCDateTime(&local, &catInfo.createDate);
|
|
|
|
// set content modification date
|
|
local.lowSeconds = dates.modify + YR_2000_SECONDS;
|
|
ConvertLocalToUTCDateTime(&local, &catInfo.contentModDate);
|
|
|
|
// set last access date
|
|
local.lowSeconds = dates.access + YR_2000_SECONDS;
|
|
ConvertLocalToUTCDateTime(&local, &catInfo.accessDate);
|
|
|
|
// set backup date
|
|
local.lowSeconds = dates.backup + YR_2000_SECONDS;
|
|
ConvertLocalToUTCDateTime(&local, &catInfo.backupDate);
|
|
|
|
// set attribute modification date
|
|
GetUTCDateTime(&catInfo.attributeModDate, kUTCDefaultOptions);
|
|
|
|
MAC_ERR_CHECK(FSSetCatalogInfo(mOutRef,
|
|
kFSCatInfoCreateDate |
|
|
kFSCatInfoContentMod |
|
|
kFSCatInfoAttrMod |
|
|
kFSCatInfoAccessDate |
|
|
kFSCatInfoBackupDate,
|
|
&catInfo));
|
|
|
|
return err;
|
|
}
|
|
|
|
OSErr
|
|
nsAppleSingleDecoder::ProcessFinderInfo(ASEntry inEntry)
|
|
{
|
|
OSErr err = noErr;
|
|
ASFinderInfo info;
|
|
UInt32 bytesRead;
|
|
FSCatalogInfo catInfo;
|
|
|
|
if (inEntry.entryLength != sizeof( ASFinderInfo ))
|
|
return -1;
|
|
|
|
MAC_ERR_CHECK(SetFPos(mInRefNum, fsFromStart, inEntry.entryOffset));
|
|
|
|
bytesRead = sizeof(info);
|
|
MAC_ERR_CHECK(FSRead(mInRefNum, (long *) &bytesRead, &info));
|
|
if (bytesRead != inEntry.entryLength)
|
|
return -1;
|
|
|
|
MAC_ERR_CHECK(FSGetCatalogInfo(mOutRef, kFSCatInfoGettableInfo, &catInfo,
|
|
NULL, NULL, NULL));
|
|
|
|
BlockMoveData((const void *) &info.ioFlFndrInfo,
|
|
(void *) &catInfo.finderInfo, sizeof(FInfo));
|
|
BlockMoveData((const void *) &info.ioFlXFndrInfo,
|
|
(void *) &catInfo.extFinderInfo, sizeof(FXInfo));
|
|
|
|
MAC_ERR_CHECK(FSSetCatalogInfo(mOutRef,
|
|
kFSCatInfoFinderInfo |
|
|
kFSCatInfoFinderXInfo,
|
|
&catInfo));
|
|
|
|
return err;
|
|
}
|
|
|
|
OSErr
|
|
nsAppleSingleDecoder::EntryToMacFile(ASEntry inEntry, UInt16 inTargetSpecRefNum)
|
|
{
|
|
#define BUFFER_SIZE 8192
|
|
|
|
OSErr err = noErr;
|
|
char buffer[BUFFER_SIZE];
|
|
UInt32 totalRead = 0, bytesRead, bytesToWrite;
|
|
|
|
MAC_ERR_CHECK(SetFPos( mInRefNum, fsFromStart, inEntry.entryOffset ));
|
|
|
|
while ( totalRead < inEntry.entryLength )
|
|
{
|
|
// Should we yield in here?
|
|
bytesRead = BUFFER_SIZE;
|
|
err = FSRead( mInRefNum, (long *) &bytesRead, buffer );
|
|
if (err!=noErr && err!=eofErr)
|
|
return err;
|
|
|
|
if ( bytesRead <= 0 )
|
|
return -1;
|
|
bytesToWrite = totalRead + bytesRead > inEntry.entryLength ?
|
|
inEntry.entryLength - totalRead :
|
|
bytesRead;
|
|
|
|
totalRead += bytesRead;
|
|
MAC_ERR_CHECK(FSWrite(inTargetSpecRefNum, (long *) &bytesToWrite,
|
|
buffer));
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
Boolean
|
|
nsAppleSingleDecoder::IsDirectory(const FSRef *inRef)
|
|
{
|
|
OSErr err;
|
|
Boolean isDir;
|
|
|
|
if (!inRef)
|
|
return false;
|
|
|
|
err = FSGetFinderInfo(inRef, NULL, NULL, &isDir);
|
|
if (err != noErr)
|
|
return false;
|
|
|
|
return isDir;
|
|
}
|
|
|
|
OSErr
|
|
nsAppleSingleDecoder::FSMakeUnique(const FSRef *inParentRef, FSRef *outRef)
|
|
{
|
|
/*
|
|
** This function has descended from Apple Sample Code, but we have
|
|
** made changes. Specifically, this function descends from the
|
|
** GenerateUniqueHFSUniStr() function in MoreFilesX.c, version 1.0.1.
|
|
*/
|
|
|
|
OSErr result = noErr;
|
|
long i, startSeed = 0x4a696d4c; /* a fine unlikely filename */
|
|
FSRefParam pb;
|
|
unsigned char hexStr[17] = "0123456789ABCDEF";
|
|
HFSUniStr255 uniqueName;
|
|
|
|
/* set up the parameter block */
|
|
pb.name = uniqueName.unicode;
|
|
pb.nameLength = 8; /* always 8 characters */
|
|
pb.textEncodingHint = kTextEncodingUnknown;
|
|
pb.newRef = outRef;
|
|
pb.ref = inParentRef;
|
|
|
|
/* loop until we get fnfErr with a filename in both directories */
|
|
result = noErr;
|
|
while ( fnfErr != result )
|
|
{
|
|
/* convert startSeed to 8 character Unicode string */
|
|
uniqueName.length = 8;
|
|
for ( i = 0; i < 8; ++i )
|
|
{
|
|
uniqueName.unicode[i] = hexStr[((startSeed >> ((7-i)*4)) & 0xf)];
|
|
}
|
|
|
|
result = PBMakeFSRefUnicodeSync(&pb);
|
|
if ( fnfErr == result )
|
|
{
|
|
OSErr err;
|
|
MAC_ERR_CHECK(FSCreateFileUnicode(inParentRef, uniqueName.length,
|
|
uniqueName.unicode, kFSCatInfoNone, NULL, outRef, NULL));
|
|
|
|
return noErr;
|
|
}
|
|
else if ( noErr != result)
|
|
{
|
|
/* exit if anything other than noErr or fnfErr */
|
|
return result;
|
|
}
|
|
|
|
/* increment seed for next pass through loop */
|
|
++(startSeed);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*
|
|
* Utilities
|
|
*----------------------------------------------------------------------*/
|
|
Boolean
|
|
nsAppleSingleDecoder::UCstrcmp(const HFSUniStr255 *str1,
|
|
const HFSUniStr255 *str2)
|
|
{
|
|
OSStatus status;
|
|
Boolean bEqual;
|
|
|
|
status = UCCompareTextDefault(kUCCollateStandardOptions, str1->unicode,
|
|
str1->length, str2->unicode, str2->length,
|
|
&bEqual, NULL);
|
|
if (status != noErr)
|
|
return false;
|
|
|
|
return bEqual;
|
|
}
|
|
|
|
#ifdef STANDALONE_ASD
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
OSErr err;
|
|
FSRef encoded, decoded;
|
|
nsAppleSingleDecoder *decoder = new nsAppleSingleDecoder;
|
|
Boolean isDir;
|
|
|
|
if (argc < 2)
|
|
{
|
|
cout << "usage: " << argv[0] << " <file/folder>" << endl
|
|
<< "\t\tAppleSingle encoded file path" << endl
|
|
<< "\t\tor" << endl
|
|
<< "\t\tfolder path containing AppleSingle encoded files." << endl;
|
|
exit(-1);
|
|
}
|
|
|
|
err = FSPathMakeRef((const UInt8 *)argv[1], &encoded, &isDir);
|
|
if (err != noErr)
|
|
return 1;
|
|
|
|
// handle AppleSingle encoded files
|
|
if (!isDir)
|
|
{
|
|
Boolean isEncoded = nsAppleSingleDecoder::IsAppleSingleFile(&encoded);
|
|
cout << "IsAppleSingleFile returned: " << (isEncoded ? "true" : "false")
|
|
<< endl;
|
|
|
|
if (isEncoded)
|
|
{
|
|
err = decoder->Decode(&encoded, &decoded);
|
|
cout << "Decode returned: " << err << endl;
|
|
}
|
|
}
|
|
|
|
// handle folders containing AppleSingle encoded files
|
|
else
|
|
{
|
|
err = decoder->DecodeFolder(&encoded);
|
|
cout << "DecodeFolder returned: " << err << endl;
|
|
}
|
|
|
|
// verify out file (n/a for folders)
|
|
if (!isDir)
|
|
{
|
|
err = FSGetCatalogInfo(&decoded, kFSCatInfoNone, NULL, NULL, NULL, NULL);
|
|
if (err == noErr)
|
|
{
|
|
cout << "Decoded file appears to exist" << endl;
|
|
char path[1024];
|
|
FSRefMakePath(&decoded, (UInt8 *)path, 1024);
|
|
cout << "Decoded file path: " << path << endl;
|
|
}
|
|
else
|
|
cout << "Decoded file doesn't appear to exist: " << err << endl;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif /* STANDALONE_ASD */
|