home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-09-17 | 22.1 KB | 669 lines | [TEXT/MPS ] |
- //========================================================================================
- //
- // File: SLBufSin.cpp
- // Release Version: $ ODF 2 $
- //
- // Copyright: (c) 1993 - 1996 by Apple Computer, Inc., all rights reserved.
- //
- //========================================================================================
-
- #include "FWFound.hpp"
-
- #include <Limits.h>
-
- #ifndef FWEXCDEF_H
- #include "FWExcDef.h"
- #endif
-
- #ifndef FWPRIDEB_H
- #include "FWPriDeb.h"
- #endif
-
- #ifndef SLSTRMRW_H
- #include "SLStrmRW.h"
- #endif
-
- #ifdef FW_BUILD_MAC
- #pragma segment FWStream
- #endif
-
-
- /*
- * This file was generated by the SOM Compiler.
- * Generated using:
- * SOM Emitter emitxtm.dll: 2.33
- */
-
- #define VARIABLE_MACROS
- #define FW_OBufferedSink_Class_Source
- #include "SLBufSin.xih"
-
- // [KVV] Work around a Visual C++ 4.0 bug. FW_Minimum is a C++ template function
- // and can't be used inside of SOMLINK (extern "C") functions.
-
- inline long FW_Minimum(long a, long b)
- { return a < b ? a : b; }
-
- //========================================================================================
- // class FW_CPrivSinkBuffer
- //
- // This class implements a buffer for use with FW_OSinks, especially FW_CStorageUnitSinks.
- // Each call to FW_CStorageUnitSink::Read() results in the creation and destruction of an
- // intermediate FW_CByteArray. To eliminate some of the expense associated with that
- // operation, ReadPeek() and WritePeek() methods of FW_CStorageUnitSink use this class
- // to allow the buffering of data being read and/or written to/from a storage unit.
- //
- // Note that none of the methods of this class actually do any reading or writing.
- // The FW_OSink instance must obtain a pointer to the buffer in memory and fill it
- // with data. This class is responsible only for maintaining the buffer and data
- // pertaining directly to it.
- //
- // The "initialPosition" is the offset within the storage unit of the start of the
- // buffer. To write the bufffer, seek to GetInitialPosition() and write from GetAddress()
- // for GetBytesWritten() bytes. To read, get the current position and pass it as the
- // 'initialPosition' argument to Initialize(). When items are read using ReadPeek()
- // and ReadPeekAdvance(), do a su->GetPosition() and pass that as the first argument
- // to ReakPeek().
- //
- // Physically, the class *is* an FW_OBufferedSinkData. Consequently, we can safely cast
- // from an FW_OBufferedSinkData* to an FW_CPrivSinkBuffer*.
- //
- //========================================================================================
-
- class FW_CPrivSinkBuffer : public FW_OBufferedSinkData
- {
- public:
- enum EBufferKind {
- kInvalid,
- kReadPeek,
- kWritePeek
- };
-
- enum {
- kInvalidPosition = 0xDEADBABE
- };
-
- // ----- Constructors, destructor, operators -----
-
- void Construct(FW_ORandomAccessSink* aSink, long fCapacity);
- void Destruct();
-
- // ----- Getters & setters -----
-
- char* GetAddress() const;
- long GetCapacity() const;
- long GetInitialPosition() const;
- long GetBytesWritten() const;
- FW_Boolean IsDirty() const;
- FW_Boolean IsValid() const;
-
- // ----- Buffer-management routines -----
-
- void Initialize(EBufferKind kind, long initialPosition, long validBytes);
- // Initializes the type and validity of the buffer.
-
- void Invalidate();
- // Marks the buffer as containing invalid data. The buffer must
- // be re-initialized before the next ReadPeek or WritePeek.
-
- void* ReadPeek(Environment* ev, long& availableReadBytes);
- // Returns a pointer to the data in the buffer starting at currentPosition.
- // availableReadBytes returns the number of valid bytes in the buffer
- // returned.
-
- void ReadPeekAdvance(Environment* ev, long bytesRead);
- // Advances the ReadPeek buffer to indicate that the user has read the
- // number of bytes specified by bytesRead.
- // This routine should be called after the user uses the data from the buffer.
- // Otherwise, the same bytes will be returned by the next ReadPeek.
-
- void* WritePeek(Environment* ev, long& availableWriteBytes);
- // Returns a pointer to the buffer starting at currentPosition. The
- // number of bytes available for writing is returned in availableWriteBytes.
-
- void WritePeekAdvance(Environment* ev, long bytesWritten);
- // Advances the WritePeek buffer to indicate that the user has written the
- // number of bytes specified by bytesWritten starting at currentPosition.
- // This routine should be alled after the user writes the data. Otherwise,
- // the data could be overwritten by future writes.
-
- void FlushAndInvalidate(Environment* ev);
- // If the buffer is "dirty", it needs to be written to disk.
-
- private:
-
- FW_CPrivSinkBuffer(){}
- ~FW_CPrivSinkBuffer(){}
-
- FW_CPrivSinkBuffer(const FW_CPrivSinkBuffer& otherBuffer);
- FW_CPrivSinkBuffer& operator=(const FW_CPrivSinkBuffer&);
- };
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivSinkBuffer::GetAddress
- //----------------------------------------------------------------------------------------
-
- inline char* FW_CPrivSinkBuffer::GetAddress() const
- {
- return fBuffer;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivSinkBuffer::GetCapacity
- //----------------------------------------------------------------------------------------
-
- inline long FW_CPrivSinkBuffer::GetCapacity() const
- {
- return fCapacity;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivSinkBuffer::GetBytesWritten
- //----------------------------------------------------------------------------------------
-
- inline long FW_CPrivSinkBuffer::GetBytesWritten() const
- {
- return fBytesWritten;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivSinkBuffer::GetInitialPosition
- //----------------------------------------------------------------------------------------
-
- inline long FW_CPrivSinkBuffer::GetInitialPosition() const
- {
- return fInitialPosition;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivSinkBuffer::IsDirty
- //----------------------------------------------------------------------------------------
-
- inline FW_Boolean FW_CPrivSinkBuffer::IsDirty() const
- {
- return fType == kWritePeek && GetBytesWritten() != 0;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivSinkBuffer::IsValid
- //----------------------------------------------------------------------------------------
-
- inline FW_Boolean FW_CPrivSinkBuffer::IsValid() const
- {
- return fType != kInvalid && fInitialPosition != kInvalidPosition;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivSinkBuffer::Invalidate
- //----------------------------------------------------------------------------------------
-
- inline void FW_CPrivSinkBuffer::Invalidate()
- {
- Initialize(kInvalid, kInvalidPosition, 0);
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivSinkBuffer::Construct
- //
- // This constructor just initializes some fields--no memory is actually allocated
- // for the buffer until Initialize() is called.
- //----------------------------------------------------------------------------------------
-
- void FW_CPrivSinkBuffer::Construct(FW_ORandomAccessSink* aSink, long capacity)
- {
- fWrappedSink = aSink;
- fBuffer = new char[capacity];
- fCapacity = capacity;
- fValidBytes = 0;
- fInitialPosition = kInvalidPosition;
- fBytesWritten = 0;
- fType = kInvalid;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivSinkBuffer::Destruct
- //----------------------------------------------------------------------------------------
-
- void FW_CPrivSinkBuffer::Destruct()
- {
- delete [] fBuffer;
- fBuffer = 0;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivSinkBuffer::Initialize
- //----------------------------------------------------------------------------------------
-
- void FW_CPrivSinkBuffer::Initialize(EBufferKind kind, long initialPosition, long validBytes)
- {
- fValidBytes = validBytes;
- fInitialPosition = initialPosition;
- fBytesWritten = 0;
- fType = kind;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivSinkBuffer::ReadPeek
- //----------------------------------------------------------------------------------------
-
- void* FW_CPrivSinkBuffer::ReadPeek(Environment* ev, long& availableReadBytes)
- {
- long currentPosition = fWrappedSink->GetPosition(ev);
- void* source = 0;
- availableReadBytes = 0;
-
- if (fType == kReadPeek && currentPosition >= fInitialPosition)
- {
- const long offsetInBuffer = currentPosition - fInitialPosition;
-
- if (offsetInBuffer < fValidBytes)
- {
- source = GetAddress() + offsetInBuffer;
- availableReadBytes = fValidBytes - offsetInBuffer;
- }
- }
-
- // If there is no buffered data available, load the buffer.
- if (availableReadBytes == 0)
- {
- // Write out any dirty data, mark the buffer invalid. Stay at this seek position
- if (IsDirty)
- {
- FlushAndInvalidate(ev);
- fWrappedSink->SetPosition(ev, currentPosition);
- }
- else
- Invalidate();
-
- // Determine the amount of data which will fit into the buffer and read it. Seek
- // back to the point where the read began. The buffer is still invalid: if an
- // exception occurs, it remains invalid. Only when the read&seek complete is the
- // buffer marked as valid
- availableReadBytes = FW_Minimum(fWrappedSink->GetReadableBytes(ev), GetCapacity());
- fWrappedSink->Read(ev, GetAddress(), availableReadBytes);
- fWrappedSink->SetPosition(ev, currentPosition);
-
- // Mark the buffer as containing valid data, peek into the buffer
- Initialize(kReadPeek, currentPosition, availableReadBytes);
- source = GetAddress();
- }
-
- return source;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivSinkBuffer::ReadPeekAdvance
- //----------------------------------------------------------------------------------------
-
- void FW_CPrivSinkBuffer::ReadPeekAdvance(Environment* ev, long bytesRead)
- {
- long currentPosition = fWrappedSink->GetPosition(ev);
-
- fWrappedSink->SetPosition(ev, currentPosition + bytesRead);
-
- #ifdef FW_DEBUG
- FW_ASSERT(fType == kReadPeek);
- FW_ASSERT(fInitialPosition <= currentPosition);
- FW_ASSERT(bytesRead >= 0);
- FW_ASSERT((currentPosition - fInitialPosition + bytesRead) <= fValidBytes);
- #endif
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivSinkBuffer::WritePeek
- //----------------------------------------------------------------------------------------
-
- void* FW_CPrivSinkBuffer::WritePeek(Environment* ev, long& availableWriteBytes)
- {
- long currentPosition = fWrappedSink->GetPosition(ev);
- void* destination = 0;
- availableWriteBytes = 0;
-
- // If no seeking has occurred, then the buffer is valid
- if (fType == kWritePeek && currentPosition == fInitialPosition)
- {
- destination = GetAddress() + GetBytesWritten();
- availableWriteBytes = fValidBytes - GetBytesWritten();
- }
-
- // If buffer is invalid (for whatever reason), write the buffer and prepare for more.
- if (availableWriteBytes == 0)
- {
- FW_Boolean repositionCursor = false;
-
- // Assure fWrappedSink->GetPosition(ev) == currentPosition after the
- // call to FlushAndInvalidate()
- if (IsDirty())
- {
- repositionCursor = (currentPosition != fInitialPosition);
- if (!repositionCursor)
- currentPosition = GetInitialPosition() + GetBytesWritten();
- }
-
- // Write out any dirty data, mark the buffer invalid.
- FlushAndInvalidate(ev);
-
- // If the cursor is not where we want it, reposition it
- if (repositionCursor)
- fWrappedSink->SetPosition(ev, currentPosition);
-
- // The invariant.
- FW_ASSERT(fWrappedSink->GetPosition(ev) == currentPosition);
-
- // Set the writable size for the buffer, peek into the buffer
- availableWriteBytes = FW_Minimum(fWrappedSink->GetWritableBytes(ev), GetCapacity());
- Initialize(kWritePeek, currentPosition, availableWriteBytes);
- destination = GetAddress();
- }
-
- return destination;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivSinkBuffer::WritePeekAdvance
- //----------------------------------------------------------------------------------------
-
- void FW_CPrivSinkBuffer::WritePeekAdvance(Environment* ev, long bytesWritten)
- {
- #ifndef FW_DEBUG
- FW_UNUSED(ev);
- #else
- long currentPosition = fWrappedSink->GetPosition(ev);
- FW_ASSERT(fType == kWritePeek);
- // FW_ASSERT(GetBytesWritten() == (currentPosition - fInitialPosition));
- FW_ASSERT(bytesWritten >= 0);
- FW_ASSERT((GetBytesWritten() + bytesWritten) <= fValidBytes);
- #endif
-
- fBytesWritten += bytesWritten;
- }
-
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivSinkBuffer::FlushAndInvalidate
- //----------------------------------------------------------------------------------------
- void FW_CPrivSinkBuffer::FlushAndInvalidate(Environment *ev)
- {
- // If the buffer is dirty, write its contents
- if (IsDirty())
- {
- fWrappedSink->SetPosition(ev, GetInitialPosition());
- fWrappedSink->Write(ev, GetAddress(), GetBytesWritten());
- }
-
- // Invalidate the buffer
- Invalidate();
- }
-
-
- //----------------------------------------------------------------------------------------
- // FW_OBufferedSink__InitFromSink
- //----------------------------------------------------------------------------------------
-
- SOM_Scope void SOMLINK FW_OBufferedSink__InitFromSink(FW_OBufferedSink *somSelf, Environment *ev,
- FW_ORandomAccessSink* aSink,
- long bufferCapacity)
- {
- FW_OBufferedSinkData *somThis = FW_OBufferedSinkGetData(somSelf);
-
- FW_SOM_TRY
- {
- FW_CPrivSinkBuffer* aSinkBuffer = (FW_CPrivSinkBuffer*)somThis;
- aSinkBuffer->Construct(aSink, bufferCapacity);
- }
- FW_SOM_CATCH
- }
-
- //----------------------------------------------------------------------------------------
- // FW_OBufferedSink__GetORandomAccessSink
- //----------------------------------------------------------------------------------------
-
- SOM_Scope FW_ORandomAccessSink* SOMLINK FW_OBufferedSink__GetORandomAccessSink(FW_OBufferedSink *somSelf, Environment *ev)
- {
- FW_UNUSED(ev);
- FW_OBufferedSinkData *somThis = FW_OBufferedSinkGetData(somSelf);
- return _fWrappedSink;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_OBufferedSink__Flush
- //----------------------------------------------------------------------------------------
-
- SOM_Scope void SOMLINK FW_OBufferedSink__Flush(FW_OBufferedSink *somSelf, Environment *ev)
- {
- FW_OBufferedSinkData *somThis = FW_OBufferedSinkGetData(somSelf);
-
- FW_SOM_TRY
- {
- FW_CPrivSinkBuffer* aSinkBuffer = (FW_CPrivSinkBuffer*)somThis;
- aSinkBuffer->FlushAndInvalidate(ev);
- }
- FW_SOM_CATCH
- }
-
- //----------------------------------------------------------------------------------------
- // FW_OBufferedSink__GetReadableBytes
- //----------------------------------------------------------------------------------------
-
- SOM_Scope long SOMLINK FW_OBufferedSink__GetReadableBytes(FW_OBufferedSink *somSelf, Environment *ev)
- {
- FW_OBufferedSinkData *somThis = FW_OBufferedSinkGetData(somSelf);
-
- FW_SOM_TRY
- {
- return _fWrappedSink->GetReadableBytes(ev);
- }
- FW_SOM_CATCH
- return 0;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_OBufferedSink__Read
- //----------------------------------------------------------------------------------------
-
- SOM_Scope void SOMLINK FW_OBufferedSink__Read(FW_OBufferedSink *somSelf, Environment *ev,
- void* destination,
- long count)
- {
- FW_OBufferedSinkData *somThis = FW_OBufferedSinkGetData(somSelf);
-
- FW_SOM_TRY
- {
- FW_CPrivSinkBuffer* aSinkBuffer = (FW_CPrivSinkBuffer*)somThis;
- long availableReadBytes;
- const char* currentSource = (char*)aSinkBuffer->ReadPeek(ev, availableReadBytes);
- long bytesToReadThisTime = FW_Minimum(count, availableReadBytes);
-
- // [jkp] 960215 Optimizing large data transfers
- // Possible future optimization is to check if "availableReadBytes" is
- // greater than "bytesToReadThisTime + _fCapacity". In that case, we
- // can read what's in the buffer, invalidate the buffer, read the remainder
- // directly from the sink. This avoids double-copying of the data: once
- // from the sink to the buffer, then from the buffer to the destination.
- //
- // This hasn't been done because streams are used for many transfers of small
- // data: buffering wins. Also, the developer can grab the underlying sink and
- // transfer directly. The buffered sink "catches up" when the seek pointer has
- // moved.
- while (bytesToReadThisTime != 0)
- {
- FW_PrimitiveCopyMemory(currentSource, destination, bytesToReadThisTime);
- aSinkBuffer->ReadPeekAdvance(ev, bytesToReadThisTime);
- destination = (char*)destination + bytesToReadThisTime;
- count -= bytesToReadThisTime;
- if (count == 0)
- break;
- currentSource = (const char*)aSinkBuffer->ReadPeek(ev, availableReadBytes);
- bytesToReadThisTime = FW_Minimum(count, availableReadBytes);
- }
-
- if (count != 0)
- FW_Failure(FW_xReadableStream);
- }
- FW_SOM_CATCH
- }
-
- //----------------------------------------------------------------------------------------
- // FW_OBufferedSink__GetWritableBytes
- //----------------------------------------------------------------------------------------
-
- SOM_Scope long SOMLINK FW_OBufferedSink__GetWritableBytes(FW_OBufferedSink *somSelf, Environment *ev)
- {
- FW_OBufferedSinkData *somThis = FW_OBufferedSinkGetData(somSelf);
-
- FW_SOM_TRY
- {
- return _fWrappedSink->GetWritableBytes(ev);
- }
- FW_SOM_CATCH
- return 0;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_OBufferedSink__Write
- //----------------------------------------------------------------------------------------
-
- SOM_Scope void SOMLINK FW_OBufferedSink__Write(FW_OBufferedSink *somSelf, Environment *ev,
- void* source,
- long count)
- {
- FW_OBufferedSinkData *somThis = FW_OBufferedSinkGetData(somSelf);
-
- FW_SOM_TRY
- {
- FW_CPrivSinkBuffer* aSinkBuffer = (FW_CPrivSinkBuffer*)somThis;
- long availableWriteBytes;
- char* currentDestination = (char*)aSinkBuffer->WritePeek(ev, availableWriteBytes);
- long bytesToWriteThisTime = FW_Minimum(count, availableWriteBytes);
-
- while (bytesToWriteThisTime != 0)
- {
- FW_PrimitiveCopyMemory(source, currentDestination, bytesToWriteThisTime);
- aSinkBuffer->WritePeekAdvance(ev, bytesToWriteThisTime);
- source = (char*)source + bytesToWriteThisTime;
- count -= bytesToWriteThisTime;
- if (count == 0)
- break;
- currentDestination = (char*)aSinkBuffer->WritePeek(ev, availableWriteBytes);
- bytesToWriteThisTime = FW_Minimum(count, availableWriteBytes);
- }
-
- if (count != 0)
- FW_Failure(FW_xWritableStream);
- }
- FW_SOM_CATCH
- }
-
- //----------------------------------------------------------------------------------------
- // FW_OBufferedSink__GetLength
- //----------------------------------------------------------------------------------------
-
- SOM_Scope long SOMLINK FW_OBufferedSink__GetLength(FW_OBufferedSink *somSelf, Environment *ev)
- {
- FW_OBufferedSinkData *somThis = FW_OBufferedSinkGetData(somSelf);
-
- FW_SOM_TRY
- {
- FW_CPrivSinkBuffer* aSinkBuffer = (FW_CPrivSinkBuffer*)somThis;
-
- if (aSinkBuffer->IsDirty())
- aSinkBuffer->FlushAndInvalidate(ev);
- return _fWrappedSink->GetLength(ev);
- }
- FW_SOM_CATCH
- return 0;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_OBufferedSink__SetLength
- //----------------------------------------------------------------------------------------
-
- SOM_Scope void SOMLINK FW_OBufferedSink__SetLength(FW_OBufferedSink *somSelf, Environment *ev,
- long length)
- {
- FW_OBufferedSinkData *somThis = FW_OBufferedSinkGetData(somSelf);
-
- FW_SOM_TRY
- {
- FW_CPrivSinkBuffer* aSinkBuffer = (FW_CPrivSinkBuffer*)somThis;
-
- aSinkBuffer->FlushAndInvalidate(ev);
- _fWrappedSink->SetLength(ev, length);
- }
- FW_SOM_CATCH
- }
-
- //----------------------------------------------------------------------------------------
- // FW_OBufferedSink__GetPosition
- //----------------------------------------------------------------------------------------
-
- SOM_Scope long SOMLINK FW_OBufferedSink__GetPosition(FW_OBufferedSink *somSelf, Environment *ev)
- {
- FW_OBufferedSinkData *somThis = FW_OBufferedSinkGetData(somSelf);
-
- FW_SOM_TRY
- {
- FW_CPrivSinkBuffer* aSinkBuffer = (FW_CPrivSinkBuffer*)somThis;
-
- if (aSinkBuffer->IsDirty())
- aSinkBuffer->FlushAndInvalidate(ev);
- return _fWrappedSink->GetPosition(ev);
- }
- FW_SOM_CATCH
- return 0;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_OBufferedSink__SetPosition
- //----------------------------------------------------------------------------------------
-
- SOM_Scope void SOMLINK FW_OBufferedSink__SetPosition(FW_OBufferedSink *somSelf, Environment *ev,
- long position)
- {
- FW_OBufferedSinkData *somThis = FW_OBufferedSinkGetData(somSelf);
-
- FW_SOM_TRY
- {
- FW_CPrivSinkBuffer* aSinkBuffer = (FW_CPrivSinkBuffer*)somThis;
-
- if (aSinkBuffer->IsDirty())
- aSinkBuffer->FlushAndInvalidate(ev);
- _fWrappedSink->SetPosition(ev, position);
- }
- FW_SOM_CATCH
- }
-
- //----------------------------------------------------------------------------------------
- // FW_OBufferedSink__somInit
- //----------------------------------------------------------------------------------------
-
- SOM_Scope void SOMLINK FW_OBufferedSink__somInit(FW_OBufferedSink *somSelf)
- {
- FW_UNUSED(somSelf);
- // FW_OBufferedSinkData *somThis = FW_OBufferedSinkGetData(somSelf);
-
- // FW_OBufferedSink_parent_FW_ORandomAccessSink_somInit(somSelf);
- }
-
- //----------------------------------------------------------------------------------------
- // FW_OBufferedSink__somUninit
- //----------------------------------------------------------------------------------------
-
- SOM_Scope void SOMLINK FW_OBufferedSink__somUninit(FW_OBufferedSink *somSelf)
- {
- FW_OBufferedSinkData *somThis = FW_OBufferedSinkGetData(somSelf);
-
- FW_SOM_UNINIT_TRY
- {
- FW_CPrivSinkBuffer* aSinkBuffer = (FW_CPrivSinkBuffer*)somThis;
- FW_SOMEnvironment ev;
-
- // Flush out any data which hasn't been written, then reclaim memory.
- aSinkBuffer->FlushAndInvalidate(ev);
- aSinkBuffer->Destruct();
-
- // FW_OBufferedSink_parent_FW_ORandomAccessSink_somInit(somSelf);
- }
- FW_SOM_UNINIT_CATCH
- }
-