nulib2/nufxlib/Thread.c

1382 lines
44 KiB
C
Raw Normal View History

2000-05-23 01:55:31 +00:00
/*
* NuFX archive manipulation library
2007-02-19 23:12:22 +00:00
* Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved.
2000-05-23 01:55:31 +00:00
* This is free software; you can redistribute it and/or modify it under the
2007-02-19 23:12:22 +00:00
* terms of the BSD License, see the file COPYING-LIB.
2000-05-23 01:55:31 +00:00
*
* Thread-level operations.
*/
#include "NufxLibPriv.h"
/*
* ===========================================================================
* Utils
2000-05-23 01:55:31 +00:00
* ===========================================================================
*/
/*
* Returns thread N, or NULL if the index is invalid.
*/
NuThread* Nu_GetThread(const NuRecord* pRecord, int idx)
{
if (idx >= (int)pRecord->recTotalThreads)
return NULL;
else
return &pRecord->pThreads[idx];
}
2000-05-23 01:55:31 +00:00
/*
* ShrinkIt v3.0.0 had a bug where the filename thread would get created
* with the high bits set. We want to undo that without stomping on
* filenames that just happen to have a fancy character in them. If all
* of the high bits are set, assume it's a "defective" name and clear
* them all. If some aren't set, assume it's just a fancy filename.
*
* This high-bit-ism was also done for disk archives by most older versions
* of ShrinkIt.
*/
void Nu_StripHiIfAllSet(char* str)
2000-05-23 01:55:31 +00:00
{
uint8_t* cp;
2000-05-23 01:55:31 +00:00
for (cp = (uint8_t*)str; *cp != '\0'; cp++)
if (!(*cp & 0x80))
return;
2000-05-23 01:55:31 +00:00
for (cp = (uint8_t*)str; *cp != '\0'; cp++)
*cp &= 0x7f;
2000-05-23 01:55:31 +00:00
}
/*
* Decide if a thread is pre-sized (i.e. has a fixed maximum size with a
* lesser amount of uncompressed data within) based on the threadID.
*/
Boolean Nu_IsPresizedThreadID(NuThreadID threadID)
2000-05-23 01:55:31 +00:00
{
if (threadID == kNuThreadIDFilename || threadID == kNuThreadIDComment)
return true;
else
return false;
2000-05-23 01:55:31 +00:00
}
/*
* Return an indication of whether the type of thread specified by ThreadID
* should ever be compressed. Right now, that's only data-class threads.
*/
Boolean Nu_IsCompressibleThreadID(NuThreadID threadID)
2000-05-23 01:55:31 +00:00
{
if (NuThreadIDGetClass(threadID) == kNuThreadClassData)
return true;
else
return false;
2000-05-23 01:55:31 +00:00
}
/*
* Decide if the thread has a CRC, based on the record version and the
* threadID.
*/
Distinguish Unicode and Mac OS Roman strings NufxLib has historically made no effort to distinguish between the character set used for filenames on the local disk, and for filenames stored within the archive. Now all Unicode filename strings use the UNICHAR type and have "UNI" in the name, and all Mac OS Roman strings have "MOR" in the name. (The naming convention makes it obvious when you're assigning the wrong thing; on Linux both formats are char*, so the compiler won't tell you if you get it wrong.) The distinction is necessary because filesystems generally support Unicode these days, but on Windows you need to use a separate set of wide-character file I/O functions. (On Linux it all works with "narrow" strings, and the UTF-8 encoding is interpreted by applications.) The character set used for NuFX archive filenames is MOR, matching what GS/OS + HFS supported, and we want to be able to convert back and forth between MOR and a Unicode representation. This change updates the various character types and string names, adds conversion functions, and updates NuLib2 for proper execution on Linux. It does not include the (probably extensive) changes required for Windows UTF-16 support. Instead, the conversion functions are no-ops, which should result in NuLib2 for Windows continuing to behave in the same slightly broken way. This adds "test-names", which exercises Unicode filenames a bit. It will not pass on Win32. Also, tweaked the Linux makefiles to have explicit dependencies, rather than empty space and an expectation that "makedepend" exists. Also, minor source code cleanups. While this probably doesn't affect binary compatibility -- it's mainly a matter of naming and string interpretation -- there's enough going on that it should be considered an API revision, so this updates the version to 3.0.0.
2014-12-24 19:14:32 +00:00
Boolean Nu_ThreadHasCRC(uint16_t recordVersion, NuThreadID threadID)
2000-05-23 01:55:31 +00:00
{
return recordVersion >= 3 &&
NuThreadIDGetClass(threadID) == kNuThreadClassData;
2000-05-23 01:55:31 +00:00
}
/*
* Search through a given NuRecord for the specified thread.
*/
NuError Nu_FindThreadByIdx(const NuRecord* pRecord, NuThreadIdx thread,
NuThread** ppThread)
2000-05-23 01:55:31 +00:00
{
NuThread* pThread;
int idx;
2000-05-23 01:55:31 +00:00
for (idx = 0; idx < (int)pRecord->recTotalThreads; idx++) {
pThread = Nu_GetThread(pRecord, idx);
2014-12-22 02:17:23 +00:00
Assert(pThread != NULL);
2000-05-23 01:55:31 +00:00
if (pThread->threadIdx == thread) {
*ppThread = pThread;
return kNuErrNone;
}
}
2000-05-23 01:55:31 +00:00
return kNuErrThreadIdxNotFound;
2000-05-23 01:55:31 +00:00
}
/*
* Search through a given NuRecord for the first thread with a matching
* threadID.
*/
NuError Nu_FindThreadByID(const NuRecord* pRecord, NuThreadID threadID,
NuThread** ppThread)
2000-05-23 01:55:31 +00:00
{
NuThread* pThread;
int idx;
2000-05-23 01:55:31 +00:00
for (idx = 0; idx < (int)pRecord->recTotalThreads; idx++) {
pThread = Nu_GetThread(pRecord, idx);
2014-12-22 02:17:23 +00:00
Assert(pThread != NULL);
2000-05-23 01:55:31 +00:00
if (NuGetThreadID(pThread) == threadID) {
*ppThread = pThread;
return kNuErrNone;
}
}
2000-05-23 01:55:31 +00:00
return kNuErrThreadIDNotFound;
2000-05-23 01:55:31 +00:00
}
/*
* Copy the contents of a NuThread.
*/
void Nu_CopyThreadContents(NuThread* pDstThread, const NuThread* pSrcThread)
2000-05-23 01:55:31 +00:00
{
2014-12-22 02:17:23 +00:00
Assert(pDstThread != NULL);
Assert(pSrcThread != NULL);
2000-05-23 01:55:31 +00:00
memcpy(pDstThread, pSrcThread, sizeof(*pDstThread));
2000-05-23 01:55:31 +00:00
}
/*
* ===========================================================================
* Reading threads from the archive
2000-05-23 01:55:31 +00:00
* ===========================================================================
*/
/*
* Read a single thread header from the archive.
*/
static NuError Nu_ReadThreadHeader(NuArchive* pArchive, NuThread* pThread,
uint16_t* pCrc)
2000-05-23 01:55:31 +00:00
{
FILE* fp;
2000-05-23 01:55:31 +00:00
2014-12-22 02:17:23 +00:00
Assert(pArchive != NULL);
Assert(pThread != NULL);
Assert(pCrc != NULL);
2000-05-23 01:55:31 +00:00
fp = pArchive->archiveFp;
2000-05-23 01:55:31 +00:00
pThread->thThreadClass = Nu_ReadTwoC(pArchive, fp, pCrc);
pThread->thThreadFormat = Nu_ReadTwoC(pArchive, fp, pCrc);
pThread->thThreadKind = Nu_ReadTwoC(pArchive, fp, pCrc);
pThread->thThreadCRC = Nu_ReadTwoC(pArchive, fp, pCrc);
pThread->thThreadEOF = Nu_ReadFourC(pArchive, fp, pCrc);
pThread->thCompThreadEOF = Nu_ReadFourC(pArchive, fp, pCrc);
2000-05-23 01:55:31 +00:00
pThread->threadIdx = Nu_GetNextThreadIdx(pArchive);
pThread->actualThreadEOF = 0; /* fix me later */
pThread->fileOffset = -1; /* mark as invalid */
pThread->used = 0xcfcf; /* init to invalid value */
2000-05-23 01:55:31 +00:00
return Nu_HeaderIOFailed(pArchive, fp);
2000-05-23 01:55:31 +00:00
}
/*
* Read the threads from the current archive file position.
*
* The storage for the threads is allocated here, in one block. We could
* have used a linked list like NuLib, but that doesn't really provide any
* benefit for us, and adds complexity.
*/
NuError Nu_ReadThreadHeaders(NuArchive* pArchive, NuRecord* pRecord,
uint16_t* pCrc)
2000-05-23 01:55:31 +00:00
{
NuError err = kNuErrNone;
NuThread* pThread;
long count;
Boolean needFakeData, needFakeRsrc;
needFakeData = true;
needFakeRsrc = (pRecord->recStorageType == kNuStorageExtended);
2014-12-22 02:17:23 +00:00
Assert(pArchive != NULL);
Assert(pRecord != NULL);
Assert(pCrc != NULL);
if (!pRecord->recTotalThreads) {
/* not sure if this is reasonable, but we can handle it */
DBUG(("--- WEIRD: no threads in the record?\n"));
goto bail;
}
pRecord->pThreads = Nu_Malloc(pArchive,
pRecord->recTotalThreads * sizeof(NuThread));
BailAlloc(pRecord->pThreads);
count = pRecord->recTotalThreads;
pThread = pRecord->pThreads;
while (count--) {
err = Nu_ReadThreadHeader(pArchive, pThread, pCrc);
BailError(err);
if (pThread->thThreadClass == kNuThreadClassData) {
if (pThread->thThreadKind == kNuThreadKindDataFork) {
needFakeData = false;
} else if (pThread->thThreadKind == kNuThreadKindRsrcFork) {
needFakeRsrc = false;
} else if (pThread->thThreadKind == kNuThreadKindDiskImage) {
/* needFakeRsrc shouldn't be set, but clear anyway */
needFakeData = needFakeRsrc = false;
}
}
/*
* Some versions of ShrinkIt write an invalid thThreadEOF for disks,
* so we have to figure out what it's supposed to be.
*/
if (NuMakeThreadID(pThread->thThreadClass, pThread->thThreadKind) ==
kNuThreadIDDiskImage)
{
if (pRecord->recStorageType <= 13) {
/* supposed to be block size, but SHK v3.0.1 stored it wrong */
pThread->actualThreadEOF = pRecord->recExtraType * 512;
} else if (pRecord->recStorageType == 256 &&
pRecord->recExtraType == 280 &&
pRecord->recFileSysID == kNuFileSysDOS33)
{
/*
* Fix for less-common ShrinkIt problem: looks like an old
* version of GS/ShrinkIt used 256 as the block size when
* compressing DOS 3.3 images from 5.25" disks. If that
* appears to be the case here, crank up the block size.
*/
DBUG(("--- no such thing as a 70K disk image!\n"));
pThread->actualThreadEOF = pRecord->recExtraType * 512;
} else {
pThread->actualThreadEOF =
pRecord->recExtraType * pRecord->recStorageType;
}
} else {
pThread->actualThreadEOF = pThread->thThreadEOF;
}
pThread->used = false;
pThread++;
}
2000-05-23 01:55:31 +00:00
/*
* If "mask threadless" is set, create "fake" threads with empty
* data and resource forks as needed.
*/
if ((needFakeData || needFakeRsrc) && pArchive->valMaskDataless) {
int firstNewThread = pRecord->recTotalThreads;
if (needFakeData) {
pRecord->recTotalThreads++;
pRecord->fakeThreads++;
}
if (needFakeRsrc) {
pRecord->recTotalThreads++;
pRecord->fakeThreads++;
}
pRecord->pThreads = Nu_Realloc(pArchive, pRecord->pThreads,
pRecord->recTotalThreads * sizeof(NuThread));
BailAlloc(pRecord->pThreads);
pThread = pRecord->pThreads + firstNewThread;
if (needFakeData) {
pThread->thThreadClass = kNuThreadClassData;
pThread->thThreadFormat = kNuThreadFormatUncompressed;
pThread->thThreadKind = kNuThreadKindDataFork;
pThread->thThreadCRC = kNuInitialThreadCRC;
pThread->thThreadEOF = 0;
pThread->thCompThreadEOF = 0;
pThread->threadIdx = Nu_GetNextThreadIdx(pArchive);
pThread->actualThreadEOF = 0;
pThread->fileOffset = -99999999;
pThread->used = false;
pThread++;
}
if (needFakeRsrc) {
pThread->thThreadClass = kNuThreadClassData;
pThread->thThreadFormat = kNuThreadFormatUncompressed;
pThread->thThreadKind = kNuThreadKindRsrcFork;
pThread->thThreadCRC = kNuInitialThreadCRC;
pThread->thThreadEOF = 0;
pThread->thCompThreadEOF = 0;
pThread->threadIdx = Nu_GetNextThreadIdx(pArchive);
pThread->actualThreadEOF = 0;
pThread->fileOffset = -99999999;
pThread->used = false;
}
}
2000-05-23 01:55:31 +00:00
bail:
return err;
2000-05-23 01:55:31 +00:00
}
/*
* Write a single thread header to the archive.
*/
static NuError Nu_WriteThreadHeader(NuArchive* pArchive,
const NuThread* pThread, FILE* fp, uint16_t* pCrc)
2000-05-23 01:55:31 +00:00
{
2014-12-22 02:17:23 +00:00
Assert(pArchive != NULL);
Assert(pThread != NULL);
Assert(fp != NULL);
Assert(pCrc != NULL);
Nu_WriteTwoC(pArchive, fp, pThread->thThreadClass, pCrc);
Nu_WriteTwoC(pArchive, fp, (uint16_t)pThread->thThreadFormat, pCrc);
Nu_WriteTwoC(pArchive, fp, pThread->thThreadKind, pCrc);
Nu_WriteTwoC(pArchive, fp, pThread->thThreadCRC, pCrc);
Nu_WriteFourC(pArchive, fp, pThread->thThreadEOF, pCrc);
Nu_WriteFourC(pArchive, fp, pThread->thCompThreadEOF, pCrc);
return Nu_HeaderIOFailed(pArchive, fp);
2000-05-23 01:55:31 +00:00
}
/*
* Write the thread headers for the record at the current file position.
*
* Note this doesn't care whether a thread was "fake" or not. In
* effect, we promote all threads to "real" status. We update the
* "fake" count in pRecord accordingly.
2000-05-23 01:55:31 +00:00
*/
NuError Nu_WriteThreadHeaders(NuArchive* pArchive, NuRecord* pRecord, FILE* fp,
uint16_t* pCrc)
2000-05-23 01:55:31 +00:00
{
NuError err = kNuErrNone;
NuThread* pThread;
int idx;
2000-05-23 01:55:31 +00:00
for (idx = 0; idx < (int)pRecord->recTotalThreads; idx++) {
pThread = Nu_GetThread(pRecord, idx);
2014-12-22 02:17:23 +00:00
Assert(pThread != NULL);
2000-05-23 01:55:31 +00:00
err = Nu_WriteThreadHeader(pArchive, pThread, fp, pCrc);
BailError(err);
}
2000-05-23 01:55:31 +00:00
if (pRecord->fakeThreads != 0) {
DBUG(("+++ promoting %ld fake threads to real\n",pRecord->fakeThreads));
pRecord->fakeThreads = 0;
}
2000-05-23 01:55:31 +00:00
bail:
return err;
2000-05-23 01:55:31 +00:00
}
/*
* Compute miscellaneous thread information, like total size and file
* offsets. Some values (like file offsets) will not be useful for
* streaming archives.
*
* Requires that the pArchive->currentOffset be set to the offset
* immediately after the last of the thread headers.
*/
NuError Nu_ComputeThreadData(NuArchive* pArchive, NuRecord* pRecord)
2000-05-23 01:55:31 +00:00
{
NuThread* pThread;
long fileOffset, count;
2000-05-23 01:55:31 +00:00
2014-12-22 02:17:23 +00:00
Assert(pArchive != NULL);
Assert(pRecord != NULL);
2000-05-23 01:55:31 +00:00
/*pRecord->totalLength = 0;*/
pRecord->totalCompLength = 0;
2000-05-23 01:55:31 +00:00
fileOffset = pArchive->currentOffset;
2000-05-23 01:55:31 +00:00
count = pRecord->recTotalThreads;
pThread = pRecord->pThreads;
while (count--) {
pThread->fileOffset = fileOffset;
2000-05-23 01:55:31 +00:00
/*pRecord->totalLength += pThread->thThreadEOF;*/
pRecord->totalCompLength += pThread->thCompThreadEOF;
fileOffset += pThread->thCompThreadEOF;
2000-05-23 01:55:31 +00:00
pThread++;
}
2000-05-23 01:55:31 +00:00
return kNuErrNone;
2000-05-23 01:55:31 +00:00
}
/*
* Skip past some or all of the thread data in the archive. For file
* archives, we scan all the threads, but for streaming archives we only
* want to scan up to the filename thread. (If the filename thread comes
* after one of the data threads, we have a problem!)
*
* The tricky part here is that we don't want to skip over a filename
* thread. We actually want to read it in, so that we have something to
* show to the application. (Someday I'll get AndyN for putting me
* through this...)
*/
NuError Nu_ScanThreads(NuArchive* pArchive, NuRecord* pRecord, long numThreads)
2000-05-23 01:55:31 +00:00
{
NuError err = kNuErrNone;
NuThread* pThread;
FILE* fp;
2014-12-22 02:17:23 +00:00
Assert(pArchive != NULL);
Assert(pRecord != NULL);
fp = pArchive->archiveFp;
Assert(numThreads <= (long)pRecord->recTotalThreads);
pThread = pRecord->pThreads;
while (numThreads--) {
Distinguish Unicode and Mac OS Roman strings NufxLib has historically made no effort to distinguish between the character set used for filenames on the local disk, and for filenames stored within the archive. Now all Unicode filename strings use the UNICHAR type and have "UNI" in the name, and all Mac OS Roman strings have "MOR" in the name. (The naming convention makes it obvious when you're assigning the wrong thing; on Linux both formats are char*, so the compiler won't tell you if you get it wrong.) The distinction is necessary because filesystems generally support Unicode these days, but on Windows you need to use a separate set of wide-character file I/O functions. (On Linux it all works with "narrow" strings, and the UTF-8 encoding is interpreted by applications.) The character set used for NuFX archive filenames is MOR, matching what GS/OS + HFS supported, and we want to be able to convert back and forth between MOR and a Unicode representation. This change updates the various character types and string names, adds conversion functions, and updates NuLib2 for proper execution on Linux. It does not include the (probably extensive) changes required for Windows UTF-16 support. Instead, the conversion functions are no-ops, which should result in NuLib2 for Windows continuing to behave in the same slightly broken way. This adds "test-names", which exercises Unicode filenames a bit. It will not pass on Win32. Also, tweaked the Linux makefiles to have explicit dependencies, rather than empty space and an expectation that "makedepend" exists. Also, minor source code cleanups. While this probably doesn't affect binary compatibility -- it's mainly a matter of naming and string interpretation -- there's enough going on that it should be considered an API revision, so this updates the version to 3.0.0.
2014-12-24 19:14:32 +00:00
if (pRecord->threadFilenameMOR == NULL &&
NuMakeThreadID(pThread->thThreadClass, pThread->thThreadKind) ==
kNuThreadIDFilename)
{
/* it's the first filename thread, read the whole thing */
if (pThread->thCompThreadEOF > kNuReasonableFilenameLen) {
err = kNuErrBadRecord;
Nu_ReportError(NU_BLOB, err, "Bad thread filename len (%u)",
pThread->thCompThreadEOF);
goto bail;
}
Distinguish Unicode and Mac OS Roman strings NufxLib has historically made no effort to distinguish between the character set used for filenames on the local disk, and for filenames stored within the archive. Now all Unicode filename strings use the UNICHAR type and have "UNI" in the name, and all Mac OS Roman strings have "MOR" in the name. (The naming convention makes it obvious when you're assigning the wrong thing; on Linux both formats are char*, so the compiler won't tell you if you get it wrong.) The distinction is necessary because filesystems generally support Unicode these days, but on Windows you need to use a separate set of wide-character file I/O functions. (On Linux it all works with "narrow" strings, and the UTF-8 encoding is interpreted by applications.) The character set used for NuFX archive filenames is MOR, matching what GS/OS + HFS supported, and we want to be able to convert back and forth between MOR and a Unicode representation. This change updates the various character types and string names, adds conversion functions, and updates NuLib2 for proper execution on Linux. It does not include the (probably extensive) changes required for Windows UTF-16 support. Instead, the conversion functions are no-ops, which should result in NuLib2 for Windows continuing to behave in the same slightly broken way. This adds "test-names", which exercises Unicode filenames a bit. It will not pass on Win32. Also, tweaked the Linux makefiles to have explicit dependencies, rather than empty space and an expectation that "makedepend" exists. Also, minor source code cleanups. While this probably doesn't affect binary compatibility -- it's mainly a matter of naming and string interpretation -- there's enough going on that it should be considered an API revision, so this updates the version to 3.0.0.
2014-12-24 19:14:32 +00:00
pRecord->threadFilenameMOR = Nu_Malloc(pArchive,
pThread->thCompThreadEOF +1);
Distinguish Unicode and Mac OS Roman strings NufxLib has historically made no effort to distinguish between the character set used for filenames on the local disk, and for filenames stored within the archive. Now all Unicode filename strings use the UNICHAR type and have "UNI" in the name, and all Mac OS Roman strings have "MOR" in the name. (The naming convention makes it obvious when you're assigning the wrong thing; on Linux both formats are char*, so the compiler won't tell you if you get it wrong.) The distinction is necessary because filesystems generally support Unicode these days, but on Windows you need to use a separate set of wide-character file I/O functions. (On Linux it all works with "narrow" strings, and the UTF-8 encoding is interpreted by applications.) The character set used for NuFX archive filenames is MOR, matching what GS/OS + HFS supported, and we want to be able to convert back and forth between MOR and a Unicode representation. This change updates the various character types and string names, adds conversion functions, and updates NuLib2 for proper execution on Linux. It does not include the (probably extensive) changes required for Windows UTF-16 support. Instead, the conversion functions are no-ops, which should result in NuLib2 for Windows continuing to behave in the same slightly broken way. This adds "test-names", which exercises Unicode filenames a bit. It will not pass on Win32. Also, tweaked the Linux makefiles to have explicit dependencies, rather than empty space and an expectation that "makedepend" exists. Also, minor source code cleanups. While this probably doesn't affect binary compatibility -- it's mainly a matter of naming and string interpretation -- there's enough going on that it should be considered an API revision, so this updates the version to 3.0.0.
2014-12-24 19:14:32 +00:00
BailAlloc(pRecord->threadFilenameMOR);
/* note there is no CRC on a filename thread */
Distinguish Unicode and Mac OS Roman strings NufxLib has historically made no effort to distinguish between the character set used for filenames on the local disk, and for filenames stored within the archive. Now all Unicode filename strings use the UNICHAR type and have "UNI" in the name, and all Mac OS Roman strings have "MOR" in the name. (The naming convention makes it obvious when you're assigning the wrong thing; on Linux both formats are char*, so the compiler won't tell you if you get it wrong.) The distinction is necessary because filesystems generally support Unicode these days, but on Windows you need to use a separate set of wide-character file I/O functions. (On Linux it all works with "narrow" strings, and the UTF-8 encoding is interpreted by applications.) The character set used for NuFX archive filenames is MOR, matching what GS/OS + HFS supported, and we want to be able to convert back and forth between MOR and a Unicode representation. This change updates the various character types and string names, adds conversion functions, and updates NuLib2 for proper execution on Linux. It does not include the (probably extensive) changes required for Windows UTF-16 support. Instead, the conversion functions are no-ops, which should result in NuLib2 for Windows continuing to behave in the same slightly broken way. This adds "test-names", which exercises Unicode filenames a bit. It will not pass on Win32. Also, tweaked the Linux makefiles to have explicit dependencies, rather than empty space and an expectation that "makedepend" exists. Also, minor source code cleanups. While this probably doesn't affect binary compatibility -- it's mainly a matter of naming and string interpretation -- there's enough going on that it should be considered an API revision, so this updates the version to 3.0.0.
2014-12-24 19:14:32 +00:00
(void) Nu_ReadBytes(pArchive, fp, pRecord->threadFilenameMOR,
pThread->thCompThreadEOF);
if ((err = Nu_HeaderIOFailed(pArchive, fp)) != kNuErrNone) {
Nu_ReportError(NU_BLOB, err, "Failed reading filename thread");
goto bail;
}
/* null-terminate on the actual len, not the buffer len */
Distinguish Unicode and Mac OS Roman strings NufxLib has historically made no effort to distinguish between the character set used for filenames on the local disk, and for filenames stored within the archive. Now all Unicode filename strings use the UNICHAR type and have "UNI" in the name, and all Mac OS Roman strings have "MOR" in the name. (The naming convention makes it obvious when you're assigning the wrong thing; on Linux both formats are char*, so the compiler won't tell you if you get it wrong.) The distinction is necessary because filesystems generally support Unicode these days, but on Windows you need to use a separate set of wide-character file I/O functions. (On Linux it all works with "narrow" strings, and the UTF-8 encoding is interpreted by applications.) The character set used for NuFX archive filenames is MOR, matching what GS/OS + HFS supported, and we want to be able to convert back and forth between MOR and a Unicode representation. This change updates the various character types and string names, adds conversion functions, and updates NuLib2 for proper execution on Linux. It does not include the (probably extensive) changes required for Windows UTF-16 support. Instead, the conversion functions are no-ops, which should result in NuLib2 for Windows continuing to behave in the same slightly broken way. This adds "test-names", which exercises Unicode filenames a bit. It will not pass on Win32. Also, tweaked the Linux makefiles to have explicit dependencies, rather than empty space and an expectation that "makedepend" exists. Also, minor source code cleanups. While this probably doesn't affect binary compatibility -- it's mainly a matter of naming and string interpretation -- there's enough going on that it should be considered an API revision, so this updates the version to 3.0.0.
2014-12-24 19:14:32 +00:00
pRecord->threadFilenameMOR[pThread->thThreadEOF] = '\0';
Distinguish Unicode and Mac OS Roman strings NufxLib has historically made no effort to distinguish between the character set used for filenames on the local disk, and for filenames stored within the archive. Now all Unicode filename strings use the UNICHAR type and have "UNI" in the name, and all Mac OS Roman strings have "MOR" in the name. (The naming convention makes it obvious when you're assigning the wrong thing; on Linux both formats are char*, so the compiler won't tell you if you get it wrong.) The distinction is necessary because filesystems generally support Unicode these days, but on Windows you need to use a separate set of wide-character file I/O functions. (On Linux it all works with "narrow" strings, and the UTF-8 encoding is interpreted by applications.) The character set used for NuFX archive filenames is MOR, matching what GS/OS + HFS supported, and we want to be able to convert back and forth between MOR and a Unicode representation. This change updates the various character types and string names, adds conversion functions, and updates NuLib2 for proper execution on Linux. It does not include the (probably extensive) changes required for Windows UTF-16 support. Instead, the conversion functions are no-ops, which should result in NuLib2 for Windows continuing to behave in the same slightly broken way. This adds "test-names", which exercises Unicode filenames a bit. It will not pass on Win32. Also, tweaked the Linux makefiles to have explicit dependencies, rather than empty space and an expectation that "makedepend" exists. Also, minor source code cleanups. While this probably doesn't affect binary compatibility -- it's mainly a matter of naming and string interpretation -- there's enough going on that it should be considered an API revision, so this updates the version to 3.0.0.
2014-12-24 19:14:32 +00:00
Nu_StripHiIfAllSet(pRecord->threadFilenameMOR);
/* prefer this one over the record one, but only one should exist */
Distinguish Unicode and Mac OS Roman strings NufxLib has historically made no effort to distinguish between the character set used for filenames on the local disk, and for filenames stored within the archive. Now all Unicode filename strings use the UNICHAR type and have "UNI" in the name, and all Mac OS Roman strings have "MOR" in the name. (The naming convention makes it obvious when you're assigning the wrong thing; on Linux both formats are char*, so the compiler won't tell you if you get it wrong.) The distinction is necessary because filesystems generally support Unicode these days, but on Windows you need to use a separate set of wide-character file I/O functions. (On Linux it all works with "narrow" strings, and the UTF-8 encoding is interpreted by applications.) The character set used for NuFX archive filenames is MOR, matching what GS/OS + HFS supported, and we want to be able to convert back and forth between MOR and a Unicode representation. This change updates the various character types and string names, adds conversion functions, and updates NuLib2 for proper execution on Linux. It does not include the (probably extensive) changes required for Windows UTF-16 support. Instead, the conversion functions are no-ops, which should result in NuLib2 for Windows continuing to behave in the same slightly broken way. This adds "test-names", which exercises Unicode filenames a bit. It will not pass on Win32. Also, tweaked the Linux makefiles to have explicit dependencies, rather than empty space and an expectation that "makedepend" exists. Also, minor source code cleanups. While this probably doesn't affect binary compatibility -- it's mainly a matter of naming and string interpretation -- there's enough going on that it should be considered an API revision, so this updates the version to 3.0.0.
2014-12-24 19:14:32 +00:00
if (pRecord->filenameMOR != NULL) {
DBUG(("--- HEY: got record filename and thread filename\n"));
}
Distinguish Unicode and Mac OS Roman strings NufxLib has historically made no effort to distinguish between the character set used for filenames on the local disk, and for filenames stored within the archive. Now all Unicode filename strings use the UNICHAR type and have "UNI" in the name, and all Mac OS Roman strings have "MOR" in the name. (The naming convention makes it obvious when you're assigning the wrong thing; on Linux both formats are char*, so the compiler won't tell you if you get it wrong.) The distinction is necessary because filesystems generally support Unicode these days, but on Windows you need to use a separate set of wide-character file I/O functions. (On Linux it all works with "narrow" strings, and the UTF-8 encoding is interpreted by applications.) The character set used for NuFX archive filenames is MOR, matching what GS/OS + HFS supported, and we want to be able to convert back and forth between MOR and a Unicode representation. This change updates the various character types and string names, adds conversion functions, and updates NuLib2 for proper execution on Linux. It does not include the (probably extensive) changes required for Windows UTF-16 support. Instead, the conversion functions are no-ops, which should result in NuLib2 for Windows continuing to behave in the same slightly broken way. This adds "test-names", which exercises Unicode filenames a bit. It will not pass on Win32. Also, tweaked the Linux makefiles to have explicit dependencies, rather than empty space and an expectation that "makedepend" exists. Also, minor source code cleanups. While this probably doesn't affect binary compatibility -- it's mainly a matter of naming and string interpretation -- there's enough going on that it should be considered an API revision, so this updates the version to 3.0.0.
2014-12-24 19:14:32 +00:00
pRecord->filenameMOR = pRecord->threadFilenameMOR;
} else {
/* not a filename (or not first filename), skip past it */
err = Nu_SeekArchive(pArchive, pArchive->archiveFp,
pThread->thCompThreadEOF, SEEK_CUR);
BailError(err);
}
pThread++;
}
/*
* Should've had one by now. Supposedly, older versions of ShrinkIt
* wouldn't prompt for a disk image name on DOS 3.3 volumes, so you'd
* end up with a disk image that had no name attached. This will tend
* to confuse things, so we go ahead and give it a name.
*/
Distinguish Unicode and Mac OS Roman strings NufxLib has historically made no effort to distinguish between the character set used for filenames on the local disk, and for filenames stored within the archive. Now all Unicode filename strings use the UNICHAR type and have "UNI" in the name, and all Mac OS Roman strings have "MOR" in the name. (The naming convention makes it obvious when you're assigning the wrong thing; on Linux both formats are char*, so the compiler won't tell you if you get it wrong.) The distinction is necessary because filesystems generally support Unicode these days, but on Windows you need to use a separate set of wide-character file I/O functions. (On Linux it all works with "narrow" strings, and the UTF-8 encoding is interpreted by applications.) The character set used for NuFX archive filenames is MOR, matching what GS/OS + HFS supported, and we want to be able to convert back and forth between MOR and a Unicode representation. This change updates the various character types and string names, adds conversion functions, and updates NuLib2 for proper execution on Linux. It does not include the (probably extensive) changes required for Windows UTF-16 support. Instead, the conversion functions are no-ops, which should result in NuLib2 for Windows continuing to behave in the same slightly broken way. This adds "test-names", which exercises Unicode filenames a bit. It will not pass on Win32. Also, tweaked the Linux makefiles to have explicit dependencies, rather than empty space and an expectation that "makedepend" exists. Also, minor source code cleanups. While this probably doesn't affect binary compatibility -- it's mainly a matter of naming and string interpretation -- there's enough going on that it should be considered an API revision, so this updates the version to 3.0.0.
2014-12-24 19:14:32 +00:00
if (pRecord->filenameMOR == NULL) {
DBUG(("+++ no filename found, using default record name\n"));
Distinguish Unicode and Mac OS Roman strings NufxLib has historically made no effort to distinguish between the character set used for filenames on the local disk, and for filenames stored within the archive. Now all Unicode filename strings use the UNICHAR type and have "UNI" in the name, and all Mac OS Roman strings have "MOR" in the name. (The naming convention makes it obvious when you're assigning the wrong thing; on Linux both formats are char*, so the compiler won't tell you if you get it wrong.) The distinction is necessary because filesystems generally support Unicode these days, but on Windows you need to use a separate set of wide-character file I/O functions. (On Linux it all works with "narrow" strings, and the UTF-8 encoding is interpreted by applications.) The character set used for NuFX archive filenames is MOR, matching what GS/OS + HFS supported, and we want to be able to convert back and forth between MOR and a Unicode representation. This change updates the various character types and string names, adds conversion functions, and updates NuLib2 for proper execution on Linux. It does not include the (probably extensive) changes required for Windows UTF-16 support. Instead, the conversion functions are no-ops, which should result in NuLib2 for Windows continuing to behave in the same slightly broken way. This adds "test-names", which exercises Unicode filenames a bit. It will not pass on Win32. Also, tweaked the Linux makefiles to have explicit dependencies, rather than empty space and an expectation that "makedepend" exists. Also, minor source code cleanups. While this probably doesn't affect binary compatibility -- it's mainly a matter of naming and string interpretation -- there's enough going on that it should be considered an API revision, so this updates the version to 3.0.0.
2014-12-24 19:14:32 +00:00
pRecord->filenameMOR = kNuDefaultRecordName;
}
pArchive->currentOffset += pRecord->totalCompLength;
if (!Nu_IsStreaming(pArchive)) {
Assert(pArchive->currentOffset == ftell(pArchive->archiveFp));
}
2000-05-23 01:55:31 +00:00
bail:
return err;
2000-05-23 01:55:31 +00:00
}
/*
* Skip the thread. This only has meaning for streaming archives, and
* assumes that the file pointer is set to the start of the thread's data
* already.
*/
NuError Nu_SkipThread(NuArchive* pArchive, const NuRecord* pRecord,
const NuThread* pThread)
2000-05-23 01:55:31 +00:00
{
NuError err;
2000-05-23 01:55:31 +00:00
if (!Nu_IsStreaming(pArchive)) /* for debugging */
return kNuErrNone; /* for debugging */
Assert(Nu_IsStreaming(pArchive));
2000-05-23 01:55:31 +00:00
err = Nu_SeekArchive(pArchive, pArchive->archiveFp,
pThread->thCompThreadEOF, SEEK_CUR);
return err;
2000-05-23 01:55:31 +00:00
}
/*
* ===========================================================================
* Extract
2000-05-23 01:55:31 +00:00
* ===========================================================================
*/
/*
* Extract the thread to the specified file pointer.
*
* If the archive is a stream, the stream must be positioned at the
* start of pThread's data. If not, it will be seeked first.
*/
static NuError Nu_ExtractThreadToDataSink(NuArchive* pArchive,
const NuRecord* pRecord, const NuThread* pThread,
NuProgressData* pProgress, NuDataSink* pDataSink)
2000-05-23 01:55:31 +00:00
{
NuError err;
2014-12-22 02:17:23 +00:00
NuFunnel* pFunnel = NULL;
/* if it's not a stream, seek to the appropriate spot in the file */
if (!Nu_IsStreaming(pArchive)) {
err = Nu_SeekArchive(pArchive, pArchive->archiveFp,
pThread->fileOffset, SEEK_SET);
if (err != kNuErrNone) {
Nu_ReportError(NU_BLOB, err, "Unable to seek input to %ld",
pThread->fileOffset);
goto bail;
}
}
/*
* Set up an output funnel to write to.
*/
err = Nu_FunnelNew(pArchive, pDataSink, Nu_DataSinkGetConvertEOL(pDataSink),
pArchive->valEOL, pProgress, &pFunnel);
BailError(err);
/*
* Write it.
*/
err = Nu_ExpandStream(pArchive, pRecord, pThread, pArchive->archiveFp,
pFunnel);
if (err != kNuErrNone) {
if (err != kNuErrSkipped && err != kNuErrAborted)
Nu_ReportError(NU_BLOB, err, "ExpandStream failed");
goto bail;
}
2000-05-23 01:55:31 +00:00
bail:
(void) Nu_FunnelFree(pArchive, pFunnel);
return err;
2000-05-23 01:55:31 +00:00
}
/*
* Extract the specified thread to "pDataSink". If the sink is to a file,
* this will take care of opening (and, if appropriate, creating) the file.
*
* If we're operating on a streaming archive, the file pointer must be
* positioned at the start of the thread's data. If not, it will be
* seeked appropriately.
*
* This calls the "should we extract" and "what pathname should we use"
* filters for every thread, which means we can reject specific kinds
* of forks and/or give them different names. This is a good thing.
*/
static NuError Nu_ExtractThreadCommon(NuArchive* pArchive,
const NuRecord* pRecord, const NuThread* pThread, NuDataSink* pDataSink)
2000-05-23 01:55:31 +00:00
{
NuError err = kNuErrNone;
NuSelectionProposal selProposal;
NuPathnameProposal pathProposal;
NuProgressData progressData;
NuProgressData* pProgressData;
NuDataSink* pOrigDataSink;
Distinguish Unicode and Mac OS Roman strings NufxLib has historically made no effort to distinguish between the character set used for filenames on the local disk, and for filenames stored within the archive. Now all Unicode filename strings use the UNICHAR type and have "UNI" in the name, and all Mac OS Roman strings have "MOR" in the name. (The naming convention makes it obvious when you're assigning the wrong thing; on Linux both formats are char*, so the compiler won't tell you if you get it wrong.) The distinction is necessary because filesystems generally support Unicode these days, but on Windows you need to use a separate set of wide-character file I/O functions. (On Linux it all works with "narrow" strings, and the UTF-8 encoding is interpreted by applications.) The character set used for NuFX archive filenames is MOR, matching what GS/OS + HFS supported, and we want to be able to convert back and forth between MOR and a Unicode representation. This change updates the various character types and string names, adds conversion functions, and updates NuLib2 for proper execution on Linux. It does not include the (probably extensive) changes required for Windows UTF-16 support. Instead, the conversion functions are no-ops, which should result in NuLib2 for Windows continuing to behave in the same slightly broken way. This adds "test-names", which exercises Unicode filenames a bit. It will not pass on Win32. Also, tweaked the Linux makefiles to have explicit dependencies, rather than empty space and an expectation that "makedepend" exists. Also, minor source code cleanups. While this probably doesn't affect binary compatibility -- it's mainly a matter of naming and string interpretation -- there's enough going on that it should be considered an API revision, so this updates the version to 3.0.0.
2014-12-24 19:14:32 +00:00
UNICHAR* newPathStorageUNI = NULL;
UNICHAR* recFilenameStorageUNI = NULL;
const UNICHAR* newPathnameUNI;
NuResult result;
uint8_t newFssep;
Boolean doFreeSink = false;
2014-12-22 02:17:23 +00:00
Assert(pRecord != NULL);
Assert(pThread != NULL);
Assert(pDataSink != NULL);
memset(&progressData, 0, sizeof(progressData));
2014-12-22 02:17:23 +00:00
pProgressData = NULL;
/*
* If we're just trying to verify the archive contents, create a
* data sink that goes nowhere at all.
*/
if (pArchive->testMode) {
err = Nu_DataSinkVoid_New(
Nu_DataSinkGetDoExpand(pDataSink),
Nu_DataSinkGetConvertEOL(pDataSink),
&pDataSink);
BailError(err);
doFreeSink = true;
}
pOrigDataSink = pDataSink; /* save a copy for the "retry" loop */
/*
* Decide if we want to extract this thread. This is mostly for
* use by the "bulk" extract, not the per-thread extract, but it
* still applies if they so desire.
*/
2014-12-22 02:17:23 +00:00
if (pArchive->selectionFilterFunc != NULL) {
selProposal.pRecord = pRecord;
selProposal.pThread = pThread;
result = (*pArchive->selectionFilterFunc)(pArchive, &selProposal);
if (result == kNuSkip)
return Nu_SkipThread(pArchive, pRecord, pThread);
if (result == kNuAbort) {
err = kNuErrAborted;
goto bail;
}
}
Distinguish Unicode and Mac OS Roman strings NufxLib has historically made no effort to distinguish between the character set used for filenames on the local disk, and for filenames stored within the archive. Now all Unicode filename strings use the UNICHAR type and have "UNI" in the name, and all Mac OS Roman strings have "MOR" in the name. (The naming convention makes it obvious when you're assigning the wrong thing; on Linux both formats are char*, so the compiler won't tell you if you get it wrong.) The distinction is necessary because filesystems generally support Unicode these days, but on Windows you need to use a separate set of wide-character file I/O functions. (On Linux it all works with "narrow" strings, and the UTF-8 encoding is interpreted by applications.) The character set used for NuFX archive filenames is MOR, matching what GS/OS + HFS supported, and we want to be able to convert back and forth between MOR and a Unicode representation. This change updates the various character types and string names, adds conversion functions, and updates NuLib2 for proper execution on Linux. It does not include the (probably extensive) changes required for Windows UTF-16 support. Instead, the conversion functions are no-ops, which should result in NuLib2 for Windows continuing to behave in the same slightly broken way. This adds "test-names", which exercises Unicode filenames a bit. It will not pass on Win32. Also, tweaked the Linux makefiles to have explicit dependencies, rather than empty space and an expectation that "makedepend" exists. Also, minor source code cleanups. While this probably doesn't affect binary compatibility -- it's mainly a matter of naming and string interpretation -- there's enough going on that it should be considered an API revision, so this updates the version to 3.0.0.
2014-12-24 19:14:32 +00:00
newPathnameUNI = NULL;
newFssep = 0;
2000-05-23 01:55:31 +00:00
Distinguish Unicode and Mac OS Roman strings NufxLib has historically made no effort to distinguish between the character set used for filenames on the local disk, and for filenames stored within the archive. Now all Unicode filename strings use the UNICHAR type and have "UNI" in the name, and all Mac OS Roman strings have "MOR" in the name. (The naming convention makes it obvious when you're assigning the wrong thing; on Linux both formats are char*, so the compiler won't tell you if you get it wrong.) The distinction is necessary because filesystems generally support Unicode these days, but on Windows you need to use a separate set of wide-character file I/O functions. (On Linux it all works with "narrow" strings, and the UTF-8 encoding is interpreted by applications.) The character set used for NuFX archive filenames is MOR, matching what GS/OS + HFS supported, and we want to be able to convert back and forth between MOR and a Unicode representation. This change updates the various character types and string names, adds conversion functions, and updates NuLib2 for proper execution on Linux. It does not include the (probably extensive) changes required for Windows UTF-16 support. Instead, the conversion functions are no-ops, which should result in NuLib2 for Windows continuing to behave in the same slightly broken way. This adds "test-names", which exercises Unicode filenames a bit. It will not pass on Win32. Also, tweaked the Linux makefiles to have explicit dependencies, rather than empty space and an expectation that "makedepend" exists. Also, minor source code cleanups. While this probably doesn't affect binary compatibility -- it's mainly a matter of naming and string interpretation -- there's enough going on that it should be considered an API revision, so this updates the version to 3.0.0.
2014-12-24 19:14:32 +00:00
recFilenameStorageUNI = Nu_CopyMORToUNI(pRecord->filenameMOR);
2000-05-23 01:55:31 +00:00
retry_name:
if (Nu_DataSinkGetType(pDataSink) == kNuDataSinkToFile) {
/*
* We're extracting. Figure out the name of the file to write it to.
* If they want to use the sleazy FILE* back door, create a new
* data sink and use that instead.
*
* Start by resetting everything to defaults, in case this isn't
* our first time through the "rename" loop.
*/
Distinguish Unicode and Mac OS Roman strings NufxLib has historically made no effort to distinguish between the character set used for filenames on the local disk, and for filenames stored within the archive. Now all Unicode filename strings use the UNICHAR type and have "UNI" in the name, and all Mac OS Roman strings have "MOR" in the name. (The naming convention makes it obvious when you're assigning the wrong thing; on Linux both formats are char*, so the compiler won't tell you if you get it wrong.) The distinction is necessary because filesystems generally support Unicode these days, but on Windows you need to use a separate set of wide-character file I/O functions. (On Linux it all works with "narrow" strings, and the UTF-8 encoding is interpreted by applications.) The character set used for NuFX archive filenames is MOR, matching what GS/OS + HFS supported, and we want to be able to convert back and forth between MOR and a Unicode representation. This change updates the various character types and string names, adds conversion functions, and updates NuLib2 for proper execution on Linux. It does not include the (probably extensive) changes required for Windows UTF-16 support. Instead, the conversion functions are no-ops, which should result in NuLib2 for Windows continuing to behave in the same slightly broken way. This adds "test-names", which exercises Unicode filenames a bit. It will not pass on Win32. Also, tweaked the Linux makefiles to have explicit dependencies, rather than empty space and an expectation that "makedepend" exists. Also, minor source code cleanups. While this probably doesn't affect binary compatibility -- it's mainly a matter of naming and string interpretation -- there's enough going on that it should be considered an API revision, so this updates the version to 3.0.0.
2014-12-24 19:14:32 +00:00
newPathnameUNI = Nu_DataSinkFile_GetPathname(pDataSink);
newFssep = Nu_DataSinkFile_GetFssep(pDataSink);
pDataSink = pOrigDataSink;
/* if they don't have a pathname func defined, we just use default */
2014-12-22 02:17:23 +00:00
if (pArchive->outputPathnameFunc != NULL) {
Distinguish Unicode and Mac OS Roman strings NufxLib has historically made no effort to distinguish between the character set used for filenames on the local disk, and for filenames stored within the archive. Now all Unicode filename strings use the UNICHAR type and have "UNI" in the name, and all Mac OS Roman strings have "MOR" in the name. (The naming convention makes it obvious when you're assigning the wrong thing; on Linux both formats are char*, so the compiler won't tell you if you get it wrong.) The distinction is necessary because filesystems generally support Unicode these days, but on Windows you need to use a separate set of wide-character file I/O functions. (On Linux it all works with "narrow" strings, and the UTF-8 encoding is interpreted by applications.) The character set used for NuFX archive filenames is MOR, matching what GS/OS + HFS supported, and we want to be able to convert back and forth between MOR and a Unicode representation. This change updates the various character types and string names, adds conversion functions, and updates NuLib2 for proper execution on Linux. It does not include the (probably extensive) changes required for Windows UTF-16 support. Instead, the conversion functions are no-ops, which should result in NuLib2 for Windows continuing to behave in the same slightly broken way. This adds "test-names", which exercises Unicode filenames a bit. It will not pass on Win32. Also, tweaked the Linux makefiles to have explicit dependencies, rather than empty space and an expectation that "makedepend" exists. Also, minor source code cleanups. While this probably doesn't affect binary compatibility -- it's mainly a matter of naming and string interpretation -- there's enough going on that it should be considered an API revision, so this updates the version to 3.0.0.
2014-12-24 19:14:32 +00:00
pathProposal.pathnameUNI = recFilenameStorageUNI;
pathProposal.filenameSeparator =
NuGetSepFromSysInfo(pRecord->recFileSysInfo);
pathProposal.pRecord = pRecord;
pathProposal.pThread = pThread;
Distinguish Unicode and Mac OS Roman strings NufxLib has historically made no effort to distinguish between the character set used for filenames on the local disk, and for filenames stored within the archive. Now all Unicode filename strings use the UNICHAR type and have "UNI" in the name, and all Mac OS Roman strings have "MOR" in the name. (The naming convention makes it obvious when you're assigning the wrong thing; on Linux both formats are char*, so the compiler won't tell you if you get it wrong.) The distinction is necessary because filesystems generally support Unicode these days, but on Windows you need to use a separate set of wide-character file I/O functions. (On Linux it all works with "narrow" strings, and the UTF-8 encoding is interpreted by applications.) The character set used for NuFX archive filenames is MOR, matching what GS/OS + HFS supported, and we want to be able to convert back and forth between MOR and a Unicode representation. This change updates the various character types and string names, adds conversion functions, and updates NuLib2 for proper execution on Linux. It does not include the (probably extensive) changes required for Windows UTF-16 support. Instead, the conversion functions are no-ops, which should result in NuLib2 for Windows continuing to behave in the same slightly broken way. This adds "test-names", which exercises Unicode filenames a bit. It will not pass on Win32. Also, tweaked the Linux makefiles to have explicit dependencies, rather than empty space and an expectation that "makedepend" exists. Also, minor source code cleanups. While this probably doesn't affect binary compatibility -- it's mainly a matter of naming and string interpretation -- there's enough going on that it should be considered an API revision, so this updates the version to 3.0.0.
2014-12-24 19:14:32 +00:00
pathProposal.newPathnameUNI = NULL;
pathProposal.newFilenameSeparator = '\0';
/*pathProposal.newStorage = (NuThreadID)-1;*/
2014-12-22 02:17:23 +00:00
pathProposal.newDataSink = NULL;
result = (*pArchive->outputPathnameFunc)(pArchive, &pathProposal);
if (result == kNuSkip)
return Nu_SkipThread(pArchive, pRecord, pThread);
if (result == kNuAbort) {
err = kNuErrAborted;
goto bail;
}
/* we don't own this string, so make a copy */
Distinguish Unicode and Mac OS Roman strings NufxLib has historically made no effort to distinguish between the character set used for filenames on the local disk, and for filenames stored within the archive. Now all Unicode filename strings use the UNICHAR type and have "UNI" in the name, and all Mac OS Roman strings have "MOR" in the name. (The naming convention makes it obvious when you're assigning the wrong thing; on Linux both formats are char*, so the compiler won't tell you if you get it wrong.) The distinction is necessary because filesystems generally support Unicode these days, but on Windows you need to use a separate set of wide-character file I/O functions. (On Linux it all works with "narrow" strings, and the UTF-8 encoding is interpreted by applications.) The character set used for NuFX archive filenames is MOR, matching what GS/OS + HFS supported, and we want to be able to convert back and forth between MOR and a Unicode representation. This change updates the various character types and string names, adds conversion functions, and updates NuLib2 for proper execution on Linux. It does not include the (probably extensive) changes required for Windows UTF-16 support. Instead, the conversion functions are no-ops, which should result in NuLib2 for Windows continuing to behave in the same slightly broken way. This adds "test-names", which exercises Unicode filenames a bit. It will not pass on Win32. Also, tweaked the Linux makefiles to have explicit dependencies, rather than empty space and an expectation that "makedepend" exists. Also, minor source code cleanups. While this probably doesn't affect binary compatibility -- it's mainly a matter of naming and string interpretation -- there's enough going on that it should be considered an API revision, so this updates the version to 3.0.0.
2014-12-24 19:14:32 +00:00
if (pathProposal.newPathnameUNI != NULL) {
Nu_Free(pArchive, newPathStorageUNI);
newPathStorageUNI = strdup(pathProposal.newPathnameUNI);
newPathnameUNI = newPathStorageUNI;
} else {
newPathnameUNI = NULL;
}
if (pathProposal.newFilenameSeparator != '\0')
newFssep = pathProposal.newFilenameSeparator;
/* if they want to send this somewhere else, let them */
2014-12-22 02:17:23 +00:00
if (pathProposal.newDataSink != NULL)
pDataSink = pathProposal.newDataSink;
}
/* at least one of these must be set */
Distinguish Unicode and Mac OS Roman strings NufxLib has historically made no effort to distinguish between the character set used for filenames on the local disk, and for filenames stored within the archive. Now all Unicode filename strings use the UNICHAR type and have "UNI" in the name, and all Mac OS Roman strings have "MOR" in the name. (The naming convention makes it obvious when you're assigning the wrong thing; on Linux both formats are char*, so the compiler won't tell you if you get it wrong.) The distinction is necessary because filesystems generally support Unicode these days, but on Windows you need to use a separate set of wide-character file I/O functions. (On Linux it all works with "narrow" strings, and the UTF-8 encoding is interpreted by applications.) The character set used for NuFX archive filenames is MOR, matching what GS/OS + HFS supported, and we want to be able to convert back and forth between MOR and a Unicode representation. This change updates the various character types and string names, adds conversion functions, and updates NuLib2 for proper execution on Linux. It does not include the (probably extensive) changes required for Windows UTF-16 support. Instead, the conversion functions are no-ops, which should result in NuLib2 for Windows continuing to behave in the same slightly broken way. This adds "test-names", which exercises Unicode filenames a bit. It will not pass on Win32. Also, tweaked the Linux makefiles to have explicit dependencies, rather than empty space and an expectation that "makedepend" exists. Also, minor source code cleanups. While this probably doesn't affect binary compatibility -- it's mainly a matter of naming and string interpretation -- there's enough going on that it should be considered an API revision, so this updates the version to 3.0.0.
2014-12-24 19:14:32 +00:00
Assert(!(newPathnameUNI == NULL && pathProposal.newDataSink == NULL));
}
/*
* Prepare the progress data if this is a data thread.
*/
Distinguish Unicode and Mac OS Roman strings NufxLib has historically made no effort to distinguish between the character set used for filenames on the local disk, and for filenames stored within the archive. Now all Unicode filename strings use the UNICHAR type and have "UNI" in the name, and all Mac OS Roman strings have "MOR" in the name. (The naming convention makes it obvious when you're assigning the wrong thing; on Linux both formats are char*, so the compiler won't tell you if you get it wrong.) The distinction is necessary because filesystems generally support Unicode these days, but on Windows you need to use a separate set of wide-character file I/O functions. (On Linux it all works with "narrow" strings, and the UTF-8 encoding is interpreted by applications.) The character set used for NuFX archive filenames is MOR, matching what GS/OS + HFS supported, and we want to be able to convert back and forth between MOR and a Unicode representation. This change updates the various character types and string names, adds conversion functions, and updates NuLib2 for proper execution on Linux. It does not include the (probably extensive) changes required for Windows UTF-16 support. Instead, the conversion functions are no-ops, which should result in NuLib2 for Windows continuing to behave in the same slightly broken way. This adds "test-names", which exercises Unicode filenames a bit. It will not pass on Win32. Also, tweaked the Linux makefiles to have explicit dependencies, rather than empty space and an expectation that "makedepend" exists. Also, minor source code cleanups. While this probably doesn't affect binary compatibility -- it's mainly a matter of naming and string interpretation -- there's enough going on that it should be considered an API revision, so this updates the version to 3.0.0.
2014-12-24 19:14:32 +00:00
if (newPathnameUNI == NULL) {
/* using a data sink; get the pathname out of the record */
Distinguish Unicode and Mac OS Roman strings NufxLib has historically made no effort to distinguish between the character set used for filenames on the local disk, and for filenames stored within the archive. Now all Unicode filename strings use the UNICHAR type and have "UNI" in the name, and all Mac OS Roman strings have "MOR" in the name. (The naming convention makes it obvious when you're assigning the wrong thing; on Linux both formats are char*, so the compiler won't tell you if you get it wrong.) The distinction is necessary because filesystems generally support Unicode these days, but on Windows you need to use a separate set of wide-character file I/O functions. (On Linux it all works with "narrow" strings, and the UTF-8 encoding is interpreted by applications.) The character set used for NuFX archive filenames is MOR, matching what GS/OS + HFS supported, and we want to be able to convert back and forth between MOR and a Unicode representation. This change updates the various character types and string names, adds conversion functions, and updates NuLib2 for proper execution on Linux. It does not include the (probably extensive) changes required for Windows UTF-16 support. Instead, the conversion functions are no-ops, which should result in NuLib2 for Windows continuing to behave in the same slightly broken way. This adds "test-names", which exercises Unicode filenames a bit. It will not pass on Win32. Also, tweaked the Linux makefiles to have explicit dependencies, rather than empty space and an expectation that "makedepend" exists. Also, minor source code cleanups. While this probably doesn't affect binary compatibility -- it's mainly a matter of naming and string interpretation -- there's enough going on that it should be considered an API revision, so this updates the version to 3.0.0.
2014-12-24 19:14:32 +00:00
newPathnameUNI = recFilenameStorageUNI;
newFssep = NuGetSepFromSysInfo(pRecord->recFileSysInfo);
}
if (pThread->thThreadClass == kNuThreadClassData) {
pProgressData = &progressData;
err = Nu_ProgressDataInit_Expand(pArchive, pProgressData, pRecord,
Distinguish Unicode and Mac OS Roman strings NufxLib has historically made no effort to distinguish between the character set used for filenames on the local disk, and for filenames stored within the archive. Now all Unicode filename strings use the UNICHAR type and have "UNI" in the name, and all Mac OS Roman strings have "MOR" in the name. (The naming convention makes it obvious when you're assigning the wrong thing; on Linux both formats are char*, so the compiler won't tell you if you get it wrong.) The distinction is necessary because filesystems generally support Unicode these days, but on Windows you need to use a separate set of wide-character file I/O functions. (On Linux it all works with "narrow" strings, and the UTF-8 encoding is interpreted by applications.) The character set used for NuFX archive filenames is MOR, matching what GS/OS + HFS supported, and we want to be able to convert back and forth between MOR and a Unicode representation. This change updates the various character types and string names, adds conversion functions, and updates NuLib2 for proper execution on Linux. It does not include the (probably extensive) changes required for Windows UTF-16 support. Instead, the conversion functions are no-ops, which should result in NuLib2 for Windows continuing to behave in the same slightly broken way. This adds "test-names", which exercises Unicode filenames a bit. It will not pass on Win32. Also, tweaked the Linux makefiles to have explicit dependencies, rather than empty space and an expectation that "makedepend" exists. Also, minor source code cleanups. While this probably doesn't affect binary compatibility -- it's mainly a matter of naming and string interpretation -- there's enough going on that it should be considered an API revision, so this updates the version to 3.0.0.
2014-12-24 19:14:32 +00:00
newPathnameUNI, newFssep, recFilenameStorageUNI,
Nu_DataSinkGetConvertEOL(pOrigDataSink));
BailError(err);
/* send initial progress so they see the right name if "open" fails */
pProgressData->state = kNuProgressOpening;
err = Nu_SendInitialProgress(pArchive, pProgressData);
BailError(err);
}
if (Nu_DataSinkGetType(pDataSink) == kNuDataSinkToFile) {
/*
* We're extracting to a file. Open it, creating it if necessary and
* allowed.
*/
2014-12-22 02:17:23 +00:00
FILE* fileFp = NULL;
Distinguish Unicode and Mac OS Roman strings NufxLib has historically made no effort to distinguish between the character set used for filenames on the local disk, and for filenames stored within the archive. Now all Unicode filename strings use the UNICHAR type and have "UNI" in the name, and all Mac OS Roman strings have "MOR" in the name. (The naming convention makes it obvious when you're assigning the wrong thing; on Linux both formats are char*, so the compiler won't tell you if you get it wrong.) The distinction is necessary because filesystems generally support Unicode these days, but on Windows you need to use a separate set of wide-character file I/O functions. (On Linux it all works with "narrow" strings, and the UTF-8 encoding is interpreted by applications.) The character set used for NuFX archive filenames is MOR, matching what GS/OS + HFS supported, and we want to be able to convert back and forth between MOR and a Unicode representation. This change updates the various character types and string names, adds conversion functions, and updates NuLib2 for proper execution on Linux. It does not include the (probably extensive) changes required for Windows UTF-16 support. Instead, the conversion functions are no-ops, which should result in NuLib2 for Windows continuing to behave in the same slightly broken way. This adds "test-names", which exercises Unicode filenames a bit. It will not pass on Win32. Also, tweaked the Linux makefiles to have explicit dependencies, rather than empty space and an expectation that "makedepend" exists. Also, minor source code cleanups. While this probably doesn't affect binary compatibility -- it's mainly a matter of naming and string interpretation -- there's enough going on that it should be considered an API revision, so this updates the version to 3.0.0.
2014-12-24 19:14:32 +00:00
err = Nu_OpenOutputFile(pArchive, pRecord, pThread, newPathnameUNI,
newFssep, &fileFp);
if (err == kNuErrRename) {
/* they want to rename; the OutputPathname callback handles this */
Distinguish Unicode and Mac OS Roman strings NufxLib has historically made no effort to distinguish between the character set used for filenames on the local disk, and for filenames stored within the archive. Now all Unicode filename strings use the UNICHAR type and have "UNI" in the name, and all Mac OS Roman strings have "MOR" in the name. (The naming convention makes it obvious when you're assigning the wrong thing; on Linux both formats are char*, so the compiler won't tell you if you get it wrong.) The distinction is necessary because filesystems generally support Unicode these days, but on Windows you need to use a separate set of wide-character file I/O functions. (On Linux it all works with "narrow" strings, and the UTF-8 encoding is interpreted by applications.) The character set used for NuFX archive filenames is MOR, matching what GS/OS + HFS supported, and we want to be able to convert back and forth between MOR and a Unicode representation. This change updates the various character types and string names, adds conversion functions, and updates NuLib2 for proper execution on Linux. It does not include the (probably extensive) changes required for Windows UTF-16 support. Instead, the conversion functions are no-ops, which should result in NuLib2 for Windows continuing to behave in the same slightly broken way. This adds "test-names", which exercises Unicode filenames a bit. It will not pass on Win32. Also, tweaked the Linux makefiles to have explicit dependencies, rather than empty space and an expectation that "makedepend" exists. Also, minor source code cleanups. While this probably doesn't affect binary compatibility -- it's mainly a matter of naming and string interpretation -- there's enough going on that it should be considered an API revision, so this updates the version to 3.0.0.
2014-12-24 19:14:32 +00:00
Nu_Free(pArchive, newPathStorageUNI);
newPathStorageUNI = NULL;
/* reset these just to be careful */
Distinguish Unicode and Mac OS Roman strings NufxLib has historically made no effort to distinguish between the character set used for filenames on the local disk, and for filenames stored within the archive. Now all Unicode filename strings use the UNICHAR type and have "UNI" in the name, and all Mac OS Roman strings have "MOR" in the name. (The naming convention makes it obvious when you're assigning the wrong thing; on Linux both formats are char*, so the compiler won't tell you if you get it wrong.) The distinction is necessary because filesystems generally support Unicode these days, but on Windows you need to use a separate set of wide-character file I/O functions. (On Linux it all works with "narrow" strings, and the UTF-8 encoding is interpreted by applications.) The character set used for NuFX archive filenames is MOR, matching what GS/OS + HFS supported, and we want to be able to convert back and forth between MOR and a Unicode representation. This change updates the various character types and string names, adds conversion functions, and updates NuLib2 for proper execution on Linux. It does not include the (probably extensive) changes required for Windows UTF-16 support. Instead, the conversion functions are no-ops, which should result in NuLib2 for Windows continuing to behave in the same slightly broken way. This adds "test-names", which exercises Unicode filenames a bit. It will not pass on Win32. Also, tweaked the Linux makefiles to have explicit dependencies, rather than empty space and an expectation that "makedepend" exists. Also, minor source code cleanups. While this probably doesn't affect binary compatibility -- it's mainly a matter of naming and string interpretation -- there's enough going on that it should be considered an API revision, so this updates the version to 3.0.0.
2014-12-24 19:14:32 +00:00
newPathnameUNI = NULL;
2014-12-22 02:17:23 +00:00
fileFp = NULL;
goto retry_name;
} else if (err != kNuErrNone) {
goto bail;
}
2014-12-22 02:17:23 +00:00
Assert(fileFp != NULL);
(void) Nu_DataSinkFile_SetFP(pDataSink, fileFp);
DBUG(("+++ EXTRACTING 0x%08lx from '%s' at offset %0ld to '%s'\n",
NuMakeThreadID(pThread->thThreadClass, pThread->thThreadKind),
pRecord->filename, pThread->fileOffset, newPathname));
} else {
DBUG(("+++ EXTRACTING 0x%08lx from '%s' at offset %0ld to sink\n",
NuMakeThreadID(pThread->thThreadClass, pThread->thThreadKind),
pRecord->filename, pThread->fileOffset));
}
/* extract to the file */
err = Nu_ExtractThreadToDataSink(pArchive, pRecord, pThread,
pProgressData, pDataSink);
BailError(err);
if (Nu_DataSinkGetType(pDataSink) == kNuDataSinkToFile) {
/*
* Close the file, adjusting the modification date and access
* permissions as appropriate.
*/
err = Nu_CloseOutputFile(pArchive, pRecord,
Distinguish Unicode and Mac OS Roman strings NufxLib has historically made no effort to distinguish between the character set used for filenames on the local disk, and for filenames stored within the archive. Now all Unicode filename strings use the UNICHAR type and have "UNI" in the name, and all Mac OS Roman strings have "MOR" in the name. (The naming convention makes it obvious when you're assigning the wrong thing; on Linux both formats are char*, so the compiler won't tell you if you get it wrong.) The distinction is necessary because filesystems generally support Unicode these days, but on Windows you need to use a separate set of wide-character file I/O functions. (On Linux it all works with "narrow" strings, and the UTF-8 encoding is interpreted by applications.) The character set used for NuFX archive filenames is MOR, matching what GS/OS + HFS supported, and we want to be able to convert back and forth between MOR and a Unicode representation. This change updates the various character types and string names, adds conversion functions, and updates NuLib2 for proper execution on Linux. It does not include the (probably extensive) changes required for Windows UTF-16 support. Instead, the conversion functions are no-ops, which should result in NuLib2 for Windows continuing to behave in the same slightly broken way. This adds "test-names", which exercises Unicode filenames a bit. It will not pass on Win32. Also, tweaked the Linux makefiles to have explicit dependencies, rather than empty space and an expectation that "makedepend" exists. Also, minor source code cleanups. While this probably doesn't affect binary compatibility -- it's mainly a matter of naming and string interpretation -- there's enough going on that it should be considered an API revision, so this updates the version to 3.0.0.
2014-12-24 19:14:32 +00:00
Nu_DataSinkFile_GetFP(pDataSink), newPathnameUNI);
2014-12-22 02:17:23 +00:00
Nu_DataSinkFile_SetFP(pDataSink, NULL);
BailError(err);
}
2000-05-23 01:55:31 +00:00
bail:
2014-12-22 02:17:23 +00:00
if (err != kNuErrNone && pProgressData != NULL) {
/* send a final progress message, indicating failure */
if (err == kNuErrSkipped)
pProgressData->state = kNuProgressSkipped;
else if (err == kNuErrAborted)
pProgressData->state = kNuProgressAborted;
else
pProgressData->state = kNuProgressFailed;
(void) Nu_SendInitialProgress(pArchive, pProgressData);
}
/* if this was an ordinary file, and it's still open, close it */
if (Nu_DataSinkGetType(pDataSink) == kNuDataSinkToFile)
Nu_DataSinkFile_Close(pDataSink);
Distinguish Unicode and Mac OS Roman strings NufxLib has historically made no effort to distinguish between the character set used for filenames on the local disk, and for filenames stored within the archive. Now all Unicode filename strings use the UNICHAR type and have "UNI" in the name, and all Mac OS Roman strings have "MOR" in the name. (The naming convention makes it obvious when you're assigning the wrong thing; on Linux both formats are char*, so the compiler won't tell you if you get it wrong.) The distinction is necessary because filesystems generally support Unicode these days, but on Windows you need to use a separate set of wide-character file I/O functions. (On Linux it all works with "narrow" strings, and the UTF-8 encoding is interpreted by applications.) The character set used for NuFX archive filenames is MOR, matching what GS/OS + HFS supported, and we want to be able to convert back and forth between MOR and a Unicode representation. This change updates the various character types and string names, adds conversion functions, and updates NuLib2 for proper execution on Linux. It does not include the (probably extensive) changes required for Windows UTF-16 support. Instead, the conversion functions are no-ops, which should result in NuLib2 for Windows continuing to behave in the same slightly broken way. This adds "test-names", which exercises Unicode filenames a bit. It will not pass on Win32. Also, tweaked the Linux makefiles to have explicit dependencies, rather than empty space and an expectation that "makedepend" exists. Also, minor source code cleanups. While this probably doesn't affect binary compatibility -- it's mainly a matter of naming and string interpretation -- there's enough going on that it should be considered an API revision, so this updates the version to 3.0.0.
2014-12-24 19:14:32 +00:00
Nu_Free(pArchive, newPathStorageUNI);
Nu_Free(pArchive, recFilenameStorageUNI);
if (doFreeSink)
Nu_DataSinkFree(pDataSink);
return err;
2000-05-23 01:55:31 +00:00
}
/*
* Extract a thread from the archive as part of a "bulk" extract operation.
*
* Streaming archives must be properly positioned.
*/
NuError Nu_ExtractThreadBulk(NuArchive* pArchive, const NuRecord* pRecord,
const NuThread* pThread)
2000-05-23 01:55:31 +00:00
{
NuError err;
2014-12-22 02:17:23 +00:00
NuDataSink* pDataSink = NULL;
Distinguish Unicode and Mac OS Roman strings NufxLib has historically made no effort to distinguish between the character set used for filenames on the local disk, and for filenames stored within the archive. Now all Unicode filename strings use the UNICHAR type and have "UNI" in the name, and all Mac OS Roman strings have "MOR" in the name. (The naming convention makes it obvious when you're assigning the wrong thing; on Linux both formats are char*, so the compiler won't tell you if you get it wrong.) The distinction is necessary because filesystems generally support Unicode these days, but on Windows you need to use a separate set of wide-character file I/O functions. (On Linux it all works with "narrow" strings, and the UTF-8 encoding is interpreted by applications.) The character set used for NuFX archive filenames is MOR, matching what GS/OS + HFS supported, and we want to be able to convert back and forth between MOR and a Unicode representation. This change updates the various character types and string names, adds conversion functions, and updates NuLib2 for proper execution on Linux. It does not include the (probably extensive) changes required for Windows UTF-16 support. Instead, the conversion functions are no-ops, which should result in NuLib2 for Windows continuing to behave in the same slightly broken way. This adds "test-names", which exercises Unicode filenames a bit. It will not pass on Win32. Also, tweaked the Linux makefiles to have explicit dependencies, rather than empty space and an expectation that "makedepend" exists. Also, minor source code cleanups. While this probably doesn't affect binary compatibility -- it's mainly a matter of naming and string interpretation -- there's enough going on that it should be considered an API revision, so this updates the version to 3.0.0.
2014-12-24 19:14:32 +00:00
UNICHAR* recFilenameStorageUNI = NULL;
NuValue eolConv;
/*
* Create a file data sink for the file. We use whatever EOL conversion
* is set as the default for the entire archive. (If you want to
* specify your own EOL conversion for each individual file, you will
* need to extract them individually, creating a data sink for each.)
*
* One exception: we turn EOL conversion off for disk image threads.
* It's *very* unlikely this would be desirable, and could be a problem
* if the user is extracting a collection of disks and files.
*/
eolConv = pArchive->valConvertExtractedEOL;
if (NuGetThreadID(pThread) == kNuThreadIDDiskImage)
eolConv = kNuConvertOff;
Distinguish Unicode and Mac OS Roman strings NufxLib has historically made no effort to distinguish between the character set used for filenames on the local disk, and for filenames stored within the archive. Now all Unicode filename strings use the UNICHAR type and have "UNI" in the name, and all Mac OS Roman strings have "MOR" in the name. (The naming convention makes it obvious when you're assigning the wrong thing; on Linux both formats are char*, so the compiler won't tell you if you get it wrong.) The distinction is necessary because filesystems generally support Unicode these days, but on Windows you need to use a separate set of wide-character file I/O functions. (On Linux it all works with "narrow" strings, and the UTF-8 encoding is interpreted by applications.) The character set used for NuFX archive filenames is MOR, matching what GS/OS + HFS supported, and we want to be able to convert back and forth between MOR and a Unicode representation. This change updates the various character types and string names, adds conversion functions, and updates NuLib2 for proper execution on Linux. It does not include the (probably extensive) changes required for Windows UTF-16 support. Instead, the conversion functions are no-ops, which should result in NuLib2 for Windows continuing to behave in the same slightly broken way. This adds "test-names", which exercises Unicode filenames a bit. It will not pass on Win32. Also, tweaked the Linux makefiles to have explicit dependencies, rather than empty space and an expectation that "makedepend" exists. Also, minor source code cleanups. While this probably doesn't affect binary compatibility -- it's mainly a matter of naming and string interpretation -- there's enough going on that it should be considered an API revision, so this updates the version to 3.0.0.
2014-12-24 19:14:32 +00:00
recFilenameStorageUNI = Nu_CopyMORToUNI(pRecord->filenameMOR);
err = Nu_DataSinkFile_New(true, eolConv, recFilenameStorageUNI,
NuGetSepFromSysInfo(pRecord->recFileSysInfo), &pDataSink);
BailError(err);
err = Nu_ExtractThreadCommon(pArchive, pRecord, pThread, pDataSink);
BailError(err);
2000-05-23 01:55:31 +00:00
bail:
2014-12-22 02:17:23 +00:00
if (pDataSink != NULL) {
NuError err2 = Nu_DataSinkFree(pDataSink);
if (err == kNuErrNone)
err = err2;
}
Distinguish Unicode and Mac OS Roman strings NufxLib has historically made no effort to distinguish between the character set used for filenames on the local disk, and for filenames stored within the archive. Now all Unicode filename strings use the UNICHAR type and have "UNI" in the name, and all Mac OS Roman strings have "MOR" in the name. (The naming convention makes it obvious when you're assigning the wrong thing; on Linux both formats are char*, so the compiler won't tell you if you get it wrong.) The distinction is necessary because filesystems generally support Unicode these days, but on Windows you need to use a separate set of wide-character file I/O functions. (On Linux it all works with "narrow" strings, and the UTF-8 encoding is interpreted by applications.) The character set used for NuFX archive filenames is MOR, matching what GS/OS + HFS supported, and we want to be able to convert back and forth between MOR and a Unicode representation. This change updates the various character types and string names, adds conversion functions, and updates NuLib2 for proper execution on Linux. It does not include the (probably extensive) changes required for Windows UTF-16 support. Instead, the conversion functions are no-ops, which should result in NuLib2 for Windows continuing to behave in the same slightly broken way. This adds "test-names", which exercises Unicode filenames a bit. It will not pass on Win32. Also, tweaked the Linux makefiles to have explicit dependencies, rather than empty space and an expectation that "makedepend" exists. Also, minor source code cleanups. While this probably doesn't affect binary compatibility -- it's mainly a matter of naming and string interpretation -- there's enough going on that it should be considered an API revision, so this updates the version to 3.0.0.
2014-12-24 19:14:32 +00:00
Nu_Free(pArchive, recFilenameStorageUNI);
2000-05-23 01:55:31 +00:00
return err;
2000-05-23 01:55:31 +00:00
}
/*
* Extract a thread, given the IDs and a data sink.
*/
NuError Nu_ExtractThread(NuArchive* pArchive, NuThreadIdx threadIdx,
NuDataSink* pDataSink)
2000-05-23 01:55:31 +00:00
{
NuError err;
NuRecord* pRecord;
NuThread* pThread;
2000-05-23 01:55:31 +00:00
if (Nu_IsStreaming(pArchive))
return kNuErrUsage;
2014-12-22 02:17:23 +00:00
if (threadIdx == 0 || pDataSink == NULL)
return kNuErrInvalidArg;
err = Nu_GetTOCIfNeeded(pArchive);
BailError(err);
2000-05-23 01:55:31 +00:00
/* find the correct record and thread by index */
err = Nu_RecordSet_FindByThreadIdx(&pArchive->origRecordSet, threadIdx,
&pRecord, &pThread);
BailError(err);
2014-12-22 02:17:23 +00:00
Assert(pRecord != NULL);
2000-05-23 01:55:31 +00:00
/* extract away */
err = Nu_ExtractThreadCommon(pArchive, pRecord, pThread, pDataSink);
BailError(err);
2000-05-23 01:55:31 +00:00
bail:
return err;
2000-05-23 01:55:31 +00:00
}
/*
* ===========================================================================
* Add/update/delete
2000-05-23 01:55:31 +00:00
* ===========================================================================
*/
/*
* Verify that a conflicting thread with the specified threadID does not
* exist in this record, now or in the future.
*
* The set of interesting threads is equal to the current threads, minus
* any that have been deleted, plus any that have been added already.
*
* If a matching threadID is found, this returns an error.
*/
static NuError Nu_FindNoFutureThread(NuArchive* pArchive,
const NuRecord* pRecord, NuThreadID threadID)
2000-05-23 01:55:31 +00:00
{
NuError err = kNuErrNone;
const NuThread* pThread;
const NuThreadMod* pThreadMod;
int idx;
/*
* Start by scanning the existing threads (if any).
*/
for (idx = 0; idx < (int)pRecord->recTotalThreads; idx++) {
pThread = Nu_GetThread(pRecord, idx);
2014-12-22 02:17:23 +00:00
Assert(pThread != NULL);
if (NuGetThreadID(pThread) == threadID) {
/* found a match, see if it has been deleted */
pThreadMod = Nu_ThreadMod_FindByThreadIdx(pRecord,
pThread->threadIdx);
2014-12-22 02:17:23 +00:00
if (pThreadMod != NULL &&
pThreadMod->entry.kind == kNuThreadModDelete)
{
/* it's deleted, ignore it */
continue;
}
DBUG(("--- found existing thread matching 0x%08lx\n", threadID));
err = kNuErrThreadAdd;
goto bail;
}
}
/*
* Now look for "add" threadMods with a matching threadID.
*/
pThreadMod = pRecord->pThreadMods;
2014-12-22 02:17:23 +00:00
while (pThreadMod != NULL) {
if (pThreadMod->entry.kind == kNuThreadModAdd &&
pThreadMod->entry.add.threadID == threadID)
{
DBUG(("--- found 'add' threadMod matching 0x%08lx\n", threadID));
err = kNuErrThreadAdd;
goto bail;
}
pThreadMod = pThreadMod->pNext;
}
2000-05-23 01:55:31 +00:00
bail:
return err;
2000-05-23 01:55:31 +00:00
}
/*
* Like Nu_FindNoFutureThread, but tests against a whole class.
*/
static NuError Nu_FindNoFutureThreadClass(NuArchive* pArchive,
const NuRecord* pRecord, long threadClass)
2000-05-23 01:55:31 +00:00
{
NuError err = kNuErrNone;
const NuThread* pThread;
const NuThreadMod* pThreadMod;
int idx;
/*
* Start by scanning the existing threads (if any).
*/
for (idx = 0; idx < (int)pRecord->recTotalThreads; idx++) {
pThread = Nu_GetThread(pRecord, idx);
2014-12-22 02:17:23 +00:00
Assert(pThread != NULL);
if (pThread->thThreadClass == threadClass) {
/* found a match, see if it has been deleted */
pThreadMod = Nu_ThreadMod_FindByThreadIdx(pRecord,
pThread->threadIdx);
2014-12-22 02:17:23 +00:00
if (pThreadMod != NULL &&
pThreadMod->entry.kind == kNuThreadModDelete)
{
/* it's deleted, ignore it */
continue;
}
DBUG(("--- Found existing thread matching 0x%04lx\n", threadClass));
err = kNuErrThreadAdd;
goto bail;
}
}
/*
* Now look for "add" threadMods with a matching threadClass.
*/
pThreadMod = pRecord->pThreadMods;
2014-12-22 02:17:23 +00:00
while (pThreadMod != NULL) {
if (pThreadMod->entry.kind == kNuThreadModAdd &&
NuThreadIDGetClass(pThreadMod->entry.add.threadID) == threadClass)
{
DBUG(("--- Found 'add' threadMod matching 0x%04lx\n", threadClass));
err = kNuErrThreadAdd;
goto bail;
}
pThreadMod = pThreadMod->pNext;
}
2000-05-23 01:55:31 +00:00
bail:
return err;
2000-05-23 01:55:31 +00:00
}
/*
* Find an existing thread somewhere in the archive. If the "copy" set
* exists it will be searched. If not, the "orig" set is searched, and
* if an entry is found a "copy" set will be created.
*
* The record and thread returned will always be from the "copy" set. An
* error result is returned if the record and thread aren't found.
*/
static NuError Nu_FindThreadForWriteByIdx(NuArchive* pArchive,
NuThreadIdx threadIdx, NuRecord** ppFoundRecord, NuThread** ppFoundThread)
2000-05-23 01:55:31 +00:00
{
NuError err;
if (Nu_RecordSet_GetLoaded(&pArchive->copyRecordSet)) {
err = Nu_RecordSet_FindByThreadIdx(&pArchive->copyRecordSet, threadIdx,
ppFoundRecord, ppFoundThread);
} else {
Assert(Nu_RecordSet_GetLoaded(&pArchive->origRecordSet));
err = Nu_RecordSet_FindByThreadIdx(&pArchive->origRecordSet, threadIdx,
ppFoundRecord, ppFoundThread);
2014-12-22 02:17:23 +00:00
*ppFoundThread = NULL; /* can't delete from here, wipe ptr */
}
BailError(err);
/*
* The thread exists. If we were looking in the "orig" set, we have
* to create a "copy" set, and delete it from that.
*/
2014-12-22 02:17:23 +00:00
if (*ppFoundThread == NULL) {
err = Nu_RecordSet_Clone(pArchive, &pArchive->copyRecordSet,
&pArchive->origRecordSet);
BailError(err);
err = Nu_RecordSet_FindByThreadIdx(&pArchive->copyRecordSet, threadIdx,
ppFoundRecord, ppFoundThread);
2014-12-22 02:17:23 +00:00
Assert(err == kNuErrNone && *ppFoundThread != NULL); /* must succeed */
BailError(err);
}
2000-05-23 01:55:31 +00:00
bail:
return err;
2000-05-23 01:55:31 +00:00
}
/*
* Determine if it's okay to add a thread of the type specified by
* "threadID" into "pRecord".
*
* Returns with an error (kNuErrThreadAdd) if it's not okay.
*/
NuError Nu_OkayToAddThread(NuArchive* pArchive, const NuRecord* pRecord,
NuThreadID threadID)
2000-05-23 01:55:31 +00:00
{
NuError err = kNuErrNone;
/*
* Check for class conflicts (can't mix data and control threads).
*/
if (NuThreadIDGetClass(threadID) == kNuThreadClassData) {
err = Nu_FindNoFutureThreadClass(pArchive, pRecord,
kNuThreadClassControl);
BailError(err);
} else if (NuThreadIDGetClass(threadID) == kNuThreadClassControl) {
err = Nu_FindNoFutureThreadClass(pArchive, pRecord,
kNuThreadClassData);
BailError(err);
}
/*
* Check for specific type conflicts.
*/
if (threadID == kNuThreadIDDataFork) {
err = Nu_FindNoFutureThread(pArchive, pRecord, kNuThreadIDDataFork);
BailError(err);
err = Nu_FindNoFutureThread(pArchive, pRecord, kNuThreadIDDiskImage);
BailError(err);
} else if (threadID == kNuThreadIDRsrcFork) {
err = Nu_FindNoFutureThread(pArchive, pRecord, kNuThreadIDRsrcFork);
BailError(err);
err = Nu_FindNoFutureThread(pArchive, pRecord, kNuThreadIDDiskImage);
BailError(err);
} else if (threadID == kNuThreadIDDiskImage) {
err = Nu_FindNoFutureThread(pArchive, pRecord, kNuThreadIDDataFork);
BailError(err);
err = Nu_FindNoFutureThread(pArchive, pRecord, kNuThreadIDRsrcFork);
BailError(err);
err = Nu_FindNoFutureThread(pArchive, pRecord, kNuThreadIDDiskImage);
BailError(err);
} else if (threadID == kNuThreadIDFilename) {
err = Nu_FindNoFutureThread(pArchive, pRecord, kNuThreadIDFilename);
BailError(err);
}
2000-05-23 01:55:31 +00:00
bail:
return err;
2000-05-23 01:55:31 +00:00
}
/*
* Add a new thread to a record.
*
* In some cases, you aren't allowed to add a thread whose type matches
* one that already exists. This applies to data threads and filenames,
* but not to comments, control threads, or IIgs icons. You also can't
* add a disk image thread when there are data-class threads, or vice-versa.
*
* This is the first and last place we do this sort of checking. If
* an illegal situation gets past this function, it will either get
* caught with a fatal assert or (if NDEBUG is defined) not at all.
*
* On success, the NuThreadIdx of the newly-created record will be placed
* in "*pThreadIdx", and "pDataSource" will be owned by NufxLib.
2000-05-23 01:55:31 +00:00
*/
NuError Nu_AddThread(NuArchive* pArchive, NuRecordIdx recIdx,
NuThreadID threadID, NuDataSource* pDataSource, NuThreadIdx* pThreadIdx)
2000-05-23 01:55:31 +00:00
{
NuError err;
NuRecord* pRecord;
2014-12-22 02:17:23 +00:00
NuThreadMod* pThreadMod = NULL;
NuThreadFormat threadFormat;
2014-12-22 02:17:23 +00:00
/* okay for pThreadIdx to be NULL */
if (recIdx == 0 || pDataSource == NULL)
return kNuErrInvalidArg;
if (Nu_IsReadOnly(pArchive))
return kNuErrArchiveRO;
err = Nu_GetTOCIfNeeded(pArchive);
BailError(err);
/*
* Find the record. If it doesn't exist in the copy set, check to
* see if it's in the "new" set.
*/
err = Nu_FindRecordForWriteByIdx(pArchive, recIdx, &pRecord);
if (err == kNuErrRecIdxNotFound &&
Nu_RecordSet_GetLoaded(&pArchive->newRecordSet))
{
err = Nu_RecordSet_FindByIdx(&pArchive->newRecordSet, recIdx, &pRecord);
}
BailError(err);
2014-12-22 02:17:23 +00:00
Assert(pRecord != NULL);
/*
* Do some tests, looking for specific types of threads that conflict
* with what we're trying to add.
*/
err = Nu_OkayToAddThread(pArchive, pRecord, threadID);
BailError(err);
/*
* Decide if we want to compress the data from this source. If the
* data is already compressed (as indicated by the data source) or
* this type of thread isn't compressible (e.g. it's a filename), then
* we don't compress it. Otherwise, we use whatever compression mode
* is currently configured.
*/
if (Nu_DataSourceGetThreadFormat(pDataSource) == kNuThreadFormatUncompressed &&
Nu_IsCompressibleThreadID(threadID))
{
threadFormat = Nu_ConvertCompressValToFormat(pArchive,
pArchive->valDataCompression);
} else {
threadFormat = kNuThreadFormatUncompressed;
}
DBUG(("--- using threadFormat = %d\n", threadFormat));
/* create a new ThreadMod (which makes a copy of the data source) */
err = Nu_ThreadModAdd_New(pArchive, threadID, threadFormat, pDataSource,
&pThreadMod);
BailError(err);
2014-12-22 02:17:23 +00:00
Assert(pThreadMod != NULL);
/* add the thread mod to the record */
Nu_RecordAddThreadMod(pRecord, pThreadMod);
2014-12-22 02:17:23 +00:00
if (pThreadIdx != NULL)
*pThreadIdx = pThreadMod->entry.add.threadIdx;
2014-12-22 02:17:23 +00:00
pThreadMod = NULL; /* successful, don't free */
/*
* If we've got a header filename and we're adding a filename thread,
* we don't want to write the record header name when we reconstruct
* the record.
*/
if (threadID == kNuThreadIDFilename && pRecord->recFilenameLength) {
DBUG(("+++ gonna drop the filename\n"));
pRecord->dropRecFilename = true;
}
2000-05-23 01:55:31 +00:00
bail:
2014-12-22 02:17:23 +00:00
if (pThreadMod != NULL)
Nu_ThreadModFree(pArchive, pThreadMod);
2014-12-22 02:17:23 +00:00
if (err == kNuErrNone && pDataSource != NULL) {
/* on success, we have ownership of the data source. ThreadMod
made its own copy, so get rid of this one */
Nu_DataSourceFree(pDataSource);
}
return err;
2000-05-23 01:55:31 +00:00
}
/*
* Update the contents of a pre-sized thread, such as a filename or
* comment thread.
*
* The data from the source must fit within the limits of the existing
* thread. The source data is never compressed, and must not come from
* a compressed source.
*
* You aren't allowed to update threads that have been deleted. Updating
* newly-added threads isn't possible, since they aren't really threads yet.
*/
NuError Nu_UpdatePresizedThread(NuArchive* pArchive, NuThreadIdx threadIdx,
Distinguish Unicode and Mac OS Roman strings NufxLib has historically made no effort to distinguish between the character set used for filenames on the local disk, and for filenames stored within the archive. Now all Unicode filename strings use the UNICHAR type and have "UNI" in the name, and all Mac OS Roman strings have "MOR" in the name. (The naming convention makes it obvious when you're assigning the wrong thing; on Linux both formats are char*, so the compiler won't tell you if you get it wrong.) The distinction is necessary because filesystems generally support Unicode these days, but on Windows you need to use a separate set of wide-character file I/O functions. (On Linux it all works with "narrow" strings, and the UTF-8 encoding is interpreted by applications.) The character set used for NuFX archive filenames is MOR, matching what GS/OS + HFS supported, and we want to be able to convert back and forth between MOR and a Unicode representation. This change updates the various character types and string names, adds conversion functions, and updates NuLib2 for proper execution on Linux. It does not include the (probably extensive) changes required for Windows UTF-16 support. Instead, the conversion functions are no-ops, which should result in NuLib2 for Windows continuing to behave in the same slightly broken way. This adds "test-names", which exercises Unicode filenames a bit. It will not pass on Win32. Also, tweaked the Linux makefiles to have explicit dependencies, rather than empty space and an expectation that "makedepend" exists. Also, minor source code cleanups. While this probably doesn't affect binary compatibility -- it's mainly a matter of naming and string interpretation -- there's enough going on that it should be considered an API revision, so this updates the version to 3.0.0.
2014-12-24 19:14:32 +00:00
NuDataSource* pDataSource, int32_t* pMaxLen)
2000-05-23 01:55:31 +00:00
{
NuError err;
2014-12-22 02:17:23 +00:00
NuThreadMod* pThreadMod = NULL;
NuRecord* pFoundRecord;
NuThread* pFoundThread;
2014-12-22 02:17:23 +00:00
if (pDataSource == NULL) {
err = kNuErrInvalidArg;
goto bail;
}
/* presized threads always contain uncompressed data */
if (Nu_DataSourceGetThreadFormat(pDataSource) !=
kNuThreadFormatUncompressed)
{
err = kNuErrBadFormat;
Nu_ReportError(NU_BLOB, err,
"presized threads can't hold compressed data");
goto bail;
}
if (Nu_IsReadOnly(pArchive))
return kNuErrArchiveRO;
err = Nu_GetTOCIfNeeded(pArchive);
BailError(err);
/*
* Find the thread in the "copy" set. (If there isn't a copy set,
* make one.)
*/
err = Nu_FindThreadForWriteByIdx(pArchive, threadIdx, &pFoundRecord,
&pFoundThread);
BailError(err);
if (!Nu_IsPresizedThreadID(NuGetThreadID(pFoundThread)) ||
!(pFoundThread->thCompThreadEOF >= pFoundThread->thThreadEOF))
{
err = kNuErrNotPreSized;
Nu_ReportError(NU_BLOB, err, "invalid thread for update");
goto bail;
}
2014-12-22 02:17:23 +00:00
if (pMaxLen != NULL)
*pMaxLen = pFoundThread->thCompThreadEOF;
/*
* Check to see if somebody is trying to delete this, or has already
* updated it.
*/
2014-12-22 02:17:23 +00:00
if (Nu_ThreadMod_FindByThreadIdx(pFoundRecord, threadIdx) != NULL) {
DBUG(("--- Tried to modify a deleted or modified thread\n"));
err = kNuErrModThreadChange;
goto bail;
}
/*
* Verify that "otherLen" in the data source is less than or equal
* to our len, if we can. If the data source is a file on disk,
* we're not really supposed to look at it until we flush. We
* could sneak a peek right now, which would prevent us from aborting
* the entire operation when it turns out the file won't fit, but
* that violates our semantics (and besides, the application really
* should've done that already).
*
* If the data source is from a file, we just assume it'll fit and
* let the chips fall where they may later on.
*/
if (Nu_DataSourceGetType(pDataSource) != kNuDataSourceFromFile) {
if (pFoundThread->thCompThreadEOF <
Nu_DataSourceGetOtherLen(pDataSource))
{
err = kNuErrPreSizeOverflow;
Nu_ReportError(NU_BLOB, err, "can't put %u bytes into %u",
Nu_DataSourceGetOtherLen(pDataSource),
pFoundThread->thCompThreadEOF);
goto bail;
}
/* check for zero-length and excessively long filenames */
if (NuGetThreadID(pFoundThread) == kNuThreadIDFilename &&
(Nu_DataSourceGetOtherLen(pDataSource) == 0 ||
Nu_DataSourceGetOtherLen(pDataSource) > kNuReasonableFilenameLen))
{
err = kNuErrInvalidFilename;
Nu_ReportError(NU_BLOB, err, "invalid filename (%u bytes)",
Nu_DataSourceGetOtherLen(pDataSource));
goto bail;
}
}
/*
* Looks like it'll fit, and it's the right kind of data. Create
* an "update" threadMod. Note this copies the data source.
*/
Assert(pFoundThread->thThreadFormat == kNuThreadFormatUncompressed);
err = Nu_ThreadModUpdate_New(pArchive, threadIdx, pDataSource, &pThreadMod);
BailError(err);
2014-12-22 02:17:23 +00:00
Assert(pThreadMod != NULL);
/* add the thread mod to the record */
Nu_RecordAddThreadMod(pFoundRecord, pThreadMod);
/*
* NOTE: changes to filename threads will be picked up later and
* incorporated into the record's threadFilename. We don't worry
* about the record header filename, because we might be doing an
* update-in-place and that prevents us from removing the filename
* (doing so would change the size of the archive). No need to
* do any filename-specific changes here.
*/
2000-05-23 01:55:31 +00:00
bail:
return err;
2000-05-23 01:55:31 +00:00
}
/*
* Delete an individual thread.
*
* You aren't allowed to delete threads that have been updated. Deleting
* newly-added threads isn't possible, since they aren't really threads yet.
*
* Don't worry about deleting filename threads here; we take care of that
* later on. Besides, it's sort of handy to hang on to the filename for
* as long as possible.
*/
NuError Nu_DeleteThread(NuArchive* pArchive, NuThreadIdx threadIdx)
2000-05-23 01:55:31 +00:00
{
NuError err;
2014-12-22 02:17:23 +00:00
NuThreadMod* pThreadMod = NULL;
NuRecord* pFoundRecord;
NuThread* pFoundThread;
if (Nu_IsReadOnly(pArchive))
return kNuErrArchiveRO;
err = Nu_GetTOCIfNeeded(pArchive);
BailError(err);
/*
* Find the thread in the "copy" set. (If there isn't a copy set,
* make one.)
*/
err = Nu_FindThreadForWriteByIdx(pArchive, threadIdx, &pFoundRecord,
&pFoundThread);
BailError(err);
/*
* Deletion of modified threads (updates or previous deletes) isn't
* allowed. Deletion of threads from deleted records can't happen,
* because deleted records are completely removed from the "copy" set.
*/
2014-12-22 02:17:23 +00:00
if (Nu_ThreadMod_FindByThreadIdx(pFoundRecord, threadIdx) != NULL) {
DBUG(("--- Tried to delete a deleted or modified thread\n"));
err = kNuErrModThreadChange;
goto bail;
}
/*
* Looks good. Add a new "delete" ThreadMod to the list.
*/
err = Nu_ThreadModDelete_New(pArchive, threadIdx,
NuGetThreadID(pFoundThread), &pThreadMod);
BailError(err);
Nu_RecordAddThreadMod(pFoundRecord, pThreadMod);
2014-12-22 02:17:23 +00:00
pThreadMod = NULL; /* successful, don't free */
2000-05-23 01:55:31 +00:00
bail:
Nu_ThreadModFree(pArchive, pThreadMod);
return err;
2000-05-23 01:55:31 +00:00
}