mirror of
https://github.com/fadden/nulib2.git
synced 2025-08-09 19:25:33 +00:00
Added support for kNuValMaskDataless, which hides records with no data
threads by giving them an empty data fork (and, if it's an extended file, an empty resource fork). This allows applications to simply ignore the bogus records and let NufxLib do the dirty work. Fixed dataless thread handling for the original (non-masked) case. We weren't creating empty resource forks when required, so a dataless record with a forked-file storage type wouldn't be recreated properly if extracted and then added. Added version numbers to the public header, so applications can test for "compiled" version vs "linked" version.
This commit is contained in:
@@ -77,8 +77,7 @@ Nu_NuArchiveNew(NuArchive** ppArchive)
|
||||
* system-specific values here; it's up to the application to decide
|
||||
* what is most appropriate for the current system.
|
||||
*/
|
||||
(*ppArchive)->valAllowDuplicates = false;
|
||||
(*ppArchive)->valConvertExtractedEOL = kNuConvertOff;
|
||||
(*ppArchive)->valIgnoreCRC = false;
|
||||
#ifdef ENABLE_LZW
|
||||
(*ppArchive)->valDataCompression = kNuCompressLZW2;
|
||||
#else
|
||||
@@ -86,11 +85,14 @@ Nu_NuArchiveNew(NuArchive** ppArchive)
|
||||
#endif
|
||||
(*ppArchive)->valDiscardWrapper = false;
|
||||
(*ppArchive)->valEOL = kNuEOLLF; /* non-UNIX apps must override */
|
||||
(*ppArchive)->valHandleExisting = kNuMaybeOverwrite;
|
||||
(*ppArchive)->valIgnoreCRC = false;
|
||||
(*ppArchive)->valMimicSHK = false;
|
||||
(*ppArchive)->valModifyOrig = false;
|
||||
(*ppArchive)->valConvertExtractedEOL = kNuConvertOff;
|
||||
(*ppArchive)->valOnlyUpdateOlder = false;
|
||||
(*ppArchive)->valAllowDuplicates = false;
|
||||
(*ppArchive)->valHandleExisting = kNuMaybeOverwrite;
|
||||
(*ppArchive)->valModifyOrig = false;
|
||||
(*ppArchive)->valMimicSHK = false;
|
||||
(*ppArchive)->valMaskDataless = false;
|
||||
|
||||
|
||||
return kNuErrNone;
|
||||
}
|
||||
|
@@ -1,3 +1,12 @@
|
||||
2003/01/10 fadden
|
||||
- Added version numbers to header.
|
||||
- Added kNuValueMaskThreadless to control handling of "threadless"
|
||||
records. Now records without threads can be silently "fixed" so
|
||||
the application does need to handle them specially.
|
||||
|
||||
2002/12/06 fadden
|
||||
- Made changes to allow NufxLib to be built as a DLL.
|
||||
|
||||
2002/10/20 ***** v1.1.0 shipped *****
|
||||
|
||||
2002/10/10 fadden
|
||||
|
@@ -231,10 +231,14 @@ Nu_DebugDumpRecord(NuArchive* pArchive, const NuRecord* pRecord,
|
||||
pRecord->extraCount, pRecord->fileOffset, pRecord->recHeaderLength);
|
||||
|
||||
for (idx = 0; idx < pRecord->recTotalThreads; idx++) {
|
||||
Boolean isFake;
|
||||
|
||||
isFake = (idx >= pRecord->recTotalThreads - pRecord->fakeThreads);
|
||||
pThread = Nu_GetThread(pRecord, idx);
|
||||
Assert(pThread != nil);
|
||||
|
||||
printf("%s--Thread #%lu (idx=%lu)\n", kInd, idx, pThread->threadIdx);
|
||||
printf("%s--Thread #%lu (idx=%lu)%s\n", kInd, idx, pThread->threadIdx,
|
||||
isFake ? " [FAKE]" : "");
|
||||
Nu_DebugDumpThread(pThread);
|
||||
}
|
||||
|
||||
|
@@ -16,6 +16,26 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* NufxLib version number. Compare these values (which represent the
|
||||
* version against which your application was compiled) to the values
|
||||
* returned by NuGetVersion (representing the version against which
|
||||
* your application is statically or dynamically linked). If the major
|
||||
* number doesn't match exactly, an existing interface has changed and you
|
||||
* should halt immediately. If the minor number from NuGetVersion is
|
||||
* less, there may be new interfaces, new features, or bug fixes missing
|
||||
* upon which your application depends, so you should halt immediately.
|
||||
* (If the minor number is greater, there are new features, but your
|
||||
* application will not be affected by them.)
|
||||
*
|
||||
* The "bug" version can usually be ignored, since it represents minor
|
||||
* fixes.
|
||||
*/
|
||||
#define kNuVersionMajor 1
|
||||
#define kNuVersionMinor 1
|
||||
#define kNuVersionBug 0
|
||||
|
||||
|
||||
/*
|
||||
* ===========================================================================
|
||||
* Types
|
||||
@@ -242,7 +262,8 @@ typedef enum NuValueID {
|
||||
kNuValueAllowDuplicates = 7,
|
||||
kNuValueHandleExisting = 8,
|
||||
kNuValueModifyOrig = 9,
|
||||
kNuValueMimicSHK = 10
|
||||
kNuValueMimicSHK = 10,
|
||||
kNuValueMaskDataless = 11
|
||||
} NuValueID;
|
||||
typedef unsigned long NuValue;
|
||||
|
||||
@@ -425,6 +446,7 @@ typedef struct NuRecord {
|
||||
const char* filename; /* points at recFilen or threadFilen */
|
||||
unsigned long recHeaderLength; /* size of rec hdr, incl thread hdrs */
|
||||
unsigned long totalCompLength; /* total len of data in archive file */
|
||||
long fakeThreads; /* used by "MaskDataless" */
|
||||
|
||||
long fileOffset; /* file offset of record header */
|
||||
|
||||
|
@@ -147,6 +147,7 @@ struct NuArchive {
|
||||
NuValue valEOL; /* EOL value to convert to */
|
||||
NuValue valHandleExisting; /* how to deal with existing files*/
|
||||
NuValue valIgnoreCRC; /* don't compute or test CRCs */
|
||||
NuValue valMaskDataless; /* alter Records w/o data threads */
|
||||
NuValue valMimicSHK; /* mimic some ShrinkIt quirks */
|
||||
NuValue valModifyOrig; /* modify original arc in place? */
|
||||
NuValue valOnlyUpdateOlder; /* modify original arc in place? */
|
||||
@@ -161,7 +162,6 @@ struct NuArchive {
|
||||
|
||||
#define kNuArchiveStructMagic 0xc0edbabe
|
||||
|
||||
|
||||
#define kNuDefaultRecordName "UNKNOWN"
|
||||
|
||||
|
||||
|
@@ -1002,6 +1002,7 @@ Nu_ReadRecordHeader(NuArchive* pArchive, NuRecord* pRecord)
|
||||
* Read the threads records. The data is included in the record header
|
||||
* CRC, so we have to pass that in too.
|
||||
*/
|
||||
pRecord->fakeThreads = 0;
|
||||
err = Nu_ReadThreadHeaders(pArchive, pRecord, &crc);
|
||||
BailError(err);
|
||||
|
||||
@@ -1018,6 +1019,8 @@ Nu_ReadRecordHeader(NuArchive* pArchive, NuRecord* pRecord)
|
||||
err = kNuErrBadRHCRC;
|
||||
Nu_ReportError(NU_BLOB, err, "Stored RH CRC=0x%04x, calc=0x%04x",
|
||||
pRecord->recHeaderCRC, crc);
|
||||
Nu_ReportError(NU_BLOB_DEBUG, kNuErrNone,
|
||||
"--- Problematic record is id=%ld", pRecord->recordIdx);
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
@@ -1027,7 +1030,8 @@ Nu_ReadRecordHeader(NuArchive* pArchive, NuRecord* pRecord)
|
||||
*/
|
||||
/* adjust "currentOffset" for the entire record header */
|
||||
pArchive->currentOffset += bytesRead;
|
||||
pArchive->currentOffset += pRecord->recTotalThreads * kNuThreadHeaderSize;
|
||||
pArchive->currentOffset +=
|
||||
(pRecord->recTotalThreads - pRecord->fakeThreads) * kNuThreadHeaderSize;
|
||||
|
||||
pRecord->recHeaderLength =
|
||||
bytesRead + pRecord->recTotalThreads * kNuThreadHeaderSize;
|
||||
@@ -1458,21 +1462,23 @@ bail:
|
||||
* thing as it is a bug-workaround thing.
|
||||
*
|
||||
* The record's storage type should tell us if it was an extended file or
|
||||
* a plain file, but I'm not sure if there's any value in creating a
|
||||
* zero-byte resource fork.
|
||||
* a plain file. Not really important when extracting, but if we want
|
||||
* to recreate the original we need to re-add the resource fork so
|
||||
* NufxLib knows to make it an extended file.
|
||||
*/
|
||||
static NuError
|
||||
Nu_FakeZeroExtract(NuArchive* pArchive, NuRecord* pRecord)
|
||||
Nu_FakeZeroExtract(NuArchive* pArchive, NuRecord* pRecord, int threadKind)
|
||||
{
|
||||
NuError err;
|
||||
NuThread fakeThread;
|
||||
|
||||
Assert(pRecord != nil);
|
||||
|
||||
DBUG(("--- found empty record, creating zero-byte data file\n"));
|
||||
DBUG(("--- found empty record, creating zero-byte file (kind=0x%04x)\n",
|
||||
threadKind));
|
||||
fakeThread.thThreadClass = kNuThreadClassData;
|
||||
fakeThread.thThreadFormat = kNuThreadFormatUncompressed;
|
||||
fakeThread.thThreadKind = 0x0000; /* assume data thread */
|
||||
fakeThread.thThreadKind = threadKind;
|
||||
fakeThread.thThreadCRC = kNuInitialThreadCRC;
|
||||
fakeThread.thThreadEOF = 0;
|
||||
fakeThread.thCompThreadEOF = 0;
|
||||
@@ -1577,17 +1583,17 @@ 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.
|
||||
* create a zero-byte data file (and possibly a resource fork).
|
||||
*
|
||||
* [ I'm going to make this a non-Mimic feature, so I can turn
|
||||
* MimicSHK off and still extract zero-byte files from GSHK
|
||||
* archives. We should perhaps consider a separate "bug
|
||||
* workaround" flag to control this. Note there's similar
|
||||
* code in Nu_ExtractRecordByPtr, below. ]
|
||||
* See notes in previous instance, above.
|
||||
*/
|
||||
if (/*pArchive->valMimicSHK &&*/ !hasInterestingThread) {
|
||||
err = Nu_FakeZeroExtract(pArchive, &tmpRecord);
|
||||
if (/*pArchive->valMaskDataless &&*/ !hasInterestingThread) {
|
||||
err = Nu_FakeZeroExtract(pArchive, &tmpRecord, 0x0000);
|
||||
BailError(err);
|
||||
if (tmpRecord.recStorageType == kNuStorageExtended) {
|
||||
err = Nu_FakeZeroExtract(pArchive, &tmpRecord, 0x0002);
|
||||
BailError(err);
|
||||
}
|
||||
}
|
||||
|
||||
/* dispose of the entry */
|
||||
@@ -1708,11 +1714,27 @@ 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 data file.
|
||||
* create a zero-byte file.
|
||||
*
|
||||
* (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.)
|
||||
*
|
||||
* NOTE: this might be doing the (slightly) wrong thing if the storage
|
||||
* type of the file indicates that it was forked. We might need to be
|
||||
* extracting zero-byte data *and* resource forks here. Only matters
|
||||
* if we want to be able to reconstruct the original archive contents
|
||||
* from what we extracted. ++ATM 20030110
|
||||
*
|
||||
* Note there's another one of these below, in Nu_StreamExtract.
|
||||
*/
|
||||
if (/*pArchive->valMimicSHK &&*/ !hasInterestingThread) {
|
||||
err = Nu_FakeZeroExtract(pArchive, pRecord);
|
||||
if (/*pArchive->valMaskDataless &&*/ !hasInterestingThread) {
|
||||
err = Nu_FakeZeroExtract(pArchive, pRecord, 0x0000 /*data*/);
|
||||
BailError(err);
|
||||
if (pRecord->recStorageType == kNuStorageExtended) {
|
||||
err = Nu_FakeZeroExtract(pArchive, pRecord, 0x0002 /*rsrc*/);
|
||||
BailError(err);
|
||||
}
|
||||
}
|
||||
|
||||
bail:
|
||||
|
@@ -189,6 +189,7 @@ Nu_ReadThreadHeaders(NuArchive* pArchive, NuRecord* pRecord, ushort* pCrc)
|
||||
NuError err = kNuErrNone;
|
||||
NuThread* pThread;
|
||||
long count;
|
||||
Boolean hasData = false;
|
||||
|
||||
Assert(pArchive != nil);
|
||||
Assert(pRecord != nil);
|
||||
@@ -210,6 +211,9 @@ Nu_ReadThreadHeaders(NuArchive* pArchive, NuRecord* pRecord, ushort* pCrc)
|
||||
err = Nu_ReadThreadHeader(pArchive, pThread, pCrc);
|
||||
BailError(err);
|
||||
|
||||
if (pThread->thThreadClass == kNuThreadClassData)
|
||||
hasData = true;
|
||||
|
||||
/*
|
||||
* Some versions of ShrinkIt write an invalid thThreadEOF for disks,
|
||||
* so we have to figure out what it's supposed to be.
|
||||
@@ -246,6 +250,51 @@ Nu_ReadThreadHeaders(NuArchive* pArchive, NuRecord* pRecord, ushort* pCrc)
|
||||
pThread++;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
int firstNewThread = pRecord->recTotalThreads;
|
||||
|
||||
pRecord->recTotalThreads++;
|
||||
pRecord->fakeThreads++;
|
||||
if (needRsrc) {
|
||||
pRecord->recTotalThreads++;
|
||||
pRecord->fakeThreads++;
|
||||
}
|
||||
|
||||
pRecord->pThreads = Nu_Realloc(pArchive, pRecord->pThreads,
|
||||
pRecord->recTotalThreads * sizeof(NuThread));
|
||||
BailAlloc(pRecord->pThreads);
|
||||
|
||||
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->actualThreadEOF = 0;
|
||||
pThread->threadIdx = Nu_GetNextThreadIdx(pArchive);
|
||||
pThread->fileOffset = -1;
|
||||
|
||||
if (needRsrc) {
|
||||
pThread++;
|
||||
pThread->thThreadClass = kNuThreadClassData;
|
||||
pThread->thThreadFormat = kNuThreadFormatUncompressed;
|
||||
pThread->thThreadKind = 0x0002; /* rsrc fork */
|
||||
pThread->thThreadCRC = kNuInitialThreadCRC;
|
||||
pThread->thThreadEOF = 0;
|
||||
pThread->thCompThreadEOF = 0;
|
||||
pThread->actualThreadEOF = 0;
|
||||
pThread->threadIdx = Nu_GetNextThreadIdx(pArchive);
|
||||
pThread->fileOffset = -1;
|
||||
}
|
||||
}
|
||||
|
||||
bail:
|
||||
return err;
|
||||
}
|
||||
|
@@ -42,6 +42,9 @@ Nu_GetValue(NuArchive* pArchive, NuValueID ident, NuValue* pValue)
|
||||
case kNuValueIgnoreCRC:
|
||||
*pValue = pArchive->valIgnoreCRC;
|
||||
break;
|
||||
case kNuValueMaskDataless:
|
||||
*pValue = pArchive->valMaskDataless;
|
||||
break;
|
||||
case kNuValueMimicSHK:
|
||||
*pValue = pArchive->valMimicSHK;
|
||||
break;
|
||||
@@ -127,6 +130,14 @@ Nu_SetValue(NuArchive* pArchive, NuValueID ident, NuValue value)
|
||||
}
|
||||
pArchive->valIgnoreCRC = value;
|
||||
break;
|
||||
case kNuValueMaskDataless:
|
||||
if (value != true && value != false) {
|
||||
Nu_ReportError(NU_BLOB, err,
|
||||
"Invalid kNuValueMaskDataless value %ld", value);
|
||||
goto bail;
|
||||
}
|
||||
pArchive->valMaskDataless = value;
|
||||
break;
|
||||
case kNuValueMimicSHK:
|
||||
if (value != true && value != false) {
|
||||
Nu_ReportError(NU_BLOB, err,
|
||||
|
@@ -10,12 +10,8 @@
|
||||
*/
|
||||
#include "NufxLibPriv.h"
|
||||
|
||||
/* version number; edit by hand */
|
||||
static const long gNuMajorVersion = 1;
|
||||
static const long gNuMinorVersion = 1;
|
||||
static const long gNuBugVersion = 0;
|
||||
|
||||
/* executable was build on or after this date (inserted automatically) */
|
||||
/* (some compilers e.g. MSC have __DATE__; use that?) */
|
||||
static const char gNuBuildDate[] = "BUILT"; /* approximate */
|
||||
static const char gNuBuildFlags[] = "OPTFLAGS";
|
||||
|
||||
@@ -28,11 +24,11 @@ Nu_GetVersion(long* pMajorVersion, long* pMinorVersion, long* pBugVersion,
|
||||
const char** ppBuildDate, const char** ppBuildFlags)
|
||||
{
|
||||
if (pMajorVersion != nil)
|
||||
*pMajorVersion = gNuMajorVersion;
|
||||
*pMajorVersion = kNuVersionMajor;
|
||||
if (pMinorVersion != nil)
|
||||
*pMinorVersion = gNuMinorVersion;
|
||||
*pMinorVersion = kNuVersionMinor;
|
||||
if (pBugVersion != nil)
|
||||
*pBugVersion = gNuBugVersion;
|
||||
*pBugVersion = kNuVersionBug;
|
||||
if (ppBuildDate != nil)
|
||||
*ppBuildDate = gNuBuildDate;
|
||||
if (ppBuildFlags != nil)
|
||||
|
Reference in New Issue
Block a user