Mozilla/mozilla/xpinstall/packager/mac/ASEncoder/src/nsAppleSingleEncoder.cpp
gerv%gerv.net f4294ea0f8 Bug 236613: change to MPL/LGPL/GPL tri-license.
git-svn-id: svn://10.0.0.236/trunk@155026 18797224-902f-48f8-a5cc-f745e15eee43
2004-04-17 14:37:35 +00:00

481 lines
11 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_APPLESINGLEENCODER_H_
#include "nsAppleSingleEncoder.h"
#endif
#include <Files.h>
#include <OSUtils.h>
#include "nsAppleSingleDecoder.h" /* AppleSingle struct definitions */
#include "MoreFilesExtras.h"
#include "IterateDirectory.h"
nsAppleSingleEncoder::nsAppleSingleEncoder()
{
mInFile = NULL;
mOutFile = NULL;
}
nsAppleSingleEncoder::~nsAppleSingleEncoder()
{
}
Boolean
nsAppleSingleEncoder::HasResourceFork(FSSpecPtr aFile)
{
OSErr err = noErr;
Boolean bHasResFork = false;
short refnum;
long bytes2Read = 1;
char buf[2];
err = FSpOpenRF(aFile, fsRdPerm, &refnum);
if (err == noErr)
{
err = FSRead(refnum, &bytes2Read, &buf[0]);
if (err == noErr) /* err==eofErr if all OK but no res fork */
bHasResFork = true;
}
FSClose(refnum);
return bHasResFork;
}
OSErr
nsAppleSingleEncoder::Encode(FSSpecPtr aFile)
{
OSErr err = noErr;
FSSpec transient, exists;
// handle init in lieu of overloading
if (!mOutFile || !mInFile)
{
mInFile = aFile;
mOutFile = aFile;
}
// param check
if (!mInFile)
return paramErr;
// stomp old temp file
mTransient = &transient;
err = FSMakeFSSpec( mInFile->vRefNum, mInFile->parID, kTransientName,
mTransient);
if (err == noErr)
FSpDelete(mTransient);
// write to transient file
ERR_CHECK( WriteHeader() );
ERR_CHECK( WriteEntryDescs() );
ERR_CHECK( WriteEntries() );
// rename transient file to out file
err = FSMakeFSSpec( mOutFile->vRefNum, mOutFile->parID, mOutFile->name,
&exists );
if (err == noErr)
FSpDelete(mOutFile);
FSpRename(mTransient, mOutFile->name);
return err;
}
OSErr
nsAppleSingleEncoder::Encode(FSSpecPtr aInFile, FSSpecPtr aOutFile)
{
OSErr err = noErr;
// param check
if (!aInFile || !aOutFile)
return paramErr;
mInFile = aInFile;
mOutFile = aOutFile;
err = Encode(NULL);
return err;
}
pascal void
EncodeDirIterateFilter(const CInfoPBRec * const cpbPtr, Boolean *quitFlag, void *yourDataPtr)
{
OSErr err = noErr;
FSSpec currFSp;
nsAppleSingleEncoder* thisObj = NULL;
Boolean isDir = false;
long dummy;
// param check
if (!yourDataPtr || !cpbPtr || !quitFlag)
return;
*quitFlag = false;
// extract 'this' -- an nsAppleSingleEncoder instance
thisObj = (nsAppleSingleEncoder*) yourDataPtr;
thisObj->ReInit();
// make an FSSpec from the CInfoPBRec*
err = FSMakeFSSpec(cpbPtr->hFileInfo.ioVRefNum, cpbPtr->hFileInfo.ioFlParID,
cpbPtr->hFileInfo.ioNamePtr, &currFSp);
if (err == noErr)
{
FSpGetDirectoryID(&currFSp, &dummy, &isDir);
// if current FSSpec is file
if (!isDir)
{
// if file has res fork
if (nsAppleSingleEncoder::HasResourceFork(&currFSp))
{
// encode file
thisObj->Encode(&currFSp);
}
}
else
{
// else if current FSSpec is folder ignore
// XXX never reached?
return;
}
}
}
OSErr
nsAppleSingleEncoder::EncodeFolder(FSSpecPtr aFolder)
{
OSErr err = noErr;
long dummy;
Boolean isDir = false;
// check that FSSpec is folder
if (aFolder)
{
FSpGetDirectoryID(aFolder, &dummy, &isDir);
if (!isDir)
return dirNFErr;
}
// recursively enumerate contents of folder (maxLevels=0 means recurse all)
FSpIterateDirectory(aFolder, 0, EncodeDirIterateFilter, (void*)this);
return err;
}
void
nsAppleSingleEncoder::ReInit()
{
mInFile = NULL;
mOutFile = NULL;
}
OSErr
nsAppleSingleEncoder::WriteHeader()
{
OSErr err = noErr;
ASHeader hdr;
int i;
long bytes2Wr;
// init header info
hdr.magicNum = kAppleSingleMagicNum;
hdr.versionNum = kAppleSingleVerNum;
for (i=0; i<16; i++)
hdr.filler[i] = 0;
hdr.numEntries = kNumASEntries;
/*
** Entries:
**
** 1> Real name
** 2> Finder info
** 3> File dates
** 4> Resource fork
** 5> Data fork
** 6> Mac info
*/
bytes2Wr = sizeof(ASHeader);
ERR_CHECK( FSpCreate(mTransient, 'MOZZ', '????', 0) );
ERR_CHECK( FSpOpenDF(mTransient, fsRdWrPerm, &mTransRefNum) );
// ERR_CHECK( SetFPos(mTransRefNum, fsFromStart, 0) ); // XXX revisit
ERR_CHECK( FSWrite(mTransRefNum, &bytes2Wr, &hdr) );
if (bytes2Wr != sizeof(ASHeader))
err = -1;
return err;
}
OSErr
nsAppleSingleEncoder::WriteEntryDescs()
{
OSErr err = noErr;
long offset = sizeof(ASHeader), bytes2Wr = kNumASEntries*sizeof(ASEntry);
ASEntry entries[kNumASEntries];
int i;
CInfoPBRec pb;
ERR_CHECK( FSpGetCatInfo(&pb, mInFile) );
// real name
entries[0].entryOffset = sizeof(ASHeader) + (sizeof(ASEntry) * kNumASEntries);
entries[0].entryID = AS_REALNAME;
entries[0].entryLength = pb.hFileInfo.ioNamePtr[0];
// finder info
entries[1].entryID = AS_FINDERINFO;
entries[1].entryLength = sizeof(FInfo) + sizeof(FXInfo);
// file dates
entries[2].entryID = AS_FILEDATES;
entries[2].entryLength = sizeof(ASFileDates);
// resource fork
entries[3].entryID = AS_RESOURCE;
entries[3].entryLength = pb.hFileInfo.ioFlRLgLen;
// data fork
entries[4].entryID = AS_DATA;
entries[4].entryLength = pb.hFileInfo.ioFlLgLen;
// mac info
entries[5].entryID = AS_MACINFO;
entries[5].entryLength = sizeof(ASMacInfo);
for (i=1; i<kNumASEntries; i++) /* start at 1, not 0 */
{
entries[i].entryOffset = entries[i-1].entryOffset + entries[i-1].entryLength;
}
// ERR_CHECK( SetFPos(mTransRefNum, fsFromStart, sizeof(ASHeader)) ); // revisit
ERR_CHECK( FSWrite(mTransRefNum, &bytes2Wr, &entries[0]) );
if (bytes2Wr != (kNumASEntries * sizeof(ASEntry)))
err = -1;
return err;
}
OSErr
nsAppleSingleEncoder::WriteEntries()
{
OSErr err = noErr;
long bytes2Wr;
DateTimeRec currTime;
ASFileDates asDates;
unsigned long currSecs;
ASMacInfo asMacInfo;
int i;
CInfoPBRec pb;
char name[32];
FSpGetCatInfo(&pb, mInFile);
// real name
bytes2Wr = pb.hFileInfo.ioNamePtr[0];
strncpy(name, (char*)(pb.hFileInfo.ioNamePtr+1), bytes2Wr);
ERR_CHECK( FSWrite(mTransRefNum, &bytes2Wr, name) );
FSpGetCatInfo(&pb, mInFile); // XXX refresh after write
if (bytes2Wr != pb.hFileInfo.ioNamePtr[0])
{
err = -1;
goto cleanup;
}
// finder info
bytes2Wr = sizeof(FInfo);
ERR_CHECK( FSWrite(mTransRefNum, &bytes2Wr, &pb.hFileInfo.ioFlFndrInfo) );
FSpGetCatInfo(&pb, mInFile); // XXX refresh after write
if (bytes2Wr != sizeof(FInfo))
{
err = -1;
goto cleanup;
}
bytes2Wr = sizeof(FXInfo);
ERR_CHECK( FSWrite(mTransRefNum, &bytes2Wr, &pb.hFileInfo.ioFlXFndrInfo) );
FSpGetCatInfo(&pb, mInFile); // XXX refresh after write
if (bytes2Wr != sizeof(FXInfo))
{
err = -1;
goto cleanup;
}
// file dates
GetTime(&currTime);
DateToSeconds(&currTime, &currSecs);
FSpGetCatInfo(&pb, mInFile); // XXX refresh after sys calls
asDates.create = pb.hFileInfo.ioFlCrDat + kConvertTime;
asDates.modify = pb.hFileInfo.ioFlMdDat + kConvertTime;
asDates.backup = pb.hFileInfo.ioFlBkDat + kConvertTime;
asDates.access = currSecs + kConvertTime;
bytes2Wr = sizeof(ASFileDates);
ERR_CHECK( FSWrite(mTransRefNum, &bytes2Wr, &asDates) );
FSpGetCatInfo(&pb, mInFile); // XXX refresh after write
if (bytes2Wr != sizeof(ASFileDates))
{
err = -1;
goto cleanup;
}
// resource fork
ERR_CHECK( WriteResourceFork() );
// data fork
ERR_CHECK( WriteDataFork() );
// mac info
for (i=0; i<3; i++)
asMacInfo.filler[i];
FSpGetCatInfo(&pb, mInFile); // XXX refresh
asMacInfo.ioFlAttrib = pb.hFileInfo.ioFlAttrib;
bytes2Wr = sizeof(ASMacInfo);
ERR_CHECK( FSWrite(mTransRefNum, &bytes2Wr, &asMacInfo) );
if (bytes2Wr != sizeof(ASMacInfo))
{
err = -1;
goto cleanup;
}
cleanup:
FSClose(mTransRefNum);
return err;
}
#define BUFSIZE 8192
OSErr
nsAppleSingleEncoder::WriteResourceFork()
{
OSErr err = noErr;
short refnum;
long bytes2Rd, bytes2Wr;
char buf[BUFSIZE];
// open infile's resource fork
ERR_CHECK( FSpOpenRF(mInFile, fsRdPerm, &refnum) );
while (err != eofErr)
{
// keep reading chunks till infile's eof encountered
bytes2Rd = BUFSIZE;
err = FSRead(refnum, &bytes2Rd, buf);
if (bytes2Rd <= 0)
goto cleanup;
if (err == noErr || err == eofErr)
{
// keep writing
bytes2Wr = bytes2Rd;
err = FSWrite(mTransRefNum, &bytes2Wr, buf);
if (err != noErr || bytes2Wr != bytes2Rd)
goto cleanup;
}
}
cleanup:
// close infile
FSClose(refnum);
// eof is OK so translate
if (err == eofErr)
err = noErr;
return err;
}
OSErr
nsAppleSingleEncoder::WriteDataFork()
{
OSErr err = noErr;
short refnum;
long bytes2Rd, bytes2Wr;
char buf[BUFSIZE];
// open infile's data fork
ERR_CHECK( FSpOpenDF(mInFile, fsRdPerm, &refnum) );
while (err != eofErr)
{
// keep reading chunks till infile's eof encountered
bytes2Rd = BUFSIZE;
err = FSRead(refnum, &bytes2Rd, buf);
if (bytes2Rd <= 0)
goto cleanup;
if (err == noErr || err == eofErr)
{
// keep writing
bytes2Wr = bytes2Rd;
err = FSWrite(mTransRefNum, &bytes2Wr, buf);
if (err != noErr || bytes2Wr != bytes2Rd)
goto cleanup;
}
}
cleanup:
// close infile
FSClose(refnum);
// eof is OK so translate
if (err == eofErr)
err = noErr;
return err;
}
OSErr
nsAppleSingleEncoder::FSpGetCatInfo(CInfoPBRec *pb, FSSpecPtr aFile)
{
OSErr err = noErr;
Str31 name;
nsAppleSingleDecoder::PLstrncpy(name, aFile->name, aFile->name[0]);
name[0] = aFile->name[0]; // XXX paranoia
pb->hFileInfo.ioNamePtr = name;
pb->hFileInfo.ioVRefNum = aFile->vRefNum;
pb->hFileInfo.ioDirID = aFile->parID;
pb->hFileInfo.ioFDirIndex = 0; // use ioNamePtr and ioDirID
ERR_CHECK( PBGetCatInfoSync(pb) );
return err;
}