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).
This commit is contained in:
Andy McFadden 2003-02-09 01:53:51 +00:00
parent 067d6d8e83
commit 1169554de3
13 changed files with 210 additions and 99 deletions

View File

@ -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 *****

View File

@ -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 {

View File

@ -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

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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 */
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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?");

View File

@ -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);

View File

@ -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);