mirror of
https://github.com/fadden/ciderpress.git
synced 2024-11-25 10:30:53 +00:00
Update NufxLib with recent 3.1.0 changes
This commit is contained in:
parent
7596c950fa
commit
6bcf388c3e
@ -1,4 +1,8 @@
|
||||
2005/01/09 ***** v3.0.0 shipped *****
|
||||
2015/12/26 fadden
|
||||
- Fix handling of entries with missing threads.
|
||||
- Improve handling of Mac OS X file type attributes.
|
||||
|
||||
2015/01/09 ***** v3.0.0 shipped *****
|
||||
|
||||
2015/01/03 fadden
|
||||
- Mac OS X: replace Carbon FinderInfo calls with BSD xattr.
|
||||
|
@ -228,6 +228,13 @@ typedef struct NuFileInfo {
|
||||
|
||||
/*
|
||||
* Determine whether the record has both data and resource forks.
|
||||
*
|
||||
* TODO: if we're not using "mask dataless", scanning threads may not
|
||||
* get the right answer, because GSHK omits theads for zero-length forks.
|
||||
* We could check pRecord->recStorageType, though we have to be careful
|
||||
* because that's overloaded for disk images. In any event, the result
|
||||
* from this method isn't relevant unless we're trying to use forked
|
||||
* files on the native filesystem.
|
||||
*/
|
||||
static Boolean Nu_IsForkedFile(NuArchive* pArchive, const NuRecord* pRecord)
|
||||
{
|
||||
@ -320,20 +327,44 @@ static NuError Nu_SetFinderInfo(NuArchive* pArchive, const NuRecord* pRecord,
|
||||
return kNuErrFile;
|
||||
}
|
||||
|
||||
/* build type and creator from 8-bit type and 16-bit aux type */
|
||||
uint32_t fileType, creator;
|
||||
fileType = ('p' << 24) | ((pRecord->recFileType & 0xff) << 16) |
|
||||
(pRecord->recExtraType & 0xffff);
|
||||
creator = 'pdos';
|
||||
uint8_t proType = (uint8_t) pRecord->recFileType;
|
||||
uint16_t proAux = (uint16_t) pRecord->recExtraType;
|
||||
|
||||
fiBuf[0] = fileType >> 24;
|
||||
fiBuf[1] = fileType >> 16;
|
||||
fiBuf[2] = fileType >> 8;
|
||||
fiBuf[3] = fileType;
|
||||
fiBuf[4] = creator >> 24;
|
||||
fiBuf[5] = creator >> 16;
|
||||
fiBuf[6] = creator >> 8;
|
||||
fiBuf[7] = creator;
|
||||
/*
|
||||
* Attempt to use one of the convenience types. If nothing matches,
|
||||
* use the generic pdos/pXYZ approach. Note that PSYS/PS16 will
|
||||
* lose the file's aux type.
|
||||
*
|
||||
* I'm told this is from page 336 of _Programmer's Reference for
|
||||
* System 6.0_.
|
||||
*/
|
||||
uint8_t* fileTypeBuf = fiBuf;
|
||||
uint8_t* creatorBuf = fiBuf + 4;
|
||||
|
||||
memcpy(creatorBuf, "pdos", 4);
|
||||
if (proType == 0x00 && proAux == 0x0000) {
|
||||
memcpy(fileTypeBuf, "BINA", 4);
|
||||
} else if (proType == 0x04 && proAux == 0x0000) {
|
||||
memcpy(fileTypeBuf, "TEXT", 4);
|
||||
} else if (proType == 0xff) {
|
||||
memcpy(fileTypeBuf, "PSYS", 4);
|
||||
} else if (proType == 0xb3 && (proAux & 0xff00) != 0xdb00) {
|
||||
memcpy(fileTypeBuf, "PS16", 4);
|
||||
} else if (proType == 0xd7 && proAux == 0x0000) {
|
||||
memcpy(fileTypeBuf, "MIDI", 4);
|
||||
} else if (proType == 0xd8 && proAux == 0x0000) {
|
||||
memcpy(fileTypeBuf, "AIFF", 4);
|
||||
} else if (proType == 0xd8 && proAux == 0x0001) {
|
||||
memcpy(fileTypeBuf, "AIFC", 4);
|
||||
} else if (proType == 0xe0 && proAux == 0x0005) {
|
||||
memcpy(creatorBuf, "dCpy", 4);
|
||||
memcpy(fileTypeBuf, "dImg", 4);
|
||||
} else {
|
||||
fileTypeBuf[0] = 'p';
|
||||
fileTypeBuf[1] = proType;
|
||||
fileTypeBuf[2] = (uint8_t) (proAux >> 8);
|
||||
fileTypeBuf[3] = (uint8_t) proAux;
|
||||
}
|
||||
|
||||
if (setxattr(pathnameUNI, XATTR_FINDERINFO_NAME, fiBuf, sizeof(fiBuf),
|
||||
0, 0) != 0)
|
||||
|
@ -33,7 +33,7 @@ extern "C" {
|
||||
* fixes. Unless, of course, your code depends upon that fix.
|
||||
*/
|
||||
#define kNuVersionMajor 3
|
||||
#define kNuVersionMinor 0
|
||||
#define kNuVersionMinor 1
|
||||
#define kNuVersionBug 0
|
||||
|
||||
|
||||
@ -201,13 +201,16 @@ typedef uint32_t NuThreadID;
|
||||
#define kNuThreadClassControl 0x0001
|
||||
#define kNuThreadClassData 0x0002
|
||||
#define kNuThreadClassFilename 0x0003
|
||||
#define kNuThreadKindDataFork 0x0000 /* when class=data */
|
||||
#define kNuThreadKindDiskImage 0x0001 /* when class=data */
|
||||
#define kNuThreadKindRsrcFork 0x0002 /* when class=data */
|
||||
#define kNuThreadIDOldComment NuMakeThreadID(kNuThreadClassMessage, 0x0000)
|
||||
#define kNuThreadIDComment NuMakeThreadID(kNuThreadClassMessage, 0x0001)
|
||||
#define kNuThreadIDIcon NuMakeThreadID(kNuThreadClassMessage, 0x0002)
|
||||
#define kNuThreadIDMkdir NuMakeThreadID(kNuThreadClassControl, 0x0000)
|
||||
#define kNuThreadIDDataFork NuMakeThreadID(kNuThreadClassData, 0x0000)
|
||||
#define kNuThreadIDDiskImage NuMakeThreadID(kNuThreadClassData, 0x0001)
|
||||
#define kNuThreadIDRsrcFork NuMakeThreadID(kNuThreadClassData, 0x0002)
|
||||
#define kNuThreadIDDataFork NuMakeThreadID(kNuThreadClassData, kNuThreadKindDataFork)
|
||||
#define kNuThreadIDDiskImage NuMakeThreadID(kNuThreadClassData, kNuThreadKindDiskImage)
|
||||
#define kNuThreadIDRsrcFork NuMakeThreadID(kNuThreadClassData, kNuThreadKindRsrcFork)
|
||||
#define kNuThreadIDFilename NuMakeThreadID(kNuThreadClassFilename, 0x0000)
|
||||
#define kNuThreadIDWildcard NuMakeThreadID(0xffff, 0xffff)
|
||||
|
||||
|
@ -1524,7 +1524,7 @@ NuError Nu_StreamExtract(NuArchive* pArchive)
|
||||
{
|
||||
NuError err = kNuErrNone;
|
||||
NuRecord tmpRecord;
|
||||
Boolean hasInterestingThread;
|
||||
Boolean needFakeData, needFakeRsrc;
|
||||
uint32_t count;
|
||||
long idx;
|
||||
|
||||
@ -1573,7 +1573,8 @@ NuError Nu_StreamExtract(NuArchive* pArchive)
|
||||
/*Nu_DebugDumpRecord(&tmpRecord);
|
||||
printf("\n");*/
|
||||
|
||||
hasInterestingThread = false;
|
||||
needFakeData = true;
|
||||
needFakeRsrc = (tmpRecord.recStorageType == kNuStorageExtended);
|
||||
|
||||
/* extract all relevant (remaining) threads */
|
||||
pArchive->lastFileCreatedUNI = NULL;
|
||||
@ -1581,7 +1582,11 @@ NuError Nu_StreamExtract(NuArchive* pArchive)
|
||||
const NuThread* pThread = Nu_GetThread(&tmpRecord, idx);
|
||||
|
||||
if (pThread->thThreadClass == kNuThreadClassData) {
|
||||
hasInterestingThread = true;
|
||||
if (pThread->thThreadKind == kNuThreadKindDataFork) {
|
||||
needFakeData = false;
|
||||
} else if (pThread->thThreadKind == kNuThreadKindRsrcFork) {
|
||||
needFakeRsrc = false;
|
||||
}
|
||||
err = Nu_ExtractThreadBulk(pArchive, &tmpRecord, pThread);
|
||||
if (err == kNuErrSkipped) {
|
||||
err = Nu_SkipThread(pArchive, &tmpRecord, pThread);
|
||||
@ -1595,7 +1600,8 @@ NuError Nu_StreamExtract(NuArchive* pArchive)
|
||||
if (NuGetThreadID(pThread) != kNuThreadIDComment &&
|
||||
NuGetThreadID(pThread) != kNuThreadIDFilename)
|
||||
{
|
||||
hasInterestingThread = true;
|
||||
/* unknown stuff in record, skip thread fakery */
|
||||
needFakeData = needFakeRsrc = false;
|
||||
}
|
||||
err = Nu_SkipThread(pArchive, &tmpRecord, pThread);
|
||||
BailError(err);
|
||||
@ -1603,19 +1609,19 @@ NuError Nu_StreamExtract(NuArchive* pArchive)
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're trying to be compatible with ShrinkIt, and the record
|
||||
* had nothing in it but comments and filenames, then we need to
|
||||
* create a zero-byte data file (and possibly a resource fork).
|
||||
*
|
||||
* See notes in previous instance, above.
|
||||
* As in Nu_ExtractRecordByPtr, we need to synthesize empty forks for
|
||||
* cases where GSHK omitted the data thread entirely.
|
||||
*/
|
||||
if (/*pArchive->valMaskDataless &&*/ !hasInterestingThread) {
|
||||
err = Nu_FakeZeroExtract(pArchive, &tmpRecord, 0x0000);
|
||||
Assert(!pArchive->valMaskDataless || (!needFakeData && !needFakeRsrc));
|
||||
if (needFakeData) {
|
||||
err = Nu_FakeZeroExtract(pArchive, &tmpRecord,
|
||||
kNuThreadKindDataFork);
|
||||
BailError(err);
|
||||
}
|
||||
if (needFakeRsrc) {
|
||||
err = Nu_FakeZeroExtract(pArchive, &tmpRecord,
|
||||
kNuThreadKindRsrcFork);
|
||||
BailError(err);
|
||||
if (tmpRecord.recStorageType == kNuStorageExtended) {
|
||||
err = Nu_FakeZeroExtract(pArchive, &tmpRecord, 0x0002);
|
||||
BailError(err);
|
||||
}
|
||||
}
|
||||
|
||||
/* dispose of the entry */
|
||||
@ -1698,20 +1704,26 @@ bail:
|
||||
static NuError Nu_ExtractRecordByPtr(NuArchive* pArchive, NuRecord* pRecord)
|
||||
{
|
||||
NuError err = kNuErrNone;
|
||||
Boolean hasInterestingThread;
|
||||
Boolean needFakeData, needFakeRsrc;
|
||||
uint32_t idx;
|
||||
|
||||
needFakeData = true;
|
||||
needFakeRsrc = (pRecord->recStorageType == kNuStorageExtended);
|
||||
|
||||
Assert(!Nu_IsStreaming(pArchive)); /* we don't skip things we don't read */
|
||||
Assert(pRecord != NULL);
|
||||
|
||||
/* extract all relevant threads */
|
||||
hasInterestingThread = false;
|
||||
pArchive->lastFileCreatedUNI = NULL;
|
||||
for (idx = 0; idx < pRecord->recTotalThreads; idx++) {
|
||||
const NuThread* pThread = Nu_GetThread(pRecord, idx);
|
||||
|
||||
if (pThread->thThreadClass == kNuThreadClassData) {
|
||||
hasInterestingThread = true;
|
||||
if (pThread->thThreadKind == kNuThreadKindDataFork) {
|
||||
needFakeData = false;
|
||||
} else if (pThread->thThreadKind == kNuThreadKindRsrcFork) {
|
||||
needFakeRsrc = false;
|
||||
}
|
||||
err = Nu_ExtractThreadBulk(pArchive, pRecord, pThread);
|
||||
if (err == kNuErrSkipped) {
|
||||
err = Nu_SkipThread(pArchive, pRecord, pThread);
|
||||
@ -1722,7 +1734,13 @@ static NuError Nu_ExtractRecordByPtr(NuArchive* pArchive, NuRecord* pRecord)
|
||||
if (NuGetThreadID(pThread) != kNuThreadIDComment &&
|
||||
NuGetThreadID(pThread) != kNuThreadIDFilename)
|
||||
{
|
||||
hasInterestingThread = true;
|
||||
/*
|
||||
* This record has a thread we don't recognize. Disable
|
||||
* the thread fakery to avoid doing anything weird -- we
|
||||
* should only need to create zero-length files for
|
||||
* simple file records.
|
||||
*/
|
||||
needFakeData = needFakeRsrc = false;
|
||||
}
|
||||
DBUG(("IGNORING 0x%08lx from '%s'\n",
|
||||
NuMakeThreadID(pThread->thThreadClass, pThread->thThreadKind),
|
||||
@ -1731,28 +1749,27 @@ static NuError Nu_ExtractRecordByPtr(NuArchive* pArchive, NuRecord* pRecord)
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're trying to be compatible with ShrinkIt, and the record
|
||||
* had nothing in it but comments and filenames, then we need to
|
||||
* create a zero-byte file.
|
||||
* GSHK creates empty threads for zero-length forks. It doesn't always
|
||||
* handle them correctly when extracting, so it appears this behavior
|
||||
* may not be intentional.
|
||||
*
|
||||
* (GSHK handles empty data and resource forks by not storing a
|
||||
* thread at all. It doesn't correctly deal with them when extracting
|
||||
* though, so it appears this behavior wasn't entirely expected.)
|
||||
* We need to create an empty file for whichever forks are missing.
|
||||
* Could be the data fork, resource fork, or both. The only way to
|
||||
* know what's expected is to examine the file's storage type.
|
||||
*
|
||||
* If it's a forked file, we also need to create an empty rsrc file.
|
||||
*
|
||||
* If valMaskDataless is enabled, this won't fire, because we "forge"
|
||||
* appropriate threads.
|
||||
* If valMaskDataless is enabled, this won't fire, because we will have
|
||||
* "forged" the appropriate threads.
|
||||
*
|
||||
* Note there's another one of these below, in Nu_StreamExtract.
|
||||
*/
|
||||
if (/*pArchive->valMaskDataless &&*/ !hasInterestingThread) {
|
||||
err = Nu_FakeZeroExtract(pArchive, pRecord, 0x0000 /*data*/);
|
||||
Assert(!pArchive->valMaskDataless || (!needFakeData && !needFakeRsrc));
|
||||
if (needFakeData) {
|
||||
err = Nu_FakeZeroExtract(pArchive, pRecord, kNuThreadKindDataFork);
|
||||
BailError(err);
|
||||
}
|
||||
if (needFakeRsrc) {
|
||||
err = Nu_FakeZeroExtract(pArchive, pRecord, kNuThreadKindRsrcFork);
|
||||
BailError(err);
|
||||
if (pRecord->recStorageType == kNuStorageExtended) {
|
||||
err = Nu_FakeZeroExtract(pArchive, pRecord, 0x0002 /*rsrc*/);
|
||||
BailError(err);
|
||||
}
|
||||
}
|
||||
|
||||
bail:
|
||||
|
@ -193,7 +193,10 @@ NuError Nu_ReadThreadHeaders(NuArchive* pArchive, NuRecord* pRecord,
|
||||
NuError err = kNuErrNone;
|
||||
NuThread* pThread;
|
||||
long count;
|
||||
Boolean hasData = false;
|
||||
Boolean needFakeData, needFakeRsrc;
|
||||
|
||||
needFakeData = true;
|
||||
needFakeRsrc = (pRecord->recStorageType == kNuStorageExtended);
|
||||
|
||||
Assert(pArchive != NULL);
|
||||
Assert(pRecord != NULL);
|
||||
@ -215,8 +218,13 @@ NuError Nu_ReadThreadHeaders(NuArchive* pArchive, NuRecord* pRecord,
|
||||
err = Nu_ReadThreadHeader(pArchive, pThread, pCrc);
|
||||
BailError(err);
|
||||
|
||||
if (pThread->thThreadClass == kNuThreadClassData)
|
||||
hasData = true;
|
||||
if (pThread->thThreadClass == kNuThreadClassData) {
|
||||
if (pThread->thThreadKind == kNuThreadKindDataFork) {
|
||||
needFakeData = false;
|
||||
} else if (pThread->thThreadKind == kNuThreadKindRsrcFork) {
|
||||
needFakeRsrc = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Some versions of ShrinkIt write an invalid thThreadEOF for disks,
|
||||
@ -258,13 +266,14 @@ NuError Nu_ReadThreadHeaders(NuArchive* pArchive, NuRecord* pRecord,
|
||||
* If "mask threadless" is set, create "fake" threads with empty
|
||||
* data and resource forks as needed.
|
||||
*/
|
||||
if (!hasData && pArchive->valMaskDataless) {
|
||||
Boolean needRsrc = (pRecord->recStorageType == kNuStorageExtended);
|
||||
if ((needFakeData || needFakeRsrc) && pArchive->valMaskDataless) {
|
||||
int firstNewThread = pRecord->recTotalThreads;
|
||||
|
||||
pRecord->recTotalThreads++;
|
||||
pRecord->fakeThreads++;
|
||||
if (needRsrc) {
|
||||
if (needFakeData) {
|
||||
pRecord->recTotalThreads++;
|
||||
pRecord->fakeThreads++;
|
||||
}
|
||||
if (needFakeRsrc) {
|
||||
pRecord->recTotalThreads++;
|
||||
pRecord->fakeThreads++;
|
||||
}
|
||||
@ -275,22 +284,23 @@ NuError Nu_ReadThreadHeaders(NuArchive* pArchive, NuRecord* pRecord,
|
||||
|
||||
pThread = pRecord->pThreads + firstNewThread;
|
||||
|
||||
pThread->thThreadClass = kNuThreadClassData;
|
||||
pThread->thThreadFormat = kNuThreadFormatUncompressed;
|
||||
pThread->thThreadKind = 0x0000; /* data fork */
|
||||
pThread->thThreadCRC = kNuInitialThreadCRC;
|
||||
pThread->thThreadEOF = 0;
|
||||
pThread->thCompThreadEOF = 0;
|
||||
pThread->threadIdx = Nu_GetNextThreadIdx(pArchive);
|
||||
pThread->actualThreadEOF = 0;
|
||||
pThread->fileOffset = -99999999;
|
||||
pThread->used = false;
|
||||
|
||||
if (needRsrc) {
|
||||
pThread++;
|
||||
if (needFakeData) {
|
||||
pThread->thThreadClass = kNuThreadClassData;
|
||||
pThread->thThreadFormat = kNuThreadFormatUncompressed;
|
||||
pThread->thThreadKind = 0x0002; /* rsrc fork */
|
||||
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;
|
||||
|
@ -24,6 +24,15 @@ static const char kFssep = PATH_SEP;
|
||||
|
||||
#define kTempFile "exer-temp"
|
||||
|
||||
#ifndef HAVE_STRCASECMP
|
||||
static int strcasecmp(const char *str1, const char *str2)
|
||||
{
|
||||
while (*str1 && *str2 && toupper(*str1) == toupper(*str2))
|
||||
str1++, str2++;
|
||||
return (toupper(*str1) - toupper(*str2));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* ===========================================================================
|
||||
@ -364,13 +373,25 @@ static NuError AbortFunc(ExerciserState* pState, int argc, char** argv)
|
||||
static NuError AddFileFunc(ExerciserState* pState, int argc, char** argv)
|
||||
{
|
||||
NuFileDetails nuFileDetails;
|
||||
int fromRsrc = false;
|
||||
|
||||
(void) pState, (void) argc, (void) argv; /* shut up, gcc */
|
||||
assert(ExerciserState_GetNuArchive(pState) != NULL);
|
||||
assert(argc == 2);
|
||||
assert(argc == 3);
|
||||
|
||||
if (strcasecmp(argv[2], "true") == 0) {
|
||||
fromRsrc = true;
|
||||
} else if (strcasecmp(argv[2], "false") != 0) {
|
||||
fprintf(stderr, "WARNING: fromRsrc should be 'true' or 'false'\n");
|
||||
/* ignore */
|
||||
}
|
||||
|
||||
memset(&nuFileDetails, 0, sizeof(nuFileDetails));
|
||||
nuFileDetails.threadID = kNuThreadIDDataFork;
|
||||
if (fromRsrc) {
|
||||
nuFileDetails.threadID = kNuThreadIDRsrcFork;
|
||||
} else {
|
||||
nuFileDetails.threadID = kNuThreadIDDataFork;
|
||||
}
|
||||
nuFileDetails.storageNameMOR = argv[1];
|
||||
nuFileDetails.fileSysID = kNuFileSysUnknown;
|
||||
nuFileDetails.fileSysInfo = (short) kFssep;
|
||||
@ -378,7 +399,7 @@ static NuError AddFileFunc(ExerciserState* pState, int argc, char** argv)
|
||||
/* fileType, extraType, storageType, dates */
|
||||
|
||||
return NuAddFile(ExerciserState_GetNuArchive(pState), argv[1],
|
||||
&nuFileDetails, false, NULL);
|
||||
&nuFileDetails, fromRsrc, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1039,7 +1060,7 @@ static const struct {
|
||||
|
||||
{ "ab", AbortFunc, 0, "", kFlagArchiveReq,
|
||||
"Abort current changes" },
|
||||
{ "af", AddFileFunc, 1, "filename", kFlagArchiveReq,
|
||||
{ "af", AddFileFunc, 2, "filename fromRsrc", kFlagArchiveReq,
|
||||
"Add file" },
|
||||
{ "ar", AddRecordFunc, 1, "storageName", kFlagArchiveReq,
|
||||
"Add record" },
|
||||
|
@ -16,8 +16,7 @@
|
||||
#include "Common.h"
|
||||
|
||||
#ifndef HAVE_STRCASECMP
|
||||
static int
|
||||
strcasecmp(const char *str1, const char *str2)
|
||||
static int strcasecmp(const char *str1, const char *str2)
|
||||
{
|
||||
while (*str1 && *str2 && toupper(*str1) == toupper(*str2))
|
||||
str1++, str2++;
|
||||
|
@ -298,7 +298,8 @@ int Test_AddStuff(NuArchive* pArchive)
|
||||
|
||||
|
||||
/*
|
||||
* Create an empty file with a rather non-empty name.
|
||||
* Create an empty file with a rather non-empty name. Add it as
|
||||
* a resource fork.
|
||||
*/
|
||||
printf("... add 'long' record\n");
|
||||
err = NuCreateDataSourceForBuffer(kNuThreadFormatUncompressed,
|
||||
@ -454,7 +455,8 @@ failed:
|
||||
|
||||
|
||||
/*
|
||||
* Selection callback filter for "test". This gets called once per record.
|
||||
* Selection callback filter for "test". This gets called once per record,
|
||||
* twice per record for forked files.
|
||||
*/
|
||||
NuResult VerifySelectionCallback(NuArchive* pArchive, void* vpProposal)
|
||||
{
|
||||
@ -523,7 +525,9 @@ int Test_Verify(NuArchive* pArchive)
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (count != kNumEntries) {
|
||||
/* the count will be one higher than the number of records because
|
||||
the last entry is forked, and each fork is tested separately */
|
||||
if (count != kNumEntries + 1) {
|
||||
fprintf(stderr, "ERROR: verified %ld when expecting %d\n", count,
|
||||
kNumEntries);
|
||||
goto failed;
|
||||
|
@ -184,6 +184,7 @@ CRCList* GatherCRCs(NuArchive* pArchive)
|
||||
goto bail;
|
||||
}
|
||||
|
||||
int rsrcCrcIdx = -1;
|
||||
for (i = 0; i < (int)NuRecordGetNumThreads(pRecord); i++) {
|
||||
pThread = NuGetThread(pRecord, i);
|
||||
if (pThread->thThreadClass == kNuThreadClassData) {
|
||||
@ -194,7 +195,30 @@ CRCList* GatherCRCs(NuArchive* pArchive)
|
||||
goto bail;
|
||||
}
|
||||
|
||||
pEntries[crcIdx++] = pThread->thThreadCRC;
|
||||
/*
|
||||
* Ensure that the data fork CRC comes first. Otherwise
|
||||
* we can fail if it gets rearranged. This is only a
|
||||
* problem for GSHK-created archives that don't have
|
||||
* threads for every fork, so "mask dataless" is create
|
||||
* fake entries.
|
||||
*
|
||||
* The correct way to do this is to store a tuple
|
||||
* { thread-kind, crc }, but that's more work.
|
||||
*/
|
||||
if (pThread->thThreadKind == kNuThreadKindRsrcFork) {
|
||||
rsrcCrcIdx = crcIdx;
|
||||
}
|
||||
|
||||
if (pThread->thThreadKind == kNuThreadKindDataFork &&
|
||||
rsrcCrcIdx != -1)
|
||||
{
|
||||
/* this is the data fork, we've already seen the
|
||||
resource fork; swap entries */
|
||||
pEntries[crcIdx++] = pEntries[rsrcCrcIdx];
|
||||
pEntries[rsrcCrcIdx] = pThread->thThreadCRC;
|
||||
} else {
|
||||
pEntries[crcIdx++] = pThread->thThreadCRC;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user