mirror of
https://github.com/fadden/nulib2.git
synced 2025-01-14 01:29:43 +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 kNuSEALength2 12001 /* length of archive (4B?) */
|
||||
|
||||
#define kDefaultJunkSkipMax 1024 /* default junk scan size */
|
||||
|
||||
static void Nu_CloseAndFree(NuArchive* pArchive);
|
||||
|
||||
@ -93,6 +94,8 @@ Nu_NuArchiveNew(NuArchive** ppArchive)
|
||||
(*ppArchive)->valMimicSHK = false;
|
||||
(*ppArchive)->valMaskDataless = false;
|
||||
(*ppArchive)->valStripHighASCII = false;
|
||||
/* bug: this can't be set by application! */
|
||||
(*ppArchive)->valJunkSkipMax = kDefaultJunkSkipMax;
|
||||
|
||||
(*ppArchive)->messageHandlerFunc = gNuGlobalErrorMessageHandler;
|
||||
|
||||
@ -231,6 +234,7 @@ bail:
|
||||
* assumed to start at offset 0.
|
||||
*
|
||||
* Wrappers must appear in this order:
|
||||
* Leading junk
|
||||
* Binary II
|
||||
* ShrinkIt SEA (Self-Extracting Archive)
|
||||
*
|
||||
@ -266,7 +270,9 @@ Nu_UpdateWrapper(NuArchive* pArchive, FILE* fp)
|
||||
hasBinary2 = hasSea = true;
|
||||
break;
|
||||
default:
|
||||
if (pArchive->headerOffset) {
|
||||
if (pArchive->headerOffset != 0 &&
|
||||
pArchive->headerOffset != pArchive->junkOffset)
|
||||
{
|
||||
Nu_ReportError(NU_BLOB, kNuErrNone, "Can't fix the wrapper??");
|
||||
err = kNuErrInternal;
|
||||
goto bail;
|
||||
@ -274,7 +280,7 @@ Nu_UpdateWrapper(NuArchive* pArchive, FILE* fp)
|
||||
goto bail;
|
||||
}
|
||||
|
||||
err = Nu_FSeek(fp, 0, SEEK_SET);
|
||||
err = Nu_FSeek(fp, pArchive->junkOffset, SEEK_SET);
|
||||
BailError(err);
|
||||
|
||||
if (hasBinary2) {
|
||||
@ -290,9 +296,10 @@ Nu_UpdateWrapper(NuArchive* pArchive, FILE* fp)
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* archiveLen includes the SEA wrapper, if any */
|
||||
/* archiveLen includes the SEA wrapper, if any, but excludes junk */
|
||||
archiveLen = pArchive->newMasterHeader.mhMasterEOF +
|
||||
(pArchive->headerOffset - kNuBinary2BlockSize);
|
||||
(pArchive->headerOffset - pArchive->junkOffset) -
|
||||
kNuBinary2BlockSize;
|
||||
archiveLen512 = (archiveLen + 511) / 512;
|
||||
|
||||
err = Nu_FSeek(fp, kNuBNYFileSizeLo - kNufileIDLen, SEEK_CUR);
|
||||
@ -411,7 +418,9 @@ Nu_AdjustWrapperPadding(NuArchive* pArchive, FILE* fp)
|
||||
hasBinary2 = hasSea = true;
|
||||
break;
|
||||
default:
|
||||
if (pArchive->headerOffset) {
|
||||
if (pArchive->headerOffset != 0 &&
|
||||
pArchive->headerOffset != pArchive->junkOffset)
|
||||
{
|
||||
Nu_ReportError(NU_BLOB, kNuErrNone, "Can't check the padding??");
|
||||
err = kNuErrInternal;
|
||||
goto bail;
|
||||
@ -433,7 +442,9 @@ Nu_AdjustWrapperPadding(NuArchive* pArchive, FILE* fp)
|
||||
|
||||
err = Nu_FTell(fp, &curOffset);
|
||||
BailError(err);
|
||||
curOffset -= pArchive->junkOffset; /* don't factor junk into account */
|
||||
|
||||
DBUG(("+++ BNY needs %ld bytes of padding\n", curOffset & 0x7f));
|
||||
if (curOffset & 0x7f) {
|
||||
int i;
|
||||
|
||||
@ -473,6 +484,13 @@ bail:
|
||||
* also interested in related formats, we try to return a meaningful error
|
||||
* 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.
|
||||
*/
|
||||
static NuError
|
||||
@ -490,7 +508,10 @@ Nu_ReadMasterHeader(NuArchive* pArchive)
|
||||
fp = pArchive->archiveFp; /* saves typing */
|
||||
pHeader = &pArchive->masterHeader;
|
||||
|
||||
pArchive->headerOffset = 0;
|
||||
pArchive->junkOffset = 0;
|
||||
|
||||
retry:
|
||||
pArchive->headerOffset = pArchive->junkOffset;
|
||||
Nu_ReadBytes(pArchive, fp, pHeader->mhNufileID, kNufileIDLen);
|
||||
/* may have read fewer than kNufileIDLen; that's okay */
|
||||
|
||||
@ -548,6 +569,22 @@ Nu_ReadMasterHeader(NuArchive* pArchive)
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (isBinary2) {
|
||||
|
@ -24,7 +24,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Read one little-endian bytes, optionally computing a CRC.
|
||||
* Read one byte, optionally computing a CRC.
|
||||
*/
|
||||
uchar
|
||||
Nu_ReadOneC(NuArchive* pArchive, FILE* fp, ushort* pCrc)
|
||||
@ -38,7 +38,7 @@ Nu_ReadOneC(NuArchive* pArchive, FILE* fp, ushort* pCrc)
|
||||
ic = getc(fp);
|
||||
*pCrc = Nu_UpdateCRC16((uchar)ic, *pCrc);
|
||||
|
||||
return ic;
|
||||
return (uchar) ic;
|
||||
}
|
||||
|
||||
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
|
||||
- Added support for resource forks and file and aux types when built
|
||||
for Mac OS X.
|
||||
|
@ -366,7 +366,8 @@ Nu_DebugDumpAll(NuArchive* pArchive)
|
||||
|
||||
printf("*Archive pathname: '%s'\n", pArchive->archivePathname);
|
||||
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",
|
||||
Nu_RecordSet_GetNumRecords(&pArchive->origRecordSet),
|
||||
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,
|
||||
* or do lots of data copying. Looks like Binary II and SEA headers
|
||||
* are both fixed size, so we should be okay.
|
||||
*
|
||||
* We also carry forward any unrecognized junk.
|
||||
*/
|
||||
if (pArchive->headerOffset) {
|
||||
if (writeToTemp) {
|
||||
|
@ -33,7 +33,7 @@ extern "C" {
|
||||
*/
|
||||
#define kNuVersionMajor 2
|
||||
#define kNuVersionMinor 0
|
||||
#define kNuVersionBug 0
|
||||
#define kNuVersionBug 1
|
||||
|
||||
|
||||
/*
|
||||
@ -268,7 +268,8 @@ typedef enum NuValueID {
|
||||
kNuValueModifyOrig = 9,
|
||||
kNuValueMimicSHK = 10,
|
||||
kNuValueMaskDataless = 11,
|
||||
kNuValueStripHighASCII = 12
|
||||
kNuValueStripHighASCII = 12,
|
||||
kNuValueJunkSkipMax = 13
|
||||
} NuValueID;
|
||||
typedef unsigned long NuValue;
|
||||
|
||||
|
@ -103,6 +103,9 @@ struct NuArchive {
|
||||
char* archivePathname; /* pathname or "(stream)" */
|
||||
FILE* archiveFp;
|
||||
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 */
|
||||
|
||||
char* tmpPathname; /* temp file, for writes */
|
||||
@ -152,6 +155,7 @@ struct NuArchive {
|
||||
NuValue valModifyOrig; /* modify original arc in place? */
|
||||
NuValue valOnlyUpdateOlder; /* modify original arc in place? */
|
||||
NuValue valStripHighASCII; /* during EOL conv, strip hi bit? */
|
||||
NuValue valJunkSkipMax; /* scan this far for header */
|
||||
|
||||
/* callback functions */
|
||||
NuCallback selectionFilterFunc;
|
||||
|
@ -953,11 +953,29 @@ Nu_ReadRecordHeader(NuArchive* pArchive, NuRecord* pRecord)
|
||||
pRecord->recOptionSize = Nu_ReadTwoC(pArchive, fp, &crc);
|
||||
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) {
|
||||
/* option size exceeds the total attribute area */
|
||||
err = 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;
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,8 @@
|
||||
*/
|
||||
#include "NufxLibPriv.h"
|
||||
|
||||
#define kMaxJunkSkipMax 8192
|
||||
|
||||
|
||||
/*
|
||||
* Get a configurable parameter.
|
||||
@ -57,6 +59,9 @@ Nu_GetValue(NuArchive* pArchive, NuValueID ident, NuValue* pValue)
|
||||
case kNuValueStripHighASCII:
|
||||
*pValue = pArchive->valStripHighASCII;
|
||||
break;
|
||||
case kNuValueJunkSkipMax:
|
||||
*pValue = pArchive->valJunkSkipMax;
|
||||
break;
|
||||
default:
|
||||
err = kNuErrInvalidArg;
|
||||
Nu_ReportError(NU_BLOB, err, "Unknown ValueID %d requested", ident);
|
||||
@ -168,11 +173,19 @@ Nu_SetValue(NuArchive* pArchive, NuValueID ident, NuValue value)
|
||||
case kNuValueStripHighASCII:
|
||||
if (value != true && value != false) {
|
||||
Nu_ReportError(NU_BLOB, err,
|
||||
"Invalid kNuStripHighASCII value %ld", value);
|
||||
"Invalid kNuValueStripHighASCII value %ld", value);
|
||||
goto bail;
|
||||
}
|
||||
pArchive->valStripHighASCII = value;
|
||||
break;
|
||||
case kNuValueJunkSkipMax:
|
||||
if (value > kMaxJunkSkipMax) {
|
||||
Nu_ReportError(NU_BLOB, err,
|
||||
"Invalid kNuValueJunkSkipMax value %ld", value);
|
||||
goto bail;
|
||||
}
|
||||
pArchive->valJunkSkipMax = value;
|
||||
break;
|
||||
default:
|
||||
Nu_ReportError(NU_BLOB, err, "Unknown ValueID %d requested", ident);
|
||||
goto bail;
|
||||
|
Loading…
x
Reference in New Issue
Block a user