/* Copyright (c) Microsoft Corporation All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. */ #include DrPropertyReader::DrPropertyReader(DrByteArrayPtr byteArray) { m_status = S_OK; m_byteArray = byteArray; m_readPtr = 0; } HRESULT DrPropertyReader::SetStatus(HRESULT newStatus) { if (m_status == S_OK) { m_status = newStatus; } return m_status; } HRESULT DrPropertyReader::PeekNextPropertyTag(/* out */ UINT16 *pEnumId, /* out */ UINT32 *pDataLen) { if (PeekUInt16(pEnumId) != S_OK) { return m_status; } BYTE tmp[sizeof(UINT16) + sizeof(UINT32)]; if (((*pEnumId) & DrPropLengthMask) == DrPropLength_Short) { if (PeekBytes(tmp, sizeof(UINT16) + sizeof(UINT8)) == S_OK) { *pDataLen = tmp[sizeof(UINT16)]; } } else { if (PeekBytes(tmp, sizeof(UINT16) + sizeof(UINT32)) == S_OK) { memcpy(pDataLen, tmp+sizeof(UINT16), sizeof(UINT32)); } } return m_status; } HRESULT DrPropertyReader::PeekNextAggregateTag(/* out */ UINT16 *pValue) { UINT16 enumIdActual; UINT32 dataLenActual; UINT16 enumId = DrProp_BeginTag; UINT32 dataLen = sizeof(UINT16); if (PeekNextPropertyTag(&enumIdActual, &dataLenActual) == S_OK) { if (enumIdActual != enumId || dataLenActual != dataLen) { DrLogW("Mismatched property peek %u,%u %u,%u", enumIdActual, enumId, dataLenActual, dataLen); SetStatus(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); } else { UINT32 hdrLen = sizeof(UINT16) + sizeof(UINT8); BYTE prop[sizeof(UINT16) + sizeof(UINT8) + sizeof(UINT16)]; if (PeekBytes(prop, hdrLen + dataLen) == S_OK) { memcpy(pValue, prop + hdrLen, dataLen); } } } return m_status; } HRESULT DrPropertyReader::PeekBytes(/* out */ BYTE* pBytes, int length) { if (m_status != S_OK) { return m_status; } else if (length + m_readPtr > m_byteArray->Allocated()) { return SetStatus(HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)); } else { DRPIN(BYTE) srcPtr = &(m_byteArray[m_readPtr]); memcpy(pBytes, srcPtr, length); return S_OK; } } HRESULT DrPropertyReader::PeekUInt16(/* out */ UINT16 *pVal) { // assumes little endian return PeekBytes((BYTE *)(void *)pVal, sizeof(*pVal)); } HRESULT DrPropertyReader::SkipBytes(int length) { if (m_status != S_OK) { return m_status; } else if (length + m_readPtr > m_byteArray->Allocated()) { return SetStatus(HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)); } else { m_readPtr += length; return S_OK; } } HRESULT DrPropertyReader::ReadBytes(/* out */ BYTE* pBytes, int length) { if (m_status != S_OK) { return m_status; } else if (length + m_readPtr > m_byteArray->Allocated()) { return SetStatus(HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)); } else { DRPIN(BYTE) srcPtr = &(m_byteArray[m_readPtr]); memcpy(pBytes, srcPtr, length); m_readPtr += length; return S_OK; } } HRESULT DrPropertyReader::ReadUInt8(/* out */ UINT8 *pVal) { return ReadBytes((BYTE *)(void *)pVal, sizeof(*pVal)); } HRESULT DrPropertyReader::ReadUInt16(/* out */ UINT16 *pVal) { // assumes little endian return ReadBytes((BYTE *)(void *)pVal, sizeof(*pVal)); } HRESULT DrPropertyReader::ReadUInt32(/* out */ UINT32 *pVal) { // assumes little endian return ReadBytes((BYTE *)(void *)pVal, sizeof(*pVal)); } HRESULT DrPropertyReader::ReadNextPropertyTag(/* out */ UINT16 *pEnumId, /* out */ UINT32 *pDataLen) { if (ReadUInt16(pEnumId) != S_OK) { return m_status; } if (((*pEnumId) & DrPropLengthMask) == DrPropLength_Short) { UINT8 lengthByte; if (ReadUInt8(&lengthByte) == S_OK) { *pDataLen = lengthByte; } } else { ReadUInt32(pDataLen); } return m_status; } HRESULT DrPropertyReader::ReadNextProperty(UINT16 enumId, UINT32 dataLen, void *pDest) { UINT16 realEnumId; UINT32 realDataLen; if (ReadNextPropertyTag(&realEnumId, &realDataLen) == S_OK) { if (realEnumId != enumId || realDataLen != dataLen) { DrLogW("Mismatched property read %u,%u %u,%u", realEnumId, enumId, realDataLen, dataLen); SetStatus(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); } else { ReadBytes((BYTE*) pDest, dataLen); } } return m_status; } HRESULT DrPropertyReader::ReadNextProperty(UINT16 enumId) { return ReadNextProperty(enumId, 0, NULL); } #ifdef _MANAGED #define MAKEDRPROPREADER(_type) \ HRESULT DrPropertyReader::ReadNextProperty(UINT16 enumId, /* out */ _type %pValue) \ { \ _type tmp; \ if (ReadNextProperty(enumId, sizeof(_type), &tmp) == S_OK) \ { \ pValue = tmp; \ } \ return m_status; \ } #else #define MAKEDRPROPREADER(_type) \ HRESULT DrPropertyReader::ReadNextProperty(UINT16 enumId, /* out */ _type &pValue) \ { \ _type tmp; \ if (ReadNextProperty(enumId, sizeof(_type), &tmp) == S_OK) \ { \ pValue = tmp; \ } \ return m_status; \ } #endif MAKEDRPROPREADER(bool) MAKEDRPROPREADER(INT8) MAKEDRPROPREADER(INT16) MAKEDRPROPREADER(INT32) MAKEDRPROPREADER(INT64) MAKEDRPROPREADER(UINT8) MAKEDRPROPREADER(UINT16) MAKEDRPROPREADER(UINT32) MAKEDRPROPREADER(UINT64) MAKEDRPROPREADER(HRESULT) MAKEDRPROPREADER(float) MAKEDRPROPREADER(double) MAKEDRPROPREADER(GUID) HRESULT DrPropertyReader::ReadNextProperty(UINT16 enumId, /* out */ DrStringR pValue) { UINT32 length; UINT16 realEnumId; if (ReadNextPropertyTag(&realEnumId, &length) == S_OK) { if (realEnumId != enumId) { DrLogW("Mismatched string property read %u,%u", realEnumId, enumId); SetStatus(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); } else { if (length > 0) { DrByteArrayRef array = DrNew DrByteArray(length+1); { DRPIN(BYTE) dst = &(array[0]); if (SUCCEEDED(ReadBytes(dst, length))) { /* ensure there's a terminator just in case */ array[(int)length] = 0; DrString s; s.SetF("%s", (const char *) dst); pValue = s; return S_OK; } } } else { pValue = DrNull; } } } return m_status; } HRESULT DrPropertyReader::ReadAggregate(UINT16 desiredTagType, DrPropertyParserPtr parser) { HRESULT err; UINT16 beginTagType; if (ReadNextProperty(DrProp_BeginTag, sizeof(UINT16), &beginTagType) != S_OK) { return m_status; } if (beginTagType != desiredTagType) { DrLogW("Mismatched aggregate read %u,%u", beginTagType, desiredTagType); return SetStatus(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); } for (;;) { UINT16 propertyType; UINT32 dataLen; if (PeekNextPropertyTag(&propertyType, &dataLen) != S_OK) { return m_status; } // If we find an end tag, it must be for the begin tag we consumed if (propertyType == DrProp_EndTag) { UINT16 endTagType; // Consume it if (ReadNextProperty(DrProp_EndTag, endTagType) != S_OK) { return m_status; } if (desiredTagType != endTagType) { DrLogW("Mismatched aggregate end read %u,%u", desiredTagType, endTagType); return SetStatus(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); } // We're done return S_OK; } else { // This could be a begin tag - it's up to the caller to call ReadAggregate() // or SkipNextPropertyOrAggregate() err = parser->ParseProperty(this, propertyType, dataLen); if (err != S_OK) { return SetStatus(err); } } } } HRESULT DrPropertyReader::SkipNextProperty() { UINT16 enumId; UINT32 dataLen; if (ReadNextPropertyTag(&enumId, &dataLen) == S_OK) { SkipBytes(dataLen); } return m_status; } HRESULT DrPropertyReader::SkipNextPropertyOrAggregate() { UINT32 dataLen; UINT16 propertyType; UINT16 beginTagType; if (PeekNextPropertyTag(&propertyType, &dataLen) != S_OK) { return m_status; } // If it's not a begin tag, just skip the property and return if (propertyType != DrProp_BeginTag) { return SkipNextProperty(); } // Read the begin tag type if (ReadNextProperty(DrProp_BeginTag, beginTagType) != S_OK) { return m_status; } // Skip until corresponding end tag // If another BeginTag is encountered, recurse as appropriate for (;;) { if (PeekNextPropertyTag(&propertyType, &dataLen) != S_OK) { return m_status; } if (propertyType == DrProp_BeginTag) { if (SkipNextPropertyOrAggregate() != S_OK) { return m_status; } } else if (propertyType == DrProp_EndTag) { UINT16 endTagType; if (ReadNextProperty(DrProp_EndTag, endTagType) != S_OK) { return m_status; } if (endTagType != beginTagType) { DrLogW("Mismatched aggregate matchup %u,%u", endTagType, beginTagType); return SetStatus(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); } return S_OK; } else { if (SkipNextProperty() != S_OK) { return m_status; } } } } DrPropertyWriter::DrPropertyWriter() { m_buffer = DrNew DrByteArrayList(); } DrByteArrayRef DrPropertyWriter::GetBuffer() { DrByteArrayRef array = DrNew DrByteArray(m_buffer->Size()); int i; for (i=0; iSize(); ++i) { array[i] = m_buffer[i]; } return array; } void DrPropertyWriter::WriteByte(BYTE b) { m_buffer->Add(b); } void DrPropertyWriter::WriteBytes(BYTE* pBytes, int length) { int i; for (i=0; i= 0) { WriteBytes((BYTE *) string.GetChars(), length); WriteByte((BYTE)0); } } void DrPropertyWriter::WriteProperty(UINT16 enumId, UINT32 dataLen, BYTE* pDest) { WritePropertyTag(enumId, dataLen); WriteBytes(pDest, dataLen); }