nulib2/nufxlib-0/Entry.c
Andy McFadden 1169554de3 Changed the DataSource API to take resource release callback pointers
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).
2003-02-09 01:53:51 +00:00

834 lines
20 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.
*
* All external entry points.
*/
#include "NufxLibPriv.h"
/*
* ===========================================================================
* Misc utils
* ===========================================================================
*/
/*
* Set the busy flag.
*
* The busy flag is intended to prevent the caller from executing illegal
* operations while inside a callback function. It is NOT intended to
* allow concurrent access to the same archive from multiple threads, so
* it does not follow all sorts of crazy semaphore semantics. If you
* have the need, go ahead and fix it.
*/
static inline void
Nu_SetBusy(NuArchive* pArchive)
{
pArchive->busy = true;
}
/*
* Clear the busy flag.
*/
static inline void
Nu_ClearBusy(NuArchive* pArchive)
{
pArchive->busy = false;
}
/*
* Do a partial validation on NuArchive. Some calls, such as GetExtraData,
* can be made during callback functions when the archive isn't fully
* consistent.
*/
static NuError
Nu_PartiallyValidateNuArchive(const NuArchive* pArchive)
{
if (pArchive == nil)
return kNuErrInvalidArg;
pArchive = pArchive;
if (pArchive->structMagic != kNuArchiveStructMagic)
return kNuErrBadStruct;
return kNuErrNone;
}
/*
* Validate the NuArchive* argument passed in to us.
*/
static NuError
Nu_ValidateNuArchive(const NuArchive* pArchive)
{
NuError err;
err = Nu_PartiallyValidateNuArchive(pArchive);
if (err != kNuErrNone)
return err;
/* explicitly block reentrant calls */
if (pArchive->busy)
return kNuErrBusy;
/* make sure the TOC state is consistent */
if (pArchive->haveToc) {
if (pArchive->masterHeader.mhTotalRecords != 0)
Assert(Nu_RecordSet_GetListHead(&pArchive->origRecordSet) != nil);
Assert(Nu_RecordSet_GetNumRecords(&pArchive->origRecordSet) ==
pArchive->masterHeader.mhTotalRecords);
} else {
Assert(Nu_RecordSet_GetListHead(&pArchive->origRecordSet) == nil);
}
/* make sure we have open files to work with */
Assert(pArchive->archivePathname == nil || pArchive->archiveFp != nil);
if (pArchive->archivePathname != nil && pArchive->archiveFp == nil)
return kNuErrInternal;
Assert(pArchive->tmpPathname == nil || pArchive->tmpFp != nil);
if (pArchive->tmpPathname != nil && pArchive->tmpFp == nil)
return kNuErrInternal;
/* further validations */
return kNuErrNone;
}
/*
* ===========================================================================
* Streaming and non-streaming read-only
* ===========================================================================
*/
NUFXLIB_API NuError
NuStreamOpenRO(FILE* infp, NuArchive** ppArchive)
{
NuError err;
if (infp == nil || ppArchive == nil)
return kNuErrInvalidArg;
err = Nu_StreamOpenRO(infp, (NuArchive**) ppArchive);
return err;
}
NUFXLIB_API NuError
NuContents(NuArchive* pArchive, NuCallback contentFunc)
{
NuError err;
if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) {
Nu_SetBusy(pArchive);
if (Nu_IsStreaming(pArchive))
err = Nu_StreamContents(pArchive, contentFunc);
else
err = Nu_Contents(pArchive, contentFunc);
Nu_ClearBusy(pArchive);
}
return err;
}
NUFXLIB_API NuError
NuExtract(NuArchive* pArchive)
{
NuError err;
if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) {
Nu_SetBusy(pArchive);
if (Nu_IsStreaming(pArchive))
err = Nu_StreamExtract(pArchive);
else
err = Nu_Extract(pArchive);
Nu_ClearBusy(pArchive);
}
return err;
}
NUFXLIB_API NuError
NuTest(NuArchive* pArchive)
{
NuError err;
if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) {
Nu_SetBusy(pArchive);
if (Nu_IsStreaming(pArchive))
err = Nu_StreamTest(pArchive);
else
err = Nu_Test(pArchive);
Nu_ClearBusy(pArchive);
}
return err;
}
/*
* ===========================================================================
* Strictly non-streaming read-only
* ===========================================================================
*/
NUFXLIB_API NuError
NuOpenRO(const char* filename, NuArchive** ppArchive)
{
NuError err;
err = Nu_OpenRO(filename, (NuArchive**) ppArchive);
return err;
}
NUFXLIB_API NuError
NuExtractRecord(NuArchive* pArchive, NuRecordIdx recordIdx)
{
NuError err;
if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) {
Nu_SetBusy(pArchive);
err = Nu_ExtractRecord(pArchive, recordIdx);
Nu_ClearBusy(pArchive);
}
return err;
}
NUFXLIB_API NuError
NuExtractThread(NuArchive* pArchive, NuThreadIdx threadIdx,
NuDataSink* pDataSink)
{
NuError err;
if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) {
Nu_SetBusy(pArchive);
err = Nu_ExtractThread(pArchive, threadIdx, pDataSink);
Nu_ClearBusy(pArchive);
}
return err;
}
NUFXLIB_API NuError
NuGetRecord(NuArchive* pArchive, NuRecordIdx recordIdx,
const NuRecord** ppRecord)
{
NuError err;
if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) {
Nu_SetBusy(pArchive);
err = Nu_GetRecord(pArchive, recordIdx, ppRecord);
Nu_ClearBusy(pArchive);
}
return err;
}
NUFXLIB_API NuError
NuGetRecordIdxByName(NuArchive* pArchive, const char* name,
NuRecordIdx* pRecordIdx)
{
NuError err;
if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) {
Nu_SetBusy(pArchive);
err = Nu_GetRecordIdxByName(pArchive, name, pRecordIdx);
Nu_ClearBusy(pArchive);
}
return err;
}
NUFXLIB_API NuError
NuGetRecordIdxByPosition(NuArchive* pArchive, unsigned long position,
NuRecordIdx* pRecordIdx)
{
NuError err;
if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) {
Nu_SetBusy(pArchive);
err = Nu_GetRecordIdxByPosition(pArchive, position, pRecordIdx);
Nu_ClearBusy(pArchive);
}
return err;
}
/*
* ===========================================================================
* Read/Write
* ===========================================================================
*/
NUFXLIB_API NuError
NuOpenRW(const char* archivePathname, const char* tmpPathname,
unsigned long flags, NuArchive** ppArchive)
{
NuError err;
err = Nu_OpenRW(archivePathname, tmpPathname, flags,
(NuArchive**) ppArchive);
return err;
}
NUFXLIB_API NuError
NuFlush(NuArchive* pArchive, long* pStatusFlags)
{
NuError err;
if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) {
Nu_SetBusy(pArchive);
err = Nu_Flush(pArchive, pStatusFlags);
Nu_ClearBusy(pArchive);
}
return err;
}
NUFXLIB_API NuError
NuAbort(NuArchive* pArchive)
{
NuError err;
if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) {
Nu_SetBusy(pArchive);
err = Nu_Abort(pArchive);
Nu_ClearBusy(pArchive);
}
return err;
}
NUFXLIB_API NuError
NuAddRecord(NuArchive* pArchive, const NuFileDetails* pFileDetails,
NuRecordIdx* pRecordIdx)
{
NuError err;
if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) {
Nu_SetBusy(pArchive);
err = Nu_AddRecord(pArchive, pFileDetails, pRecordIdx, nil);
Nu_ClearBusy(pArchive);
}
return err;
}
NUFXLIB_API NuError
NuAddThread(NuArchive* pArchive, NuRecordIdx recordIdx, NuThreadID threadID,
NuDataSource* pDataSource, NuThreadIdx* pThreadIdx)
{
NuError err;
if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) {
Nu_SetBusy(pArchive);
err = Nu_AddThread(pArchive, recordIdx, threadID,
pDataSource, pThreadIdx);
Nu_ClearBusy(pArchive);
}
return err;
}
NUFXLIB_API NuError
NuAddFile(NuArchive* pArchive, const char* pathname,
const NuFileDetails* pFileDetails, short isFromRsrcFork,
NuRecordIdx* pRecordIdx)
{
NuError err;
if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) {
Nu_SetBusy(pArchive);
err = Nu_AddFile(pArchive, pathname, pFileDetails,
(Boolean)(isFromRsrcFork != 0), pRecordIdx);
Nu_ClearBusy(pArchive);
}
return err;
}
NUFXLIB_API NuError
NuRename(NuArchive* pArchive, NuRecordIdx recordIdx, const char* pathname,
char fssep)
{
NuError err;
if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) {
Nu_SetBusy(pArchive);
err = Nu_Rename(pArchive, recordIdx, pathname, fssep);
Nu_ClearBusy(pArchive);
}
return err;
}
NUFXLIB_API NuError
NuSetRecordAttr(NuArchive* pArchive, NuRecordIdx recordIdx,
const NuRecordAttr* pRecordAttr)
{
NuError err;
if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) {
Nu_SetBusy(pArchive);
err = Nu_SetRecordAttr(pArchive, recordIdx, pRecordAttr);
Nu_ClearBusy(pArchive);
}
return err;
}
NUFXLIB_API NuError
NuUpdatePresizedThread(NuArchive* pArchive, NuThreadIdx threadIdx,
NuDataSource* pDataSource, long* pMaxLen)
{
NuError err;
if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) {
Nu_SetBusy(pArchive);
err = Nu_UpdatePresizedThread(pArchive, threadIdx,
pDataSource, pMaxLen);
Nu_ClearBusy(pArchive);
}
return err;
}
NUFXLIB_API NuError
NuDelete(NuArchive* pArchive)
{
NuError err;
if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) {
Nu_SetBusy(pArchive);
err = Nu_Delete(pArchive);
Nu_ClearBusy(pArchive);
}
return err;
}
NUFXLIB_API NuError
NuDeleteRecord(NuArchive* pArchive, NuRecordIdx recordIdx)
{
NuError err;
if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) {
Nu_SetBusy(pArchive);
err = Nu_DeleteRecord(pArchive, recordIdx);
Nu_ClearBusy(pArchive);
}
return err;
}
NUFXLIB_API NuError
NuDeleteThread(NuArchive* pArchive, NuThreadIdx threadIdx)
{
NuError err;
if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) {
Nu_SetBusy(pArchive);
err = Nu_DeleteThread(pArchive, threadIdx);
Nu_ClearBusy(pArchive);
}
return err;
}
/*
* ===========================================================================
* General interfaces
* ===========================================================================
*/
NUFXLIB_API NuError
NuClose(NuArchive* pArchive)
{
NuError err;
if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone) {
Nu_SetBusy(pArchive);
err = Nu_Close(pArchive);
/* on success, pArchive has been freed */
if (err != kNuErrNone)
Nu_ClearBusy(pArchive);
}
return err;
}
NUFXLIB_API NuError
NuGetMasterHeader(NuArchive* pArchive, const NuMasterHeader** ppMasterHeader)
{
NuError err;
if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone)
err = Nu_GetMasterHeader(pArchive, ppMasterHeader);
return err;
}
NUFXLIB_API NuError
NuGetExtraData(NuArchive* pArchive, void** ppData)
{
NuError err;
if (ppData == nil)
return kNuErrInvalidArg;
if ((err = Nu_PartiallyValidateNuArchive(pArchive)) == kNuErrNone)
*ppData = pArchive->extraData;
return err;
}
NUFXLIB_API NuError
NuSetExtraData(NuArchive* pArchive, void* pData)
{
NuError err;
if ((err = Nu_PartiallyValidateNuArchive(pArchive)) == kNuErrNone)
pArchive->extraData = pData;
return err;
}
NUFXLIB_API NuError
NuGetValue(NuArchive* pArchive, NuValueID ident, NuValue* pValue)
{
NuError err;
if ((err = Nu_PartiallyValidateNuArchive(pArchive)) == kNuErrNone)
return Nu_GetValue(pArchive, ident, pValue);
return err;
}
NUFXLIB_API NuError
NuSetValue(NuArchive* pArchive, NuValueID ident, NuValue value)
{
NuError err;
if ((err = Nu_PartiallyValidateNuArchive(pArchive)) == kNuErrNone)
return Nu_SetValue(pArchive, ident, value);
return err;
}
NUFXLIB_API NuError
NuGetAttr(NuArchive* pArchive, NuAttrID ident, NuAttr* pAttr)
{
NuError err;
if ((err = Nu_PartiallyValidateNuArchive(pArchive)) == kNuErrNone)
return Nu_GetAttr(pArchive, ident, pAttr);
return err;
}
NUFXLIB_API NuError
NuDebugDumpArchive(NuArchive* pArchive)
{
#if defined(DEBUG_MSGS)
/* skip validation checks for this one */
Nu_DebugDumpAll(pArchive);
return kNuErrNone;
#else
/* function doesn't exist */
return kNuErrGeneric;
#endif
}
/*
* ===========================================================================
* Sources and Sinks
* ===========================================================================
*/
NUFXLIB_API NuError
NuCreateDataSourceForFile(NuThreadFormat threadFormat,
unsigned long otherLen, const char* pathname, short isFromRsrcFork,
NuDataSource** ppDataSource)
{
return Nu_DataSourceFile_New(threadFormat, otherLen,
pathname, (Boolean)(isFromRsrcFork != 0), ppDataSource);
}
NUFXLIB_API NuError
NuCreateDataSourceForFP(NuThreadFormat threadFormat,
unsigned long otherLen, FILE* fp, long offset, long length,
NuCallback fcloseFunc, NuDataSource** ppDataSource)
{
return Nu_DataSourceFP_New(threadFormat, otherLen,
fp, offset, length, fcloseFunc, ppDataSource);
}
NUFXLIB_API NuError
NuCreateDataSourceForBuffer(NuThreadFormat threadFormat,
unsigned long otherLen, const unsigned char* buffer, long offset,
long length, NuCallback freeFunc, NuDataSource** ppDataSource)
{
return Nu_DataSourceBuffer_New(threadFormat, otherLen,
buffer, offset, length, freeFunc, ppDataSource);
}
NUFXLIB_API NuError
NuFreeDataSource(NuDataSource* pDataSource)
{
return Nu_DataSourceFree(pDataSource);
}
NUFXLIB_API NuError
NuDataSourceSetRawCrc(NuDataSource* pDataSource, unsigned short crc)
{
if (pDataSource == nil)
return kNuErrInvalidArg;
Nu_DataSourceSetRawCrc(pDataSource, crc);
return kNuErrNone;
}
NUFXLIB_API NuError
NuCreateDataSinkForFile(short doExpand, NuValue convertEOL,
const char* pathname, char fssep, NuDataSink** ppDataSink)
{
return Nu_DataSinkFile_New((Boolean)(doExpand != 0), convertEOL, pathname,
fssep, ppDataSink);
}
NUFXLIB_API NuError
NuCreateDataSinkForFP(short doExpand, NuValue convertEOL, FILE* fp,
NuDataSink** ppDataSink)
{
return Nu_DataSinkFP_New((Boolean)(doExpand != 0), convertEOL, fp,
ppDataSink);
}
NUFXLIB_API NuError
NuCreateDataSinkForBuffer(short doExpand, NuValue convertEOL,
unsigned char* buffer, unsigned long bufLen, NuDataSink** ppDataSink)
{
return Nu_DataSinkBuffer_New((Boolean)(doExpand != 0), convertEOL, buffer,
bufLen, ppDataSink);
}
NUFXLIB_API NuError
NuFreeDataSink(NuDataSink* pDataSink)
{
return Nu_DataSinkFree(pDataSink);
}
NUFXLIB_API NuError
NuDataSinkGetOutCount(NuDataSink* pDataSink, ulong* pOutCount)
{
if (pDataSink == nil || pOutCount == nil)
return kNuErrInvalidArg;
*pOutCount = Nu_DataSinkGetOutCount(pDataSink);
return kNuErrNone;
}
/*
* ===========================================================================
* Non-archive operations
* ===========================================================================
*/
NUFXLIB_API const char*
NuStrError(NuError err)
{
return Nu_StrError(err);
}
NUFXLIB_API NuError
NuGetVersion(long* pMajorVersion, long* pMinorVersion, long* pBugVersion,
const char** ppBuildDate, const char** ppBuildFlags)
{
return Nu_GetVersion(pMajorVersion, pMinorVersion, pBugVersion,
ppBuildDate, ppBuildFlags);
}
NUFXLIB_API NuError
NuTestFeature(NuFeature feature)
{
NuError err = kNuErrUnsupFeature;
switch (feature) {
case kNuFeatureCompressSQ:
#ifdef ENABLE_SQ
err = kNuErrNone;
#endif
break;
case kNuFeatureCompressLZW:
#ifdef ENABLE_LZW
err = kNuErrNone;
#endif
break;
case kNuFeatureCompressLZC:
#ifdef ENABLE_LZC
err = kNuErrNone;
#endif
break;
case kNuFeatureCompressDeflate:
#ifdef ENABLE_DEFLATE
err = kNuErrNone;
#endif
break;
case kNuFeatureCompressBzip2:
#ifdef ENABLE_BZIP2
err = kNuErrNone;
#endif
break;
default:
err = kNuErrUnknownFeature;
break;
}
return err;
}
NUFXLIB_API void
NuRecordCopyAttr(NuRecordAttr* pRecordAttr, const NuRecord* pRecord)
{
pRecordAttr->fileSysID = pRecord->recFileSysID;
/*pRecordAttr->fileSysInfo = pRecord->recFileSysInfo;*/
pRecordAttr->access = pRecord->recAccess;
pRecordAttr->fileType = pRecord->recFileType;
pRecordAttr->extraType = pRecord->recExtraType;
pRecordAttr->createWhen = pRecord->recCreateWhen;
pRecordAttr->modWhen = pRecord->recModWhen;
pRecordAttr->archiveWhen = pRecord->recArchiveWhen;
}
NUFXLIB_API NuError
NuRecordCopyThreads(const NuRecord* pNuRecord, NuThread** ppThreads)
{
if (pNuRecord == nil || ppThreads == nil)
return kNuErrInvalidArg;
Assert(pNuRecord->pThreads != nil);
*ppThreads = Nu_Malloc(nil, pNuRecord->recTotalThreads * sizeof(NuThread));
if (*ppThreads == nil)
return kNuErrMalloc;
memcpy(*ppThreads, pNuRecord->pThreads,
pNuRecord->recTotalThreads * sizeof(NuThread));
return kNuErrNone;
}
NUFXLIB_API unsigned long
NuRecordGetNumThreads(const NuRecord* pNuRecord)
{
if (pNuRecord == nil)
return -1;
return pNuRecord->recTotalThreads;
}
NUFXLIB_API const NuThread*
NuThreadGetByIdx(const NuThread* pNuThread, long idx)
{
if (pNuThread == nil)
return nil;
return &pNuThread[idx]; /* can't range-check here */
}
NUFXLIB_API short
NuIsPresizedThreadID(NuThreadID threadID)
{
return Nu_IsPresizedThreadID(threadID);
}
/*
* ===========================================================================
* Callback setters
* ===========================================================================
*/
NUFXLIB_API NuError
NuSetSelectionFilter(NuArchive* pArchive, NuCallback filterFunc)
{
NuError err;
/*Assert(!((ulong)filterFunc % 4));*/
if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone)
pArchive->selectionFilterFunc = filterFunc;
return err;
}
NUFXLIB_API NuError
NuSetOutputPathnameFilter(NuArchive* pArchive, NuCallback filterFunc)
{
NuError err;
/*Assert(!((ulong)filterFunc % 4));*/
if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone)
pArchive->outputPathnameFunc = filterFunc;
return err;
}
NUFXLIB_API NuError
NuSetProgressUpdater(NuArchive* pArchive, NuCallback updateFunc)
{
NuError err;
/*Assert(!((ulong)updateFunc % 4));*/
if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone)
pArchive->progressUpdaterFunc = updateFunc;
return err;
}
NUFXLIB_API NuError
NuSetErrorHandler(NuArchive* pArchive, NuCallback errorFunc)
{
NuError err;
/*Assert(!((ulong)errorFunc % 4));*/
if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone)
pArchive->errorHandlerFunc = errorFunc;
return err;
}
NUFXLIB_API NuError
NuSetErrorMessageHandler(NuArchive* pArchive, NuCallback messageHandlerFunc)
{
NuError err;
/*Assert(!((ulong)messageHandlerFunc % 4));*/
if ((err = Nu_ValidateNuArchive(pArchive)) == kNuErrNone)
pArchive->messageHandlerFunc = messageHandlerFunc;
return err;
}
NUFXLIB_API NuError
NuSetGlobalErrorMessageHandler(NuCallback messageHandlerFunc)
{
/*Assert(!((ulong)messageHandlerFunc % 4));*/
gNuGlobalErrorMessageHandler = messageHandlerFunc;
return kNuErrNone;
}