mirror of
https://github.com/fadden/nulib2.git
synced 2025-01-15 07:34:38 +00:00
Added workaround for malformed HFS option lists.
Added support for skipping junk found at the start of an archive file.
This commit is contained in:
parent
cd1f9e78a1
commit
68193a70c3
@ -39,6 +39,7 @@ static const uchar kNuSHKSEAID[] =
|
|||||||
#define kNuSEALength1 11946 /* length of archive (4B?) */
|
#define kNuSEALength1 11946 /* length of archive (4B?) */
|
||||||
#define kNuSEALength2 12001 /* length of archive (4B?) */
|
#define kNuSEALength2 12001 /* length of archive (4B?) */
|
||||||
|
|
||||||
|
#define kDefaultJunkSkipMax 1024 /* default junk scan size */
|
||||||
|
|
||||||
static void Nu_CloseAndFree(NuArchive* pArchive);
|
static void Nu_CloseAndFree(NuArchive* pArchive);
|
||||||
|
|
||||||
@ -93,6 +94,8 @@ Nu_NuArchiveNew(NuArchive** ppArchive)
|
|||||||
(*ppArchive)->valMimicSHK = false;
|
(*ppArchive)->valMimicSHK = false;
|
||||||
(*ppArchive)->valMaskDataless = false;
|
(*ppArchive)->valMaskDataless = false;
|
||||||
(*ppArchive)->valStripHighASCII = false;
|
(*ppArchive)->valStripHighASCII = false;
|
||||||
|
/* bug: this can't be set by application! */
|
||||||
|
(*ppArchive)->valJunkSkipMax = kDefaultJunkSkipMax;
|
||||||
|
|
||||||
(*ppArchive)->messageHandlerFunc = gNuGlobalErrorMessageHandler;
|
(*ppArchive)->messageHandlerFunc = gNuGlobalErrorMessageHandler;
|
||||||
|
|
||||||
@ -231,6 +234,7 @@ bail:
|
|||||||
* assumed to start at offset 0.
|
* assumed to start at offset 0.
|
||||||
*
|
*
|
||||||
* Wrappers must appear in this order:
|
* Wrappers must appear in this order:
|
||||||
|
* Leading junk
|
||||||
* Binary II
|
* Binary II
|
||||||
* ShrinkIt SEA (Self-Extracting Archive)
|
* ShrinkIt SEA (Self-Extracting Archive)
|
||||||
*
|
*
|
||||||
@ -266,7 +270,9 @@ Nu_UpdateWrapper(NuArchive* pArchive, FILE* fp)
|
|||||||
hasBinary2 = hasSea = true;
|
hasBinary2 = hasSea = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (pArchive->headerOffset) {
|
if (pArchive->headerOffset != 0 &&
|
||||||
|
pArchive->headerOffset != pArchive->junkOffset)
|
||||||
|
{
|
||||||
Nu_ReportError(NU_BLOB, kNuErrNone, "Can't fix the wrapper??");
|
Nu_ReportError(NU_BLOB, kNuErrNone, "Can't fix the wrapper??");
|
||||||
err = kNuErrInternal;
|
err = kNuErrInternal;
|
||||||
goto bail;
|
goto bail;
|
||||||
@ -274,7 +280,7 @@ Nu_UpdateWrapper(NuArchive* pArchive, FILE* fp)
|
|||||||
goto bail;
|
goto bail;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = Nu_FSeek(fp, 0, SEEK_SET);
|
err = Nu_FSeek(fp, pArchive->junkOffset, SEEK_SET);
|
||||||
BailError(err);
|
BailError(err);
|
||||||
|
|
||||||
if (hasBinary2) {
|
if (hasBinary2) {
|
||||||
@ -290,9 +296,10 @@ Nu_UpdateWrapper(NuArchive* pArchive, FILE* fp)
|
|||||||
goto bail;
|
goto bail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* archiveLen includes the SEA wrapper, if any */
|
/* archiveLen includes the SEA wrapper, if any, but excludes junk */
|
||||||
archiveLen = pArchive->newMasterHeader.mhMasterEOF +
|
archiveLen = pArchive->newMasterHeader.mhMasterEOF +
|
||||||
(pArchive->headerOffset - kNuBinary2BlockSize);
|
(pArchive->headerOffset - pArchive->junkOffset) -
|
||||||
|
kNuBinary2BlockSize;
|
||||||
archiveLen512 = (archiveLen + 511) / 512;
|
archiveLen512 = (archiveLen + 511) / 512;
|
||||||
|
|
||||||
err = Nu_FSeek(fp, kNuBNYFileSizeLo - kNufileIDLen, SEEK_CUR);
|
err = Nu_FSeek(fp, kNuBNYFileSizeLo - kNufileIDLen, SEEK_CUR);
|
||||||
@ -411,7 +418,9 @@ Nu_AdjustWrapperPadding(NuArchive* pArchive, FILE* fp)
|
|||||||
hasBinary2 = hasSea = true;
|
hasBinary2 = hasSea = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (pArchive->headerOffset) {
|
if (pArchive->headerOffset != 0 &&
|
||||||
|
pArchive->headerOffset != pArchive->junkOffset)
|
||||||
|
{
|
||||||
Nu_ReportError(NU_BLOB, kNuErrNone, "Can't check the padding??");
|
Nu_ReportError(NU_BLOB, kNuErrNone, "Can't check the padding??");
|
||||||
err = kNuErrInternal;
|
err = kNuErrInternal;
|
||||||
goto bail;
|
goto bail;
|
||||||
@ -433,7 +442,9 @@ Nu_AdjustWrapperPadding(NuArchive* pArchive, FILE* fp)
|
|||||||
|
|
||||||
err = Nu_FTell(fp, &curOffset);
|
err = Nu_FTell(fp, &curOffset);
|
||||||
BailError(err);
|
BailError(err);
|
||||||
|
curOffset -= pArchive->junkOffset; /* don't factor junk into account */
|
||||||
|
|
||||||
|
DBUG(("+++ BNY needs %ld bytes of padding\n", curOffset & 0x7f));
|
||||||
if (curOffset & 0x7f) {
|
if (curOffset & 0x7f) {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -473,6 +484,13 @@ bail:
|
|||||||
* also interested in related formats, we try to return a meaningful error
|
* also interested in related formats, we try to return a meaningful error
|
||||||
* code for stuff we recognize (especially Binary II).
|
* code for stuff we recognize (especially Binary II).
|
||||||
*
|
*
|
||||||
|
* If at first we don't succeed, we keep trying further along until we
|
||||||
|
* find something we recognize. We don't want to just scan for the
|
||||||
|
* NuFile ID, because that might prevent this from working properly with
|
||||||
|
* SEA archives which push the NuFX start out about 12K. We also wouldn't
|
||||||
|
* be able to update the BNY/SEA wrappers correctly. So, we inch our way
|
||||||
|
* along until we find something we recognize or get bored.
|
||||||
|
*
|
||||||
* On exit, the stream will be positioned just past the master header.
|
* On exit, the stream will be positioned just past the master header.
|
||||||
*/
|
*/
|
||||||
static NuError
|
static NuError
|
||||||
@ -490,7 +508,10 @@ Nu_ReadMasterHeader(NuArchive* pArchive)
|
|||||||
fp = pArchive->archiveFp; /* saves typing */
|
fp = pArchive->archiveFp; /* saves typing */
|
||||||
pHeader = &pArchive->masterHeader;
|
pHeader = &pArchive->masterHeader;
|
||||||
|
|
||||||
pArchive->headerOffset = 0;
|
pArchive->junkOffset = 0;
|
||||||
|
|
||||||
|
retry:
|
||||||
|
pArchive->headerOffset = pArchive->junkOffset;
|
||||||
Nu_ReadBytes(pArchive, fp, pHeader->mhNufileID, kNufileIDLen);
|
Nu_ReadBytes(pArchive, fp, pHeader->mhNufileID, kNufileIDLen);
|
||||||
/* may have read fewer than kNufileIDLen; that's okay */
|
/* may have read fewer than kNufileIDLen; that's okay */
|
||||||
|
|
||||||
@ -548,6 +569,22 @@ Nu_ReadMasterHeader(NuArchive* pArchive)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (memcmp(kNuMasterID, pHeader->mhNufileID, kNufileIDLen) != 0) {
|
if (memcmp(kNuMasterID, pHeader->mhNufileID, kNufileIDLen) != 0) {
|
||||||
|
/*
|
||||||
|
* Doesn't look like a NuFX archive. Scan forward and see if we
|
||||||
|
* can find the start past some leading junk. MacBinary headers
|
||||||
|
* and chunks of HTTP seem popular on FTP sites.
|
||||||
|
*/
|
||||||
|
if ((pArchive->openMode == kNuOpenRO ||
|
||||||
|
pArchive->openMode == kNuOpenRW) &&
|
||||||
|
pArchive->junkOffset < (long)pArchive->valJunkSkipMax)
|
||||||
|
{
|
||||||
|
pArchive->junkOffset++;
|
||||||
|
DBUG(("+++ scanning from offset %ld\n", pArchive->junkOffset));
|
||||||
|
err = Nu_SeekArchive(pArchive, fp, pArchive->junkOffset, SEEK_SET);
|
||||||
|
BailError(err);
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
|
||||||
err = kNuErrNotNuFX;
|
err = kNuErrNotNuFX;
|
||||||
|
|
||||||
if (isBinary2) {
|
if (isBinary2) {
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read one little-endian bytes, optionally computing a CRC.
|
* Read one byte, optionally computing a CRC.
|
||||||
*/
|
*/
|
||||||
uchar
|
uchar
|
||||||
Nu_ReadOneC(NuArchive* pArchive, FILE* fp, ushort* pCrc)
|
Nu_ReadOneC(NuArchive* pArchive, FILE* fp, ushort* pCrc)
|
||||||
@ -38,7 +38,7 @@ Nu_ReadOneC(NuArchive* pArchive, FILE* fp, ushort* pCrc)
|
|||||||
ic = getc(fp);
|
ic = getc(fp);
|
||||||
*pCrc = Nu_UpdateCRC16((uchar)ic, *pCrc);
|
*pCrc = Nu_UpdateCRC16((uchar)ic, *pCrc);
|
||||||
|
|
||||||
return ic;
|
return (uchar) ic;
|
||||||
}
|
}
|
||||||
|
|
||||||
uchar
|
uchar
|
||||||
|
@ -1,3 +1,11 @@
|
|||||||
|
2003/10/16 ***** v2.0.1 shipped *****
|
||||||
|
|
||||||
|
2003/10/16 fadden
|
||||||
|
- Added workaround for bad HFS option lists created by GSHK.
|
||||||
|
- Added junk-skipping feature. Up to 1024 bytes of crud (e.g.
|
||||||
|
MacBinary headers or HTTP remnants) will be searched for evidence
|
||||||
|
of an archive.
|
||||||
|
|
||||||
2003/06/19 sheppy
|
2003/06/19 sheppy
|
||||||
- Added support for resource forks and file and aux types when built
|
- Added support for resource forks and file and aux types when built
|
||||||
for Mac OS X.
|
for Mac OS X.
|
||||||
|
@ -366,7 +366,8 @@ Nu_DebugDumpAll(NuArchive* pArchive)
|
|||||||
|
|
||||||
printf("*Archive pathname: '%s'\n", pArchive->archivePathname);
|
printf("*Archive pathname: '%s'\n", pArchive->archivePathname);
|
||||||
printf("*Archive type: %d\n", pArchive->archiveType);
|
printf("*Archive type: %d\n", pArchive->archiveType);
|
||||||
printf("*Header offset: %ld\n", pArchive->headerOffset);
|
printf("*Header offset: %ld (junk offset=%ld)\n",
|
||||||
|
pArchive->headerOffset, pArchive->junkOffset);
|
||||||
printf("*Num records: %ld orig, %ld copy, %ld new\n",
|
printf("*Num records: %ld orig, %ld copy, %ld new\n",
|
||||||
Nu_RecordSet_GetNumRecords(&pArchive->origRecordSet),
|
Nu_RecordSet_GetNumRecords(&pArchive->origRecordSet),
|
||||||
Nu_RecordSet_GetNumRecords(&pArchive->copyRecordSet),
|
Nu_RecordSet_GetNumRecords(&pArchive->copyRecordSet),
|
||||||
|
@ -2351,6 +2351,8 @@ Nu_Flush(NuArchive* pArchive, long* pStatusFlags)
|
|||||||
* assumption is invalid, we'd need to adjust "headerOffset" earlier,
|
* assumption is invalid, we'd need to adjust "headerOffset" earlier,
|
||||||
* or do lots of data copying. Looks like Binary II and SEA headers
|
* or do lots of data copying. Looks like Binary II and SEA headers
|
||||||
* are both fixed size, so we should be okay.
|
* are both fixed size, so we should be okay.
|
||||||
|
*
|
||||||
|
* We also carry forward any unrecognized junk.
|
||||||
*/
|
*/
|
||||||
if (pArchive->headerOffset) {
|
if (pArchive->headerOffset) {
|
||||||
if (writeToTemp) {
|
if (writeToTemp) {
|
||||||
|
@ -33,7 +33,7 @@ extern "C" {
|
|||||||
*/
|
*/
|
||||||
#define kNuVersionMajor 2
|
#define kNuVersionMajor 2
|
||||||
#define kNuVersionMinor 0
|
#define kNuVersionMinor 0
|
||||||
#define kNuVersionBug 0
|
#define kNuVersionBug 1
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -268,7 +268,8 @@ typedef enum NuValueID {
|
|||||||
kNuValueModifyOrig = 9,
|
kNuValueModifyOrig = 9,
|
||||||
kNuValueMimicSHK = 10,
|
kNuValueMimicSHK = 10,
|
||||||
kNuValueMaskDataless = 11,
|
kNuValueMaskDataless = 11,
|
||||||
kNuValueStripHighASCII = 12
|
kNuValueStripHighASCII = 12,
|
||||||
|
kNuValueJunkSkipMax = 13
|
||||||
} NuValueID;
|
} NuValueID;
|
||||||
typedef unsigned long NuValue;
|
typedef unsigned long NuValue;
|
||||||
|
|
||||||
|
@ -103,6 +103,9 @@ struct NuArchive {
|
|||||||
char* archivePathname; /* pathname or "(stream)" */
|
char* archivePathname; /* pathname or "(stream)" */
|
||||||
FILE* archiveFp;
|
FILE* archiveFp;
|
||||||
NuArchiveType archiveType;
|
NuArchiveType archiveType;
|
||||||
|
|
||||||
|
/* stuff before NuFX; both offsets are from 0, i.e. hdrOff includes junk */
|
||||||
|
long junkOffset; /* skip past leading junk */
|
||||||
long headerOffset; /* adjustment for BXY/SEA/BSE */
|
long headerOffset; /* adjustment for BXY/SEA/BSE */
|
||||||
|
|
||||||
char* tmpPathname; /* temp file, for writes */
|
char* tmpPathname; /* temp file, for writes */
|
||||||
@ -152,6 +155,7 @@ struct NuArchive {
|
|||||||
NuValue valModifyOrig; /* modify original arc in place? */
|
NuValue valModifyOrig; /* modify original arc in place? */
|
||||||
NuValue valOnlyUpdateOlder; /* modify original arc in place? */
|
NuValue valOnlyUpdateOlder; /* modify original arc in place? */
|
||||||
NuValue valStripHighASCII; /* during EOL conv, strip hi bit? */
|
NuValue valStripHighASCII; /* during EOL conv, strip hi bit? */
|
||||||
|
NuValue valJunkSkipMax; /* scan this far for header */
|
||||||
|
|
||||||
/* callback functions */
|
/* callback functions */
|
||||||
NuCallback selectionFilterFunc;
|
NuCallback selectionFilterFunc;
|
||||||
|
@ -953,11 +953,29 @@ Nu_ReadRecordHeader(NuArchive* pArchive, NuRecord* pRecord)
|
|||||||
pRecord->recOptionSize = Nu_ReadTwoC(pArchive, fp, &crc);
|
pRecord->recOptionSize = Nu_ReadTwoC(pArchive, fp, &crc);
|
||||||
bytesRead += 2;
|
bytesRead += 2;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* It appears GS/ShrinkIt is creating bad option lists, claiming
|
||||||
|
* 36 bytes of data when there's only room for 18. Since we don't
|
||||||
|
* really pay attention to the option list
|
||||||
|
*/
|
||||||
|
if (pRecord->recOptionSize + bytesRead > pRecord->recAttribCount -2) {
|
||||||
|
DBUG(("--- truncating option list from %d to %d\n",
|
||||||
|
pRecord->recOptionSize,
|
||||||
|
pRecord->recAttribCount -2 - bytesRead));
|
||||||
|
if (pRecord->recAttribCount -2 > bytesRead)
|
||||||
|
pRecord->recOptionSize = pRecord->recAttribCount -2 - bytesRead;
|
||||||
|
else
|
||||||
|
pRecord->recOptionSize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* this is the older test, which rejected funky archives */
|
||||||
if (pRecord->recOptionSize + bytesRead > pRecord->recAttribCount -2) {
|
if (pRecord->recOptionSize + bytesRead > pRecord->recAttribCount -2) {
|
||||||
/* option size exceeds the total attribute area */
|
/* option size exceeds the total attribute area */
|
||||||
err = kNuErrBadRecord;
|
err = kNuErrBadRecord;
|
||||||
Nu_ReportError(NU_BLOB, kNuErrBadRecord,
|
Nu_ReportError(NU_BLOB, kNuErrBadRecord,
|
||||||
"Option size exceeds attribs (%u)", pRecord->recOptionSize);
|
"Option size (%u) exceeds attribs (%u,%u-2)",
|
||||||
|
pRecord->recOptionSize, bytesRead,
|
||||||
|
pRecord->recAttribCount);
|
||||||
goto bail;
|
goto bail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
*/
|
*/
|
||||||
#include "NufxLibPriv.h"
|
#include "NufxLibPriv.h"
|
||||||
|
|
||||||
|
#define kMaxJunkSkipMax 8192
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get a configurable parameter.
|
* Get a configurable parameter.
|
||||||
@ -57,6 +59,9 @@ Nu_GetValue(NuArchive* pArchive, NuValueID ident, NuValue* pValue)
|
|||||||
case kNuValueStripHighASCII:
|
case kNuValueStripHighASCII:
|
||||||
*pValue = pArchive->valStripHighASCII;
|
*pValue = pArchive->valStripHighASCII;
|
||||||
break;
|
break;
|
||||||
|
case kNuValueJunkSkipMax:
|
||||||
|
*pValue = pArchive->valJunkSkipMax;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
err = kNuErrInvalidArg;
|
err = kNuErrInvalidArg;
|
||||||
Nu_ReportError(NU_BLOB, err, "Unknown ValueID %d requested", ident);
|
Nu_ReportError(NU_BLOB, err, "Unknown ValueID %d requested", ident);
|
||||||
@ -168,11 +173,19 @@ Nu_SetValue(NuArchive* pArchive, NuValueID ident, NuValue value)
|
|||||||
case kNuValueStripHighASCII:
|
case kNuValueStripHighASCII:
|
||||||
if (value != true && value != false) {
|
if (value != true && value != false) {
|
||||||
Nu_ReportError(NU_BLOB, err,
|
Nu_ReportError(NU_BLOB, err,
|
||||||
"Invalid kNuStripHighASCII value %ld", value);
|
"Invalid kNuValueStripHighASCII value %ld", value);
|
||||||
goto bail;
|
goto bail;
|
||||||
}
|
}
|
||||||
pArchive->valStripHighASCII = value;
|
pArchive->valStripHighASCII = value;
|
||||||
break;
|
break;
|
||||||
|
case kNuValueJunkSkipMax:
|
||||||
|
if (value > kMaxJunkSkipMax) {
|
||||||
|
Nu_ReportError(NU_BLOB, err,
|
||||||
|
"Invalid kNuValueJunkSkipMax value %ld", value);
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
|
pArchive->valJunkSkipMax = value;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
Nu_ReportError(NU_BLOB, err, "Unknown ValueID %d requested", ident);
|
Nu_ReportError(NU_BLOB, err, "Unknown ValueID %d requested", ident);
|
||||||
goto bail;
|
goto bail;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user