📄 olepicture.c
字号:
* Loads the binary data from the IStream. Starts at current position.
* There appears to be an 2 DWORD header:
* DWORD magic;
* DWORD len;
*
* Currently implemented: BITMAP, ICON, JPEG, GIF, WMF, EMF
*/
static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
HRESULT hr = E_FAIL;
BOOL headerisdata = FALSE;
BOOL statfailed = FALSE;
ULONG xread, toread;
ULONG headerread;
BYTE *xbuf;
DWORD header[2];
WORD magic;
STATSTG statstg;
OLEPictureImpl *This = impl_from_IPersistStream(iface);
TRACE("(%p,%p)\n",This,pStm);
/****************************************************************************************
* Part 1: Load the data
*/
/* Sometimes we have a header, sometimes we don't. Apply some guesses to find
* out whether we do.
*
* UPDATE: the IStream can be mapped to a plain file instead of a stream in a
* compound file. This may explain most, if not all, of the cases of "no
* header", and the header validation should take this into account.
* At least in Visual Basic 6, resource streams, valid headers are
* header[0] == "lt\0\0",
* header[1] == length_of_stream.
*
* Also handle streams where we do not have a working "Stat" method by
* reading all data until the end of the stream.
*/
hr=IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
if (hr) {
TRACE("stat failed with hres %x, proceeding to read all data.\n",hr);
statfailed = TRUE;
/* we will read at least 8 byte ... just right below */
statstg.cbSize.QuadPart = 8;
}
toread = 0;
headerread = 0;
headerisdata = FALSE;
do {
hr=IStream_Read(pStm,header,8,&xread);
if (hr || xread!=8) {
FIXME("Failure while reading picture header (hr is %x, nread is %d).\n",hr,xread);
return hr;
}
headerread += xread;
xread = 0;
if (!memcmp(&(header[0]),"lt\0\0", 4) && (statfailed || (header[1] + headerread <= statstg.cbSize.QuadPart))) {
if (toread != 0 && toread != header[1])
FIXME("varying lengths of image data (prev=%u curr=%u), only last one will be used\n",
toread, header[1]);
toread = header[1];
if (toread == 0) break;
} else {
if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
!memcmp(&(header[0]), "BM", 2) || /* BMP header */
!memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
(header[1] > statstg.cbSize.QuadPart)|| /* invalid size */
(header[1]==0)
) {/* Found start of bitmap data */
headerisdata = TRUE;
if (toread == 0)
toread = statstg.cbSize.QuadPart-8;
else toread -= 8;
xread = 8;
} else {
FIXME("Unknown stream header magic: %08x\n", header[0]);
toread = header[1];
}
}
} while (!headerisdata);
if (statfailed) { /* we don't know the size ... read all we get */
int sizeinc = 4096;
int origsize = sizeinc;
ULONG nread = 42;
TRACE("Reading all data from stream.\n");
xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
if (headerisdata)
memcpy (xbuf, &header, 8);
while (1) {
while (xread < origsize) {
hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
xread+=nread;
if (hr || !nread)
break;
}
if (!nread || hr) /* done, or error */
break;
if (xread == origsize) {
origsize += sizeinc;
sizeinc = 2*sizeinc; /* exponential increase */
xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
}
}
if (hr)
TRACE("hr in no-stat loader case is %08x\n", hr);
TRACE("loaded %d bytes.\n", xread);
This->datalen = xread;
This->data = xbuf;
} else {
This->datalen = toread+(headerisdata?8:0);
xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
if (headerisdata)
memcpy (xbuf, &header, 8);
while (xread < This->datalen) {
ULONG nread;
hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
xread+=nread;
if (hr || !nread)
break;
}
if (xread != This->datalen)
FIXME("Could only read %d of %d bytes out of stream?\n",xread,This->datalen);
}
if (This->datalen == 0) { /* Marks the "NONE" picture */
This->desc.picType = PICTYPE_NONE;
return S_OK;
}
/****************************************************************************************
* Part 2: Process the loaded data
*/
magic = xbuf[0] + (xbuf[1]<<8);
This->loadtime_format = magic;
switch (magic) {
case 0x4947: /* GIF */
hr = OLEPictureImpl_LoadGif(This, xbuf, xread);
break;
case 0xd8ff: /* JPEG */
hr = OLEPictureImpl_LoadJpeg(This, xbuf, xread);
break;
case 0x4d42: /* Bitmap */
hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
break;
case 0x5089: /* PNG */
hr = OLEPictureImpl_LoadPNG(This, xbuf, xread);
break;
case 0x0000: { /* ICON , first word is dwReserved */
hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
break;
}
default:
{
unsigned int i;
/* let's see if it's a metafile */
hr = OLEPictureImpl_LoadMetafile(This, xbuf, xread);
if (hr == S_OK) break;
FIXME("Unknown magic %04x, %d read bytes:\n",magic,xread);
hr=E_FAIL;
for (i=0;i<xread+8;i++) {
if (i<8) MESSAGE("%02x ",((unsigned char*)&header)[i]);
else MESSAGE("%02x ",xbuf[i-8]);
if (i % 10 == 9) MESSAGE("\n");
}
MESSAGE("\n");
break;
}
}
This->bIsDirty = FALSE;
/* FIXME: this notify is not really documented */
if (hr==S_OK)
OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
return hr;
}
static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
{
int iSuccess = 0;
HDC hDC;
BITMAPINFO * pInfoBitmap;
int iNumPaletteEntries;
unsigned char * pPixelData;
BITMAPFILEHEADER * pFileHeader;
BITMAPINFO * pInfoHeader;
pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
/* Find out bitmap size and padded length */
hDC = GetDC(0);
pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
/* Fetch bitmap palette & pixel data */
pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
/* Calculate the total length required for the BMP data */
if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
} else {
if (pInfoBitmap->bmiHeader.biBitCount <= 8)
iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
else
iNumPaletteEntries = 0;
}
*pLength =
sizeof(BITMAPFILEHEADER) +
sizeof(BITMAPINFOHEADER) +
iNumPaletteEntries * sizeof(RGBQUAD) +
pInfoBitmap->bmiHeader.biSizeImage;
*ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
/* Fill the BITMAPFILEHEADER */
pFileHeader = (BITMAPFILEHEADER *)(*ppBuffer);
pFileHeader->bfType = 0x4d42;
pFileHeader->bfSize = *pLength;
pFileHeader->bfOffBits =
sizeof(BITMAPFILEHEADER) +
sizeof(BITMAPINFOHEADER) +
iNumPaletteEntries * sizeof(RGBQUAD);
/* Fill the BITMAPINFOHEADER and the palette data */
pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
memcpy(
(unsigned char *)(*ppBuffer) +
sizeof(BITMAPFILEHEADER) +
sizeof(BITMAPINFOHEADER) +
iNumPaletteEntries * sizeof(RGBQUAD),
pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
iSuccess = 1;
HeapFree(GetProcessHeap(), 0, pPixelData);
HeapFree(GetProcessHeap(), 0, pInfoBitmap);
return iSuccess;
}
static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
{
ICONINFO infoIcon;
int iSuccess = 0;
*ppBuffer = NULL; *pLength = 0;
if (GetIconInfo(hIcon, &infoIcon)) {
HDC hDC;
BITMAPINFO * pInfoBitmap;
unsigned char * pIconData = NULL;
unsigned int iDataSize = 0;
pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
/* Find out icon size */
hDC = GetDC(0);
pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
if (1) {
/* Auxiliary pointers */
CURSORICONFILEDIR * pIconDir;
CURSORICONFILEDIRENTRY * pIconEntry;
BITMAPINFOHEADER * pIconBitmapHeader;
unsigned int iOffsetPalette;
unsigned int iOffsetColorData;
unsigned int iOffsetMaskData;
unsigned int iLengthScanLineColor;
unsigned int iLengthScanLineMask;
unsigned int iNumEntriesPalette;
iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
iLengthScanLineColor = ((pInfoBitmap->bmiHeader.biWidth * pInfoBitmap->bmiHeader.biBitCount + 31) >> 5) << 2;
/*
FIXME("DEBUG: bitmap size is %d x %d\n",
pInfoBitmap->bmiHeader.biWidth,
pInfoBitmap->bmiHeader.biHeight);
FIXME("DEBUG: bitmap bpp is %d\n",
pInfoBitmap->bmiHeader.biBitCount);
FIXME("DEBUG: bitmap nplanes is %d\n",
pInfoBitmap->bmiHeader.biPlanes);
FIXME("DEBUG: bitmap biSizeImage is %u\n",
pInfoBitmap->bmiHeader.biSizeImage);
*/
/* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
/* Fill out the CURSORICONFILEDIR */
pIconDir = (CURSORICONFILEDIR *)pIconData;
pIconDir->idType = 1;
pIconDir->idCount = 1;
/* Fill out the CURSORICONFILEDIRENTRY */
pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
pIconEntry->bColorCount =
(pInfoBitmap->bmiHeader.biBitCount < 8)
? 1 << pInfoBitmap->bmiHeader.biBitCount
: 0;
pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
pIconEntry->dwDIBSize = 0;
pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
/* Fill out the BITMAPINFOHEADER */
pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
memcpy(pIconBitmapHeader, &pInfoBitmap->bmiHeader, sizeof(BITMAPINFOHEADER));
/* Find out whether a palette exists for the bitmap */
if ( (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
|| (pInfoBitmap->bmiHeader.biBitCount == 24)
|| (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
if (iNumEntriesPalette > 256) iNumEntriesPalette = 256;
} else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
&& pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
iNumEntriesPalette = 3;
} else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
} else {
iNumEntriesPalette = 0;
}
/* Add bitmap size and header size to icon data size. */
iOffsetPalette = iDataSize;
iDataSize += iNumEntriesPalette * sizeof(DWORD);
iOffsetColorData = iDataSize;
iDataSize += pIconBitmapHeader->biSizeImage;
iOffsetMaskData = iDataSize;
iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
pIconBitmapHeader->biHeight *= 2;
pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
/* Get the actual bitmap data from the icon bitmap */
GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
if (iNumEntriesPalette > 0) {
memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
iNumEntriesPalette * sizeof(RGBQUAD));
}
/* Reset all values so that GetDIBits call succeeds */
memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
/*
if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
&& GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
printf("ERROR: unable to get bitmap mask (error %u)\n",
GetLastError());
}
*/
GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
/* Write out everything produced so far to the stream */
*ppBuffer = pIconData; *pLength = iDataSize;
iSuccess = 1;
} else {
/*
printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
GetLastError());
*/
}
/*
Remarks (from MSDN entry on GetIconInfo):
GetIconInfo creates bitmaps for the hbmMask and hbmColor
members of ICONINFO. The calling application must manage
these bitmaps and delete them when they are no longer
necessary.
*/
if (hDC) ReleaseDC(0, hDC);
DeleteObject(infoIcon.hbmMask);
if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
HeapFree(GetProcessHeap(), 0, pInfoBitmap);
} else {
printf("ERROR: Unable to get icon information (error %u)\n",
GetLastError());
}
return iSuccess;
}
static HRESULT WINAPI OLEPictureImpl_Save(
IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
{
HRESULT
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -