/*****************************************************************************/
// 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);
}
}
/*****************************************************************************/