mirror of
https://github.com/fadden/ciderpress.git
synced 2024-11-26 17:49:21 +00:00
51b5f00f5c
CiderPress and MDC now compile, and execute far enough to open their respective "about" boxes, but I doubt they'll do much more than that. * Switch from MBCS to UNICODE APIs Microsoft switched to UTF-16 (by way of UCS-2) a long time ago, and the support for MBCS seems to be getting phased out. So it's time to switch to wide strings. This is a bit awkward for CiderPress because it works with disk and file archives with 8-bit filenames, and I want NufxLib and DiskImgLib to continue to work on Linux (which has largely taken the UTF-8 approach to Unicode). The libraries will continue to work with 8-bit filenames, with CiderPress/MDC doing the conversion at the appropriate point. There were a couple of places where strings from a structure handed back by one of the libraries were used directly in the UI, or vice-versa, which is a problem because we have nowhere to store the result of the conversion. These currently have fixed place-holder "xyzzy" strings. All UI strings are now wide. Various format strings now use "%ls" and "%hs" to explicitly specify wide and narrow. This doesn't play well with gcc, so only the Windows-specific parts use those. * Various updates to vcxproj files The project-file conversion had some cruft that is now largely gone. The build now has a common output directory for the EXEs and libraries, avoiding the old post-build copy steps. * Added zlib 1.2.8 and nufxlib 2.2.2 source snapshots The old "prebuilts" directory is now gone. The libraries are now built as part of building the apps. I added a minimal set of files for zlib, and a full set for nufxlib. The Linux-specific nufxlib goodies are included for the benefit of the Linux utilities, which are currently broken (don't build). * Replace symbols used for include guards Symbols with a leading "__" are reserved.
871 lines
35 KiB
C
871 lines
35 KiB
C
/*
|
|
* NuFX archive manipulation library
|
|
* Copyright (C) 2000-2007 by Andy McFadden, All Rights Reserved.
|
|
* This is free software; you can redistribute it and/or modify it under the
|
|
* terms of the BSD 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;
|
|
|
|
/* 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 */
|
|
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? */
|
|
NuValue valStripHighASCII; /* during EOL conv, strip hi bit? */
|
|
NuValue valJunkSkipMax; /* scan this far for header */
|
|
NuValue valIgnoreLZW2Len; /* don't verify LZW/II len field */
|
|
NuValue valHandleBadMac; /* handle "bad Mac" archives */
|
|
|
|
/* 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 */
|
|
|
|
/* text 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 checkStripHighASCII; /* do we want to check for it? */
|
|
Boolean doStripHighASCII; /* strip high ASCII during EOL conv */
|
|
Boolean lastCR; /* was last char a CR? */
|
|
|
|
Boolean isFirstWrite; /* cleared on first write */
|
|
|
|
#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_TestRecord(NuArchive* pArchive, NuRecordIdx recIdx);
|
|
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__*/
|