//*@@@+++@@@@****************************************************************** // // Copyright © Microsoft Corp. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // • Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // • Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. // //*@@@---@@@@****************************************************************** #include "JXRMeta.h" #include "JXRGlue.h" // read and write big and little endian words/dwords from a buffer on both big and little endian cpu's // with full buffer overflow checking ERR getbfcpy(U8* pbdest, const U8* pb, size_t cb, size_t ofs, U32 n) { ERR err = WMP_errSuccess; FailIf(ofs + n > cb, WMP_errBufferOverflow); memcpy(pbdest, &pb[ofs], n); Cleanup: return err; } ERR getbfw(const U8* pb, size_t cb, size_t ofs, U16* pw) { ERR err = WMP_errSuccess; FailIf(ofs + sizeof(U16) > cb, WMP_errBufferOverflow); *pw = (U16)( pb[ofs] + ( pb[ofs + 1] << 8 ) ); Cleanup: return err; } ERR getbfdw(const U8* pb, size_t cb, size_t ofs, U32* pdw) { ERR err = WMP_errSuccess; FailIf(ofs + sizeof(U32) > cb, WMP_errBufferOverflow); *pdw = pb[ofs] + ( pb[ofs + 1] << 8 ) + ( pb[ofs + 2] << 16UL ) + ( pb[ofs + 3] << 24UL ); Cleanup: return err; } ERR getbfwbig(const U8* pb, size_t cb, size_t ofs, U16* pw) { ERR err = WMP_errSuccess; FailIf(ofs + sizeof(U16) > cb, WMP_errBufferOverflow); *pw = (U16)( pb[ofs + 1] + ( pb[ofs] << 8 ) ); Cleanup: return err; } ERR getbfdwbig(const U8* pb, size_t cb, size_t ofs, U32* pdw) { ERR err = WMP_errSuccess; FailIf(ofs + sizeof(U32) > cb, WMP_errBufferOverflow); *pdw = pb[ofs + 3] + ( pb[ofs + 2] << 8 ) + ( pb[ofs + 1] << 16UL ) + ( pb[ofs] << 24UL ); Cleanup: return err; } ERR getbfwe(const U8* pb, size_t cb, size_t ofs, U16* pw, U8 endian) { if ( endian == WMP_INTEL_ENDIAN ) return ( getbfw(pb, cb, ofs, pw) ); else return ( getbfwbig(pb, cb, ofs, pw) ); } ERR getbfdwe(const U8* pb, size_t cb, size_t ofs, U32* pdw, U8 endian) { if ( endian == WMP_INTEL_ENDIAN ) return ( getbfdw(pb, cb, ofs, pdw) ); else return ( getbfdwbig(pb, cb, ofs, pdw) ); } ERR setbfcpy(U8* pb, size_t cb, size_t ofs, const U8* pbset, size_t cbset) { ERR err = WMP_errSuccess; FailIf(ofs + cbset > cb, WMP_errBufferOverflow); memcpy(&pb[ofs], pbset, cbset); Cleanup: return err; } ERR setbfw(U8* pb, size_t cb, size_t ofs, U16 dw) { ERR err = WMP_errSuccess; FailIf(ofs + sizeof(U16) > cb, WMP_errBufferOverflow); pb[ofs] = (U8)dw; pb[ofs + 1] = (U8)( dw >> 8 ); Cleanup: return err; } ERR setbfdw(U8* pb, size_t cb, size_t ofs, U32 dw) { ERR err = WMP_errSuccess; FailIf(ofs + sizeof(U32) > cb, WMP_errBufferOverflow); pb[ofs] = (U8)dw; pb[ofs + 1] = (U8)( dw >> 8 ); pb[ofs + 2] = (U8)( dw >> 16 ); pb[ofs + 3] = (U8)( dw >> 24 ); Cleanup: return err; } ERR setbfwbig(U8* pb, size_t cb, size_t ofs, U16 dw) { ERR err = WMP_errSuccess; FailIf(ofs + sizeof(U16) > cb, WMP_errBufferOverflow); pb[ofs + 1] = (U8)dw; pb[ofs] = (U8)( dw >> 8 ); Cleanup: return err; } ERR setbfdwbig(U8* pb, size_t cb, size_t ofs, U32 dw) { ERR err = WMP_errSuccess; FailIf(ofs + sizeof(U32) > cb, WMP_errBufferOverflow); pb[ofs + 3] = (U8)dw; pb[ofs + 2] = (U8)( dw >> 8 ); pb[ofs + 1] = (U8)( dw >> 16 ); pb[ofs] = (U8)( dw >> 24 ); Cleanup: return err; } //================================================================ // BufferCalcIFDSize (arbitrary endian) // StreamCalcIFDSize (little endian) // // count up the number of bytes needed to store the IFD and all // associated data including a subordinate interoperability IFD if any //================================================================ ERR BufferCalcIFDSize(const U8* pbdata, size_t cbdata, U32 ofsifd, U8 endian, U32* pcbifd) { ERR err = WMP_errSuccess; U16 cDir; U16 i; U32 ofsdir; U32 cbifd = 0; U32 cbEXIFIFD = 0; U32 cbGPSInfoIFD = 0; U32 cbInteroperabilityIFD = 0; *pcbifd = 0; Call(getbfwe(pbdata, cbdata, ofsifd, &cDir, endian)); cbifd = sizeof(U16) + cDir * SizeofIFDEntry + sizeof(U32); ofsdir = ofsifd + sizeof(U16); for ( i = 0; i < cDir; i++ ) { U16 tag; U16 type; U32 count; U32 value; U32 datasize; Call(getbfwe(pbdata, cbdata, ofsdir, &tag, endian)); Call(getbfwe(pbdata, cbdata, ofsdir + sizeof(U16), &type, endian)); Call(getbfdwe(pbdata, cbdata, ofsdir + 2 * sizeof(U16), &count, endian)); Call(getbfdwe(pbdata, cbdata, ofsdir + 2 * sizeof(U16) + sizeof(U32), &value, endian)); FailIf(type == 0 || type >= sizeof(IFDEntryTypeSizes) / sizeof(IFDEntryTypeSizes[0]), WMP_errFail); if ( tag == WMP_tagEXIFMetadata ) { Call(BufferCalcIFDSize(pbdata, cbdata, value, endian, &cbEXIFIFD)); } else if ( tag == WMP_tagGPSInfoMetadata ) { Call(BufferCalcIFDSize(pbdata, cbdata, value, endian, &cbGPSInfoIFD)); } else if ( tag == WMP_tagInteroperabilityIFD ) { Call(BufferCalcIFDSize(pbdata, cbdata, value, endian, &cbInteroperabilityIFD)); } else { datasize = IFDEntryTypeSizes[type] * count; if ( datasize > 4 ) cbifd += datasize; } ofsdir += SizeofIFDEntry; } if ( cbEXIFIFD != 0 ) cbifd += ( cbifd & 1 ) + cbEXIFIFD; if ( cbGPSInfoIFD != 0 ) cbifd += ( cbifd & 1 ) + cbGPSInfoIFD; if ( cbInteroperabilityIFD != 0 ) cbifd += ( cbifd & 1 ) + cbInteroperabilityIFD; *pcbifd = cbifd; Cleanup: return err; } ERR StreamCalcIFDSize(struct WMPStream* pWS, U32 uIFDOfs, U32 *pcbifd) { ERR err = WMP_errSuccess; size_t offCurPos = 0; Bool GetPosOK = FALSE; U16 cDir; U32 i; U32 ofsdir; U32 cbifd = 0; U32 cbEXIFIFD = 0; U32 cbGPSInfoIFD = 0; U32 cbInteroperabilityIFD = 0; *pcbifd = 0; Call(pWS->GetPos(pWS, &offCurPos)); GetPosOK = TRUE; Call(GetUShort(pWS, uIFDOfs, &cDir)); cbifd = sizeof(U16) + cDir * SizeofIFDEntry + sizeof(U32); ofsdir = uIFDOfs + sizeof(U16); for ( i = 0; i < cDir; i++ ) { U16 tag; U16 type; U32 count; U32 value; U32 datasize; Call(GetUShort(pWS, ofsdir, &tag)); Call(GetUShort(pWS, ofsdir + sizeof(U16), &type)); Call(GetULong(pWS, ofsdir + 2 * sizeof(U16), &count)); Call(GetULong(pWS, ofsdir + 2 * sizeof(U16) + sizeof(U32), &value)); FailIf(type == 0 || type >= sizeof(IFDEntryTypeSizes) / sizeof(IFDEntryTypeSizes[0]), WMP_errUnsupportedFormat); if ( tag == WMP_tagEXIFMetadata ) { Call(StreamCalcIFDSize(pWS, value, &cbEXIFIFD)); } else if ( tag == WMP_tagGPSInfoMetadata ) { Call(StreamCalcIFDSize(pWS, value, &cbGPSInfoIFD)); } else if ( tag == WMP_tagInteroperabilityIFD ) { Call(StreamCalcIFDSize(pWS, value, &cbInteroperabilityIFD)); } else { datasize = IFDEntryTypeSizes[type] * count; if ( datasize > 4 ) cbifd += datasize; } ofsdir += SizeofIFDEntry; } if ( cbEXIFIFD != 0 ) cbifd += ( cbifd & 1 ) + cbEXIFIFD; if ( cbGPSInfoIFD != 0 ) cbifd += ( cbifd & 1 ) + cbGPSInfoIFD; if ( cbInteroperabilityIFD != 0 ) cbifd += ( cbifd & 1 ) + cbInteroperabilityIFD; *pcbifd = cbifd; Cleanup: if ( GetPosOK ) Call(pWS->SetPos(pWS, offCurPos)); return ( err ); } // src IFD copied to dst IFD with any nested IFD's // src IFD is arbitrary endian, arbitrary data arrangement // dst IFD is little endian, data arranged in tag order // dst IFD tags are ordered the same as src IFD so src IFD tags must be in order ERR BufferCopyIFD(const U8* pbsrc, U32 cbsrc, U32 ofssrc, U8 endian, U8* pbdst, U32 cbdst, U32* pofsdst) { ERR err = WMP_errSuccess; U16 cDir; U16 i; U16 ofsEXIFIFDEntry = 0; U16 ofsGPSInfoIFDEntry = 0; U16 ofsInteroperabilityIFDEntry = 0; U32 ofsEXIFIFD = 0; U32 ofsGPSInfoIFD = 0; U32 ofsInteroperabilityIFD = 0; U32 ofsdstnextdata; U32 ofsdst = *pofsdst; U32 ofssrcdir; U32 ofsdstdir; U32 ofsnextifd; Call(getbfwe(pbsrc, cbsrc, ofssrc, &cDir, endian)); Call(setbfw(pbdst, cbdst, ofsdst, cDir)); ofsnextifd = ofsdst + sizeof(U16) + SizeofIFDEntry * cDir; ofsdstnextdata = ofsnextifd + sizeof(U32); ofssrcdir = ofssrc + sizeof(U16); ofsdstdir = ofsdst + sizeof(U16); for ( i = 0; i < cDir; i++ ) { U16 tag; U16 type; U32 count; U32 value; U32 size; Call(getbfwe(pbsrc, cbsrc, ofssrcdir, &tag, endian)); Call(setbfw(pbdst, cbdst, ofsdstdir, tag)); Call(getbfwe(pbsrc, cbsrc, ofssrcdir + sizeof(U16), &type, endian)); Call(setbfw(pbdst, cbdst, ofsdstdir + sizeof(U16), type)); Call(getbfdwe(pbsrc, cbsrc, ofssrcdir + 2 * sizeof(U16), &count, endian)); Call(setbfdw(pbdst, cbdst, ofsdstdir + 2 * sizeof(U16), count)); Call(getbfdwe(pbsrc, cbsrc, ofssrcdir + 2 * sizeof(U16) + sizeof(U32), &value, endian)); Call(setbfdw(pbdst, cbdst, ofsdstdir + 2 * sizeof(U16) + sizeof(U32), 0)); FailIf(type == 0 || type >= sizeof(IFDEntryTypeSizes) / sizeof(IFDEntryTypeSizes[0]), WMP_errFail); if ( tag == WMP_tagEXIFMetadata ) { ofsEXIFIFDEntry = (U16) ofsdstdir; ofsEXIFIFD = value; } else if ( tag == WMP_tagGPSInfoMetadata ) { ofsGPSInfoIFDEntry = (U16) ofsdstdir; ofsGPSInfoIFD = value; } else if ( tag == WMP_tagInteroperabilityIFD ) { ofsInteroperabilityIFDEntry = (U16) ofsdstdir; ofsInteroperabilityIFD = value; } else { U32 ofsdstdata = ofsdstdir + 2 * sizeof(U16) + sizeof(U32); U32 ofssrcdata = ofssrcdir + 2 * sizeof(U16) + sizeof(U32); size = count * IFDEntryTypeSizes[type]; if ( size > 4 ) { ofssrcdata = value; Call(setbfdw(pbdst, cbdst, ofsdstdata, ofsdstnextdata)); ofsdstdata = ofsdstnextdata; ofsdstnextdata += size; } FailIf(ofssrcdata + size > cbsrc || ofsdstdata + size > cbdst, WMP_errBufferOverflow); if ( size == count || endian == WMP_INTEL_ENDIAN ) // size == count means 8-bit data means endian doesn't matter memcpy(&pbdst[ofsdstdata], &pbsrc[ofssrcdata], size); else { // big endian source and endian matters U32 j; switch ( IFDEntryTypeSizes[type] ) { case 2: for ( j = 0; j < count; j++ ) { U16 w; getbfwbig(pbsrc, cbsrc, ofssrcdata + j * sizeof(U16), &w); setbfw(pbdst, cbdst, ofsdstdata + j * sizeof(U16), w); } break; case 8: if ( type == WMP_typDOUBLE ) { for ( j = 0; j < count; j++ ) { U32 dwlo; U32 dwhi; getbfdwbig(pbsrc, cbsrc, ofssrcdata + j * 8, &dwhi); getbfdwbig(pbsrc, cbsrc, ofssrcdata + j * 8 + sizeof(U32), &dwlo); setbfdw(pbdst, cbdst, ofsdstdata + j * 8, dwlo); setbfdw(pbdst, cbdst, ofsdstdata + j * 8 + sizeof(U32), dwhi); } break; } count *= 2; // RATIONAL's fall through to be handled as LONG's case 4: for ( j = 0; j < count; j++ ) { U32 dw; getbfdwbig(pbsrc, cbsrc, ofssrcdata + j * sizeof(U32), &dw); setbfdw(pbdst, cbdst, ofsdstdata + j * sizeof(U32), dw); } break; } } } ofssrcdir += SizeofIFDEntry; ofsdstdir += SizeofIFDEntry; } Call(setbfdw(pbdst, cbdst, ofsnextifd, 0)); // no nextIFD if ( ofsEXIFIFDEntry != 0 ) { ofsdstnextdata += ( ofsdstnextdata & 1 ); Call(setbfdw(pbdst, cbdst, ofsEXIFIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata)); Call(BufferCopyIFD(pbsrc, cbsrc, ofsEXIFIFD, endian, pbdst, cbdst, &ofsdstnextdata)); } if ( ofsGPSInfoIFDEntry != 0 ) { ofsdstnextdata += ( ofsdstnextdata & 1 ); Call(setbfdw(pbdst, cbdst, ofsGPSInfoIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata)); Call(BufferCopyIFD(pbsrc, cbsrc, ofsGPSInfoIFD, endian, pbdst, cbdst, &ofsdstnextdata)); } if ( ofsInteroperabilityIFDEntry != 0 ) { ofsdstnextdata += ( ofsdstnextdata & 1 ); Call(setbfdw(pbdst, cbdst, ofsInteroperabilityIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata)); Call(BufferCopyIFD(pbsrc, cbsrc, ofsInteroperabilityIFD, endian, pbdst, cbdst, &ofsdstnextdata)); } *pofsdst = ofsdstnextdata; Cleanup: return err; } // src IFD copied to dst IFD with any nested IFD's // src IFD is little endian, arbitrary data arrangement // dst IFD is little endian, data arranged in tag order // dst IFD tags are ordered the same as src IFD so src IFD tags must be in order ERR StreamCopyIFD(struct WMPStream* pWS, U32 ofssrc, U8* pbdst, U32 cbdst, U32* pofsdst) { ERR err = WMP_errSuccess; size_t offCurPos = 0; Bool GetPosOK = FALSE; U16 cDir; U16 i; U16 ofsEXIFIFDEntry = 0; U16 ofsGPSInfoIFDEntry = 0; U16 ofsInteroperabilityIFDEntry = 0; U32 ofsEXIFIFD = 0; U32 ofsGPSInfoIFD = 0; U32 ofsInteroperabilityIFD = 0; U32 ofsdstnextdata; U32 ofsdst = *pofsdst; U32 ofssrcdir; U32 ofsdstdir; U32 ofsnextifd; Call(pWS->GetPos(pWS, &offCurPos)); GetPosOK = TRUE; Call(GetUShort(pWS, ofssrc, &cDir)); Call(setbfw(pbdst, cbdst, ofsdst, cDir)); ofsnextifd = ofsdst + sizeof(U16) + SizeofIFDEntry * cDir; ofsdstnextdata = ofsnextifd + sizeof(U32); ofssrcdir = ofssrc + sizeof(U16); ofsdstdir = ofsdst + sizeof(U16); for ( i = 0; i < cDir; i++ ) { U16 tag; U16 type; U32 count; U32 value; U32 size; Call(GetUShort(pWS, ofssrcdir, &tag)); Call(setbfw(pbdst, cbdst, ofsdstdir, tag)); Call(GetUShort(pWS, ofssrcdir + sizeof(U16), &type)); Call(setbfw(pbdst, cbdst, ofsdstdir + sizeof(U16), type)); Call(GetULong(pWS, ofssrcdir + 2 * sizeof(U16), &count)); Call(setbfdw(pbdst, cbdst, ofsdstdir + 2 * sizeof(U16), count)); Call(GetULong(pWS, ofssrcdir + 2 * sizeof(U16) + sizeof(U32), &value)); Call(setbfdw(pbdst, cbdst, ofsdstdir + 2 * sizeof(U16) + sizeof(U32), 0)); FailIf(type == 0 || type >= sizeof(IFDEntryTypeSizes) / sizeof(IFDEntryTypeSizes[0]), WMP_errFail); if ( tag == WMP_tagEXIFMetadata ) { ofsEXIFIFDEntry = (U16) ofsdstdir; ofsEXIFIFD = value; } else if ( tag == WMP_tagGPSInfoMetadata ) { ofsGPSInfoIFDEntry = (U16) ofsdstdir; ofsGPSInfoIFD = value; } else if ( tag == WMP_tagInteroperabilityIFD ) { ofsInteroperabilityIFDEntry = (U16) ofsdstdir; ofsInteroperabilityIFD = value; } else { U32 ofsdstdata = ofsdstdir + 2 * sizeof(U16) + sizeof(U32); U32 ofssrcdata = ofssrcdir + 2 * sizeof(U16) + sizeof(U32); size = count * IFDEntryTypeSizes[type]; if ( size > 4 ) { ofssrcdata = value; Call(setbfdw(pbdst, cbdst, ofsdstdata, ofsdstnextdata)); ofsdstdata = ofsdstnextdata; ofsdstnextdata += size; } FailIf(ofsdstdata + size > cbdst, WMP_errBufferOverflow); Call(pWS->SetPos(pWS, ofssrcdata)); Call(pWS->Read(pWS, &pbdst[ofsdstdata], size)); } ofssrcdir += SizeofIFDEntry; ofsdstdir += SizeofIFDEntry; } Call(setbfdw(pbdst, cbdst, ofsnextifd, 0)); // no nextIFD if ( ofsEXIFIFDEntry != 0 ) { ofsdstnextdata += ( ofsdstnextdata & 1 ); Call(setbfdw(pbdst, cbdst, ofsEXIFIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata)); Call(StreamCopyIFD(pWS, ofsEXIFIFD, pbdst, cbdst, &ofsdstnextdata)); } if ( ofsGPSInfoIFDEntry != 0 ) { ofsdstnextdata += ( ofsdstnextdata & 1 ); Call(setbfdw(pbdst, cbdst, ofsGPSInfoIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata)); Call(StreamCopyIFD(pWS, ofsGPSInfoIFD, pbdst, cbdst, &ofsdstnextdata)); } if ( ofsInteroperabilityIFDEntry != 0 ) { ofsdstnextdata += ( ofsdstnextdata & 1 ); Call(setbfdw(pbdst, cbdst, ofsInteroperabilityIFDEntry + 2 * sizeof(U16) + sizeof(U32), ofsdstnextdata)); Call(StreamCopyIFD(pWS, ofsInteroperabilityIFD, pbdst, cbdst, &ofsdstnextdata)); } *pofsdst = ofsdstnextdata; Cleanup: if ( GetPosOK ) Call(pWS->SetPos(pWS, offCurPos)); return err; } //================================================================ ERR GetUShort( __in_ecount(1) struct WMPStream* pWS, size_t offPos, __out_ecount(1) U16* puValue) { ERR err = WMP_errSuccess; U8 cVal; Call(pWS->SetPos(pWS, offPos)); Call(pWS->Read(pWS, &cVal, sizeof(cVal))); puValue[0] = (U16) cVal; Call(pWS->Read(pWS, &cVal, sizeof(cVal))); puValue[0] += ((U16) cVal) << 8; Cleanup: return err; } ERR PutUShort( __in_ecount(1) struct WMPStream* pWS, size_t offPos, U16 uValue) { ERR err = WMP_errSuccess; U8 cVal = (U8) uValue; Call(pWS->SetPos(pWS, offPos)); Call(pWS->Write(pWS, &cVal, sizeof(cVal))); cVal = (U8) (uValue >> 8); Call(pWS->Write(pWS, &cVal, sizeof(cVal))); Cleanup: return err; } ERR GetULong( __in_ecount(1) struct WMPStream* pWS, size_t offPos, __out_ecount(1) U32* puValue) { ERR err = WMP_errSuccess; U8 cVal; Call(pWS->SetPos(pWS, offPos)); Call(pWS->Read(pWS, &cVal, sizeof(cVal))); puValue[0] = (U32) cVal; Call(pWS->Read(pWS, &cVal, sizeof(cVal))); puValue[0] += ((U32) cVal) << 8; Call(pWS->Read(pWS, &cVal, sizeof(cVal))); puValue[0] += ((U32) cVal) << 16; Call(pWS->Read(pWS, &cVal, sizeof(cVal))); puValue[0] += ((U32) cVal) << 24; Cleanup: return err; } ERR PutULong( __in_ecount(1) struct WMPStream* pWS, size_t offPos, U32 uValue) { ERR err = WMP_errSuccess; U8 cVal = (U8) uValue; Call(pWS->SetPos(pWS, offPos)); Call(pWS->Write(pWS, &cVal, sizeof(cVal))); cVal = (U8) (uValue >> 8); Call(pWS->Write(pWS, &cVal, sizeof(cVal))); cVal = (U8) (uValue >> 16); Call(pWS->Write(pWS, &cVal, sizeof(cVal))); cVal = (U8) (uValue >> 24); Call(pWS->Write(pWS, &cVal, sizeof(cVal))); Cleanup: return err; } ERR ReadBinaryData(__in_ecount(1) struct WMPStream* pWS, const __in_win U32 uCount, const __in_win U32 uValue, U8 **ppbData) { ERR err = WMP_errSuccess; U8 *pbData = NULL; Call(PKAlloc((void **) &pbData, uCount + 2)); // Allocate buffer to store data with space for an added ascii or unicode null if (uCount <= 4) { unsigned int i; for (i = 0; i < uCount; i++) pbData[i] = ((U8*)&uValue)[i]; // Copy least sig bytes - we assume 'II' type TIFF files } else { size_t offPosPrev; Call(pWS->GetPos(pWS, &offPosPrev)); Call(pWS->SetPos(pWS, uValue)); Call(pWS->Read(pWS, pbData, uCount)); Call(pWS->SetPos(pWS, offPosPrev)); } *ppbData = pbData; Cleanup: if (Failed(err)) { if (pbData) PKFree((void **) &pbData); } return err; } ERR ReadPropvar(__in_ecount(1) struct WMPStream* pWS, const __in_win U16 uType, const __in_win U32 uCount, const __in_win U32 uValue, __out_win DPKPROPVARIANT *pvar) { ERR err = WMP_errSuccess; // U8 *pbData = NULL; memset(pvar, 0, sizeof(*pvar)); if (uCount == 0) goto Cleanup; // Nothing to read in here switch (uType) { case WMP_typASCII: pvar->vt = DPKVT_LPSTR; Call(ReadBinaryData(pWS, uCount, uValue, (U8 **) &pvar->VT.pszVal)); assert(0 == pvar->VT.pszVal[uCount - 1]); // Check that it's null-terminated // make sure (ReadBinaryData allocated uCount + 2 so this and unicode can have forced nulls) pvar->VT.pszVal[uCount] = 0; break; case WMP_typBYTE: case WMP_typUNDEFINED: // Return as regular C array rather than safearray, as this type is sometimes // used to convey unicode (which does not require a count field). Caller knows // uCount and can convert to safearray if necessary. pvar->vt = (DPKVT_BYREF | DPKVT_UI1); Call(ReadBinaryData(pWS, uCount, uValue, &pvar->VT.pbVal)); break; case WMP_typSHORT: if (1 == uCount) { pvar->vt = DPKVT_UI2; pvar->VT.uiVal = (U16)(uValue & 0x0000FFFF); } else if (2 == uCount) { pvar->vt = DPKVT_UI4; pvar->VT.ulVal = uValue; } else { assert(FALSE); // NYI FailIf(TRUE, WMP_errNotYetImplemented); } break; default: assert(FALSE); // Unhandled type FailIf(TRUE, WMP_errNotYetImplemented); break; } Cleanup: return err; } ERR WriteWmpDE( __in_ecount(1) struct WMPStream* pWS, size_t *pOffPos, const __in_ecount(1) WmpDE* pDE, const U8 *pbData, U32 *pcbDataWrittenToOffset) { ERR err = WMP_errSuccess; size_t offPos = *pOffPos; assert(-1 != pDE->uCount); assert(-1 != pDE->uValueOrOffset); if (pcbDataWrittenToOffset) { assert(pbData); // Makes no sense to provide this arg without pbData *pcbDataWrittenToOffset = 0; } Call(PutUShort(pWS, offPos, pDE->uTag)); offPos += 2; Call(PutUShort(pWS, offPos, pDE->uType)); offPos += 2; Call(PutULong(pWS, offPos, pDE->uCount)); offPos += 4; switch (pDE->uType) { case WMP_typASCII: case WMP_typUNDEFINED: case WMP_typBYTE: if (pDE->uCount <= 4) { U8 pad[4] = {0}; Call(pWS->SetPos(pWS, offPos)); if (NULL == pbData) pbData = (U8*)&pDE->uValueOrOffset; Call(pWS->Write(pWS, pbData, pDE->uCount)); Call(pWS->Write(pWS, pad, 4 - pDE->uCount)); offPos += 4; } else { Call(PutULong(pWS, offPos, pDE->uValueOrOffset)); offPos += 4; // Write the data if requested to do so if (pbData) { Call(pWS->SetPos(pWS, pDE->uValueOrOffset)); Call(pWS->Write(pWS, pbData, pDE->uCount)); Call(pWS->SetPos(pWS, offPos)); *pcbDataWrittenToOffset = pDE->uCount; } } break; case WMP_typSHORT: if (pDE->uCount <= 2) { U16 uiShrt1 = 0; U16 uiShrt2 = 0; if (NULL == pbData) pbData = (U8*)&pDE->uValueOrOffset; if (pDE->uCount > 0) uiShrt1 = *((U16*)pbData); if (pDE->uCount > 1) { assert(FALSE); // Untested - remove this assert after this has been tested uiShrt2 = *(U16*)(pbData + 2); } Call(PutUShort(pWS, offPos, uiShrt1)); offPos += 2; Call(PutUShort(pWS, offPos, uiShrt2)); offPos += 2; } else { assert(FALSE); // Untested - remove this assert after this has been tested Call(PutULong(pWS, offPos, pDE->uValueOrOffset)); offPos += 4; // Write the data if requested to do so if (pbData) { U32 i; Call(pWS->SetPos(pWS, pDE->uValueOrOffset)); for (i = 0; i < pDE->uCount; i++) { const U16 uiShort = *(U16*)(pbData + i*sizeof(U16)); Call(PutUShort(pWS, offPos, uiShort)); // Write one at a time for endian purposes - but inefficient } Call(pWS->SetPos(pWS, offPos)); *pcbDataWrittenToOffset = pDE->uCount * sizeof(U16); } } break; case WMP_typFLOAT: case WMP_typLONG: if (pDE->uCount <= 1) { if (NULL == pbData) pbData = (U8*)&pDE->uValueOrOffset; Call(PutULong(pWS, offPos, *(U32*)pbData)); offPos += 4; } else { assert(FALSE); // Untested - remove this assert after this has been tested Call(PutULong(pWS, offPos, pDE->uValueOrOffset)); offPos += 4; // Write the data if requested to do so if (pbData) { U32 i; Call(pWS->SetPos(pWS, pDE->uValueOrOffset)); for (i = 0; i < pDE->uCount; i++) { const U32 uLong = *(U32*)(pbData + i*sizeof(U32)); Call(PutULong(pWS, offPos, uLong)); // Write one at a time for endian purposes - but inefficient } Call(pWS->SetPos(pWS, offPos)); *pcbDataWrittenToOffset = pDE->uCount * sizeof(U32); } } break; default: assert(FALSE); // Alert the programmer Call(WMP_errInvalidParameter); break; } Cleanup: *pOffPos = offPos; return err; }