Beispiel #1
0
PlankResult pl_LockFreeQueue_DeInit (PlankLockFreeQueueRef p)
{
    PlankResult result = PlankResult_OK;
    
    if (p == PLANK_NULL)
    {
        result = PlankResult_MemoryError;
        goto exit;
    }
        
    if (pl_LockFreeQueue_GetSize (p) != 0)
    {
        result = PlankResult_ContainerNotEmptyOnDeInit;
        goto exit;
    }
    
    pl_LockFreeQueueElement_DeInit (&p->dummyElement);
    
    pl_AtomicPX_DeInit (&p->head);
    pl_AtomicPX_DeInit (&p->tail);
    pl_MemoryZero (p, sizeof (PlankLockFreeQueue));

exit:
    return result;    
}
Beispiel #2
0
PlankResult pl_LockFreeQueue_Init (PlankLockFreeQueueRef p)
{
    PlankResult result = PlankResult_OK;
    
    if (p == PLANK_NULL)
    {
        result = PlankResult_MemoryError;
        goto exit;
    }
    
    pl_MemoryZero (p, sizeof (PlankLockFreeQueue));
    
    pl_AtomicPX_Init (&p->head);
    pl_AtomicPX_Init (&p->tail);
        
    pl_LockFreeQueueElement_Init (&p->dummyElement);
    
    pl_AtomicPX_SetAllUnchecked (&p->head, &p->dummyElement, 0);
    pl_AtomicPX_SetAllUnchecked (&p->tail, &p->dummyElement, 0);
    
    pl_LockFreeQueueElement_SetNext (&p->dummyElement, (PlankLockFreeQueueElementRef)p);
    
exit:
    return result;    
}
Beispiel #3
0
PlankMemoryRef pl_Memory_Create()
{
    PlankMemoryRef p = (PlankMemoryRef)pl_MemoryDefaultAllocateBytes (0, sizeof (PlankMemory));
    
    if (p != PLANK_NULL)
        pl_MemoryZero (p, sizeof (PlankMemory));
        
    return p;
}
Beispiel #4
0
PlankResult pl_Memory_DeInit (PlankMemoryRef p)
{
    if (p == PLANK_NULL)
        return PlankResult_MemoryError;
    
    pl_Lock_Lock (&p->lock);
    pl_MemoryZero (p, sizeof (PlankMemory));
    pl_Lock_Unlock (&p->lock);
    
    return PlankResult_OK;
}
Beispiel #5
0
PlankResult pl_IffFileWriter_Init (PlankIffFileWriterRef p)
{
    PlankResult result = PlankResult_OK;
    
    pl_MemoryZero (p, sizeof (PlankIffFileWriter));
    pl_File_Init ((PlankFileRef)p);
    
    result = pl_DynamicArray_InitWithItemSizeAndCapacity (&p->chunkInfos, sizeof(PlankIffFileWriterChunkInfo), 16);
    
//exit:
    return result;
}
Beispiel #6
0
PlankSimpleMapRef pl_SimpleMap_Create()
{
    PlankMemoryRef m;
    PlankSimpleMapRef p;
    
    m = pl_MemoryGlobal();
    p = (PlankSimpleMapRef)pl_Memory_AllocateBytes (m, sizeof (PlankSimpleMap));
    
    if (p != PLANK_NULL)
        pl_MemoryZero (p, sizeof (PlankSimpleMap));
    
    return p;
}
Beispiel #7
0
PlankLockRef pl_Lock_Create()
{
    PlankMemoryRef m;
    PlankLockRef p;
    
    m = pl_MemoryGlobal();
    p = (PlankLockRef)pl_Memory_AllocateBytes (m, sizeof (PlankLock));
    
    if (p != PLANK_NULL)
        pl_MemoryZero (p, sizeof (PlankLock));
    
    return p;
}
Beispiel #8
0
PlankIffFileWriterRef pl_IffFileWriter_Create()
{
    PlankMemoryRef m;
    PlankIffFileWriterRef p;
    
    m = pl_MemoryGlobal();
    p = (PlankIffFileWriterRef)pl_Memory_AllocateBytes (m, sizeof (PlankIffFileWriter));
    
    if (p != PLANK_NULL)
        pl_MemoryZero (p, sizeof (PlankIffFileWriter));
    
    return p;
}
PlankLockFreeLinkedListElementRef pl_LockFreeLinkedListElement_Create()
{
    PlankMemoryRef m;
    PlankLockFreeLinkedListElementRef p;
    
    m = pl_MemoryGlobal(); // must use the lock free one when done... nope just live with it and use alogrithms that reuse the memory allocs
    p = (PlankLockFreeLinkedListElementRef)pl_Memory_AllocateBytes (m, sizeof (PlankLockFreeLinkedListElement));
    
    if (p != PLANK_NULL)
        pl_MemoryZero (p, sizeof (PlankLockFreeLinkedListElement));
    
    return p;    
}
Beispiel #10
0
PlankLockFreeQueueRef pl_LockFreeQueue_Create()
{
    PlankMemoryRef m;
    PlankLockFreeQueueRef p;
    
    m = pl_MemoryGlobal(); // OK, creation of the queue isn't itself lock free
    p = (PlankLockFreeQueueRef)pl_Memory_AllocateBytes (m, sizeof (PlankLockFreeQueue));
    
    if (p != PLANK_NULL)
        pl_MemoryZero (p, sizeof (PlankLockFreeQueue));
    
    return p;
}
Beispiel #11
0
PlankResult pl_SimpleQueue_Init (PlankSimpleQueueRef p)
{
    PlankResult result = PlankResult_OK;
    
    if (p == PLANK_NULL)
    {
        result = PlankResult_MemoryError;
        goto exit;
    }
    
    pl_MemoryZero (p, sizeof (PlankSimpleQueue));
                
exit:
    return result;
}
Beispiel #12
0
PlankResult pl_SimpleMap_Init (PlankSimpleMapRef p)
{
    PlankResult result = PlankResult_OK;
    
    if (p == PLANK_NULL)
    {
        result = PlankResult_MemoryError;
        goto exit;
    }
    
    pl_MemoryZero (p, sizeof (PlankSimpleMap));
    result = pl_SimpleLinkedList_Init (&p->list);
            
exit:
    return result;
}
Beispiel #13
0
PlankResult pl_Lock_DeInit (PlankLockRef p)
{
    PlankResult result = PlankResult_OK;
    
    if (p == PLANK_NULL)
    {
        result = PlankResult_MemoryError;
        goto exit;
    }
    
    DeleteCriticalSection (&p->mutex);
    CloseHandle (p->condition);    
    pl_MemoryZero (p, sizeof (PlankLock));

exit:
    return result;
}
PlankResult pl_LockFreeLinkedListElement_DeInit (PlankLockFreeLinkedListElementRef p)
{
    PlankResult result = PlankResult_OK;

    if (p == PLANK_NULL)
    {
        result = PlankResult_MemoryError;
        goto exit;
    }
        
    pl_AtomicPX_DeInit (&p->next);
    pl_AtomicPX_DeInit (&p->data);
    pl_MemoryZero (p, sizeof (PlankLockFreeLinkedListElement));

exit:
    return result;    
}
Beispiel #15
0
PlankResult pl_Lock_DeInit (PlankLockRef p)
{
    PlankResult result = PlankResult_OK;
    
    if (p == PLANK_NULL)
    {
        result = PlankResult_MemoryError;
        goto exit;
    }
    
    pthread_mutex_destroy (&p->mutex);
    pthread_cond_destroy (&p->condition);
    
    pl_MemoryZero (p, sizeof (PlankLock));
    
exit:
    return result;
}
Beispiel #16
0
PlankResult pl_SimpleQueue_DeInit (PlankSimpleQueueRef p)
{
    PlankResult result = PlankResult_OK;
    
    if (p == PLANK_NULL)
    {
        result = PlankResult_MemoryError;
        goto exit;
    }
        
    if (pl_SimpleQueue_GetSize (p) != 0)
        result = PlankResult_ContainerNotEmptyOnDeInit;
    
    pl_MemoryZero (p, sizeof (PlankSimpleQueue));

exit:
    return result;    
}
Beispiel #17
0
PlankResult pl_SimpleMap_DeInit (PlankSimpleMapRef p)
{
    PlankResult result = PlankResult_OK;
    
    if (p == PLANK_NULL)
    {
        result = PlankResult_MemoryError;
        goto exit;
    }
        
    if (pl_SimpleMap_GetSize (p) != 0)
        result = PlankResult_ContainerNotEmptyOnDeInit;
    
    if ((result = pl_SimpleLinkedList_DeInit (&p->list)) != PlankResult_OK)
        goto exit;
            
    pl_MemoryZero (p, sizeof (PlankSimpleMap));

exit:
    return result;    
}
Beispiel #18
0
PlankResult pl_IffFileWriter_OpenWithFile (PlankIffFileWriterRef p,
                                           PlankFileRef file,
                                           const char* mainID,
                                           const char* formatID,
                                           const int idType)
{
    PlankResult result = PlankResult_OK;
    int mode;
    
    if ((result = pl_File_GetMode (file, &mode)) != PlankResult_OK) goto exit;
    
    if (! (mode & PLANKFILE_BINARY))
    {
        result = PlankResult_AudioFileInavlidType;
        goto exit;
    }
    
    if (! (mode & PLANKFILE_READ))
    {
        result = PlankResult_AudioFileInavlidType;
        goto exit;
    }
    
    if (! (mode & PLANKFILE_WRITE))
    {
        result = PlankResult_AudioFileInavlidType;
        goto exit;
    }
        
    pl_MemoryCopy ((PlankFileRef)p, file, sizeof (PlankFile));
    pl_MemoryZero (file, sizeof (PlankFile));

    if ((result = pl_IffFileWriter_ParseMainInfo (p, mainID, formatID, idType)) != PlankResult_OK) goto exit;
    if ((result = pl_IffFileWriter_WriteHeader (p)) != PlankResult_OK) goto exit;
    
exit:
    return result;
}
Beispiel #19
0
void AudioFileReaderInternal::disownPeer (PlankAudioFileReaderRef otherReader) throw()
{
    pl_MemoryCopy (otherReader, getPeerRef(), sizeof (PlankAudioFileReader));
    pl_MemoryZero (getPeerRef(), sizeof (PlankAudioFileReader));
    pl_AudioFileReader_Init (getPeerRef());
}
Beispiel #20
0
PlankResult pl_IffFileWriter_RewriteFileUpdatingChunkInfo (PlankIffFileWriterRef p, PlankIffFileWriterChunkInfo* updatedChunkInfo)
{
    PlankUC copyBuffer[PLANKIFFFILEWRITER_COPYLENGTH];
    PlankResult result = PlankResult_OK;
    PlankIffFileWriterChunkInfo* chunkInfos;
    PlankIffFileWriter tempWriter;
    PlankPath tempPath;
    int mode, numChunks, i, bytesRead, bytesThisTime;
    PlankLL copyChunkLengthRemain;
    PlankB eraseOriginalFile;
    char chunkIDStr[64];
    char otherIDStr[64];
    
    eraseOriginalFile = PLANK_FALSE;
    
    if ((result = pl_File_GetMode ((PlankFileRef)p, &mode)) != PlankResult_OK)              return result;
    if (! (mode & PLANKFILE_READ))                                                           return PlankResult_FileReadError;
    if ((result = pl_Path_InitTemp (&tempPath, "IffWriter-", "tmp")) != PlankResult_OK)     return result;
    if ((result = pl_IffFileWriter_Init (&tempWriter)) != PlankResult_OK)                   goto earlyExit;
    
    pl_IffFile_ChunkIDString ((PlankIffFileRef)p, &p->common.headerInfo.mainID, chunkIDStr);
    pl_IffFile_ChunkIDString ((PlankIffFileRef)p, &p->common.headerInfo.formatID, otherIDStr);

    result = pl_IffFileWriter_OpenReplacing (&tempWriter,
                                             pl_Path_GetFullPath (&tempPath),
                                             pl_File_IsBigEndian ((PlankFileRef)p),
                                             chunkIDStr,
                                             otherIDStr,
                                             p->common.headerInfo.idType);
    
    if (result != PlankResult_OK) goto earlyExit;

    numChunks = (int)pl_DynamicArray_GetSize (&p->chunkInfos);
    chunkInfos = (PlankIffFileWriterChunkInfo*)pl_DynamicArray_GetArray (&p->chunkInfos);
    
    for (i = 0; i < numChunks; ++i)
    {
        if (pl_IffFile_IsNullID ((PlankIffFileRef)p, &chunkInfos[i].chunkID))
            continue; // this was a deleted chunk
            
        if (! pl_IffFile_EqualIDs ((PlankIffFileRef)p, &chunkInfos[i].chunkID, &updatedChunkInfo->chunkID))
        {            
            if ((result = pl_File_SetPosition ((PlankFileRef)p, chunkInfos[i].chunkPos)) != PlankResult_OK) goto exit;
            
            copyChunkLengthRemain = chunkInfos[i].chunkLength;
            
            while (copyChunkLengthRemain > 0)
            {
                bytesThisTime = (int)pl_MinLL (copyChunkLengthRemain, PLANKIFFFILEWRITER_COPYLENGTH);
                
                if ((result = pl_File_Read ((PlankFileRef)p, copyBuffer, bytesThisTime, &bytesRead)) != PlankResult_OK) goto exit;
                
                if (bytesThisTime != bytesRead)
                {
                    // something is wrong if these don't match here
                    result = PlankResult_FileReadError;
                    goto exit;
                }
                
                pl_IffFile_ChunkIDString ((PlankIffFileRef)p, &chunkInfos[i].chunkID, chunkIDStr);
                                    
                if ((result = pl_IffFileWriter_WriteChunk (&tempWriter,
                                                           PLANKIFFFILE_CURRENTCHUNKPOSITION, chunkIDStr,
                                                           copyBuffer, bytesThisTime,
                                                           PLANKIFFFILEWRITER_MODEAPPEND)) != PlankResult_OK) goto exit;
                
                copyChunkLengthRemain -= bytesThisTime;
            }
        }
        else
        {
            if (chunkInfos[i].chunkPos != updatedChunkInfo->chunkPos)
            {
                // something is wrong if these don't match here
                result = PlankResult_FileReadError;
                goto exit;
            }
            
            if (updatedChunkInfo->chunkLength < chunkInfos[i].chunkLength)
                eraseOriginalFile = PLANK_TRUE;

            if ((result = pl_File_SetPosition ((PlankFileRef)p, chunkInfos[i].chunkPos)) != PlankResult_OK) goto exit;
            
            copyChunkLengthRemain = pl_MinLL (chunkInfos[i].chunkLength, updatedChunkInfo->chunkLength);

            while (copyChunkLengthRemain > 0)
            {
                bytesThisTime = (int)pl_MinLL (copyChunkLengthRemain, PLANKIFFFILEWRITER_COPYLENGTH);
                
                if ((result = pl_File_Read ((PlankFileRef)p, copyBuffer, bytesThisTime, &bytesRead)) != PlankResult_OK) goto exit;

                if ((int)bytesThisTime != bytesRead)
                {
                    // something is wrong if these don't match here
                    result = PlankResult_FileReadError;
                    goto exit;
                }
                
                pl_IffFile_ChunkIDString ((PlankIffFileRef)p, &chunkInfos[i].chunkID, chunkIDStr);
                
                if ((result = pl_IffFileWriter_WriteChunk (&tempWriter,
                                                           PLANKIFFFILE_CURRENTCHUNKPOSITION, chunkIDStr,
                                                           copyBuffer, bytesThisTime,
                                                           PLANKIFFFILEWRITER_MODEAPPEND)) != PlankResult_OK) goto exit;
                
                copyChunkLengthRemain -= bytesThisTime;
            }
            
            // pad with zero for the larger size, no need to round to even bytes as pl_IffFileWriter_WriteChunk does this for us
            if (updatedChunkInfo->chunkLength > chunkInfos[i].chunkLength)
            {
                bytesThisTime = (int)(updatedChunkInfo->chunkLength - chunkInfos[i].chunkLength);
                
                pl_MemoryZero (copyBuffer, bytesThisTime);
                pl_IffFile_ChunkIDString ((PlankIffFileRef)p, &chunkInfos[i].chunkID, chunkIDStr);

                if ((result = pl_IffFileWriter_WriteChunk (&tempWriter,
                                                           PLANKIFFFILE_CURRENTCHUNKPOSITION, chunkIDStr,
                                                           copyBuffer, bytesThisTime,
                                                           PLANKIFFFILEWRITER_MODEAPPEND)) != PlankResult_OK) goto exit;
            }
        }
        
        // after copying a chunk need to copy chunk infos from the temp back to this file's infos        
        if ((result = pl_DynamicArray_GetItem (&tempWriter.chunkInfos, i, &chunkInfos[i])) != PlankResult_OK) goto exit;        
    }
    

    if (eraseOriginalFile)
    {
        if ((result = pl_File_Clear ((PlankFileRef)p)) != PlankResult_OK) goto exit;
    }
    else
    {
        if ((result = pl_File_ResetPosition ((PlankFileRef)p)) != PlankResult_OK) goto exit;
    }
    
    if ((result = pl_File_ResetPosition (pl_IffFileWriter_GetFile (&tempWriter))) != PlankResult_OK) goto exit;
    if ((result = pl_File_Copy ((PlankFileRef)p, pl_IffFileWriter_GetFile (&tempWriter), 0)) != PlankResult_OK) goto exit;
    
exit:
    pl_IffFileWriter_DeInit (&tempWriter);
    pl_FileErase (pl_Path_GetFullPath (&tempPath));
    
earlyExit:
    pl_Path_DeInit (&tempPath);

    return result;
}
Beispiel #21
0
void TextFileInternal::disownPeer (PlankFileRef otherFile) throw()
{
    pl_MemoryCopy (otherFile, getPeerRef(), sizeof (PlankFile));
    pl_MemoryZero (getPeerRef(), sizeof (PlankFile));
    pl_File_Init (getPeerRef());
}
Beispiel #22
0
PlankResult pl_IffFileWriter_ResizeChunk (PlankIffFileWriterRef p, const PlankLL startPosition, const char* chunkID, const PlankLL newLength, const PlankB concatenateJunk)
{
    PlankIffFileWriterChunkInfo updatedChunkInfo;
    PlankIffFileWriterChunkInfo newJunkChunkInfo;
    PlankIffFileWriterChunkInfo* thisChunkInfo;
    PlankIffFileWriterChunkInfo* nextChunkInfo;
    
    PlankLL chunkChange, alignedNewLength, position;
    PlankIffID nextChunkID;
    PlankB thisChunkIsLast, nextChunkIsLast;
    PlankResult result;
    int chunkHeaderLength;
    char chunkIDStr[64];
    
    result = PlankResult_OK;
    
    if ((result = pl_IffFileWriter_SeekChunk (p, startPosition, chunkID, &thisChunkInfo, &thisChunkIsLast)) != PlankResult_OK) goto exit;
    
    if (! thisChunkInfo)
    {
        result = PlankResult_IffFileReaderChunkNotFound;
        goto exit;
    }
    
    if (newLength == thisChunkInfo->chunkLength)
        goto exit; // nothing to do!
    
    alignedNewLength = pl_AlignLL (newLength, p->common.headerInfo.alignment);
    chunkChange = newLength - thisChunkInfo->chunkLength;
    
    if ((p->common.headerInfo.lengthSize == 4) && (chunkChange > 0x7fffffff))
    {
        // could support this but it is a highly suspicious request to reserve such a large space..
        result = PlankResult_UnknownError;
        goto exit;
    }
    
    chunkHeaderLength = p->common.headerInfo.lengthSize + pl_IffFile_ChunkIDLength ((PlankIffFileRef)p);
    
    if (thisChunkIsLast)
    {
        if (thisChunkIsLast && (chunkChange > 0))
        {
            // if it is getting larger then expand the chunk adding zeros to the end
            if ((result = pl_File_SetPosition ((PlankFileRef)p, thisChunkInfo->chunkPos + thisChunkInfo->chunkLength)) != PlankResult_OK) goto exit; // not including the original padding byte if present
            if ((result = pl_File_WriteZeros  ((PlankFileRef)p, (int)chunkChange + (int)(alignedNewLength - newLength))) != PlankResult_OK) goto exit; // add padding bytes based on the new length if needed
            if ((result = pl_File_SetPosition ((PlankFileRef)p, thisChunkInfo->chunkPos - p->common.headerInfo.lengthSize)) != PlankResult_OK) goto exit;
            if ((result = pl_IffFile_WriteChunkLength ((PlankIffFileRef)p, newLength)) != PlankResult_OK) goto exit;
            
            thisChunkInfo->chunkLength = newLength;
        }
        else // getting smaller
        {
            // flip the sign
            chunkChange = -chunkChange;
            
            // could put back more complex criteria based on alignment
            if (chunkChange >= chunkHeaderLength)
            {
                // if it is getting smaller, shrink it and add junk at the end
                if ((result = pl_File_SetPosition ((PlankFileRef)p, thisChunkInfo->chunkPos - p->common.headerInfo.lengthSize)) != PlankResult_OK) goto exit;
                if ((result = pl_IffFile_WriteChunkLength ((PlankIffFileRef)p, newLength)) != PlankResult_OK) goto exit;
                
                if (chunkChange > 1)  // keep in case we put back the more specific criteria..
                {
                    // need to add junk
                    newJunkChunkInfo.chunkID     = p->common.headerInfo.junkID;
                    newJunkChunkInfo.chunkPos    = thisChunkInfo->chunkPos + alignedNewLength + chunkHeaderLength;
                    newJunkChunkInfo.chunkLength = pl_AlignULL (chunkChange, p->common.headerInfo.alignment) - chunkHeaderLength;
                    
                    if ((p->common.headerInfo.lengthSize == 4) && (newJunkChunkInfo.chunkLength > 0xffffffff))
                    {
                        // need multiple junk chunks rather than one, unlikely to need to reserve this amount of free space
                        result = PlankResult_UnknownError;
                        goto exit;
                    }
                    
                    if ((result = pl_File_SetPosition ((PlankFileRef)p, newJunkChunkInfo.chunkPos - chunkHeaderLength)) != PlankResult_OK) goto exit;
                    if ((result = pl_IffFile_WriteChunkID ((PlankIffFileRef)p, &newJunkChunkInfo.chunkID)) != PlankResult_OK) goto exit;
                    if ((result = pl_IffFile_WriteChunkLength ((PlankIffFileRef)p, newJunkChunkInfo.chunkLength)) != PlankResult_OK) goto exit;
                    if ((result = pl_DynamicArray_AddItem (&p->chunkInfos, &newJunkChunkInfo)) != PlankResult_OK) goto exit;
                }
                
                thisChunkInfo->chunkLength = newLength;
            }
            else goto slowCopy;
        }
    }
    else
    {
        // we know this isn't the last chunk so see if the next chunk is junk
        position = thisChunkInfo->chunkPos + pl_AlignULL (thisChunkInfo->chunkLength, p->common.headerInfo.alignment);
        if ((result = pl_File_SetPosition ((PlankFileRef)p, position)) != PlankResult_OK) goto exit;
        if ((result = pl_IffFile_ReadChunkID ((PlankIffFileRef)p, &nextChunkID)) != PlankResult_OK) goto exit;
        
        pl_IffFile_ChunkIDString ((PlankIffFileRef)p, &nextChunkID, chunkIDStr);
        if ((result = pl_IffFileWriter_SeekChunk (p, position, chunkIDStr, &nextChunkInfo, &nextChunkIsLast)) != PlankResult_OK) goto exit;
        
        if (! nextChunkInfo)
        {
            // something really unexpected happened, we already checked there was another chunk following...
            result = PlankResult_UnknownError;
            goto exit;
        }
        
        if (concatenateJunk && pl_IffFile_EqualIDs ((PlankIffFileRef)p, &nextChunkInfo->chunkID, &p->common.headerInfo.junkID))
        {
            if (chunkChange > 0) // getting bigger
            {
                if ((chunkChange < p->common.headerInfo.alignment) && ((thisChunkInfo->chunkLength % p->common.headerInfo.alignment) != 0))
                {
                    // just change the length and leave the junk alone
                    if ((result = pl_File_SetPosition ((PlankFileRef)p, thisChunkInfo->chunkPos - p->common.headerInfo.lengthSize)) != PlankResult_OK) goto exit;
                    if ((result = pl_IffFile_WriteChunkLength ((PlankIffFileRef)p, newLength)) != PlankResult_OK) goto exit;
                    
                    thisChunkInfo->chunkLength =  newLength;
                }
                else if (chunkChange <= (nextChunkInfo->chunkLength + chunkHeaderLength))
                {                    
                    if (chunkChange > nextChunkInfo->chunkLength)
                    {
                        if (((chunkChange - nextChunkInfo->chunkLength) >= p->common.headerInfo.alignment) &&
                            ((chunkChange - nextChunkInfo->chunkLength) < chunkHeaderLength))
                        {
                            goto slowCopy; // incompatible length change
                        }
                        
                        // zero the junk header to avoid the file looking confusing during debugging
                        if ((result = pl_File_SetPosition ((PlankFileRef)p, nextChunkInfo->chunkPos - chunkHeaderLength)) != PlankResult_OK) goto exit;
                        if ((result = pl_File_WriteZeros  ((PlankFileRef)p, chunkHeaderLength)) != PlankResult_OK) goto exit;
                        
                        // expand this chunk
                        if ((result = pl_File_SetPosition ((PlankFileRef)p, thisChunkInfo->chunkPos - p->common.headerInfo.lengthSize)) != PlankResult_OK) goto exit;
                        if ((result = pl_IffFile_WriteChunkLength ((PlankIffFileRef)p, newLength)) != PlankResult_OK) goto exit;
                        
                        thisChunkInfo->chunkLength =  newLength;
                        
                        // null the junk chunk reference
                        pl_MemoryZero (&nextChunkInfo->chunkID, sizeof (PlankIffID));
                    }
                    else
                    {
                        // zero the junk header to avoid the file looking confusing during debugging
                        if ((result = pl_File_SetPosition ((PlankFileRef)p, nextChunkInfo->chunkPos - chunkHeaderLength)) != PlankResult_OK) goto exit;
                        if ((result = pl_File_WriteZeros  ((PlankFileRef)p, chunkHeaderLength)) != PlankResult_OK) goto exit;
                        
                        // expand this chunk
                        if ((result = pl_File_SetPosition ((PlankFileRef)p, thisChunkInfo->chunkPos - p->common.headerInfo.lengthSize)) != PlankResult_OK) goto exit;
                        if ((result = pl_IffFile_WriteChunkLength ((PlankIffFileRef)p, newLength)) != PlankResult_OK) goto exit;
                        
                        thisChunkInfo->chunkLength =  newLength;

                        //..and shrink the junk
                        nextChunkInfo->chunkPos    =  thisChunkInfo->chunkPos + pl_AlignULL (thisChunkInfo->chunkLength, p->common.headerInfo.alignment) + chunkHeaderLength;
                        nextChunkInfo->chunkLength -= chunkChange;
                        
                        if ((result = pl_File_SetPosition  ((PlankFileRef)p, nextChunkInfo->chunkPos - chunkHeaderLength)) != PlankResult_OK) goto exit;
                        if ((result = pl_IffFile_WriteChunkID ((PlankIffFileRef)p, &nextChunkInfo->chunkID)) != PlankResult_OK) goto exit;
                        if ((result = pl_IffFile_WriteChunkLength ((PlankIffFileRef)p, nextChunkInfo->chunkLength)) != PlankResult_OK) goto exit;
                    }
                }
                else
                {
                    // recursively concatenate junk chunks as far as we can...
                    alignedNewLength = thisChunkInfo->chunkLength + pl_AlignLL (nextChunkInfo->chunkLength, p->common.headerInfo.alignment) + chunkHeaderLength;
                    if ((result = pl_IffFileWriter_ResizeChunk (p, startPosition, chunkID, alignedNewLength, PLANK_TRUE)) != PlankResult_OK) goto exit;
                    if ((result = pl_IffFileWriter_ResizeChunk (p, startPosition, chunkID, newLength, PLANK_TRUE)) != PlankResult_OK) goto exit;
                }
            }
            else // getting smaller
            {
                // flip the sign
                chunkChange = -chunkChange;
                
                // zero the junk header to avoid the file looking confusing during debugging
                if ((result = pl_File_SetPosition ((PlankFileRef)p, nextChunkInfo->chunkPos - chunkHeaderLength)) != PlankResult_OK) goto exit;
                if ((result = pl_File_WriteZeros  ((PlankFileRef)p, chunkHeaderLength)) != PlankResult_OK) goto exit;
                
                // resize this chunk
                if ((result = pl_File_SetPosition ((PlankFileRef)p, thisChunkInfo->chunkPos - p->common.headerInfo.lengthSize)) != PlankResult_OK) goto exit;
                if ((result = pl_IffFile_WriteChunkLength ((PlankIffFileRef)p, newLength)) != PlankResult_OK) goto exit;
                
                thisChunkInfo->chunkLength =  newLength;
                
                // move and resize junk
                nextChunkInfo->chunkPos    =  thisChunkInfo->chunkPos + pl_AlignULL (thisChunkInfo->chunkLength, p->common.headerInfo.alignment) + chunkHeaderLength;
                nextChunkInfo->chunkLength += chunkChange;
                
                if ((p->common.headerInfo.lengthSize == 4) && (nextChunkInfo->chunkLength > 0xffffffff))
                {
                    // need multiple junk chunks rather than one, unlikely to need to reserve this amount of free space
                    result = PlankResult_UnknownError;
                    goto exit;
                }
                
                if ((result = pl_File_SetPosition ((PlankFileRef)p, nextChunkInfo->chunkPos - chunkHeaderLength)) != PlankResult_OK) goto exit;
                if ((result = pl_IffFile_WriteChunkID ((PlankIffFileRef)p, &nextChunkInfo->chunkID)) != PlankResult_OK) goto exit;
                if ((result = pl_IffFile_WriteChunkLength ((PlankIffFileRef)p, nextChunkInfo->chunkLength)) != PlankResult_OK) goto exit;
            }
        }
        else if ((chunkChange > 0) && (chunkChange < p->common.headerInfo.alignment) && ((thisChunkInfo->chunkLength % p->common.headerInfo.alignment) != 0))
        {
            // just change the chunk length
            if ((result = pl_File_SetPosition ((PlankFileRef)p, thisChunkInfo->chunkPos - p->common.headerInfo.lengthSize)) != PlankResult_OK) goto exit;
            if ((result = pl_IffFile_WriteChunkLength ((PlankIffFileRef)p, newLength)) != PlankResult_OK) goto exit;
            
            thisChunkInfo->chunkLength = newLength;
        }
        else if (chunkChange < 0)
        {
            chunkChange = -chunkChange;
            
            if (chunkChange >= chunkHeaderLength)
            {
                // if it is getting smaller, shrink it and add junk at the end
                if ((result = pl_File_SetPosition ((PlankFileRef)p, thisChunkInfo->chunkPos - p->common.headerInfo.lengthSize)) != PlankResult_OK) goto exit;
                if ((result = pl_IffFile_WriteChunkLength ((PlankIffFileRef)p, newLength)) != PlankResult_OK) goto exit;
                
                if (chunkChange > 1) // keep in case we put back the more specific criteria..
                {
                    // need to add junk
                    newJunkChunkInfo.chunkID     = p->common.headerInfo.junkID;
                    newJunkChunkInfo.chunkPos    = thisChunkInfo->chunkPos + alignedNewLength + chunkHeaderLength;
                    newJunkChunkInfo.chunkLength = pl_AlignULL (chunkChange, p->common.headerInfo.alignment) - chunkHeaderLength;
                    
                    if ((p->common.headerInfo.lengthSize == 4) && (newJunkChunkInfo.chunkLength > 0xffffffff))
                    {
                        // need multiple junk chunks rather than one, unlikely to need to reserve this amount of free space
                        result = PlankResult_UnknownError;
                        goto exit;
                    }
                    
                    if ((result = pl_File_SetPosition ((PlankFileRef)p, newJunkChunkInfo.chunkPos - chunkHeaderLength)) != PlankResult_OK) goto exit;
                    if ((result = pl_IffFile_WriteChunkID ((PlankIffFileRef)p, &newJunkChunkInfo.chunkID)) != PlankResult_OK) goto exit;
                    if ((result = pl_IffFile_WriteChunkLength ((PlankIffFileRef)p, newJunkChunkInfo.chunkLength)) != PlankResult_OK) goto exit;
                    if ((result = pl_DynamicArray_AddItem (&p->chunkInfos, &newJunkChunkInfo)) != PlankResult_OK) goto exit;
                }
                
                thisChunkInfo->chunkLength = newLength;
            }
            else goto slowCopy;
        }
        else
        {
        slowCopy:
            // we're going to have to do a slow rewrite..
            updatedChunkInfo.chunkID     = thisChunkInfo->chunkID;
            updatedChunkInfo.chunkLength = newLength;
            updatedChunkInfo.chunkPos    = thisChunkInfo->chunkPos;
            
            if ((result = pl_IffFileWriter_RewriteFileUpdatingChunkInfo (p, &updatedChunkInfo)) != PlankResult_OK) goto exit;
        }
    }
    
    // seek back to the position of the chunk's data
    if ((result = pl_File_SetPosition ((PlankFileRef)p, thisChunkInfo->chunkPos)) != PlankResult_OK) goto exit;
    
    p->currentChunk = thisChunkInfo;
    
exit:
    return result;
}