| /*****************************************************************************/ |
| // Copyright 2006-2007 Adobe Systems Incorporated |
| // All Rights Reserved. |
| // |
| // NOTICE: Adobe permits you to use, modify, and distribute this file in |
| // accordance with the terms of the Adobe license agreement accompanying it. |
| /*****************************************************************************/ |
| |
| /* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_memory_stream.cpp#1 $ */ |
| /* $DateTime: 2012/05/30 13:28:51 $ */ |
| /* $Change: 832332 $ */ |
| /* $Author: tknoll $ */ |
| |
| /*****************************************************************************/ |
| |
| #include "dng_memory_stream.h" |
| |
| #include "dng_bottlenecks.h" |
| #include "dng_exceptions.h" |
| #include "dng_safe_arithmetic.h" |
| #include "dng_utils.h" |
| |
| /*****************************************************************************/ |
| |
| dng_memory_stream::dng_memory_stream (dng_memory_allocator &allocator, |
| dng_abort_sniffer *sniffer, |
| uint32 pageSize) |
| |
| : dng_stream (sniffer, |
| kDefaultBufferSize, |
| kDNGStreamInvalidOffset) |
| |
| , fAllocator (allocator) |
| , fPageSize (pageSize ) |
| |
| , fPageCount (0) |
| , fPagesAllocated (0) |
| , fPageList (NULL) |
| |
| , fMemoryStreamLength (0) |
| |
| { |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_memory_stream::~dng_memory_stream () |
| { |
| |
| if (fPageList) |
| { |
| |
| for (uint32 index = 0; index < fPageCount; index++) |
| { |
| |
| delete fPageList [index]; |
| |
| } |
| |
| free (fPageList); |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| uint64 dng_memory_stream::DoGetLength () |
| { |
| |
| return fMemoryStreamLength; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_memory_stream::DoRead (void *data, |
| uint32 count, |
| uint64 offset) |
| { |
| |
| if (offset + count > fMemoryStreamLength) |
| { |
| |
| ThrowEndOfFile (); |
| |
| } |
| |
| uint64 baseOffset = offset; |
| |
| while (count) |
| { |
| |
| uint32 pageIndex = (uint32) (offset / fPageSize); |
| uint32 pageOffset = (uint32) (offset % fPageSize); |
| |
| uint32 blockCount = Min_uint32 (fPageSize - pageOffset, count); |
| |
| const uint8 *sPtr = fPageList [pageIndex]->Buffer_uint8 () + |
| pageOffset; |
| |
| uint8 *dPtr = ((uint8 *) data) + (uint32) (offset - baseOffset); |
| |
| DoCopyBytes (sPtr, dPtr, blockCount); |
| |
| offset += blockCount; |
| count -= blockCount; |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_memory_stream::DoSetLength (uint64 length) |
| { |
| |
| while (length > fPageCount * (uint64) fPageSize) |
| { |
| |
| if (fPageCount == fPagesAllocated) |
| { |
| |
| uint32 newSizeTemp1 = 0, newSizeTemp2 = 0; |
| if (!SafeUint32Add (fPagesAllocated, 32u, &newSizeTemp1) || |
| !SafeUint32Mult (fPagesAllocated, 2u, &newSizeTemp2)) |
| { |
| ThrowMemoryFull ("Arithmetic overflow in DoSetLength()"); |
| } |
| uint32 newSize = Max_uint32 (newSizeTemp1, newSizeTemp2); |
| uint32 numBytes; |
| if (!SafeUint32Mult (newSize, sizeof (dng_memory_block *), |
| &numBytes)) |
| { |
| ThrowMemoryFull ("Arithmetic overflow in DoSetLength()"); |
| } |
| |
| dng_memory_block **list = (dng_memory_block **) malloc (numBytes); |
| |
| if (!list) |
| { |
| |
| ThrowMemoryFull (); |
| |
| } |
| |
| if (fPageCount) |
| { |
| |
| // The multiplication here is safe against overflow. fPageCount |
| // can never reach a value that is large enough to cause |
| // overflow because the computation of numBytes above would fail |
| // before a list of that size could be allocated. |
| DoCopyBytes (fPageList, |
| list, |
| fPageCount * (uint32) sizeof (dng_memory_block *)); |
| |
| } |
| |
| if (fPageList) |
| { |
| |
| free (fPageList); |
| |
| } |
| |
| fPageList = list; |
| |
| fPagesAllocated = newSize; |
| |
| } |
| |
| fPageList [fPageCount] = fAllocator.Allocate (fPageSize); |
| |
| fPageCount++; |
| |
| } |
| |
| fMemoryStreamLength = length; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_memory_stream::DoWrite (const void *data, |
| uint32 count, |
| uint64 offset) |
| { |
| |
| DoSetLength (Max_uint64 (fMemoryStreamLength, |
| offset + count)); |
| |
| uint64 baseOffset = offset; |
| |
| while (count) |
| { |
| |
| uint32 pageIndex = (uint32) (offset / fPageSize); |
| uint32 pageOffset = (uint32) (offset % fPageSize); |
| |
| uint32 blockCount = Min_uint32 (fPageSize - pageOffset, count); |
| |
| const uint8 *sPtr = ((const uint8 *) data) + (uint32) (offset - baseOffset); |
| |
| uint8 *dPtr = fPageList [pageIndex]->Buffer_uint8 () + |
| pageOffset; |
| |
| DoCopyBytes (sPtr, dPtr, blockCount); |
| |
| offset += blockCount; |
| count -= blockCount; |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_memory_stream::CopyToStream (dng_stream &dstStream, |
| uint64 count) |
| { |
| |
| if (count < kBigBufferSize) |
| { |
| |
| dng_stream::CopyToStream (dstStream, count); |
| |
| } |
| |
| else |
| { |
| |
| Flush (); |
| |
| uint64 offset = Position (); |
| |
| if (offset + count > Length ()) |
| { |
| |
| ThrowEndOfFile (); |
| |
| } |
| |
| while (count) |
| { |
| |
| uint32 pageIndex = (uint32) (offset / fPageSize); |
| uint32 pageOffset = (uint32) (offset % fPageSize); |
| |
| uint32 blockCount = (uint32) Min_uint64 (fPageSize - pageOffset, count); |
| |
| const uint8 *sPtr = fPageList [pageIndex]->Buffer_uint8 () + |
| pageOffset; |
| |
| dstStream.Put (sPtr, blockCount); |
| |
| offset += blockCount; |
| count -= blockCount; |
| |
| } |
| |
| SetReadPosition (offset); |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |