|
|
/**************************************************************************\
* * Copyright (c) 1999 Microsoft Corporation * * Module Name: * * dibstream.hpp * * Abstract: * * Wrap an IStream interface around DIB data. * * Revision History: * * 07/01/1999 davidx * Created it. * \**************************************************************************/
#ifndef _DIBSTREAM_HPP
#define _DIBSTREAM_HPP
// NOTE: This is not a thread-safe object.
class DibStream : public IStream { public:
// Constructor
DibStream(const BITMAPINFO* bmi, const BYTE* bits) { ComRefCount = 1; CurrentPos = 0; DibBits = bits;
ZeroMemory(HeaderBuffer, sizeof(HeaderBuffer));
// Figure out the size of header information
HeaderSize = sizeof(BITMAPINFOHEADER);
const BITMAPINFOHEADER* bmih = &bmi->bmiHeader; ULONG n = bmih->biClrUsed;
if (n == 0) { switch (bmih->biBitCount) { case 1: case 4: case 8: n = 1 << bmih->biBitCount; break;
case 16: case 32: if (bmih->biCompression == BI_BITFIELDS) n = 3; break; } }
HeaderSize += n * sizeof(RGBQUAD);
memcpy(&HeaderBuffer[sizeof(BITMAPFILEHEADER)], bmi, HeaderSize); HeaderSize += sizeof(BITMAPFILEHEADER);
// Figure out the size of bitmap data
n = bmih->biSizeImage;
if (n == 0 && bmih->biCompression == BI_RGB) { // Scanline is always DWORD-aligned
n = ((bmih->biWidth * bmih->biBitCount) + 7) / 8; n = (n + 3) & ~3;
n *= abs(bmih->biHeight); }
TotalSize = HeaderSize + n;
// Fix BMP file header information
BITMAPFILEHEADER* fileHeader = (BITMAPFILEHEADER*) HeaderBuffer; fileHeader->bfType = 0x4D42; fileHeader->bfSize = TotalSize; fileHeader->bfOffBits = HeaderSize; }
// Query interface
STDMETHOD(QueryInterface)(REFIID riid, VOID** ppv) { if (riid == IID_IUnknown) *ppv = static_cast<IUnknown*>(this); else if (riid == IID_IStream) *ppv = static_cast<IStream*>(this); else { *ppv = NULL; return E_NOINTERFACE; }
reinterpret_cast<IUnknown*>(*ppv)->AddRef(); return S_OK; }
// Increment reference count
STDMETHOD_(ULONG, AddRef)(VOID) { return InterlockedIncrement(&ComRefCount); }
// Decrement reference count
STDMETHOD_(ULONG, Release)(VOID) { ULONG count = InterlockedDecrement(&ComRefCount);
if (count == 0) delete this;
return count; }
// Read data
STDMETHOD(Read)( VOID* buf, ULONG cb, ULONG* cbRead ) { ULONG n = TotalSize - CurrentPos;
if (cb > n) cb = n;
if (CurrentPos >= HeaderSize) { // Read bitmap data
memcpy(buf, DibBits + (CurrentPos - HeaderSize), cb); } else { // Read header data
n = HeaderSize - CurrentPos;
if (cb <= n) { memcpy(buf, &HeaderBuffer[CurrentPos], cb); } else { memcpy(buf, &HeaderBuffer[CurrentPos], n); memcpy((BYTE*) buf + n, DibBits, cb - n); } }
CurrentPos += cb; *cbRead = cb;
return S_OK; }
// Change read pointer
STDMETHOD(Seek)( LARGE_INTEGER offset, DWORD origin, ULARGE_INTEGER* newPos ) { LONGLONG pos;
switch (origin) { case STREAM_SEEK_SET:
pos = offset.QuadPart; break;
case STREAM_SEEK_END:
pos = TotalSize; break;
case STREAM_SEEK_CUR:
pos = (LONGLONG) CurrentPos + offset.QuadPart; break;
default:
pos = -1; break; }
if (pos < 0 || pos > TotalSize) return E_INVALIDARG;
CurrentPos = (ULONG) pos;
if (newPos) newPos->QuadPart = pos;
return S_OK; }
// Get information
STDMETHOD(Stat)( STATSTG* statstg, DWORD statFlag ) { ZeroMemory(statstg, sizeof(STATSTG));
statstg->type = STGTY_STREAM; statstg->cbSize.QuadPart = TotalSize; statstg->grfMode = STGM_READ;
return S_OK; }
STDMETHOD(Write)( const VOID* buf, ULONG cb, ULONG* cbWritten ) { return STG_E_ACCESSDENIED; }
STDMETHOD(CopyTo)( IStream* stream, ULARGE_INTEGER cb, ULARGE_INTEGER* cbRead, ULARGE_INTEGER* cbWritten ) { return E_NOTIMPL; }
STDMETHOD(SetSize)( ULARGE_INTEGER newSize ) { return E_NOTIMPL; }
STDMETHOD(Commit)( DWORD commitFlags ) { return S_OK; }
STDMETHOD(Revert)() { return E_NOTIMPL; }
STDMETHOD(LockRegion)( ULARGE_INTEGER offset, ULARGE_INTEGER cb, DWORD lockType ) { return E_NOTIMPL; }
STDMETHOD(UnlockRegion)( ULARGE_INTEGER offset, ULARGE_INTEGER cb, DWORD lockType ) { return E_NOTIMPL; }
STDMETHOD(Clone)( IStream** stream ) { return E_NOTIMPL; }
private:
LONG ComRefCount; ULONG HeaderSize; ULONG TotalSize; ULONG CurrentPos; const BYTE* DibBits;
// Large enough buffer for storing bitmap file header information
BYTE HeaderBuffer[sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256]; };
#endif // !_DIBSTREAM_HPP
|