/*****************************************************************************/
// 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_stream.h#2 $ */
/* $DateTime: 2012/06/01 07:28:57 $ */
/* $Change: 832715 $ */
/* $Author: tknoll $ */
/** Data stream abstraction for serializing and deserializing sequences of
* basic types and RAW image data.
*/
/*****************************************************************************/
#ifndef __dng_stream__
#define __dng_stream__
/*****************************************************************************/
#include "dng_classes.h"
#include "dng_types.h"
#include "dng_memory.h"
#include "dng_rational.h"
#include "dng_utils.h"
/*****************************************************************************/
// Constants for invalid offset in streams.
const uint64 kDNGStreamInvalidOffset = (uint64) (int64) -1;
/*****************************************************************************/
/// Base stream abstraction. Has support for going between stream and pointer
/// abstraction.
class dng_stream
{
public:
enum
{
kSmallBufferSize = 4 * 1024,
kBigBufferSize = 64 * 1024,
kDefaultBufferSize = kSmallBufferSize
};
private:
bool fSwapBytes;
bool fHaveLength;
uint64 fLength;
const uint64 fOffsetInOriginalFile;
uint64 fPosition;
dng_memory_data fMemBlock;
uint8 *fBuffer;
uint32 fBufferSize;
uint64 fBufferStart;
uint64 fBufferEnd;
uint64 fBufferLimit;
bool fBufferDirty;
dng_abort_sniffer *fSniffer;
protected:
dng_stream (dng_abort_sniffer *sniffer = NULL,
uint32 bufferSize = kDefaultBufferSize,
uint64 offsetInOriginalFile = kDNGStreamInvalidOffset);
virtual uint64 DoGetLength ();
virtual void DoRead (void *data,
uint32 count,
uint64 offset);
virtual void DoSetLength (uint64 length);
virtual void DoWrite (const void *data,
uint32 count,
uint64 offset);
public:
/// Construct a stream with initial data.
/// \param data Pointer to initial contents of stream.
/// \param count Number of bytes data is valid for.
/// \param offsetInOriginalFile If data came from a file originally,
/// offset can be saved here for later use.
dng_stream (const void *data,
uint32 count,
uint64 offsetInOriginalFile = kDNGStreamInvalidOffset);
virtual ~dng_stream ();
/// Getter for whether stream is swapping byte order on input/output.
/// \retval If true, data will be swapped on input/output.
bool SwapBytes () const
{
return fSwapBytes;
}
/// Setter for whether stream is swapping byte order on input/output.
/// \param swapBytes If true, stream will swap byte order on input or
/// output for future reads/writes.
void SetSwapBytes (bool swapBytes)
{
fSwapBytes = swapBytes;
}
/// Getter for whether data in stream is big endian.
/// \retval If true, data in stream is big endian.
bool BigEndian () const;
/// Setter for whether data in stream is big endian.
/// \param bigEndian If true, data in stream is big endian.
void SetBigEndian (bool bigEndian = true);
/// Getter for whether data in stream is big endian.
/// \retval If true, data in stream is big endian.
bool LittleEndian () const
{
return !BigEndian ();
}
/// Setter for whether data in stream is big endian.
/// \param littleEndian If true, data in stream is big endian.
void SetLittleEndian (bool littleEndian = true)
{
SetBigEndian (!littleEndian);
}
/// Returns the size of the buffer used by the stream.
uint32 BufferSize () const
{
return fBufferSize;
}
/// Getter for length of data in stream.
/// \retval Length of readable data in stream.
uint64 Length ()
{
if (!fHaveLength)
{
fLength = DoGetLength ();
fHaveLength = true;
}
return fLength;
}
/// Getter for current offset in stream.
/// \retval current offset from start of stream.
uint64 Position () const
{
return fPosition;
}
/// Getter for current position in original file, taking into account
/// OffsetInOriginalFile stream data was taken from.
/// \retval kInvalidOffset if no offset in original file is set, sum
/// of offset in original file and current position otherwise.
uint64 PositionInOriginalFile () const;
/// Getter for offset in original file.
/// \retval kInvalidOffset if no offset in original file is set,
/// offset in original file otherwise.
uint64 OffsetInOriginalFile () const;
/// Return pointer to stream contents if the stream is entirely
/// available as a single memory block, NULL otherwise.
const void * Data () const;
/// Return the entire stream as a single memory block.
/// This works for all streams, but requires copying the data to a new buffer.
/// \param allocator Allocator used to allocate memory.
dng_memory_block * AsMemoryBlock (dng_memory_allocator &allocator);
/// Seek to a new position in stream for reading.
void SetReadPosition (uint64 offset);
/// Skip forward in stream.
/// \param delta Number of bytes to skip forward.
void Skip (uint64 delta)
{
SetReadPosition (Position () + delta);
}
/// Get data from stream. Exception is thrown and no data is read if
/// insufficient data available in stream.
/// \param data Buffer to put data into. Must be valid for count bytes.
/// \param count Bytes of data to read.
/// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
/// if not enough data in stream.
void Get (void *data, uint32 count);
/// Seek to a new position in stream for writing.
void SetWritePosition (uint64 offset);
/// Force any stored data in stream to be written to underlying storage.
void Flush ();
/// Set length of available data.
/// \param length Number of bytes of avialble data in stream.
void SetLength (uint64 length);
/// Write data to stream.
/// \param data Buffer of data to write to stream.
/// \param count Bytes of in data.
void Put (const void *data, uint32 count);
/// Get an unsigned 8-bit integer from stream and advance read position.
/// \retval One unsigned 8-bit integer.
/// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
/// if not enough data in stream.
uint8 Get_uint8 ()
{
// Fast check to see if in buffer
if (fPosition >= fBufferStart && fPosition < fBufferEnd)
{
return fBuffer [fPosition++ - fBufferStart];
}
// Not in buffer, let main routine do the work.
uint8 x;
Get (&x, 1);
return x;
}
/// Put an unsigned 8-bit integer to stream and advance write position.
/// \param x One unsigned 8-bit integer.
void Put_uint8 (uint8 x)
{
if (fBufferDirty &&
fPosition >= fBufferStart &&
fPosition <= fBufferEnd &&
fPosition < fBufferLimit)
{
fBuffer [fPosition - fBufferStart] = x;
fPosition++;
if (fBufferEnd < fPosition)
fBufferEnd = fPosition;
fLength = Max_uint64 (Length (), fPosition);
}
else
{
Put (&x, 1);
}
}
/// Get an unsigned 16-bit integer from stream and advance read position.
/// Byte swap if byte swapping is turned on.
/// \retval One unsigned 16-bit integer.
/// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
/// if not enough data in stream.
uint16 Get_uint16 ();
/// Put an unsigned 16-bit integer to stream and advance write position.
/// Byte swap if byte swapping is turned on.
/// \param x One unsigned 16-bit integer.
void Put_uint16 (uint16 x);
/// Get an unsigned 32-bit integer from stream and advance read position.
/// Byte swap if byte swapping is turned on.
/// \retval One unsigned 32-bit integer.
/// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
/// if not enough data in stream.
uint32 Get_uint32 ();
/// Put an unsigned 32-bit integer to stream and advance write position.
/// Byte swap if byte swapping is turned on.
/// \param x One unsigned 32-bit integer.
void Put_uint32 (uint32 x);
/// Get an unsigned 64-bit integer from stream and advance read position.
/// Byte swap if byte swapping is turned on.
/// \retval One unsigned 64-bit integer.
/// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
/// if not enough data in stream.
uint64 Get_uint64 ();
/// Put an unsigned 64-bit integer to stream and advance write position.
/// Byte swap if byte swapping is turned on.
/// \param x One unsigned 64-bit integer.
void Put_uint64 (uint64 x);
/// Get one 8-bit integer from stream and advance read position.
/// \retval One 8-bit integer.
/// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
/// if not enough data in stream.
int8 Get_int8 ()
{
return (int8) Get_uint8 ();
}
/// Put one 8-bit integer to stream and advance write position.
/// \param x One 8-bit integer.
void Put_int8 (int8 x)
{
Put_uint8 ((uint8) x);
}
/// Get one 16-bit integer from stream and advance read position.
/// Byte swap if byte swapping is turned on.
/// \retval One 16-bit integer.
/// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
/// if not enough data in stream.
int16 Get_int16 ()
{
return (int16) Get_uint16 ();
}
/// Put one 16-bit integer to stream and advance write position.
/// Byte swap if byte swapping is turned on.
/// \param x One 16-bit integer.
void Put_int16 (int16 x)
{
Put_uint16 ((uint16) x);
}
/// Get one 32-bit integer from stream and advance read position.
/// Byte swap if byte swapping is turned on.
/// \retval One 32-bit integer.
/// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
/// if not enough data in stream.
int32 Get_int32 ()
{
return (int32) Get_uint32 ();
}
/// Put one 32-bit integer to stream and advance write position.
/// Byte swap if byte swapping is turned on.
/// \param x One 32-bit integer.
void Put_int32 (int32 x)
{
Put_uint32 ((uint32) x);
}
/// Get one 64-bit integer from stream and advance read position.
/// Byte swap if byte swapping is turned on.
/// \retval One 64-bit integer.
/// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
/// if not enough data in stream.
int64 Get_int64 ()
{
return (int64) Get_uint64 ();
}
/// Put one 64-bit integer to stream and advance write position.
/// Byte swap if byte swapping is turned on.
/// \param x One 64-bit integer.
void Put_int64 (int64 x)
{
Put_uint64 ((uint64) x);
}
/// Get one 32-bit IEEE floating-point number from stream and advance
/// read position. Byte swap if byte swapping is turned on.
/// \retval One 32-bit IEEE floating-point number.
/// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
/// if not enough data in stream.
real32 Get_real32 ();
/// Put one 32-bit IEEE floating-point number to stream and advance write
/// position. Byte swap if byte swapping is turned on.
/// \param x One 32-bit IEEE floating-point number.
void Put_real32 (real32 x);
/// Get one 64-bit IEEE floating-point number from stream and advance
/// read position. Byte swap if byte swapping is turned on.
/// \retval One 64-bit IEEE floating-point number .
/// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
/// if not enough data in stream.
real64 Get_real64 ();
/// Put one 64-bit IEEE floating-point number to stream and advance write
/// position. Byte swap if byte swapping is turned on.
/// \param x One64-bit IEEE floating-point number.
void Put_real64 (real64 x);
/// Get an 8-bit character string from stream and advance read position.
/// Routine always reads until a NUL character (8-bits of zero) is read.
/// (That is, only maxLength bytes will be returned in buffer, but the
/// stream is always advanced until a NUL is read or EOF is reached.)
/// \param data Buffer in which string is returned.
/// \param maxLength Maximum number of bytes to place in buffer.
/// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
/// if stream runs out before NUL is seen.
void Get_CString (char *data,
uint32 maxLength);
/// Get a 16-bit character string from stream and advance read position.
/// 16-bit characters are truncated to 8-bits.
/// Routine always reads until a NUL character (16-bits of zero) is read.
/// (That is, only maxLength bytes will be returned in buffer, but the
/// stream is always advanced until a NUL is read or EOF is reached.)
/// \param data Buffer to place string in.
/// \param maxLength Maximum number of bytes to place in buffer.
/// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
/// if stream runs out before NUL is seen.
void Get_UString (char *data,
uint32 maxLength);
/// Writes the specified number of zero bytes to stream.
/// \param count Number of zero bytes to write.
void PutZeros (uint64 count);
/// Writes zeros to align the stream position to a multiple of 2.
void PadAlign2 ();
/// Writes zeros to align the stream position to a multiple of 4.
void PadAlign4 ();
/// Get a value of size indicated by tag type from stream and advance
/// read position. Byte swap if byte swapping is turned on and tag type
/// is larger than a byte. Value is returned as an unsigned 32-bit integer.
/// \param tagType Tag type of data stored in stream.
/// \retval One unsigned 32-bit integer.
/// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
/// if not enough data in stream.
uint32 TagValue_uint32 (uint32 tagType);
/// Get a value of size indicated by tag type from stream and advance read
/// position. Byte swap if byte swapping is turned on and tag type is larger
/// than a byte. Value is returned as a 32-bit integer.
/// \param tagType Tag type of data stored in stream.
/// \retval One 32-bit integer.
/// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
/// if not enough data in stream.
int32 TagValue_int32 (uint32 tagType);
/// Get a value of size indicated by tag type from stream and advance read
/// position. Byte swap if byte swapping is turned on and tag type is larger
/// than a byte. Value is returned as a dng_urational.
/// \param tagType Tag type of data stored in stream.
/// \retval One dng_urational.
/// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
/// if not enough data in stream.
dng_urational TagValue_urational (uint32 tagType);
/// Get a value of size indicated by tag type from stream and advance read
/// position. Byte swap if byte swapping is turned on and tag type is larger
/// than a byte. Value is returned as a dng_srational.
/// \param tagType Tag type of data stored in stream.
/// \retval One dng_srational.
/// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
/// if not enough data in stream.
dng_srational TagValue_srational (uint32 tagType);
/// Get a value of size indicated by tag type from stream and advance read
/// position. Byte swap if byte swapping is turned on and tag type is larger
/// than a byte. Value is returned as a 64-bit IEEE floating-point number.
/// \param tagType Tag type of data stored in stream.
/// \retval One 64-bit IEEE floating-point number.
/// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
/// if not enough data in stream.
real64 TagValue_real64 (uint32 tagType);
/// Getter for sniffer associated with stream.
/// \retval The sniffer for this stream.
dng_abort_sniffer * Sniffer () const
{
return fSniffer;
}
/// Putter for sniffer associated with stream.
/// \param sniffer The new sniffer to use (or NULL for none).
void SetSniffer (dng_abort_sniffer *sniffer)
{
fSniffer = sniffer;
}
/// Copy a specified number of bytes to a target stream.
/// \param dstStream The target stream.
/// \param count The number of bytes to copy.
virtual void CopyToStream (dng_stream &dstStream,
uint64 count);
/// Makes the target stream a copy of this stream.
/// \param dstStream The target stream.
void DuplicateStream (dng_stream &dstStream);
private:
// Hidden copy constructor and assignment operator.
dng_stream (const dng_stream &stream);
dng_stream & operator= (const dng_stream &stream);
};
/*****************************************************************************/
class TempBigEndian
{
private:
dng_stream & fStream;
bool fOldSwap;
public:
TempBigEndian (dng_stream &stream,
bool bigEndian = true);
virtual ~TempBigEndian ();
};
/*****************************************************************************/
class TempLittleEndian: public TempBigEndian
{
public:
TempLittleEndian (dng_stream &stream,
bool littleEndian = true)
: TempBigEndian (stream, !littleEndian)
{
}
virtual ~TempLittleEndian ()
{
}
};
/*****************************************************************************/
class TempStreamSniffer
{
private:
dng_stream & fStream;
dng_abort_sniffer *fOldSniffer;
public:
TempStreamSniffer (dng_stream &stream,
dng_abort_sniffer *sniffer);
virtual ~TempStreamSniffer ();
private:
// Hidden copy constructor and assignment operator.
TempStreamSniffer (const TempStreamSniffer &temp);
TempStreamSniffer & operator= (const TempStreamSniffer &temp);
};
/*****************************************************************************/
class PreserveStreamReadPosition
{
private:
dng_stream & fStream;
uint64 fPosition;
public:
PreserveStreamReadPosition (dng_stream &stream)
: fStream (stream)
, fPosition (stream.Position ())
{
}
~PreserveStreamReadPosition ()
{
fStream.SetReadPosition (fPosition);
}
private:
// Hidden copy constructor and assignment operator.
PreserveStreamReadPosition (const PreserveStreamReadPosition &rhs);
PreserveStreamReadPosition & operator= (const PreserveStreamReadPosition &rhs);
};
/*****************************************************************************/
#endif
/*****************************************************************************/