From 1169554de3d6b29487b50c8851b8dd06e4954812 Mon Sep 17 00:00:00 2001 From: Andy McFadden Date: Sun, 9 Feb 2003 01:53:51 +0000 Subject: [PATCH] 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). --- nufxlib-0/ChangeLog.txt | 11 ++++- nufxlib-0/Deferred.c | 24 ++++++---- nufxlib-0/Entry.c | 22 ++++----- nufxlib-0/MiscUtils.c | 12 +++++ nufxlib-0/NufxLib.h | 11 +++-- nufxlib-0/NufxLibPriv.h | 18 ++++--- nufxlib-0/Record.c | 13 ++--- nufxlib-0/SourceSink.c | 89 ++++++++++++++++++++++------------- nufxlib-0/Thread.c | 7 ++- nufxlib-0/samples/Exerciser.c | 19 ++++++-- nufxlib-0/samples/ImgConv.c | 32 +++++++++++-- nufxlib-0/samples/Launder.c | 26 ++++++---- nufxlib-0/samples/TestBasic.c | 25 ++++++---- 13 files changed, 210 insertions(+), 99 deletions(-) diff --git a/nufxlib-0/ChangeLog.txt b/nufxlib-0/ChangeLog.txt index a580d59..0ed372f 100644 --- a/nufxlib-0/ChangeLog.txt +++ b/nufxlib-0/ChangeLog.txt @@ -1,3 +1,12 @@ +2003/02/08 fadden + - Upped version to v2.0.0. + - Changed DataSource API. Removed "doClose" and added an optional + callback function that handles releasing of resources. Necessary + to make Win32 DLLs work right with unsuspecting apps. + - Changed DataSource "copy" function to use refcounting. Still + not quite right, but it'll do for now. Memory leaks in DataSource + handling appear to be fixed. (I love valgrind.) + 2003/01/10 fadden - Added version numbers to header. - Added kNuValueMaskThreadless to control handling of "threadless" @@ -5,7 +14,7 @@ the application does need to handle them specially. 2002/12/06 fadden - - Made changes to allow NufxLib to be built as a DLL. + - Made changes to allow NufxLib to be built as a Win32 DLL. 2002/10/20 ***** v1.1.0 shipped ***** diff --git a/nufxlib-0/Deferred.c b/nufxlib-0/Deferred.c index 37b01bf..74a5d76 100644 --- a/nufxlib-0/Deferred.c +++ b/nufxlib-0/Deferred.c @@ -39,7 +39,7 @@ Nu_ThreadModAdd_New(NuArchive* pArchive, NuThreadID threadID, (*ppThreadMod)->entry.add.threadIdx = Nu_GetNextThreadIdx(pArchive); (*ppThreadMod)->entry.add.threadID = threadID; (*ppThreadMod)->entry.add.threadFormat = threadFormat; - (*ppThreadMod)->entry.add.pDataSource = pDataSource; + (*ppThreadMod)->entry.add.pDataSource = Nu_DataSourceCopy(pDataSource); /* decide if this is a pre-sized thread [do we want to do this here??] */ (*ppThreadMod)->entry.add.isPresized = Nu_IsPresizedThreadID(threadID); @@ -1302,14 +1302,15 @@ Nu_ConstructNewRecord(NuArchive* pArchive, NuRecord* pRecord, FILE* fp) len = strlen(pRecord->filename); maxLen = len > kNuDefaultFilenameThreadSize ? len : kNuDefaultFilenameThreadSize; - err = Nu_DataSourceBuffer_New(kNuThreadFormatUncompressed, false, + err = Nu_DataSourceBuffer_New(kNuThreadFormatUncompressed, maxLen, (const uchar*)pRecord->filename, 0, - strlen(pRecord->filename), &pTmpDataSource); + strlen(pRecord->filename), nil, &pTmpDataSource); BailError(err); - /* put in a new "add" threadMod */ + /* put in a new "add" threadMod (which copies the data source) */ err = Nu_ThreadModAdd_New(pArchive, kNuThreadIDFilename, kNuThreadFormatUncompressed, pTmpDataSource, &pNewThreadMod); + Nu_DataSourceFree(pTmpDataSource); BailError(err); /* add it to the list */ @@ -2060,8 +2061,8 @@ Nu_AddCommentToFirstNewRecord(NuArchive* pArchive) err = kNuErrNone; /* create a new data source with nothing in it */ - err = Nu_DataSourceBuffer_New(kNuThreadFormatUncompressed, false, - kNuDefaultCommentSize, nil, 0, 0, &pDataSource); + err = Nu_DataSourceBuffer_New(kNuThreadFormatUncompressed, + kNuDefaultCommentSize, nil, 0, 0, nil, &pDataSource); BailError(err); Assert(pDataSource != nil); @@ -2070,7 +2071,7 @@ Nu_AddCommentToFirstNewRecord(NuArchive* pArchive) kNuThreadFormatUncompressed, pDataSource, &pThreadMod); BailError(err); Assert(pThreadMod != nil); - pDataSource = nil; /* don't free on exit */ + /*pDataSource = nil;*/ /* ThreadModAdd_New makes a copy */ /* add the thread mod to the record */ Nu_RecordAddThreadMod(pRecord, pThreadMod); @@ -2479,10 +2480,13 @@ bail: * we are able to do so. This retains any BXY/BSE wrapper padding. */ if (!writeToTemp) { - err = Nu_TruncateOpenFile(pArchive->archiveFp, initialEOF); - if (err == kNuErrNone) { - DBUG(("+++ truncating orig archive back to %ld\n", + NuError err2; + err2 = Nu_TruncateOpenFile(pArchive->archiveFp, initialEOF); + if (err2 == kNuErrNone) { + DBUG(("+++ truncated orig archive back to %ld\n", initialEOF)); + } else { + DBUG(("+++ truncate orig failed (err=%d)\n", err2)); } } } else { diff --git a/nufxlib-0/Entry.c b/nufxlib-0/Entry.c index 168cd3d..c471306 100644 --- a/nufxlib-0/Entry.c +++ b/nufxlib-0/Entry.c @@ -555,30 +555,30 @@ NuDebugDumpArchive(NuArchive* pArchive) */ NUFXLIB_API NuError -NuCreateDataSourceForFile(NuThreadFormat threadFormat, short doClose, +NuCreateDataSourceForFile(NuThreadFormat threadFormat, unsigned long otherLen, const char* pathname, short isFromRsrcFork, NuDataSource** ppDataSource) { - return Nu_DataSourceFile_New(threadFormat, (Boolean)(doClose != 0), - otherLen, pathname, (Boolean)(isFromRsrcFork != 0), ppDataSource); + return Nu_DataSourceFile_New(threadFormat, otherLen, + pathname, (Boolean)(isFromRsrcFork != 0), ppDataSource); } NUFXLIB_API NuError -NuCreateDataSourceForFP(NuThreadFormat threadFormat, short doClose, +NuCreateDataSourceForFP(NuThreadFormat threadFormat, unsigned long otherLen, FILE* fp, long offset, long length, - NuDataSource** ppDataSource) + NuCallback fcloseFunc, NuDataSource** ppDataSource) { - return Nu_DataSourceFP_New(threadFormat, (Boolean)(doClose != 0), - otherLen, fp, offset, length, ppDataSource); + return Nu_DataSourceFP_New(threadFormat, otherLen, + fp, offset, length, fcloseFunc, ppDataSource); } NUFXLIB_API NuError -NuCreateDataSourceForBuffer(NuThreadFormat threadFormat, short doClose, +NuCreateDataSourceForBuffer(NuThreadFormat threadFormat, unsigned long otherLen, const unsigned char* buffer, long offset, - long length, NuDataSource** ppDataSource) + long length, NuCallback freeFunc, NuDataSource** ppDataSource) { - return Nu_DataSourceBuffer_New(threadFormat, (Boolean)(doClose != 0), - otherLen, buffer, offset, length, ppDataSource); + return Nu_DataSourceBuffer_New(threadFormat, otherLen, + buffer, offset, length, freeFunc, ppDataSource); } NUFXLIB_API NuError diff --git a/nufxlib-0/MiscUtils.c b/nufxlib-0/MiscUtils.c index fe9b8af..6fdba7d 100644 --- a/nufxlib-0/MiscUtils.c +++ b/nufxlib-0/MiscUtils.c @@ -366,3 +366,15 @@ Nu_Free(NuArchive* pArchive, void* ptr) } #endif +/* + * If somebody internal wants to set doClose on a buffer DataSource + * (looks like "Rename" does), we need to supply a "free" callback. + */ +NuResult +Nu_InternalFreeCallback(NuArchive* pArchive, void* args) +{ + DBUG(("+++ internal free callback 0x%08lx\n", (long) args)); + Nu_Free(nil, args); + return kNuOK; +} + diff --git a/nufxlib-0/NufxLib.h b/nufxlib-0/NufxLib.h index 9a23a59..105e318 100644 --- a/nufxlib-0/NufxLib.h +++ b/nufxlib-0/NufxLib.h @@ -760,14 +760,14 @@ NUFXLIB_API NuError NuDebugDumpArchive(NuArchive* pArchive); /* sources and sinks */ NUFXLIB_API NuError NuCreateDataSourceForFile(NuThreadFormat threadFormat, - short doClose, unsigned long otherLen, const char* pathname, + unsigned long otherLen, const char* pathname, short isFromRsrcFork, NuDataSource** ppDataSource); NUFXLIB_API NuError NuCreateDataSourceForFP(NuThreadFormat threadFormat, - short doClose, unsigned long otherLen, FILE* fp, long offset, - long length, NuDataSource** ppDataSource); + unsigned long otherLen, FILE* fp, long offset, long length, + NuCallback closeFunc, NuDataSource** ppDataSource); NUFXLIB_API NuError NuCreateDataSourceForBuffer(NuThreadFormat threadFormat, - short doClose, unsigned long otherLen, const unsigned char* buffer, - long offset, long length, NuDataSource** ppDataSource); + unsigned long otherLen, const unsigned char* buffer, long offset, + long length, NuCallback freeFunc, NuDataSource** ppDataSource); NUFXLIB_API NuError NuFreeDataSource(NuDataSource* pDataSource); NUFXLIB_API NuError NuDataSourceSetRawCrc(NuDataSource* pDataSource, unsigned short crc); @@ -809,6 +809,7 @@ NUFXLIB_API NuError NuSetOutputPathnameFilter(NuArchive* pArchive, NuCallback filterFunc); NUFXLIB_API NuError NuSetProgressUpdater(NuArchive* pArchive, NuCallback updateFunc); +NUFXLIB_API NuError NuSetFreeHandler(NuArchive* pArchive, NuCallback freeFunc); NUFXLIB_API NuError NuSetErrorHandler(NuArchive* pArchive,NuCallback errorFunc); NUFXLIB_API NuError NuSetErrorMessageHandler(NuArchive* pArchive, NuCallback messageHandlerFunc); diff --git a/nufxlib-0/NufxLibPriv.h b/nufxlib-0/NufxLibPriv.h index 342105f..c610a20 100644 --- a/nufxlib-0/NufxLibPriv.h +++ b/nufxlib-0/NufxLibPriv.h @@ -319,9 +319,10 @@ typedef struct NuDataSourceCommon { NuDataSourceType sourceType; NuThreadFormat threadFormat; /* is it already compressed? */ ushort rawCrc; /* crc for already-compressed data*/ - Boolean doClose; /* close on completion? */ + /*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 { @@ -342,6 +343,8 @@ union NuDataSource { NuDataSourceCommon common; FILE* fp; long offset; /* starting offset */ + + NuCallback fcloseFunc; /* how to fclose the file */ } fromFP; struct { @@ -351,6 +354,8 @@ union NuDataSource { long curOffset; /* current offset */ long curDataLen; /* remaining data */ + + NuCallback freeFunc; /* how to free data */ } fromBuffer; }; @@ -679,6 +684,7 @@ 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); @@ -739,15 +745,15 @@ NuError Nu_Delete(NuArchive* pArchive); NuError Nu_DeleteRecord(NuArchive* pArchive, NuRecordIdx rec); /* SourceSink.c */ -NuError Nu_DataSourceFile_New(NuThreadFormat threadFormat, Boolean doClose, +NuError Nu_DataSourceFile_New(NuThreadFormat threadFormat, ulong otherLen, const char* pathname, Boolean isFromRsrcFork, NuDataSource** ppDataSource); -NuError Nu_DataSourceFP_New(NuThreadFormat threadFormat, Boolean doClose, +NuError Nu_DataSourceFP_New(NuThreadFormat threadFormat, ulong otherLen, FILE* fp, long offset, long length, - NuDataSource** ppDataSource); + NuCallback fcloseFunc, NuDataSource** ppDataSource); NuError Nu_DataSourceBuffer_New(NuThreadFormat threadFormat, - Boolean doClose, ulong otherLen, const uchar* buffer, long offset, - long length, NuDataSource** ppDataSource); + 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); diff --git a/nufxlib-0/Record.c b/nufxlib-0/Record.c index b7a92bd..0d49e1a 100644 --- a/nufxlib-0/Record.c +++ b/nufxlib-0/Record.c @@ -2301,7 +2301,7 @@ Nu_AddFileThreadMod(NuArchive* pArchive, NuRecord* pRecord, threadFormat = kNuThreadFormatUncompressed; /* create a data source for this file, which is assumed uncompressed */ - err = Nu_DataSourceFile_New(kNuThreadFormatUncompressed, false, 0, + err = Nu_DataSourceFile_New(kNuThreadFormatUncompressed, 0, pathname, fromRsrcFork, &pDataSource); BailError(err); @@ -2310,7 +2310,7 @@ Nu_AddFileThreadMod(NuArchive* pArchive, NuRecord* pRecord, pDataSource, &pThreadMod); BailError(err); Assert(pThreadMod != nil); - pDataSource = nil; /* don't free on exit */ + /*pDataSource = nil;*/ /* ThreadModAdd_New makes a copy */ /* add the thread mod to the record */ Nu_RecordAddThreadMod(pRecord, pThreadMod); @@ -2552,9 +2552,10 @@ Nu_Rename(NuArchive* pArchive, NuRecordIdx recIdx, const char* pathname, /* create a data source for the filename, if needed */ if (doAdd || doUpdate) { Assert(newCapacity); - err = Nu_DataSourceBuffer_New(kNuThreadFormatUncompressed, true, + err = Nu_DataSourceBuffer_New(kNuThreadFormatUncompressed, newCapacity, (const uchar*)strdup(pathname), 0, - requiredCapacity /*(strlen)*/, &pDataSource); + requiredCapacity /*(strlen)*/, Nu_InternalFreeCallback, + &pDataSource); BailError(err); } @@ -2570,7 +2571,7 @@ Nu_Rename(NuArchive* pArchive, NuRecordIdx recIdx, const char* pathname, err = Nu_ThreadModAdd_New(pArchive, kNuThreadIDFilename, kNuThreadFormatUncompressed, pDataSource, &pNewThreadMod); BailError(err); - pDataSource = nil; /* successful, don't free */ + /*pDataSource = nil;*/ /* ThreadModAdd_New makes a copy */ Nu_RecordAddThreadMod(pRecord, pNewThreadMod); pNewThreadMod = nil; /* successful, don't free */ } @@ -2579,7 +2580,7 @@ Nu_Rename(NuArchive* pArchive, NuRecordIdx recIdx, const char* pathname, err = Nu_ThreadModUpdate_New(pArchive, pFilenameThread->threadIdx, pDataSource, &pNewThreadMod); BailError(err); - pDataSource = nil; /* successful, don't free */ + /*pDataSource = nil;*/ /* ThreadModAdd_New makes a copy */ Nu_RecordAddThreadMod(pRecord, pNewThreadMod); pNewThreadMod = nil; /* successful, don't free */ } diff --git a/nufxlib-0/SourceSink.c b/nufxlib-0/SourceSink.c index e49acf9..b210e15 100644 --- a/nufxlib-0/SourceSink.c +++ b/nufxlib-0/SourceSink.c @@ -35,18 +35,28 @@ Nu_DataSourceNew(NuDataSource** ppDataSource) /* - * Make a copy of a DataSource. + * Make a copy of a DataSource. Actually just increments a reference count. * - * IMPORTANT: if the original had the "doClose" flag set, it will be cleared, - * but left set in the duplicate. The assumption is that the original will - * be thrown out before the duplicate. If this isn't the case, you will - * need to fix the flags on the copied data. + * What we *really* want to be doing is copying the structure (since we + * can't guarantee copy-on-write semantics for the fields without adding + * more stuff) and refcounting the underlying resource, so that "auto-free" + * semantics work out right. + * + * We're okay for now, since for the most part we only do work on one + * copy of each. (I wish I could remember why this copying thing was + * needed in the first place.) Buffer sources are a little scary since + * they include a "curOffset" value. * * Returns nil on error. */ NuDataSource* Nu_DataSourceCopy(NuDataSource* pDataSource) { + Assert(pDataSource->common.refCount >= 1); + pDataSource->common.refCount++; + return pDataSource; + +#if 0 /* we used to copy them -- very bad idea */ NuDataSource* pNewDataSource; Assert(pDataSource != nil); @@ -72,6 +82,7 @@ Nu_DataSourceCopy(NuDataSource* pDataSource) } return pNewDataSource; +#endif } @@ -84,6 +95,12 @@ Nu_DataSourceFree(NuDataSource* pDataSource) if (pDataSource == nil) return kNuErrNone; + Assert(pDataSource->common.refCount > 0); + if (pDataSource->common.refCount > 1) { + pDataSource->common.refCount--; + return kNuErrNone; + } + switch (pDataSource->sourceType) { case kNuDataSourceFromFile: Nu_Free(nil, pDataSource->fromFile.pathname); @@ -93,14 +110,17 @@ Nu_DataSourceFree(NuDataSource* pDataSource) } break; case kNuDataSourceFromFP: - if (pDataSource->common.doClose) { - fclose(pDataSource->fromFile.fp); - pDataSource->fromFile.fp = nil; + if (pDataSource->fromFP.fcloseFunc != nil && + pDataSource->fromFP.fp != nil) + { + (*pDataSource->fromFP.fcloseFunc)(nil, pDataSource->fromFP.fp); + pDataSource->fromFP.fp = nil; } break; case kNuDataSourceFromBuffer: - if (pDataSource->common.doClose) { - Nu_Free(nil, (char*)pDataSource->fromBuffer.buffer); + if (pDataSource->fromBuffer.freeFunc != nil) { + (*pDataSource->fromBuffer.freeFunc)(nil, + (void*)pDataSource->fromBuffer.buffer); pDataSource->fromBuffer.buffer = nil; } break; @@ -120,14 +140,12 @@ Nu_DataSourceFree(NuDataSource* pDataSource) * Create a data source for an unopened file. */ NuError -Nu_DataSourceFile_New(NuThreadFormat threadFormat, Boolean doClose, - ulong otherLen, const char* pathname, Boolean isFromRsrcFork, - NuDataSource** ppDataSource) +Nu_DataSourceFile_New(NuThreadFormat threadFormat, ulong otherLen, + const char* pathname, Boolean isFromRsrcFork, NuDataSource** ppDataSource) { NuError err; - if (!(doClose == true || doClose == false) || - pathname == nil || + if (pathname == nil || !(isFromRsrcFork == true || isFromRsrcFork == false) || ppDataSource == nil) { @@ -139,12 +157,13 @@ Nu_DataSourceFile_New(NuThreadFormat threadFormat, Boolean doClose, (*ppDataSource)->common.sourceType = kNuDataSourceFromFile; (*ppDataSource)->common.threadFormat = threadFormat; - (*ppDataSource)->common.doClose = doClose; + (*ppDataSource)->common.rawCrc = 0; + (*ppDataSource)->common.dataLen = 0; /* to be filled in later */ (*ppDataSource)->common.otherLen = otherLen; + (*ppDataSource)->common.refCount = 1; + (*ppDataSource)->fromFile.pathname = strdup(pathname); (*ppDataSource)->fromFile.fromRsrcFork = isFromRsrcFork; - - (*ppDataSource)->common.dataLen = 0; /* to be filled in later */ (*ppDataSource)->fromFile.fp = nil; /* to be filled in later */ bail: @@ -157,14 +176,13 @@ bail: * must be seekable. */ NuError -Nu_DataSourceFP_New(NuThreadFormat threadFormat, Boolean doClose, - ulong otherLen, FILE* fp, long offset, long length, +Nu_DataSourceFP_New(NuThreadFormat threadFormat, ulong otherLen, + FILE* fp, long offset, long length, NuCallback fcloseFunc, NuDataSource** ppDataSource) { NuError err; - if (!(doClose == true || doClose == false) || - fp == nil || offset < 0 || length < 0 || + if (fp == nil || offset < 0 || length < 0 || ppDataSource == nil) { return kNuErrInvalidArg; @@ -181,11 +199,14 @@ Nu_DataSourceFP_New(NuThreadFormat threadFormat, Boolean doClose, (*ppDataSource)->common.sourceType = kNuDataSourceFromFP; (*ppDataSource)->common.threadFormat = threadFormat; - (*ppDataSource)->common.doClose = doClose; + (*ppDataSource)->common.rawCrc = 0; (*ppDataSource)->common.dataLen = length; (*ppDataSource)->common.otherLen = otherLen; + (*ppDataSource)->common.refCount = 1; + (*ppDataSource)->fromFP.fp = fp; (*ppDataSource)->fromFP.offset = offset; + (*ppDataSource)->fromFP.fcloseFunc = fcloseFunc; bail: return err; @@ -200,23 +221,21 @@ bail: * blank comment fields. */ NuError -Nu_DataSourceBuffer_New(NuThreadFormat threadFormat, Boolean doClose, - ulong otherLen, const uchar* buffer, long offset, long length, +Nu_DataSourceBuffer_New(NuThreadFormat threadFormat, ulong otherLen, + const uchar* buffer, long offset, long length, NuCallback freeFunc, NuDataSource** ppDataSource) { NuError err; - if (!(doClose == true || doClose == false) || - offset < 0 || length < 0 || ppDataSource == nil) - { + if (offset < 0 || length < 0 || ppDataSource == nil) return kNuErrInvalidArg; - } if (buffer == nil && (offset != 0 || length != 0)) - { return kNuErrInvalidArg; + + if (buffer == nil) { + DBUG(("+++ zeroing freeFunc for empty-buffer DataSource\n")); + freeFunc = nil; } - if (buffer == nil) - doClose = false; if (otherLen && otherLen < (ulong)length) { DBUG(("--- rejecting buffer len=%ld other=%ld\n", length, otherLen)); @@ -229,14 +248,16 @@ Nu_DataSourceBuffer_New(NuThreadFormat threadFormat, Boolean doClose, (*ppDataSource)->common.sourceType = kNuDataSourceFromBuffer; (*ppDataSource)->common.threadFormat = threadFormat; - (*ppDataSource)->common.doClose = doClose; + (*ppDataSource)->common.rawCrc = 0; (*ppDataSource)->common.dataLen = length; (*ppDataSource)->common.otherLen = otherLen; + (*ppDataSource)->common.refCount = 1; + (*ppDataSource)->fromBuffer.buffer = buffer; (*ppDataSource)->fromBuffer.offset = offset; - (*ppDataSource)->fromBuffer.curOffset = offset; (*ppDataSource)->fromBuffer.curDataLen = length; + (*ppDataSource)->fromBuffer.freeFunc = freeFunc; bail: return err; diff --git a/nufxlib-0/Thread.c b/nufxlib-0/Thread.c index 14c5f00..6c0366c 100644 --- a/nufxlib-0/Thread.c +++ b/nufxlib-0/Thread.c @@ -1126,7 +1126,7 @@ Nu_AddThread(NuArchive* pArchive, NuRecordIdx recIdx, NuThreadID threadID, } DBUG(("--- using threadFormat = %d\n", threadFormat)); - /* create a new ThreadMod */ + /* create a new ThreadMod (which makes a copy of the data source) */ err = Nu_ThreadModAdd_New(pArchive, threadID, threadFormat, pDataSource, &pThreadMod); BailError(err); @@ -1151,6 +1151,11 @@ Nu_AddThread(NuArchive* pArchive, NuRecordIdx recIdx, NuThreadID threadID, bail: if (pThreadMod != nil) Nu_ThreadModFree(pArchive, pThreadMod); + if (err == kNuErrNone && pDataSource != nil) { + /* on success, we have ownership of the data source. ThreadMod + made its own copy, so get rid of this one */ + Nu_DataSourceFree(pDataSource); + } return err; } diff --git a/nufxlib-0/samples/Exerciser.c b/nufxlib-0/samples/Exerciser.c index 5a70312..88eaeb3 100644 --- a/nufxlib-0/samples/Exerciser.c +++ b/nufxlib-0/samples/Exerciser.c @@ -300,6 +300,15 @@ ErrorHandler(NuArchive* pArchive, void* vErrorStatus) return result; } +/* + * This gets called when a buffer DataSource is no longer needed. + */ +NuResult +FreeCallback(NuArchive* pArchive, void* args) +{ + free(args); +} + /* * =========================================================================== @@ -448,7 +457,7 @@ AddThreadFunc(ExerciserState* pState, int argc, char** argv) } err = NuCreateDataSourceForFile(kNuThreadFormatUncompressed, - true, 0, lineBuf, false, &pDataSource); + 0, lineBuf, false, &pDataSource); if (err != kNuErrNone) { fprintf(stderr, "Exerciser: file data source create failed (err=%d)\n", err); @@ -477,7 +486,8 @@ AddThreadFunc(ExerciserState* pState, int argc, char** argv) /* create a data source from the buffer */ err = NuCreateDataSourceForBuffer(kNuThreadFormatUncompressed, - true, maxLen, (unsigned char*)lineBuf, 0, ourLen, &pDataSource); + maxLen, (unsigned char*)lineBuf, 0, ourLen, FreeCallback, + &pDataSource); if (err != kNuErrNone) { fprintf(stderr, "Exerciser: buffer data source create failed (err=%d)\n", err); @@ -1004,7 +1014,8 @@ UpdatePresizedThreadFunc(ExerciserState* pState, int argc, char** argv) /* use "ourLen" for both buffer len and data len */ err = NuCreateDataSourceForBuffer(kNuThreadFormatUncompressed, - true, ourLen, (unsigned char*)lineBuf, 0, ourLen, &pDataSource); + ourLen, (unsigned char*)lineBuf, 0, ourLen, FreeCallback, + &pDataSource); if (err != kNuErrNone) { fprintf(stderr, "Exerciser: data source create failed (err=%d)\n", err); @@ -1303,7 +1314,7 @@ CommandLoop(void) } if (pState != nil) - free(pState); + ExerciserState_Free(pState); if (argv != nil) free(argv); return kNuErrNone; diff --git a/nufxlib-0/samples/ImgConv.c b/nufxlib-0/samples/ImgConv.c index 95fb387..359f4d5 100644 --- a/nufxlib-0/samples/ImgConv.c +++ b/nufxlib-0/samples/ImgConv.c @@ -212,16 +212,38 @@ DumpImgHeader(ImgHeader* pHeader) typedef enum ArchiveKind { kKindUnknown, kKindShk, kKindImg } ArchiveKind; +/* + * This gets called when a buffer DataSource is no longer needed. + */ +NuResult +FreeCallback(NuArchive* pArchive, void* args) +{ + free(args); +} + +/* + * This gets called when an "FP" DataSource is no longer needed. + */ +NuResult +FcloseCallback(NuArchive* pArchive, void* args) +{ + fclose((FILE*) args); +} + /* * Create a data source for a ProDOS-ordered image. Since this is already * in the correct format, we just point at the correct offset in the 2MG file. + * + * This supplies an FcloseCallback so that we can exercise that feature + * of NufxLib. We could just as easily not set it and call fclose() + * ourselves, because the structure of this program is pretty simple. */ NuError CreateProdosSource(const ImgHeader* pHeader, FILE* fp, NuDataSource** ppDataSource) { - return NuCreateDataSourceForFP(kNuThreadFormatUncompressed, false, 0, fp, - pHeader->dataOffset, pHeader->dataLen, ppDataSource); + return NuCreateDataSourceForFP(kNuThreadFormatUncompressed, 0, fp, + pHeader->dataOffset, pHeader->dataLen, FcloseCallback,ppDataSource); } /* @@ -290,9 +312,9 @@ CreateDosSource(const ImgHeader* pHeader, FILE* fp, * Create a data source for the buffer. We set the "doClose" flag to * "true", so NufxLib will free the buffer for us. */ - err = NuCreateDataSourceForBuffer(kNuThreadFormatUncompressed, true, 0, + err = NuCreateDataSourceForBuffer(kNuThreadFormatUncompressed, 0, (const unsigned char*) diskBuffer, 0, pHeader->dataLen, - ppDataSource); + FreeCallback, ppDataSource); if (err == kNuErrNone) diskBuffer = nil; @@ -405,9 +427,11 @@ ConvertFromImgToShk(const char* srcName, const char* dstName) switch (header.imageFormat) { case kImageFormatDOS: err = CreateDosSource(&header, fp, &pDataSource); + fp = nil; break; case kImageFormatProDOS: err = CreateProdosSource(&header, fp, &pDataSource); + fp = nil; break; default: fprintf(stderr, "How the heck did I get here?"); diff --git a/nufxlib-0/samples/Launder.c b/nufxlib-0/samples/Launder.c index c4d1a83..caa20e3 100644 --- a/nufxlib-0/samples/Launder.c +++ b/nufxlib-0/samples/Launder.c @@ -44,6 +44,14 @@ char gSentRecordWarning = false; +/* + * This gets called when a buffer DataSource is no longer needed. + */ +NuResult +FreeCallback(NuArchive* pArchive, void* args) +{ + free(args); +} /* * Copy a thread, expanding and recompressing it. @@ -107,18 +115,18 @@ CopyThreadRecompressed(NuArchive* pInArchive, NuArchive* pOutArchive, * the right thing. */ if (NuIsPresizedThreadID(NuGetThreadID(pThread))) { - err = NuCreateDataSourceForBuffer(kNuThreadFormatUncompressed, true, + err = NuCreateDataSourceForBuffer(kNuThreadFormatUncompressed, pThread->thCompThreadEOF, buffer, 0, - pThread->actualThreadEOF, &pDataSource); + pThread->actualThreadEOF, FreeCallback, &pDataSource); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to create pre-sized data source (err=%d)\n",err); goto bail; } } else { - err = NuCreateDataSourceForBuffer(kNuThreadFormatUncompressed, true, - 0, buffer, 0, - pThread->actualThreadEOF, &pDataSource); + err = NuCreateDataSourceForBuffer(kNuThreadFormatUncompressed, + 0, buffer, 0, pThread->actualThreadEOF, + FreeCallback, &pDataSource); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to create data source (err=%d)\n", err); @@ -234,18 +242,18 @@ CopyThreadUncompressed(NuArchive* pInArchive, NuArchive* pOutArchive, * for disk archives created by certain versions of ShrinkIt. */ if (NuIsPresizedThreadID(NuGetThreadID(pThread))) { - err = NuCreateDataSourceForBuffer(pThread->thThreadFormat, true, + err = NuCreateDataSourceForBuffer(pThread->thThreadFormat, pThread->thCompThreadEOF, buffer, 0, - pThread->actualThreadEOF, &pDataSource); + pThread->actualThreadEOF, FreeCallback, &pDataSource); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to create pre-sized data source (err=%d)\n",err); goto bail; } } else { - err = NuCreateDataSourceForBuffer(pThread->thThreadFormat, true, + err = NuCreateDataSourceForBuffer(pThread->thThreadFormat, pThread->actualThreadEOF, buffer, 0, - pThread->thCompThreadEOF, &pDataSource); + pThread->thCompThreadEOF, FreeCallback, &pDataSource); if (err != kNuErrNone) { fprintf(stderr, "ERROR: unable to create data source (err=%d)\n", err); diff --git a/nufxlib-0/samples/TestBasic.c b/nufxlib-0/samples/TestBasic.c index b143537..702769b 100644 --- a/nufxlib-0/samples/TestBasic.c +++ b/nufxlib-0/samples/TestBasic.c @@ -91,6 +91,15 @@ ErrorMessageHandler(NuArchive* pArchive, void* vErrorMessage) return kNuOK; } +/* + * This gets called when a buffer DataSource is no longer needed. + */ +NuResult +FreeCallback(NuArchive* pArchive, void* args) +{ + free(args); +} + /* * =========================================================================== @@ -186,8 +195,8 @@ Test_AddStuff(NuArchive* pArchive) *(buf+i) = i & 0xff; FAIL_OK; - err = NuCreateDataSourceForBuffer(kNuThreadFormatUncompressed, true, - 0, nil, 0, 131072, &pDataSource); + err = NuCreateDataSourceForBuffer(kNuThreadFormatUncompressed, + 0, nil, 0, 131072, FreeCallback, &pDataSource); FAIL_BAD; if (err == kNuErrNone) { fprintf(stderr, "ERROR: that should've failed!\n"); @@ -197,8 +206,8 @@ Test_AddStuff(NuArchive* pArchive) /* * Create a data source for the big batch of bytes. */ - err = NuCreateDataSourceForBuffer(kNuThreadFormatUncompressed, true, - 0, buf, 0, 131072, &pDataSource); + err = NuCreateDataSourceForBuffer(kNuThreadFormatUncompressed, + 0, buf, 0, 131072, FreeCallback, &pDataSource); if (err != kNuErrNone) { fprintf(stderr, "ERROR: 'bytes' data source create failed (err=%d)\n", err); @@ -225,8 +234,8 @@ Test_AddStuff(NuArchive* pArchive) * Create a data source for our lovely text message. */ printf("... add 'English' record\n"); - err = NuCreateDataSourceForBuffer(kNuThreadFormatUncompressed, false, - 0, (const uchar*)testMsg, 0, strlen(testMsg), &pDataSource); + err = NuCreateDataSourceForBuffer(kNuThreadFormatUncompressed, + 0, (const uchar*)testMsg, 0, strlen(testMsg), nil, &pDataSource); if (err != kNuErrNone) { fprintf(stderr, "ERROR: 'English' source create failed (err=%d)\n", err); @@ -269,8 +278,8 @@ Test_AddStuff(NuArchive* pArchive) * Create an empty file with a rather non-empty name. */ printf("... add 'long' record\n"); - err = NuCreateDataSourceForBuffer(kNuThreadFormatUncompressed, false, - 0, nil, 0, 0, &pDataSource); + err = NuCreateDataSourceForBuffer(kNuThreadFormatUncompressed, + 0, nil, 0, 0, nil, &pDataSource); if (err != kNuErrNone) { fprintf(stderr, "ERROR: 'English' source create failed (err=%d)\n", err);