mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1173 lines
28 KiB
1173 lines
28 KiB
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// stmio.c
|
|
//
|
|
// Property Set Stream I/O
|
|
//
|
|
// Change history:
|
|
//
|
|
// Date Who What
|
|
// --------------------------------------------------------------------------
|
|
// 07/30/94 B. Wentz Created file
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "priv.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
|
|
// Globals from stmio.h
|
|
|
|
// Max size of the write buffer.
|
|
#define BUFMAX 2048
|
|
|
|
// Internal prototypes
|
|
static BOOL PASCAL FLpstmReadVT_VECTOR (LPSTREAM lpStm,
|
|
DWORD irglpUnk,
|
|
LPPROPIDTYPELP rglpUnk);
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FLpstmReadVT_LPTSTR
|
|
//
|
|
// Purpose:
|
|
// Read a VT_LPSTR from the stream.
|
|
// RickTu: also added conversion to UNICODE when appropriate
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOL PASCAL
|
|
FLpstmReadVT_LPTSTR
|
|
(LPSTREAM lpStm, // Pointer to stream
|
|
LPTSTR FAR *lplpstz, // Pointer to string
|
|
BOOL (*lpfnFCPConvert)(LPTSTR, DWORD, DWORD, BOOL), // Code page converter
|
|
DWORD dwType) // Indicates the type of information being read
|
|
{
|
|
DWORD cch,cb;
|
|
DWORD cbT;
|
|
HRESULT hr;
|
|
LPGLOBALS lpg = (LPGLOBALS)TlsGetValue( g_tls );
|
|
|
|
//
|
|
// Get size of string
|
|
//
|
|
if (!SUCCEEDED (lpStm->lpVtbl->Read (lpStm, &cch, sizeof (DWORD), NULL)))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Check the degenerative case...
|
|
//
|
|
|
|
*lplpstz = NULL;
|
|
if (cch == 0)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// For wide (UNICODE) strings, the size if not a cb, but a cw!
|
|
//
|
|
cb = cch;
|
|
if (dwType == VT_LPWSTR)
|
|
{
|
|
cb *= sizeof(WCHAR);
|
|
}
|
|
|
|
//
|
|
// If we're dealing with an "Office97" file, EVERYTHING is
|
|
// 32-bit aligned.
|
|
//
|
|
if (lpg->gfUnicode)
|
|
{
|
|
cb += CBALIGN32 (cb);
|
|
}
|
|
|
|
cbT = cb+2*sizeof(DWORD);
|
|
cbT += CBALIGN32 (cbT);
|
|
|
|
|
|
if (((*lplpstz) = (TCHAR *) PvMemAlloc(cbT)) == NULL)
|
|
{
|
|
goto Fail;
|
|
}
|
|
|
|
CBBUF (*lplpstz) = cbT;
|
|
CCHSTR (*lplpstz) = cch;
|
|
|
|
hr = lpStm->lpVtbl->Read (lpStm, PSTR (*lplpstz), cb, NULL);
|
|
if (!SUCCEEDED(hr))
|
|
{
|
|
DebugHr(hr);
|
|
goto Fail;
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
if (dwType == VT_LPSTR)
|
|
{
|
|
LPWSTR wszTmp;
|
|
|
|
//
|
|
// refigure size
|
|
//
|
|
cbT = (cch*sizeof(WCHAR)) + (2*sizeof(DWORD));
|
|
cbT += CBALIGN32 (cbT);
|
|
wszTmp = (LPWSTR) PvMemAlloc(cbT);
|
|
|
|
if (wszTmp)
|
|
{
|
|
CBBUF(wszTmp) = cbT;
|
|
CCHSTR(wszTmp) = cch;
|
|
MultiByteToWideChar( lpg->gdwCurrentCP, 0,
|
|
PSTR(*lplpstz),
|
|
-1,
|
|
(LPWSTR)PSTR(wszTmp),
|
|
cch );
|
|
VFreeMemP(*lplpstz,cbT);
|
|
*lplpstz = wszTmp;
|
|
}
|
|
else
|
|
{
|
|
goto Fail;
|
|
}
|
|
|
|
}
|
|
#else
|
|
if (dwType == VT_LPWSTR)
|
|
{
|
|
LPSTR szTmp;
|
|
|
|
//
|
|
// refigure size
|
|
//
|
|
cbT = (cch+ (2*sizeof(DWORD));
|
|
cbT += CBALIGN32 (cbT);
|
|
szTmp = (LPSTR) PvMemAlloc(cbT);
|
|
|
|
if (szTmp)
|
|
{
|
|
CBBUF(szTmp) = cbT;
|
|
CCHSTR(szTmp) = cch;
|
|
WideCharToMultiByte( lpg->gdwCurrentCP, 0,
|
|
(LPWSTR)PSTR(*lplpstz),
|
|
-1,
|
|
(LPSTR)PSTR(wszTmp),
|
|
cch,
|
|
NULL,
|
|
NULL );
|
|
VFreeMemP(*lplpstz,cbT);
|
|
*lplpstz = szTmp;
|
|
}
|
|
else
|
|
{
|
|
goto Fail;
|
|
}
|
|
}
|
|
|
|
if (lpg->gdwFileCP != lpg->gdwCurrentCP)
|
|
{
|
|
if (!(*lpfnFCPConvert)(PSTR (*lplpstz), lpg->gdwFileCP, lpg->gdwCurrentCP, lpg->gfMacintosh))
|
|
{
|
|
DebugSz ("Code page conversion failed");
|
|
goto Fail;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return TRUE;
|
|
|
|
Fail:
|
|
if (*lplpstz != NULL)
|
|
{
|
|
VFreeMemP(*lplpstz, cbT);
|
|
}
|
|
return FALSE;
|
|
|
|
} // FLpstmReadVT_LPTSTR
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FLpstmWriteVT_LPTSTR
|
|
//
|
|
// Purpose:
|
|
// Write a VT_LPSTR to the stream.
|
|
// Ricktu: also added converstion FROM UNICODE when appropriate
|
|
//
|
|
// Notes: This does the NULL checking, it is OK to pass a null lpstz.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOL PASCAL
|
|
FLpstmWriteVT_LPTSTR
|
|
(LPSTREAM lpStm, // Stream pointer
|
|
LPTSTR lpstz, // String to write
|
|
BOOL fAlign, // Indicates the string should be 32-bit aligned
|
|
DWORD dwType) // Type indicator to write out
|
|
{
|
|
DWORD dw,cch;
|
|
DWORD cb;
|
|
BOOL f = FALSE;
|
|
LPGLOBALS lpg = (LPGLOBALS)TlsGetValue( g_tls );
|
|
|
|
|
|
if (lpstz == NULL)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Temporarily stuff the property type for the VT_LPSTR in the
|
|
// first dword of the string to save an extra write.
|
|
//
|
|
cb = CBBUF (lpstz);
|
|
CBBUF (lpstz) = dwType;
|
|
|
|
//
|
|
// Calculate the padding needed to align on boundary.
|
|
//
|
|
cch = CCHSTR (lpstz);
|
|
if (dwType == VT_LPWSTR)
|
|
{
|
|
dw = cch*sizeof(WCHAR);
|
|
}
|
|
else
|
|
{
|
|
dw = cch;
|
|
}
|
|
dw += 2*sizeof(DWORD);
|
|
|
|
if (fAlign)
|
|
{
|
|
dw += CBALIGN32 (dw);
|
|
}
|
|
#ifdef UNICODE
|
|
// Need to convert from UNICODE to ANSI before writing to the disk!
|
|
if (dwType == VT_LPSTR)
|
|
{
|
|
LPSTR szStr = PvMemAlloc( dw );
|
|
|
|
if (szStr)
|
|
{
|
|
WideCharToMultiByte( lpg->gdwCurrentCP, 0,
|
|
(LPTSTR)PSTR(lpstz),
|
|
CCHSTR(lpstz),
|
|
(LPSTR)PSTR(szStr),
|
|
CCHSTR(lpstz),
|
|
NULL,
|
|
NULL );
|
|
CBBUF(szStr) = dwType;
|
|
CCHSTR(szStr) = (DWORD)CCHSTR(lpstz);
|
|
f = FLpstmWrite (lpStm, szStr, dw );
|
|
VFreeMemP(szStr,dw);
|
|
}
|
|
else
|
|
{
|
|
f = FALSE;
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
f = FLpstmWrite (lpStm, &(lpstz[0]), dw);
|
|
|
|
Exit:
|
|
CBBUF (lpstz) = cb; // Put the buffer length back
|
|
|
|
return(f);
|
|
|
|
} // FLpstmWriteVT_LPTSTR
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FLpstmWriteVT_FILETIME
|
|
//
|
|
// Purpose:
|
|
// To write a VT_FILETIME to the given stream.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOL PASCAL
|
|
FLpstmWriteVT_FILETIME
|
|
(LPSTREAM lpStm, // The stream to write to
|
|
LPFILETIME lpFt) // The file time to write
|
|
{
|
|
BYTE rgb[sizeof(DWORD)+sizeof(FILETIME)];
|
|
BOOL f;
|
|
|
|
*(DWORD *) &(rgb[0]) = VT_FILETIME;
|
|
*(LPFILETIME) &(rgb[sizeof(DWORD)]) = *lpFt;
|
|
|
|
// Write out the type and filetime
|
|
f = FLpstmWrite (lpStm, rgb, sizeof(rgb));
|
|
|
|
// Should be no need to 32-bit align since this already is.
|
|
AssertSz (((sizeof(FILETIME)%4) == 0), "Huh? FILETIME size no longer multiple of 4");
|
|
return(f);
|
|
|
|
} // FLpstmWriteVT_FILETIME
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FLpstmWriteVT_I4
|
|
//
|
|
// Purpose:
|
|
// Write a VT_I4 to the stream.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOL PASCAL
|
|
FLpstmWriteVT_I4
|
|
(LPSTREAM lpStm, // Stream to write to
|
|
DWORD dwI4) // The VT_I4 to write
|
|
{
|
|
DWORD rgdw[2];
|
|
|
|
rgdw[0] = VT_I4;
|
|
rgdw[1] = dwI4;
|
|
|
|
// VT_I4
|
|
return(FLpstmWrite (lpStm, &(rgdw[0]), sizeof(rgdw)));
|
|
|
|
} // FLpstmWriteVT_I4
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FLpstmReadVT_CF
|
|
//
|
|
// Purpose:
|
|
// Read a VT_CF from the stream.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOL PASCAL
|
|
FLpstmReadVT_CF
|
|
(LPSTREAM lpStm,
|
|
LPSINAIL lpSINail)
|
|
{
|
|
HRESULT hr;
|
|
DWORD cftag;
|
|
DWORD cbData;
|
|
DWORD cbTag;
|
|
|
|
hr = lpStm->lpVtbl->Read (lpStm, &cbData, sizeof (DWORD), NULL);
|
|
if (!SUCCEEDED (hr))
|
|
{
|
|
DebugHr (hr);
|
|
return FALSE;
|
|
}
|
|
|
|
hr = lpStm->lpVtbl->Read (lpStm, &cftag, sizeof (DWORD), NULL);
|
|
if (!SUCCEEDED (hr))
|
|
{
|
|
DebugHr (hr);
|
|
return FALSE;
|
|
}
|
|
|
|
cbTag = CbThumbNailFMTID(cftag);
|
|
cbData = cbData-4-cbTag;
|
|
|
|
if (cbData != 0)
|
|
{
|
|
lpSINail->pbData = PvMemAlloc(cbData);
|
|
if (lpSINail->pbData == NULL)
|
|
return(FALSE);
|
|
}
|
|
else
|
|
lpSINail->pbData = NULL;
|
|
|
|
|
|
if (cbTag != 0)
|
|
{
|
|
lpSINail->pbFMTID = PvMemAlloc(cbTag);
|
|
if (lpSINail->pbFMTID == NULL)
|
|
{
|
|
if (cbData != 0)
|
|
VFreeMemP(lpSINail->pbData, cbData);
|
|
return(FALSE);
|
|
}
|
|
}
|
|
else
|
|
lpSINail->pbFMTID = NULL;
|
|
|
|
|
|
lpSINail->cbData = cbData;
|
|
lpSINail->cftag = cftag;
|
|
|
|
if (cbTag != 0)
|
|
{
|
|
hr = lpStm->lpVtbl->Read (lpStm, lpSINail->pbFMTID, cbTag, NULL);
|
|
if (!SUCCEEDED (hr))
|
|
goto Error;
|
|
}
|
|
|
|
if (cbData != 0)
|
|
{
|
|
hr = lpStm->lpVtbl->Read (lpStm, lpSINail->pbData, cbData, NULL);
|
|
if (!SUCCEEDED (hr))
|
|
{
|
|
Error:
|
|
DebugHr (hr);
|
|
if (cbTag != 0)
|
|
VFreeMemP(lpSINail->pbFMTID,cbTag);
|
|
if (cbData != 0)
|
|
VFreeMemP(lpSINail->pbData,cbData);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
} // FLpstmReadVT_CF
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FLpstmWriteVT_CF
|
|
//
|
|
// Purpose:
|
|
// Writes a VT_VF to the given stream
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOL PASCAL
|
|
FLpstmWriteVT_CF
|
|
(LPSTREAM lpStm, // Stream to write to
|
|
LPSINAIL lpSINail) // VT_CF to write out
|
|
{
|
|
DWORD rgdw[3];
|
|
DWORD cb;
|
|
|
|
rgdw[0] = VT_CF;
|
|
cb = CbThumbNailFMTID(lpSINail->cftag);
|
|
// Bytes that follow, see page 875 in OLE 2 Programmer's Ref. Vol.1
|
|
rgdw[1] = lpSINail->cbData+4+cb;
|
|
rgdw[2] = lpSINail->cftag;
|
|
|
|
// Write the type, size and clip fmt.
|
|
if (!FLpstmWrite (lpStm, rgdw, sizeof(rgdw)))
|
|
return FALSE;
|
|
|
|
// Write out FMTID
|
|
// Should be no need to 32-bit align since this already is.
|
|
AssertSz (((cb%4) == 0), "Huh? cbFMTID size no longer multiple of 4");
|
|
if (!FLpstmWrite (lpStm, lpSINail->pbFMTID, cb))
|
|
return FALSE;
|
|
|
|
// Write out the data
|
|
if (lpSINail->cbData) // Some PPT files have 0 data. Are they old files?
|
|
{
|
|
cb = lpSINail->cbData;
|
|
cb += CBALIGN32(cb);
|
|
if (!FLpstmWrite (lpStm, lpSINail->pbData, cb))
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
} // FLpstmWriteVT_CF
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FLpstmWriteVT_I2
|
|
//
|
|
// Purpose:
|
|
// Writes a VT_I2 to the stream
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOL PASCAL
|
|
FLpstmWriteVT_I2
|
|
(LPSTREAM lpStm, // Pointer to stream
|
|
WORD w) // Word to write out
|
|
{
|
|
BYTE rgb[2*sizeof(DWORD)];
|
|
|
|
*(DWORD *) &rgb[0] = VT_I2; // The type
|
|
*(DWORD *) &rgb[sizeof(DWORD)] = 0; // clear out the space
|
|
*(WORD *) &rgb[sizeof(DWORD)] = w; // The value itself, but on a 32-bit boundary
|
|
|
|
return(FLpstmWrite (lpStm, rgb, sizeof(rgb)));
|
|
|
|
} // FLpstmWriteVT_I2
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FLpstmReadVT_I2
|
|
//
|
|
// Purpose:
|
|
// Reads a VT_I2 from the stream.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOL PASCAL
|
|
FLpstmReadVT_I2
|
|
(LPSTREAM lpStm, // Pointer to stream
|
|
WORD *pw) // Pointer to word to read data into
|
|
{
|
|
HRESULT hr;
|
|
WORD w;
|
|
|
|
// Read the word itself
|
|
hr = lpStm->lpVtbl->Read (lpStm, pw, sizeof(WORD), NULL);
|
|
if (!SUCCEEDED (hr))
|
|
{
|
|
DebugHr (hr);
|
|
return FALSE;
|
|
}
|
|
|
|
// Read the extra 2 byte padding
|
|
lpStm->lpVtbl->Read (lpStm, &w, sizeof(WORD), NULL);
|
|
if (!SUCCEEDED (hr))
|
|
{
|
|
DebugHr (hr);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
} // FLpstmReadVT_I2
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FLpstmReadVT_BOOL
|
|
//
|
|
// Purpose:
|
|
// Read a VT_BOOL from the stream
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOL PASCAL
|
|
FLpstmReadVT_BOOL
|
|
(LPSTREAM lpStm, // Pointer to stream
|
|
WORD *fBool) // Flag indicating value
|
|
{
|
|
DWORD dw;
|
|
HRESULT hr;
|
|
|
|
hr = lpStm->lpVtbl->Read (lpStm, &dw, sizeof(DWORD), NULL);
|
|
if (!SUCCEEDED (hr))
|
|
{
|
|
DebugHr (hr);
|
|
return FALSE;
|
|
}
|
|
|
|
*fBool = (WORD) dw;
|
|
|
|
return TRUE;
|
|
|
|
} // FLpstmReadVT_BOOL
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FLpstmWriteVT_BOOL
|
|
//
|
|
// Purpose:
|
|
// Write a VT_BOOL to the stream
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOL PASCAL
|
|
FLpstmWriteVT_BOOL
|
|
(LPSTREAM lpStm, // Pointer to stream
|
|
WORD fBool) // Flag indicating value
|
|
{
|
|
DWORD rgdw[2];
|
|
|
|
rgdw[0] = VT_BOOL;
|
|
rgdw[1] = (DWORD) fBool;
|
|
|
|
// Remember that Bools align on 32-bit boundary
|
|
return(FLpstmWrite (lpStm, rgdw, sizeof(rgdw)));
|
|
|
|
} // FLpstmWriteVT_BOOL
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FLpstmReadVT_R8_DATE
|
|
//
|
|
// Purpose:
|
|
// Read a VT_R8 or VT_DATE from the stream
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOL PASCAL
|
|
FLpstmReadVT_R8_DATE
|
|
(LPSTREAM lpStm, // Pointer to stream
|
|
NUM *pdbl) // double to read into
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = lpStm->lpVtbl->Read (lpStm, pdbl, sizeof(NUM), NULL);
|
|
if (!SUCCEEDED (hr))
|
|
{
|
|
DebugHr (hr);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
} // FLpstmReadVT_R8_DATE
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FLpstmWriteVT_R8_DATE
|
|
//
|
|
// Purpose:
|
|
// Write a VT_R8 or VT_DATE to the stream
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOL PASCAL
|
|
FLpstmWriteVT_R8_DATE
|
|
(LPSTREAM lpStm, // Pointer to stream
|
|
NUM *pdbl, // double or date to write out
|
|
BOOL fDate) // Indicates if dbl is a date
|
|
{
|
|
DWORD rgdw[3];
|
|
|
|
rgdw[0] = (fDate) ? VT_DATE : VT_R8;
|
|
*(NUM *) &(rgdw[1]) = *pdbl;
|
|
|
|
return(FLpstmWrite (lpStm, &rgdw, sizeof(rgdw)));
|
|
|
|
} // FLpstmWriteVT_R8_DATE
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FLpstmReadVT_BLOB
|
|
//
|
|
// Purpose:
|
|
// Read a VT_BLOB from the stream.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOL PASCAL
|
|
FLpstmReadVT_BLOB
|
|
(LPSTREAM lpStm, // Stream
|
|
DWORD *pcb, // Number of bytes in blob
|
|
BYTE FAR * FAR *ppbData) // pointer to pointer to blob
|
|
{
|
|
if (!SUCCEEDED (lpStm->lpVtbl->Read (lpStm, pcb, sizeof (DWORD), NULL)))
|
|
return FALSE;
|
|
|
|
// A blob of size 0 is legit.
|
|
if (*pcb == 0)
|
|
{
|
|
*ppbData = NULL;
|
|
return TRUE;
|
|
}
|
|
|
|
if ((*ppbData = PvMemAlloc(*pcb)) == NULL)
|
|
{
|
|
// REVIEW: add alert
|
|
return FALSE;
|
|
}
|
|
|
|
if (!SUCCEEDED (lpStm->lpVtbl->Read (lpStm, *ppbData, *pcb, NULL)))
|
|
{
|
|
VFreeMemP(*ppbData, *pcb);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
} // FLpstmReadVT_BLOB
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FLpstmWriteVT_BLOB
|
|
//
|
|
// Purpose:
|
|
// Write a VT_BLOB to the stream
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOL PASCAL
|
|
FLpstmWriteVT_BLOB
|
|
(LPSTREAM lpStm, // Pointer to stream
|
|
DWORD cb, // Size of blob
|
|
BYTE *bData) // Pointer to blob data
|
|
{
|
|
DWORD rgdw[2];
|
|
|
|
rgdw[0] = VT_BLOB;
|
|
rgdw[1] = cb;
|
|
|
|
if (!FLpstmWrite (lpStm, &(rgdw[0]), 2*sizeof(DWORD)))
|
|
return FALSE;
|
|
|
|
return(FLpstmWrite (lpStm, bData, cb));
|
|
|
|
} // FLpstmWriteVT_BLOB
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FLpstmReadVT_CLSID
|
|
//
|
|
// Purpose:
|
|
// Read a VT_CLSID from the stream
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOL PASCAL
|
|
FLpstmReadVT_CLSID
|
|
(LPSTREAM lpStm, // Pointer to stream
|
|
CLSID *pClsId) // Pointer to CLSID
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = lpStm->lpVtbl->Read (lpStm, pClsId, sizeof(CLSID), NULL);
|
|
if (!SUCCEEDED (hr))
|
|
{
|
|
DebugHr (hr);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
} // FLpstmReadVT_CLSID
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FLpstmWriteVT_CLSID
|
|
//
|
|
// Purpose:
|
|
// Write a VT_CLSID to the stream
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOL PASCAL
|
|
FLpstmWriteVT_CLSID
|
|
(LPSTREAM lpStm,
|
|
CLSID *pClsId)
|
|
{
|
|
DWORD rgdw[5];
|
|
|
|
rgdw[0] = VT_CLSID;
|
|
*(CLSID *) &(rgdw[1]) = *pClsId;
|
|
|
|
return(FLpstmWrite (lpStm, rgdw, sizeof(rgdw)));
|
|
|
|
} // FLpstmWriteVT_CLSID
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FLpstmReadVT_VECTOR
|
|
//
|
|
// Purpose:
|
|
// Reads a VT_VECTOR of unknown type in to the unknown data
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
static BOOL PASCAL
|
|
FLpstmReadVT_VECTOR
|
|
(LPSTREAM lpStm, // Pointer to stream
|
|
DWORD irglpUnk, // Index of unknown data for vector
|
|
LPPROPIDTYPELP rglpUnk) // Array of unknowns
|
|
{
|
|
|
|
// REVIEW: What is this?
|
|
return TRUE;
|
|
|
|
} // FLpstmReadVT_VECTOR
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FLpstmReadUnknown
|
|
//
|
|
// Purpose:
|
|
// Read in unknown data into the array
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOL PASCAL
|
|
FLpstmReadUnknown
|
|
(LPSTREAM lpStm,
|
|
DWORD dwType, // Type to read
|
|
DWORD dwId, // The id being read
|
|
DWORD *pirglpUnk, // Current index into rglpUnk
|
|
LPPROPIDTYPELP rglpUnk) // Array of unknowns
|
|
|
|
{
|
|
HRESULT hr;
|
|
TCHAR *lpstz;
|
|
|
|
DebugSzdw ("Doh! Unknown PId %x in stream!", dwId);
|
|
|
|
rglpUnk[*pirglpUnk].dwType = dwType;
|
|
rglpUnk[*pirglpUnk].dwId = dwId;
|
|
|
|
if (dwType & VT_VECTOR)
|
|
{
|
|
if (!FLpstmReadVT_VECTOR (lpStm, *pirglpUnk, rglpUnk))
|
|
{
|
|
DebugSz ("Failed reading VT_VECTOR");
|
|
goto ReadFail;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (dwType)
|
|
{
|
|
case VT_LPSTR :
|
|
case VT_BSTR :
|
|
case VT_LPWSTR :
|
|
case VT_STREAM :
|
|
case VT_STORAGE :
|
|
case VT_STREAMED_OBJECT :
|
|
case VT_STORED_OBJECT :
|
|
case VT_BLOB_OBJECT :
|
|
// BUGBUG: Fix to take codepage param.
|
|
if (!FLpstmReadVT_LPTSTR (lpStm, &lpstz, NULL, dwType))
|
|
{
|
|
DebugSz ("Failed reading VT_LPSTR or similiar type");
|
|
goto ReadFail;
|
|
}
|
|
rglpUnk[*pirglpUnk].dwSize = CBBUF (lpstz);
|
|
rglpUnk[*pirglpUnk].lpvData = (void *) lpstz;
|
|
break;
|
|
|
|
case VT_FILETIME :
|
|
rglpUnk[*pirglpUnk].dwSize = sizeof (FILETIME);
|
|
rglpUnk[*pirglpUnk].lpvData = PvMemAlloc(sizeof (FILETIME));
|
|
|
|
hr = lpStm->lpVtbl->Read (lpStm, rglpUnk[*pirglpUnk].lpvData, sizeof (FILETIME), NULL);
|
|
if (!SUCCEEDED (hr))
|
|
{
|
|
DebugHr (hr);
|
|
goto ReadFail;
|
|
}
|
|
break;
|
|
|
|
case VT_I2 :
|
|
rglpUnk[*pirglpUnk].dwSize = sizeof (WORD);
|
|
if (!FLpstmReadVT_I2 (lpStm, (WORD *) &(rglpUnk[*pirglpUnk].lpvData)))
|
|
goto ReadFail;
|
|
break;
|
|
|
|
case VT_I4 :
|
|
case VT_R4 :
|
|
rglpUnk[*pirglpUnk].dwSize = sizeof (DWORD);
|
|
hr = lpStm->lpVtbl->Read (lpStm, &(rglpUnk[*pirglpUnk].lpvData), sizeof (DWORD), NULL);
|
|
if (!SUCCEEDED (hr))
|
|
{
|
|
DebugHr (hr);
|
|
goto ReadFail;
|
|
}
|
|
break;
|
|
|
|
case VT_CF :
|
|
rglpUnk[*pirglpUnk].lpvData = PvMemAlloc(sizeof(CLIPDATA));
|
|
|
|
hr = lpStm->lpVtbl->Read (lpStm, rglpUnk[*pirglpUnk].lpvData, sizeof (DWORD), NULL);
|
|
if (!SUCCEEDED (hr))
|
|
{
|
|
DebugHr (hr);
|
|
goto ReadFail;
|
|
}
|
|
|
|
rglpUnk[*pirglpUnk].dwSize = sizeof (CLIPDATA) + rglpUnk[*pirglpUnk].dwSize;
|
|
break;
|
|
|
|
case VT_BOOL :
|
|
rglpUnk[*pirglpUnk].dwSize = sizeof (DWORD);
|
|
if (!FLpstmReadVT_BOOL (lpStm, (WORD *) &(rglpUnk[*pirglpUnk].lpvData)))
|
|
goto ReadFail;
|
|
break;
|
|
|
|
case VT_R8 :
|
|
case VT_CY :
|
|
case VT_I8 :
|
|
case VT_DATE :
|
|
|
|
if ((rglpUnk[*pirglpUnk].lpvData = PvMemAlloc(sizeof(NUM))) == NULL)
|
|
goto ReadFail;
|
|
rglpUnk[*pirglpUnk].dwSize = sizeof (NUM);
|
|
|
|
if (!FLpstmReadVT_R8_DATE (lpStm, (NUM *)(rglpUnk[*pirglpUnk].lpvData)))
|
|
{
|
|
DebugSz ("Failed reading VT_R8 or VT_DATE");
|
|
goto ReadFail;
|
|
}
|
|
break;
|
|
|
|
case VT_BLOB :
|
|
if (!FLpstmReadVT_BLOB (lpStm, &(rglpUnk[*pirglpUnk].dwSize),
|
|
(BYTE **) &(rglpUnk[*pirglpUnk].lpvData)))
|
|
{
|
|
DebugSz ("Failed reading VT_BLOB or similiar type");
|
|
goto ReadFail;
|
|
}
|
|
break;
|
|
|
|
case VT_CLSID :
|
|
rglpUnk[*pirglpUnk].dwSize = sizeof(CLSID);
|
|
rglpUnk[*pirglpUnk].lpvData = PvMemAlloc(sizeof(CLSID));
|
|
if (rglpUnk[*pirglpUnk].lpvData == NULL)
|
|
goto ReadFail;
|
|
if (!FLpstmReadVT_CLSID (lpStm, (CLSID *) rglpUnk[*pirglpUnk].lpvData))
|
|
goto ReadFail;
|
|
break;
|
|
case VT_EMPTY :
|
|
case VT_NULL :
|
|
rglpUnk[*pirglpUnk].dwSize = 0;
|
|
break;
|
|
} // switch
|
|
}
|
|
|
|
(*pirglpUnk)++;
|
|
return TRUE;
|
|
|
|
ReadFail :
|
|
|
|
return FALSE;
|
|
|
|
} // FLpstmReadUnknown
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FLpstmWriteUnknowns
|
|
//
|
|
// Purpose:
|
|
// Write out the unknown data in the array.
|
|
//
|
|
// Note:
|
|
// Some of the stuff here is special-cased, and doesn't use the normal
|
|
// write routines, because some of the types we don't normally use are
|
|
// easier to lump together here.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOL PASCAL
|
|
FLpstmWriteUnknowns
|
|
(LPSTREAM lpStm,
|
|
DWORD dwcUnk,
|
|
LPPROPIDTYPELP rglpUnk)
|
|
{
|
|
DWORD irg;
|
|
DWORD rgdw[3];
|
|
BOOL f;
|
|
|
|
// REVIEW: Need to update to do all of the types.....
|
|
|
|
for (irg = 0; irg < dwcUnk; irg++)
|
|
{
|
|
switch (rglpUnk[irg].dwType)
|
|
{
|
|
case VT_LPSTR :
|
|
case VT_BSTR :
|
|
case VT_LPWSTR :
|
|
case VT_STREAM :
|
|
case VT_STORAGE :
|
|
case VT_STREAMED_OBJECT :
|
|
case VT_STORED_OBJECT :
|
|
case VT_BLOB_OBJECT :
|
|
f = FLpstmWriteVT_LPTSTR (lpStm, (LPTSTR) rglpUnk[irg].lpvData, TRUE, rglpUnk[irg].dwType);
|
|
break;
|
|
case VT_I2 :
|
|
f = FLpstmWriteVT_I2 (lpStm, (WORD) rglpUnk[irg].lpvData);
|
|
break;
|
|
case VT_I4 :
|
|
case VT_R4 :
|
|
rgdw[0] = rglpUnk[irg].dwType;
|
|
rgdw[1] = (DWORD) rglpUnk[irg].lpvData;
|
|
f = FLpstmWrite (lpStm, rgdw, 2*sizeof(DWORD));
|
|
break;
|
|
case VT_FILETIME :
|
|
f = FLpstmWriteVT_FILETIME (lpStm, (LPFILETIME) rglpUnk[irg].lpvData);
|
|
break;
|
|
case VT_CF :
|
|
f = FLpstmWriteVT_CF (lpStm, (LPSINAIL) rglpUnk[irg].lpvData);
|
|
break;
|
|
case VT_BOOL :
|
|
f = FLpstmWriteVT_BOOL (lpStm, (WORD) rglpUnk[irg].lpvData);
|
|
break;
|
|
case VT_R8 :
|
|
case VT_CY :
|
|
case VT_I8 :
|
|
case VT_DATE :
|
|
rgdw[0] = rglpUnk[irg].dwType;
|
|
*(NUM *) &(rgdw[1]) = *(NUM *) rglpUnk[irg].lpvData;
|
|
f = FLpstmWrite (lpStm, rgdw, sizeof(rgdw));
|
|
break;
|
|
case VT_BLOB :
|
|
f = FLpstmWriteVT_BLOB (lpStm, rglpUnk[irg].dwSize, rglpUnk[irg].lpvData);
|
|
break;
|
|
case VT_CLSID :
|
|
f = FLpstmWriteVT_CLSID (lpStm, (CLSID *) rglpUnk[irg].lpvData);
|
|
break;
|
|
case VT_EMPTY :
|
|
case VT_NULL :
|
|
f = FLpstmWrite (lpStm, &(rglpUnk[irg].dwType), sizeof(DWORD));
|
|
break;
|
|
default:
|
|
AssertSz (0, "Doh! Unknown type!");
|
|
} // switch
|
|
|
|
if (!f)
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
} // FLpstmWriteUnknowns
|
|
|
|
static BYTE *lpOlePropBuf; // Buffer to hold data
|
|
static DWORD cbOlePropBuf; // Current cb into buffer
|
|
static ULARGE_INTEGER cbTotWritten; // Total count of bytes written to the stream
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// VAllocWriteBuf
|
|
//
|
|
// Purpose:
|
|
// Allocate a buffer to hold all the data that will eventually get written
|
|
// out to the stream.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void VAllocWriteBuf(void)
|
|
{
|
|
// No need to check to see if this works since all other places
|
|
// that access lpOlePropBuf need to check for NULL anyway.
|
|
lpOlePropBuf = PvMemAlloc(BUFMAX);
|
|
cbOlePropBuf = 0;
|
|
cbTotWritten.LowPart = 0;
|
|
cbTotWritten.HighPart = 0;
|
|
}
|
|
|
|
// Free the buffer
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// VFreeWriteBuf
|
|
//
|
|
// Purpose:
|
|
// Free the buffer that holds all the data that will eventually get written
|
|
// out to the stream.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void VFreeWriteBuf(void)
|
|
{
|
|
if(lpOlePropBuf!=NULL)
|
|
{
|
|
VFreeMemP(lpOlePropBuf, BUFMAX);
|
|
lpOlePropBuf = NULL;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FFlushWriteBuf
|
|
//
|
|
// Purpose:
|
|
// Actually write data to the stream.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOL FFlushWriteBuf(LPSTREAM lpStm)
|
|
{
|
|
HRESULT hr;
|
|
if ((lpOlePropBuf != NULL) && (cbOlePropBuf))
|
|
{
|
|
hr = lpStm->lpVtbl->Write (lpStm, lpOlePropBuf, cbOlePropBuf, NULL);
|
|
if (!SUCCEEDED (hr))
|
|
{
|
|
DebugHr (hr);
|
|
return fFalse;
|
|
}
|
|
cbOlePropBuf = 0;
|
|
}
|
|
return fTrue;
|
|
}
|
|
|
|
//
|
|
// VSetRealStmSize
|
|
//
|
|
// Sets the stream size to be the actual count of bytes written.
|
|
//
|
|
// This should only be done if we are doing a normal save, i.e. not if
|
|
// we are doing a Simple Doc File save.
|
|
//
|
|
void VSetRealStmSize(LPSTREAM lpStm)
|
|
{
|
|
lpStm->lpVtbl->SetSize(lpStm, cbTotWritten);
|
|
cbTotWritten.LowPart = 0;
|
|
cbTotWritten.HighPart = 0;
|
|
}
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FLpstmWrite
|
|
//
|
|
// Purpose:
|
|
// Writes data to the buffer, eventually writing to the stream.
|
|
//
|
|
// In low memory conditions where lpfnAlloc fails, this will write
|
|
// directly to the stream.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOL PASCAL
|
|
FLpstmWrite
|
|
(LPSTREAM lpStm, // Pointer to stream
|
|
LPVOID lpv, // Pointer to data to write
|
|
DWORD cb) // Size of lpv
|
|
{
|
|
HRESULT hr;
|
|
|
|
Assert ((lpStm != NULL));
|
|
Assert ((lpv != NULL));
|
|
Assert ((cb > 0));
|
|
|
|
if (lpOlePropBuf != NULL)
|
|
{
|
|
// We're not going to bother with splitting data across a buffer,
|
|
// we'll just flush the current buffer if the new data would fill it.
|
|
if (cbOlePropBuf+cb > BUFMAX)
|
|
{
|
|
hr = lpStm->lpVtbl->Write (lpStm, lpOlePropBuf, cbOlePropBuf, NULL);
|
|
|
|
// We're not going to allow a retry, so reset the buffer
|
|
// regardless of if we fail.
|
|
cbOlePropBuf = 0;
|
|
|
|
if (!SUCCEEDED (hr))
|
|
{
|
|
DebugHr (hr);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (cb < BUFMAX)
|
|
{
|
|
PbMemCopy ((lpOlePropBuf+cbOlePropBuf), lpv, cb);
|
|
cbOlePropBuf += cb;
|
|
}
|
|
else
|
|
{
|
|
// The size of the data is bigger than our buffer, so write
|
|
// the data directly.
|
|
hr = lpStm->lpVtbl->Write (lpStm, lpv, cb, NULL);
|
|
if (!SUCCEEDED (hr))
|
|
{
|
|
DebugHr (hr);
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DebugSz ("Either memory is really low or the buffer wasn't init'd by the client");
|
|
|
|
// Low memory save case (or someone forgot to init the buffer)
|
|
hr = lpStm->lpVtbl->Write (lpStm, lpv, cb, NULL);
|
|
if (!SUCCEEDED (hr))
|
|
{
|
|
DebugHr (hr);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
cbTotWritten.LowPart += cb;
|
|
return TRUE;
|
|
|
|
} // FLpstmWrite
|
|
|
|
|