mirror of
https://github.com/fadden/nulib2.git
synced 2024-11-19 14:33:47 +00:00
1169554de3
instead of a "doClose" argument. NufxLib should no longer try to free anything allocated by the application (or vice-versa). The DataSource "copy" function now does refcounting instead of copying. This was done as part of cleaning up some memory leaks in the DataSource code. The samples were all updated with the changes to the API (and the occasional minor valgrind-inspired bug fix).
859 lines
35 KiB
C
859 lines
35 KiB
C
/*
|
|
* NuFX archive manipulation library
|
|
* Copyright (C) 2000-2003 by Andy McFadden, All Rights Reserved.
|
|
* This is free software; you can redistribute it and/or modify it under the
|
|
* terms of the GNU Library General Public License, see the file COPYING-LIB.
|
|
*
|
|
* Global internal declarations and definitions.
|
|
*/
|
|
#ifndef __NufxLibPriv__
|
|
#define __NufxLibPriv__
|
|
|
|
/* include files that everybody needs */
|
|
#include "SysDefs.h"
|
|
#include "NufxLib.h"
|
|
#include "MiscStuff.h"
|
|
|
|
#ifdef USE_DMALLOC
|
|
/* enable with something like "dmalloc -l logfile -i 100 medium" */
|
|
# include "dmalloc.h"
|
|
#endif
|
|
|
|
|
|
/*
|
|
* ===========================================================================
|
|
* NuArchive definition
|
|
* ===========================================================================
|
|
*/
|
|
|
|
/*
|
|
* Archives can be opened in streaming read-only, non-streaming read-only,
|
|
* and non-streaming read-write mode.
|
|
*/
|
|
typedef enum NuOpenMode {
|
|
kNuOpenUnknown,
|
|
kNuOpenStreamingRO,
|
|
kNuOpenRO,
|
|
kNuOpenRW
|
|
} NuOpenMode;
|
|
#define Nu_IsStreaming(pArchive) ((pArchive)->openMode == kNuOpenStreamingRO)
|
|
#define Nu_IsReadOnly(pArchive) ((pArchive)->openMode == kNuOpenStreamingRO ||\
|
|
(pArchive)->openMode == kNuOpenRO)
|
|
|
|
#ifdef FOPEN_WANTS_B
|
|
# define kNuFileOpenReadOnly "rb"
|
|
# define kNuFileOpenReadWrite "r+b"
|
|
# define kNuFileOpenWriteTrunc "wb"
|
|
# define kNuFileOpenReadWriteCreat "w+b"
|
|
#else
|
|
# define kNuFileOpenReadOnly "r"
|
|
# define kNuFileOpenReadWrite "r+"
|
|
# define kNuFileOpenWriteTrunc "w"
|
|
# define kNuFileOpenReadWriteCreat "w+"
|
|
#endif
|
|
|
|
|
|
/*
|
|
* Some NuFX and Binary II definitions.
|
|
*/
|
|
#define kNuMasterHeaderSize 48 /* size of fixed-length master header */
|
|
#define kNuRecordHeaderBaseSize 58 /* size of rec hdr up to variable stuff */
|
|
#define kNuThreadHeaderSize 16 /* size of fixed-length thread header */
|
|
#define kNuDefaultFilenameThreadSize 32 /* default size of filename thred */
|
|
#define kNuDefaultCommentSize 200 /* size of GSHK-mimic comments */
|
|
#define kNuBinary2BlockSize 128 /* size of bxy header and padding */
|
|
#define kNuSEAOffset 0x2ee5 /* fixed(??) offset to data in SEA */
|
|
|
|
#define kNuInitialChunkCRC 0x0000 /* start for CRC in LZW/1 chunk */
|
|
#define kNuInitialThreadCRC 0xffff /* start for CRC in v3 thread header */
|
|
|
|
/* size of general-purpose compression buffer */
|
|
#define kNuGenCompBufSize 32768
|
|
|
|
#define kNuCharLF 0x0a
|
|
#define kNuCharCR 0x0d
|
|
|
|
|
|
/*
|
|
* A list of records. Generally we use one of these for read-only
|
|
* archives, and two for read-write.
|
|
*
|
|
* The "loaded" flag is set when we've made some use of the record set.
|
|
* Relying on "numRecords" won't always work; for example, if the "copy"
|
|
* record set was initialized from "orig", and then had all of its records
|
|
* deleted, you couldn't look at "numRecords" and decide whether it was
|
|
* appropriate to use "orig" or not.
|
|
*/
|
|
typedef struct NuRecordSet {
|
|
Boolean loaded;
|
|
ulong numRecords;
|
|
NuRecord* nuRecordHead;
|
|
NuRecord* nuRecordTail;
|
|
} NuRecordSet;
|
|
|
|
/*
|
|
* Archive state.
|
|
*/
|
|
struct NuArchive {
|
|
ulong structMagic;
|
|
Boolean busy;
|
|
|
|
NuOpenMode openMode;
|
|
Boolean newlyCreated;
|
|
char* archivePathname; /* pathname or "(stream)" */
|
|
FILE* archiveFp;
|
|
NuArchiveType archiveType;
|
|
long headerOffset; /* adjustment for BXY/SEA/BSE */
|
|
|
|
char* tmpPathname; /* temp file, for writes */
|
|
FILE* tmpFp;
|
|
|
|
/* used during initial processing; helps avoid ftell() calls */
|
|
long currentOffset;
|
|
|
|
/* setting this changes Extract into Test */
|
|
Boolean testMode;
|
|
|
|
/* clumsy way of remembering name used for other fork in forked file */
|
|
const char* lastFileCreated;
|
|
/* clumsy way to avoid trying to create the same subdir several times */
|
|
const char* lastDirCreated;
|
|
|
|
/* master header from the archive */
|
|
NuMasterHeader masterHeader; /* original */
|
|
NuMasterHeader newMasterHeader; /* working copy during update */
|
|
|
|
/* list of records from archive, plus some extra state */
|
|
NuRecordIdx recordIdxSeed; /* where the NuRecordIdxs start */
|
|
NuRecordIdx nextRecordIdx; /* next record gets this value */
|
|
Boolean haveToc; /* set if we have full TOC */
|
|
NuRecordSet origRecordSet; /* records from archive */
|
|
NuRecordSet copyRecordSet; /* copy of orig, for write ops */
|
|
NuRecordSet newRecordSet; /* newly-added records */
|
|
|
|
/* state for compression functions */
|
|
uchar* compBuf; /* large general-purpose buffer */
|
|
void* lzwCompressState; /* state for LZW/1 and LZW/2 */
|
|
void* lzwExpandState; /* state for LZW/1 and LZW/2 */
|
|
|
|
/* options and attributes that the user can set */
|
|
/* (these can be changed by a callback, so don't cache them internally) */
|
|
void* extraData; /* application-defined pointer */
|
|
|
|
NuValue valAllowDuplicates; /* allow dups when adding? */
|
|
NuValue valConvertExtractedEOL; /* convert EOL during extract? */
|
|
NuValue valDataCompression; /* how to compress when adding? */
|
|
NuValue valDiscardWrapper; /* remove BNY or SEA header? */
|
|
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? */
|
|
|
|
/* callback functions */
|
|
NuCallback selectionFilterFunc;
|
|
NuCallback outputPathnameFunc;
|
|
NuCallback progressUpdaterFunc;
|
|
NuCallback errorHandlerFunc;
|
|
NuCallback messageHandlerFunc;
|
|
};
|
|
|
|
#define kNuArchiveStructMagic 0xc0edbabe
|
|
|
|
#define kNuDefaultRecordName "UNKNOWN"
|
|
|
|
|
|
/*
|
|
* ===========================================================================
|
|
* ThreadMod definition
|
|
* ===========================================================================
|
|
*/
|
|
|
|
/* operations we can perform on threads in a record */
|
|
typedef enum ThreadModKind {
|
|
kNuThreadModUnknown = 0,
|
|
|
|
kNuThreadModAdd,
|
|
kNuThreadModUpdate,
|
|
kNuThreadModDelete
|
|
} ThreadModKind;
|
|
|
|
/*
|
|
* We attach a list of these to records we plan to modify. Care is taken
|
|
* to ensure that they don't conflict, e.g. you can't update a thread
|
|
* right after you delete it, nor delete one you have modified.
|
|
*/
|
|
struct NuThreadMod {
|
|
union {
|
|
ThreadModKind kind;
|
|
|
|
struct {
|
|
ThreadModKind kind;
|
|
Boolean used;
|
|
} generic;
|
|
|
|
struct {
|
|
ThreadModKind kind;
|
|
Boolean used;
|
|
Boolean isPresized;
|
|
NuThreadIdx threadIdx;
|
|
NuThreadID threadID;
|
|
NuThreadFormat threadFormat;
|
|
NuDataSource* pDataSource;
|
|
} add;
|
|
|
|
struct {
|
|
ThreadModKind kind;
|
|
Boolean used;
|
|
NuThreadIdx threadIdx;
|
|
NuDataSource* pDataSource;
|
|
} update;
|
|
|
|
struct {
|
|
ThreadModKind kind;
|
|
Boolean used;
|
|
NuThreadIdx threadIdx;
|
|
NuThreadID threadID; /* used for watching filename threads */
|
|
} delete;
|
|
} entry;
|
|
|
|
struct NuThreadMod* pNext;
|
|
};
|
|
|
|
|
|
/*
|
|
* ===========================================================================
|
|
* NuFunnel/NuStraw definition
|
|
* ===========================================================================
|
|
*/
|
|
|
|
#define kNuFunnelBufSize 16384
|
|
|
|
/*
|
|
* File funnel definition. This is used for writing output to files
|
|
* (so we can do things like pipe compressed output through an LF->CR
|
|
* converter) and archive files (so we can halt compression when the
|
|
* output size exceeds the uncompressed original). [ for various reasons,
|
|
* I'm not using this on the archive anymore. ]
|
|
*
|
|
* Funnels are unidirectional. You write data into them with a
|
|
* function call; the top-level action (which is usually compressing or
|
|
* expanding data) reads from the input and crams things into the pipe.
|
|
* We could fully abstract the concept, and write the compression
|
|
* functions so that they operate as a Funnel filter, but it's much
|
|
* easier to write block-oriented compression than stream-oriented (and
|
|
* more to the point, the ShrinkIt LZW functions are very much
|
|
* block-oriented).
|
|
*/
|
|
typedef struct NuFunnel {
|
|
/* data storage */
|
|
uchar* buffer; /* kNuFunnelBufSize worth of storage */
|
|
long bufCount; /* #of bytes in buffer */
|
|
|
|
/* EOL conversion; if "auto", on first flush we convert to "on" or "off" */
|
|
NuValue convertEOL; /* on/off/auto */
|
|
NuValue convertEOLTo; /* EOL to switch to */
|
|
NuValue convertEOLFrom; /* EOL terminator we think we found */
|
|
Boolean lastCR; /* was last char a CR? */
|
|
|
|
#if 0
|
|
ulong inCount; /* total #of bytes in the top */
|
|
ulong outCount; /* total #of bytes out the bottom */
|
|
|
|
ulong outMax; /* flag an err when outCount exceeds this */
|
|
Boolean outMaxExceeded; /* in fact, it's this flag */
|
|
#endif
|
|
|
|
/* update this when stuff happens */
|
|
NuProgressData* pProgress;
|
|
|
|
/* data goeth out here */
|
|
NuDataSink* pDataSink;
|
|
} NuFunnel;
|
|
|
|
|
|
/*
|
|
* File straw definition. This is used for slurping up input data.
|
|
*
|
|
* Mostly this is an encapsulation of an input source and a progress
|
|
* updater, useful for reading uncompressed data and feeding it to a
|
|
* compressor. It doesn't make sense to show a thermometer based on
|
|
* compressed output, since we don't know how big the eventual result
|
|
* will be, so we want to do it for the input.
|
|
*/
|
|
typedef struct NuStraw {
|
|
/* update this when stuff happens */
|
|
NuProgressData* pProgress;
|
|
|
|
/* data cometh in here */
|
|
NuDataSource* pDataSource;
|
|
|
|
/* progress update fields */
|
|
ulong lastProgress;
|
|
ulong lastDisplayed;
|
|
} NuStraw;
|
|
|
|
/*NuError Nu_CopyStreamToStream(FILE* outfp, FILE* infp, ulong count);*/
|
|
|
|
|
|
/*
|
|
* ===========================================================================
|
|
* Data source and sink abstractions
|
|
* ===========================================================================
|
|
*/
|
|
|
|
/*
|
|
* DataSource is used when adding data to an archive.
|
|
*/
|
|
|
|
typedef enum NuDataSourceType {
|
|
kNuDataSourceUnknown = 0,
|
|
kNuDataSourceFromFile,
|
|
kNuDataSourceFromFP,
|
|
kNuDataSourceFromBuffer
|
|
} NuDataSourceType;
|
|
|
|
typedef struct NuDataSourceCommon {
|
|
NuDataSourceType sourceType;
|
|
NuThreadFormat threadFormat; /* is it already compressed? */
|
|
ushort rawCrc; /* crc for already-compressed data*/
|
|
/*Boolean doClose; \* close on completion? */
|
|
ulong dataLen; /* length of data (var for buf) */
|
|
ulong otherLen; /* uncomp len or preset buf size */
|
|
int refCount; /* so we can copy structs */
|
|
} NuDataSourceCommon;
|
|
|
|
union NuDataSource {
|
|
NuDataSourceType sourceType;
|
|
|
|
NuDataSourceCommon common;
|
|
|
|
struct {
|
|
NuDataSourceCommon common;
|
|
char* pathname;
|
|
Boolean fromRsrcFork;
|
|
|
|
/* temp storage; only valid when processing in library */
|
|
FILE* fp;
|
|
} fromFile;
|
|
|
|
struct {
|
|
NuDataSourceCommon common;
|
|
FILE* fp;
|
|
long offset; /* starting offset */
|
|
|
|
NuCallback fcloseFunc; /* how to fclose the file */
|
|
} fromFP;
|
|
|
|
struct {
|
|
NuDataSourceCommon common;
|
|
const uchar* buffer; /* non-const if doClose=true */
|
|
long offset; /* starting offset */
|
|
|
|
long curOffset; /* current offset */
|
|
long curDataLen; /* remaining data */
|
|
|
|
NuCallback freeFunc; /* how to free data */
|
|
} fromBuffer;
|
|
};
|
|
|
|
|
|
/*
|
|
* DataSink is used when extracting data from an archive.
|
|
*/
|
|
|
|
typedef enum NuDataSinkType {
|
|
kNuDataSinkUnknown = 0,
|
|
kNuDataSinkToFile,
|
|
kNuDataSinkToFP,
|
|
kNuDataSinkToBuffer,
|
|
kNuDataSinkToVoid
|
|
} NuDataSinkType;
|
|
|
|
typedef struct NuDataSinkCommon {
|
|
NuDataSinkType sinkType;
|
|
Boolean doExpand; /* expand file? */
|
|
NuValue convertEOL; /* convert EOL? (req "expand") */
|
|
ulong outCount;
|
|
} NuDataSinkCommon;
|
|
|
|
union NuDataSink {
|
|
NuDataSinkType sinkType;
|
|
|
|
NuDataSinkCommon common;
|
|
|
|
struct {
|
|
NuDataSinkCommon common;
|
|
char* pathname; /* file to open */
|
|
char fssep;
|
|
|
|
/* temp storage; must be nil except when processing in library */
|
|
FILE* fp;
|
|
} toFile;
|
|
|
|
struct {
|
|
NuDataSinkCommon common;
|
|
FILE* fp;
|
|
} toFP;
|
|
|
|
struct {
|
|
NuDataSinkCommon common;
|
|
uchar* buffer;
|
|
ulong bufLen; /* max amount of data "buffer" holds */
|
|
NuError stickyErr;
|
|
} toBuffer;
|
|
};
|
|
|
|
|
|
/*
|
|
* ===========================================================================
|
|
* Function prototypes
|
|
* ===========================================================================
|
|
*/
|
|
|
|
/*
|
|
* This is a little unpleasant. This blob of stuff gets stuffed in as
|
|
* the first arguments to Nu_ReportError, so we don't have to type them
|
|
* in every time we use the function. It would've been much easier to
|
|
* use a gcc-style varargs macro, but not everybody uses gcc.
|
|
*/
|
|
#ifdef DEBUG_MSGS
|
|
#ifdef HAS__FUNCTION__
|
|
#define _FUNCTION_ __FUNCTION__
|
|
#else
|
|
#define _FUNCTION_ ""
|
|
#endif
|
|
|
|
#define NU_BLOB pArchive, __FILE__, __LINE__, _FUNCTION_, false
|
|
#define NU_BLOB_DEBUG pArchive, __FILE__, __LINE__, _FUNCTION_, true
|
|
#define NU_NILBLOB NULL, __FILE__, __LINE__, _FUNCTION_, false
|
|
#define DebugShowError(err) \
|
|
Nu_ReportError(pArchive, __FILE__, __LINE__, _FUNCTION_, \
|
|
true, err, "(DEBUG)");
|
|
#else
|
|
#define NU_BLOB pArchive, "", 0, "", false
|
|
#define NU_BLOB_DEBUG pArchive, "", 0, "", true
|
|
#define NU_NILBLOB NULL, "", 0, "", false
|
|
#define DebugShowError(err) ((void)0)
|
|
#endif
|
|
|
|
/*
|
|
* The BailError macro serves two purposes. First, it's a convenient
|
|
* way to avoid typing, "if (err != kNuErrNone) goto bail;". Second,
|
|
* when the library is built with debugging enabled, it vitually gives
|
|
* us a stack trace of exiting functions. This makes it easier to debug
|
|
* problems sent in as screen dumps via e-mail.
|
|
*/
|
|
#define BailError(err) { \
|
|
if ((err) != kNuErrNone) { \
|
|
/* [should this be debug-only, or all the time?] */ \
|
|
DebugShowError(err); \
|
|
goto bail; \
|
|
} \
|
|
}
|
|
#define BailErrorQuiet(err) { \
|
|
if ((err) != kNuErrNone) \
|
|
goto bail; \
|
|
}
|
|
#define BailNil(val) { \
|
|
if ((val) == nil) { \
|
|
err = kNuErrUnexpectedNil; \
|
|
BailError(err); \
|
|
} \
|
|
}
|
|
#define BailAlloc(val) { \
|
|
if ((val) == nil) { \
|
|
err = kNuErrMalloc; \
|
|
BailError(err); \
|
|
} \
|
|
}
|
|
|
|
|
|
/*
|
|
* Internal function prototypes and inline functions.
|
|
*/
|
|
|
|
/* Archive.c */
|
|
void Nu_MasterHeaderCopy(NuArchive* pArchive, NuMasterHeader* pDstHeader,
|
|
const NuMasterHeader* pSrcHeader);
|
|
NuError Nu_GetMasterHeader(NuArchive* pArchive,
|
|
const NuMasterHeader** ppMasterHeader);
|
|
NuRecordIdx Nu_GetNextRecordIdx(NuArchive* pArchive);
|
|
NuThreadIdx Nu_GetNextThreadIdx(NuArchive* pArchive);
|
|
NuError Nu_CopyWrapperToTemp(NuArchive* pArchive);
|
|
NuError Nu_UpdateWrapper(NuArchive* pArchive, FILE* fp);
|
|
NuError Nu_AdjustWrapperPadding(NuArchive* pArchive, FILE* fp);
|
|
NuError Nu_AllocCompressionBufferIFN(NuArchive* pArchive);
|
|
NuError Nu_StreamOpenRO(FILE* infp, NuArchive** ppArchive);
|
|
NuError Nu_OpenRO(const char* filename, NuArchive** ppArchive);
|
|
NuError Nu_OpenRW(const char* archivePathname, const char* tempPathname,
|
|
ulong flags, NuArchive** ppArchive);
|
|
NuError Nu_WriteMasterHeader(NuArchive* pArchive, FILE* fp,
|
|
NuMasterHeader* pMasterHeader);
|
|
NuError Nu_Close(NuArchive* pArchive);
|
|
NuError Nu_Abort(NuArchive* pArchive);
|
|
NuError Nu_RenameTempToArchive(NuArchive* pArchive);
|
|
NuError Nu_DeleteArchiveFile(NuArchive* pArchive);
|
|
|
|
/* ArchiveIO.c */
|
|
uchar Nu_ReadOneC(NuArchive* pArchive, FILE* fp, ushort* pCrc);
|
|
uchar Nu_ReadOne(NuArchive* pArchive, FILE* fp);
|
|
void Nu_WriteOneC(NuArchive* pArchive, FILE* fp, uchar val, ushort* pCrc);
|
|
void Nu_WriteOne(NuArchive* pArchive, FILE* fp, uchar val);
|
|
ushort Nu_ReadTwoC(NuArchive* pArchive, FILE* fp, ushort* pCrc);
|
|
ushort Nu_ReadTwo(NuArchive* pArchive, FILE* fp);
|
|
void Nu_WriteTwoC(NuArchive* pArchive, FILE* fp, ushort val, ushort* pCrc);
|
|
void Nu_WriteTwo(NuArchive* pArchive, FILE* fp, ushort val);
|
|
ulong Nu_ReadFourC(NuArchive* pArchive, FILE* fp, ushort* pCrc);
|
|
ulong Nu_ReadFour(NuArchive* pArchive, FILE* fp);
|
|
void Nu_WriteFourC(NuArchive* pArchive, FILE* fp, ulong val, ushort* pCrc);
|
|
void Nu_WriteFour(NuArchive* pArchive, FILE* fp, ulong val);
|
|
NuDateTime Nu_ReadDateTimeC(NuArchive* pArchive, FILE* fp, ushort* pCrc);
|
|
NuDateTime Nu_ReadDateTime(NuArchive* pArchive, FILE* fp, ushort* pCrc);
|
|
void Nu_WriteDateTimeC(NuArchive* pArchive, FILE* fp, NuDateTime dateTime,
|
|
ushort* pCrc);
|
|
void Nu_WriteDateTime(NuArchive* pArchive, FILE* fp, NuDateTime dateTime);
|
|
void Nu_ReadBytesC(NuArchive* pArchive, FILE* fp, void* vbuffer, long count,
|
|
ushort* pCrc);
|
|
void Nu_ReadBytes(NuArchive* pArchive, FILE* fp, void* vbuffer, long count);
|
|
void Nu_WriteBytesC(NuArchive* pArchive, FILE* fp, const void* vbuffer,
|
|
long count, ushort* pCrc);
|
|
void Nu_WriteBytes(NuArchive* pArchive, FILE* fp, const void* vbuffer,
|
|
long count);
|
|
NuError Nu_HeaderIOFailed(NuArchive* pArchive, FILE* fp);
|
|
NuError Nu_SeekArchive(NuArchive* pArchive, FILE* fp, long offset,
|
|
int ptrname);
|
|
NuError Nu_RewindArchive(NuArchive* pArchive);
|
|
|
|
/* Bzip2.c */
|
|
NuError Nu_CompressBzip2(NuArchive* pArchive, NuStraw* pStraw, FILE* fp,
|
|
ulong srcLen, ulong* pDstLen, ushort* pCrc);
|
|
NuError Nu_ExpandBzip2(NuArchive* pArchive, const NuRecord* pRecord,
|
|
const NuThread* pThread, FILE* infp, NuFunnel* pFunnel, ushort* pCrc);
|
|
|
|
/* Compress.c */
|
|
NuError Nu_CompressToArchive(NuArchive* pArchive, NuDataSource* pDataSource,
|
|
NuThreadID threadID, NuThreadFormat sourceFormat,
|
|
NuThreadFormat targetFormat, NuProgressData* progressData, FILE* dstFp,
|
|
NuThread* pThread);
|
|
NuError Nu_CopyPresizedToArchive(NuArchive* pArchive,
|
|
NuDataSource* pDataSource, NuThreadID threadID, FILE* dstFp,
|
|
NuThread* pThread, char** ppSavedCopy);
|
|
|
|
/* Crc16.c */
|
|
extern const ushort gNuCrc16Table[256];
|
|
ushort Nu_CalcCRC16(ushort seed, const uchar* ptr, int count);
|
|
#ifdef __Crc16_c__ /* just doing "static inline" warns def-but-not-used */
|
|
#define CRC_INLINE /**/
|
|
#else
|
|
#define CRC_INLINE extern inline
|
|
#endif
|
|
#if defined(inline) && !defined(__Crc16_c__) /* somebody ovrd inline def? */
|
|
ushort Nu_UpdateCRC16(uchar val, ushort crc);
|
|
#else
|
|
CRC_INLINE ushort
|
|
Nu_UpdateCRC16(uchar val, ushort crc)
|
|
{
|
|
return (gNuCrc16Table[((crc >> 8) & 0xFF) ^ val] ^ (crc << 8)) & 0xFFFF;
|
|
}
|
|
#endif
|
|
|
|
/* Debug.c */
|
|
#if defined(DEBUG_MSGS) || !defined(NDEBUG)
|
|
void Nu_DebugDumpAll(NuArchive* pArchive);
|
|
void Nu_DebugDumpThread(const NuThread* pThread);
|
|
#endif
|
|
|
|
/* Deferred.c */
|
|
NuError Nu_ThreadModAdd_New(NuArchive* pArchive, NuThreadID threadID,
|
|
NuThreadFormat threadFormat, NuDataSource* pDataSource,
|
|
NuThreadMod** ppThreadMod);
|
|
NuError Nu_ThreadModUpdate_New(NuArchive* pArchive, NuThreadIdx threadIdx,
|
|
NuDataSource* pDataSource, NuThreadMod** ppThreadMod);
|
|
NuError Nu_ThreadModDelete_New(NuArchive* pArchive, NuThreadIdx threadIdx,
|
|
NuThreadID threadID, NuThreadMod** ppThreadMod);
|
|
void Nu_ThreadModFree(NuArchive* pArchive, NuThreadMod* pThreadMod);
|
|
NuError Nu_ThreadModAdd_FindByThreadID(const NuRecord* pRecord,
|
|
NuThreadID threadID, NuThreadMod** ppThreadMod);
|
|
void Nu_FreeThreadMods(NuArchive* pArchive, NuRecord* pRecord);
|
|
NuThreadMod* Nu_ThreadMod_FindByThreadIdx(const NuRecord* pRecord,
|
|
NuThreadIdx threadIdx);
|
|
NuError Nu_Flush(NuArchive* pArchive, long* pStatusFlags);
|
|
|
|
/* Deflate.c */
|
|
NuError Nu_CompressDeflate(NuArchive* pArchive, NuStraw* pStraw, FILE* fp,
|
|
ulong srcLen, ulong* pDstLen, ushort* pCrc);
|
|
NuError Nu_ExpandDeflate(NuArchive* pArchive, const NuRecord* pRecord,
|
|
const NuThread* pThread, FILE* infp, NuFunnel* pFunnel, ushort* pCrc);
|
|
|
|
/* Expand.c */
|
|
NuError Nu_ExpandStream(NuArchive* pArchive, const NuRecord* pRecord,
|
|
const NuThread* pThread, FILE* infp, NuFunnel* pFunnel);
|
|
|
|
/* FileIO.c */
|
|
void Nu_SetCurrentDateTime(NuDateTime* pDateTime);
|
|
Boolean Nu_IsOlder(const NuDateTime* pWhen1, const NuDateTime* pWhen2);
|
|
NuError Nu_OpenOutputFile(NuArchive* pArchive, const NuRecord* pRecord,
|
|
const NuThread* pThread, const char* newPathname, char newFssep,
|
|
FILE** pFp);
|
|
NuError Nu_CloseOutputFile(NuArchive* pArchive, const NuRecord* pRecord,
|
|
FILE* fp, const char* pathname);
|
|
NuError Nu_OpenInputFile(NuArchive* pArchive, const char* pathname,
|
|
Boolean openRsrc, FILE** pFp);
|
|
NuError Nu_DeleteFile(const char* pathname);
|
|
NuError Nu_RenameFile(const char* fromPath, const char* toPath);
|
|
NuError Nu_FTell(FILE* fp, long* pOffset);
|
|
NuError Nu_FSeek(FILE* fp, long offset, int ptrname);
|
|
NuError Nu_FRead(FILE* fp, void* buf, size_t nbyte);
|
|
NuError Nu_FWrite(FILE* fp, const void* buf, size_t nbyte);
|
|
NuError Nu_CopyFileSection(NuArchive* pArchive, FILE* dstFp, FILE* srcFp,
|
|
long length);
|
|
NuError Nu_GetFileLength(NuArchive* pArchive, FILE* fp, long* pLength);
|
|
NuError Nu_TruncateOpenFile(FILE* fp, long length);
|
|
|
|
/* Funnel.c */
|
|
NuError Nu_ProgressDataInit_Compress(NuArchive* pArchive,
|
|
NuProgressData* pProgressData, const NuRecord* pRecord,
|
|
const char* origPathname);
|
|
NuError Nu_ProgressDataInit_Expand(NuArchive* pArchive,
|
|
NuProgressData* pProgressData, const NuRecord* pRecord,
|
|
const char* newPathname, char newFssep, NuValue convertEOL);
|
|
NuError Nu_SendInitialProgress(NuArchive* pArchive, NuProgressData* pProgress);
|
|
|
|
NuError Nu_FunnelNew(NuArchive* pArchive, NuDataSink* pDataSink,
|
|
NuValue convertEOL, NuValue convertEOLTo, NuProgressData* pProgress,
|
|
NuFunnel** ppFunnel);
|
|
NuError Nu_FunnelFree(NuArchive* pArchive, NuFunnel* pFunnel);
|
|
/*void Nu_FunnelSetMaxOutput(NuFunnel* pFunnel, ulong maxBytes);*/
|
|
NuError Nu_FunnelWrite(NuArchive* pArchive, NuFunnel* pFunnel,
|
|
const uchar* buffer, ulong count);
|
|
NuError Nu_FunnelFlush(NuArchive* pArchive, NuFunnel* pFunnel);
|
|
NuError Nu_ProgressDataCompressPrep(NuArchive* pArchive, NuStraw* pStraw,
|
|
NuThreadFormat threadFormat, ulong sourceLen);
|
|
NuError Nu_ProgressDataExpandPrep(NuArchive* pArchive, NuFunnel* pFunnel,
|
|
const NuThread* pThread);
|
|
NuError Nu_FunnelSetProgressState(NuFunnel* pFunnel, NuProgressState state);
|
|
NuError Nu_FunnelSendProgressUpdate(NuArchive* pArchive, NuFunnel* pFunnel);
|
|
Boolean Nu_FunnelGetDoExpand(NuFunnel* pFunnel);
|
|
|
|
NuError Nu_StrawNew(NuArchive* pArchive, NuDataSource* pDataSource,
|
|
NuProgressData* pProgress, NuStraw** ppStraw);
|
|
NuError Nu_StrawFree(NuArchive* pArchive, NuStraw* pStraw);
|
|
NuError Nu_StrawSetProgressState(NuStraw* pStraw, NuProgressState state);
|
|
NuError Nu_StrawSendProgressUpdate(NuArchive* pArchive, NuStraw* pStraw);
|
|
NuError Nu_StrawRead(NuArchive* pArchive, NuStraw* pStraw, uchar* buffer,
|
|
long len);
|
|
NuError Nu_StrawRewind(NuArchive* pArchive, NuStraw* pStraw);
|
|
|
|
/* Lzc.c */
|
|
NuError Nu_CompressLZC12(NuArchive* pArchive, NuStraw* pStraw, FILE* fp,
|
|
ulong srcLen, ulong* pDstLen, ushort* pCrc);
|
|
NuError Nu_CompressLZC16(NuArchive* pArchive, NuStraw* pStraw, FILE* fp,
|
|
ulong srcLen, ulong* pDstLen, ushort* pCrc);
|
|
NuError Nu_ExpandLZC(NuArchive* pArchive, const NuRecord* pRecord,
|
|
const NuThread* pThread, FILE* infp, NuFunnel* pFunnel, ushort* pCrc);
|
|
|
|
/* Lzw.c */
|
|
NuError Nu_CompressLZW1(NuArchive* pArchive, NuStraw* pStraw, FILE* fp,
|
|
ulong srcLen, ulong* pDstLen, ushort* pCrc);
|
|
NuError Nu_CompressLZW2(NuArchive* pArchive, NuStraw* pStraw, FILE* fp,
|
|
ulong srcLen, ulong* pDstLen, ushort* pCrc);
|
|
NuError Nu_ExpandLZW(NuArchive* pArchive, const NuRecord* pRecord,
|
|
const NuThread* pThread, FILE* infp, NuFunnel* pFunnel, ushort* pThreadCrc);
|
|
|
|
/* MiscUtils.c */
|
|
extern const char* kNufxLibName;
|
|
extern NuCallback gNuGlobalErrorMessageHandler;
|
|
const char* Nu_StrError(NuError err);
|
|
void Nu_ReportError(NuArchive* pArchive, const char* file, int line,
|
|
const char* function, Boolean isDebug, NuError err, const char* format, ...)
|
|
#if defined(__GNUC__)
|
|
__attribute__ ((format(printf, 7, 8)))
|
|
#endif
|
|
;
|
|
#ifdef USE_DMALLOC /* want file and line numbers for calls */
|
|
# define Nu_Malloc(archive, size) malloc(size)
|
|
# define Nu_Calloc(archive, size) calloc(1, size)
|
|
# define Nu_Realloc(archive, ptr, size) realloc(ptr, size)
|
|
# define Nu_Free(archive, ptr) (ptr != nil ? free(ptr) : (void)0)
|
|
#else
|
|
void* Nu_Malloc(NuArchive* pArchive, size_t size);
|
|
void* Nu_Calloc(NuArchive* pArchive, size_t size);
|
|
void* Nu_Realloc(NuArchive* pArchive, void* ptr, size_t size);
|
|
void Nu_Free(NuArchive* pArchive, void* ptr);
|
|
#endif
|
|
NuResult Nu_InternalFreeCallback(NuArchive* pArchive, void* args);
|
|
|
|
/* Record.c */
|
|
void Nu_RecordAddThreadMod(NuRecord* pRecord, NuThreadMod* pThreadMod);
|
|
Boolean Nu_RecordIsEmpty(NuArchive* pArchive, const NuRecord* pRecord);
|
|
Boolean Nu_RecordSet_GetLoaded(const NuRecordSet* pRecordSet);
|
|
ulong Nu_RecordSet_GetNumRecords(const NuRecordSet* pRecordSet);
|
|
void Nu_RecordSet_SetNumRecords(NuRecordSet* pRecordSet, ulong val);
|
|
void Nu_RecordSet_IncNumRecords(NuRecordSet* pRecordSet);
|
|
NuRecord* Nu_RecordSet_GetListHead(const NuRecordSet* pRecordSet);
|
|
NuRecord** Nu_RecordSet_GetListHeadPtr(NuRecordSet* pRecordSet);
|
|
NuRecord* Nu_RecordSet_GetListTail(const NuRecordSet* pRecordSet);
|
|
Boolean Nu_RecordSet_IsEmpty(const NuRecordSet* pRecordSet);
|
|
NuError Nu_RecordSet_FreeAllRecords(NuArchive* pArchive,
|
|
NuRecordSet* pRecordSet);
|
|
NuError Nu_RecordSet_DeleteRecordPtr(NuArchive* pArchive,
|
|
NuRecordSet* pRecordSet, NuRecord** ppRecord);
|
|
NuError Nu_RecordSet_DeleteRecord(NuArchive* pArchive, NuRecordSet* pRecordSet,
|
|
NuRecord* pRecord);
|
|
NuError Nu_RecordSet_Clone(NuArchive* pArchive, NuRecordSet* pDstSet,
|
|
const NuRecordSet* pSrcSet);
|
|
NuError Nu_RecordSet_MoveAllRecords(NuArchive* pArchive, NuRecordSet* pDstSet,
|
|
NuRecordSet* pSrcSet);
|
|
NuError Nu_RecordSet_FindByIdx(const NuRecordSet* pRecordSet, NuRecordIdx rec,
|
|
NuRecord** ppRecord);
|
|
NuError Nu_RecordSet_FindByThreadIdx(NuRecordSet* pRecordSet,
|
|
NuThreadIdx threadIdx, NuRecord** ppRecord, NuThread** ppThread);
|
|
NuError Nu_RecordSet_ReplaceRecord(NuArchive* pArchive, NuRecordSet* pBadSet,
|
|
NuRecord* pBadRecord, NuRecordSet* pGoodSet, NuRecord** ppGoodRecord);
|
|
Boolean Nu_ShouldIgnoreBadCRC(NuArchive* pArchive, const NuRecord* pRecord,
|
|
NuError err);
|
|
NuError Nu_WriteRecordHeader(NuArchive* pArchive, NuRecord* pRecord, FILE* fp);
|
|
NuError Nu_GetTOCIfNeeded(NuArchive* pArchive);
|
|
NuError Nu_StreamContents(NuArchive* pArchive, NuCallback contentFunc);
|
|
NuError Nu_StreamExtract(NuArchive* pArchive);
|
|
NuError Nu_StreamTest(NuArchive* pArchive);
|
|
NuError Nu_Contents(NuArchive* pArchive, NuCallback contentFunc);
|
|
NuError Nu_Extract(NuArchive* pArchive);
|
|
NuError Nu_ExtractRecord(NuArchive* pArchive, NuRecordIdx recIdx);
|
|
NuError Nu_Test(NuArchive* pArchive);
|
|
NuError Nu_GetRecord(NuArchive* pArchive, NuRecordIdx recordIdx,
|
|
const NuRecord** ppRecord);
|
|
NuError Nu_GetRecordIdxByName(NuArchive* pArchive, const char* name,
|
|
NuRecordIdx* pRecordIdx);
|
|
NuError Nu_GetRecordIdxByPosition(NuArchive* pArchive, ulong position,
|
|
NuRecordIdx* pRecordIdx);
|
|
NuError Nu_FindRecordForWriteByIdx(NuArchive* pArchive, NuRecordIdx recIdx,
|
|
NuRecord** ppFoundRecord);
|
|
NuError Nu_AddFile(NuArchive* pArchive, const char* pathname,
|
|
const NuFileDetails* pFileDetails, Boolean fromRsrcFork,
|
|
NuRecordIdx* pRecordIdx);
|
|
NuError Nu_AddRecord(NuArchive* pArchive, const NuFileDetails* pFileDetails,
|
|
NuRecordIdx* pRecordIdx, NuRecord** ppRecord);
|
|
NuError Nu_Rename(NuArchive* pArchive, NuRecordIdx recIdx,
|
|
const char* pathname, char fssep);
|
|
NuError Nu_SetRecordAttr(NuArchive* pArchive, NuRecordIdx recordIdx,
|
|
const NuRecordAttr* pRecordAttr);
|
|
NuError Nu_Delete(NuArchive* pArchive);
|
|
NuError Nu_DeleteRecord(NuArchive* pArchive, NuRecordIdx rec);
|
|
|
|
/* SourceSink.c */
|
|
NuError Nu_DataSourceFile_New(NuThreadFormat threadFormat,
|
|
ulong otherLen, const char* pathname, Boolean isFromRsrcFork,
|
|
NuDataSource** ppDataSource);
|
|
NuError Nu_DataSourceFP_New(NuThreadFormat threadFormat,
|
|
ulong otherLen, FILE* fp, long offset, long length,
|
|
NuCallback fcloseFunc, NuDataSource** ppDataSource);
|
|
NuError Nu_DataSourceBuffer_New(NuThreadFormat threadFormat,
|
|
ulong otherLen, const uchar* buffer, long offset, long length,
|
|
NuCallback freeFunc, NuDataSource** ppDataSource);
|
|
NuDataSource* Nu_DataSourceCopy(NuDataSource* pDataSource);
|
|
NuError Nu_DataSourceFree(NuDataSource* pDataSource);
|
|
NuDataSourceType Nu_DataSourceGetType(const NuDataSource* pDataSource);
|
|
NuThreadFormat Nu_DataSourceGetThreadFormat(const NuDataSource* pDataSource);
|
|
ulong Nu_DataSourceGetDataLen(const NuDataSource* pDataSource);
|
|
ulong Nu_DataSourceGetOtherLen(const NuDataSource* pDataSource);
|
|
void Nu_DataSourceSetOtherLen(NuDataSource* pDataSource, long otherLen);
|
|
ushort Nu_DataSourceGetRawCrc(const NuDataSource* pDataSource);
|
|
void Nu_DataSourceSetRawCrc(NuDataSource* pDataSource, ushort crc);
|
|
NuError Nu_DataSourcePrepareInput(NuArchive* pArchive,
|
|
NuDataSource* pDataSource);
|
|
void Nu_DataSourceUnPrepareInput(NuArchive* pArchive,
|
|
NuDataSource* pDataSource);
|
|
const char* Nu_DataSourceFile_GetPathname(NuDataSource* pDataSource);
|
|
NuError Nu_DataSourceGetBlock(NuDataSource* pDataSource, uchar* buf, ulong len);
|
|
NuError Nu_DataSourceRewind(NuDataSource* pDataSource);
|
|
NuError Nu_DataSinkFile_New(Boolean doExpand, NuValue convertEOL,
|
|
const char* pathname, char fssep, NuDataSink** ppDataSink);
|
|
NuError Nu_DataSinkFP_New(Boolean doExpand, NuValue convertEOL, FILE* fp,
|
|
NuDataSink** ppDataSink);
|
|
NuError Nu_DataSinkBuffer_New(Boolean doExpand, NuValue convertEOL,
|
|
uchar* buffer, ulong bufLen, NuDataSink** ppDataSink);
|
|
NuError Nu_DataSinkVoid_New(Boolean doExpand, NuValue convertEOL,
|
|
NuDataSink** ppDataSink);
|
|
NuError Nu_DataSinkFree(NuDataSink* pDataSink);
|
|
NuDataSinkType Nu_DataSinkGetType(const NuDataSink* pDataSink);
|
|
Boolean Nu_DataSinkGetDoExpand(const NuDataSink* pDataSink);
|
|
NuValue Nu_DataSinkGetConvertEOL(const NuDataSink* pDataSink);
|
|
ulong Nu_DataSinkGetOutCount(const NuDataSink* pDataSink);
|
|
const char* Nu_DataSinkFile_GetPathname(const NuDataSink* pDataSink);
|
|
char Nu_DataSinkFile_GetFssep(const NuDataSink* pDataSink);
|
|
FILE* Nu_DataSinkFile_GetFP(const NuDataSink* pDataSink);
|
|
void Nu_DataSinkFile_SetFP(NuDataSink* pDataSink, FILE* fp);
|
|
void Nu_DataSinkFile_Close(NuDataSink* pDataSink);
|
|
NuError Nu_DataSinkPutBlock(NuDataSink* pDataSink, const uchar* buf, ulong len);
|
|
NuError Nu_DataSinkGetError(NuDataSink* pDataSink);
|
|
|
|
/* Squeeze.c */
|
|
NuError Nu_CompressHuffmanSQ(NuArchive* pArchive, NuStraw* pStraw, FILE* fp,
|
|
ulong srcLen, ulong* pDstLen, ushort* pCrc);
|
|
NuError Nu_ExpandHuffmanSQ(NuArchive* pArchive, const NuRecord* pRecord,
|
|
const NuThread* pThread, FILE* infp, NuFunnel* pFunnel, ushort* pCrc);
|
|
|
|
/* Thread.c */
|
|
#ifdef __Thread_c__
|
|
#define THREAD_INLINE /**/
|
|
#else
|
|
#define THREAD_INLINE extern inline
|
|
#endif
|
|
#if defined(inline) && !defined(__Thread_c__) /* somebody ovrd inline def? */
|
|
NuThread* Nu_GetThread(const NuRecord* pRecord, int idx);
|
|
#else
|
|
THREAD_INLINE NuThread*
|
|
Nu_GetThread(const NuRecord* pRecord, int idx)
|
|
{
|
|
if (idx >= (int)pRecord->recTotalThreads)
|
|
return nil;
|
|
else
|
|
return &pRecord->pThreads[idx];
|
|
}
|
|
#endif
|
|
void Nu_StripHiIfAllSet(char* str);
|
|
Boolean Nu_IsPresizedThreadID(NuThreadID threadID);
|
|
Boolean Nu_IsCompressibleThreadID(NuThreadID threadID);
|
|
Boolean Nu_ThreadHasCRC(long recordVersion, NuThreadID threadID);
|
|
NuError Nu_FindThreadByIdx(const NuRecord* pRecord, NuThreadIdx thread,
|
|
NuThread** ppThread);
|
|
NuError Nu_FindThreadByID(const NuRecord* pRecord, NuThreadID threadID,
|
|
NuThread** ppThread);
|
|
void Nu_CopyThreadContents(NuThread* pDstThread, const NuThread* pSrcThread);
|
|
NuError Nu_ReadThreadHeaders(NuArchive* pArchive, NuRecord* pRecord,
|
|
ushort* pCrc);
|
|
NuError Nu_WriteThreadHeaders(NuArchive* pArchive, NuRecord* pRecord, FILE* fp,
|
|
ushort* pCrc);
|
|
NuError Nu_ComputeThreadData(NuArchive* pArchive, NuRecord* pRecord);
|
|
NuError Nu_ScanThreads(NuArchive* pArchive, NuRecord* pRecord,long numThreads);
|
|
NuError Nu_ExtractThreadBulk(NuArchive* pArchive, const NuRecord* pRecord,
|
|
const NuThread* pThread);
|
|
NuError Nu_SkipThread(NuArchive* pArchive, const NuRecord* pRecord,
|
|
const NuThread* pThread);
|
|
NuError Nu_ExtractThread(NuArchive* pArchive, NuThreadIdx threadIdx,
|
|
NuDataSink* pDataSink);
|
|
NuError Nu_OkayToAddThread(NuArchive* pArchive, const NuRecord* pRecord,
|
|
NuThreadID threadID);
|
|
NuError Nu_AddThread(NuArchive* pArchive, NuRecordIdx rec, NuThreadID threadID,
|
|
NuDataSource* pDataSource, NuThreadIdx* pThreadIdx);
|
|
NuError Nu_UpdatePresizedThread(NuArchive* pArchive, NuThreadIdx threadIdx,
|
|
NuDataSource* pDataSource, long* pMaxLen);
|
|
NuError Nu_DeleteThread(NuArchive* pArchive, NuThreadIdx threadIdx);
|
|
|
|
/* Value.c */
|
|
NuError Nu_GetValue(NuArchive* pArchive, NuValueID ident, NuValue* pValue);
|
|
NuError Nu_SetValue(NuArchive* pArchive, NuValueID ident, NuValue value);
|
|
NuError Nu_GetAttr(NuArchive* pArchive, NuAttrID ident, NuAttr* pAttr);
|
|
NuThreadFormat Nu_ConvertCompressValToFormat(NuArchive* pArchive,
|
|
NuValue compValue);
|
|
|
|
/* Version.c */
|
|
NuError Nu_GetVersion(long* pMajorVersion, long* pMinorVersion,
|
|
long* pBugVersion, const char** ppBuildDate, const char** ppBuildFlags);
|
|
|
|
#endif /*__NufxLibPriv__*/
|