/* * 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) { if (NuThreadIDGetClass(threadID) == kNuThreadClassData) return true; else return false; }
/* * 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) { 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); } bail: return err; }
/* * Like Nu_FindNoFutureThread, but tests against a whole class. */ static NuError Nu_FindNoFutureThreadClass(NuArchive* pArchive, const NuRecord* pRecord, long threadClass) { 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); Assert(pThread != NULL); if (pThread->thThreadClass == threadClass) { /* found a match, see if it has been deleted */ pThreadMod = Nu_ThreadMod_FindByThreadIdx(pRecord, pThread->threadIdx); 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; 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; } bail: return err; }
/* * at - add thread to record */ static NuError AddThreadFunc(ExerciserState* pState, int argc, char** argv) { NuError err; NuDataSource* pDataSource = nil; char* lineBuf = nil; long ourLen, maxLen; NuThreadID threadID; NuThreadIdx threadIdx; (void) pState, (void) argc, (void) argv; /* shut up, gcc */ assert(ExerciserState_GetNuArchive(pState) != nil); assert(argc == 3); lineBuf = (char*)malloc(kNiceLineLen); assert(lineBuf != nil); threadID = strtol(argv[2], nil, 0); if (NuThreadIDGetClass(threadID) == kNuThreadClassData) { /* load data from a file on disk */ maxLen = 0; err = GetLine("Enter filename", lineBuf, kNiceLineLen); if (err != kNuErrNone) goto bail; if (!lineBuf[0]) { fprintf(stderr, "Invalid filename\n"); err = kNuErrInvalidArg; goto bail; } err = NuCreateDataSourceForFile(kNuThreadFormatUncompressed, 0, lineBuf, false, &pDataSource); if (err != kNuErrNone) { fprintf(stderr, "Exerciser: file data source create failed (err=%d)\n", err); goto bail; } } else { if (threadID == kNuThreadIDFilename || threadID == kNuThreadIDComment) { /* select the buffer pre-size */ err = GetLine("Enter max buffer size", lineBuf, kNiceLineLen); if (err != kNuErrNone) goto bail; maxLen = strtol(lineBuf, nil, 0); if (maxLen <= 0) { fprintf(stderr, "Bad length\n"); err = kNuErrInvalidArg; goto bail; } } else { maxLen = 0; } err = GetLine("Enter the thread contents", lineBuf, kNiceLineLen); if (err != kNuErrNone) goto bail; ourLen = strlen(lineBuf); /* create a data source from the buffer */ err = NuCreateDataSourceForBuffer(kNuThreadFormatUncompressed, maxLen, (unsigned char*)lineBuf, 0, ourLen, FreeCallback, &pDataSource); if (err != kNuErrNone) { fprintf(stderr, "Exerciser: buffer data source create failed (err=%d)\n", err); goto bail; } lineBuf = nil; /* now owned by the library */ } err = NuAddThread(ExerciserState_GetNuArchive(pState), strtol(argv[1], nil, 0), threadID, pDataSource, &threadIdx); if (err == kNuErrNone) { pDataSource = nil; /* library owns it now */ printf("Exerciser: success; function returned threadIdx=%ld\n", threadIdx); } bail: NuFreeDataSource(pDataSource); if (lineBuf != nil) free(lineBuf); return err; }
/* * NuContents callback function. Print the contents of an individual record. */ NuResult PrintEntry(NuArchive* pArchive, void* vpRecord) { const NuRecord* pRecord = (const NuRecord*) vpRecord; int idx; (void)pArchive; /* shut up, gcc */ printf("RecordIdx %ld: '%s'\n", pRecord->recordIdx, pRecord->filename); for (idx = 0; idx < (int) pRecord->recTotalThreads; idx++) { const NuThread* pThread; NuThreadID threadID; const char* threadLabel; pThread = NuGetThread(pRecord, idx); assert(pThread != nil); threadID = NuGetThreadID(pThread); switch (NuThreadIDGetClass(threadID)) { case kNuThreadClassMessage: threadLabel = "message class"; break; case kNuThreadClassControl: threadLabel = "control class"; break; case kNuThreadClassData: threadLabel = "data class"; break; case kNuThreadClassFilename: threadLabel = "filename class"; break; default: threadLabel = "(unknown class)"; break; } switch (threadID) { case kNuThreadIDComment: threadLabel = "comment"; break; case kNuThreadIDIcon: threadLabel = "icon"; break; case kNuThreadIDMkdir: threadLabel = "mkdir"; break; case kNuThreadIDDataFork: threadLabel = "data fork"; break; case kNuThreadIDDiskImage: threadLabel = "disk image"; break; case kNuThreadIDRsrcFork: threadLabel = "rsrc fork"; break; case kNuThreadIDFilename: threadLabel = "filename"; break; default: break; } printf(" ThreadIdx %ld - 0x%08lx (%s)\n", pThread->threadIdx, threadID, threadLabel); } return kNuOK; }
/* * Decide if the thread has a CRC, based on the record version and the * threadID. */ Boolean Nu_ThreadHasCRC(uint16_t recordVersion, NuThreadID threadID) { return recordVersion >= 3 && NuThreadIDGetClass(threadID) == kNuThreadClassData; }