Windows2003-3790/windows/advcore/gdiplus/test/emfdcode/dibstream.hpp
2020-09-30 16:53:55 +02:00

313 lines
6.3 KiB
C++

/**************************************************************************\
*
* 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