1226584Sdim//===-- DataExtractor.cpp -------------------------------------------------===// 2226584Sdim// 3226584Sdim// The LLVM Compiler Infrastructure 4226584Sdim// 5226584Sdim// This file is distributed under the University of Illinois Open Source 6226584Sdim// License. See LICENSE.TXT for details. 7226584Sdim// 8226584Sdim//===----------------------------------------------------------------------===// 9226584Sdim 10226584Sdim#include "llvm/Support/DataExtractor.h" 11226584Sdim#include "llvm/Support/ErrorHandling.h" 12226584Sdim#include "llvm/Support/Host.h" 13226584Sdim#include "llvm/Support/SwapByteOrder.h" 14226584Sdimusing namespace llvm; 15226584Sdim 16226584Sdimtemplate <typename T> 17226584Sdimstatic T getU(uint32_t *offset_ptr, const DataExtractor *de, 18226584Sdim bool isLittleEndian, const char *Data) { 19226584Sdim T val = 0; 20226584Sdim uint32_t offset = *offset_ptr; 21226584Sdim if (de->isValidOffsetForDataOfSize(offset, sizeof(val))) { 22226584Sdim std::memcpy(&val, &Data[offset], sizeof(val)); 23251662Sdim if (sys::IsLittleEndianHost != isLittleEndian) 24226584Sdim val = sys::SwapByteOrder(val); 25226584Sdim 26226584Sdim // Advance the offset 27226584Sdim *offset_ptr += sizeof(val); 28226584Sdim } 29226584Sdim return val; 30226584Sdim} 31226584Sdim 32226584Sdimtemplate <typename T> 33226584Sdimstatic T *getUs(uint32_t *offset_ptr, T *dst, uint32_t count, 34226584Sdim const DataExtractor *de, bool isLittleEndian, const char *Data){ 35226584Sdim uint32_t offset = *offset_ptr; 36226584Sdim 37226584Sdim if (count > 0 && de->isValidOffsetForDataOfSize(offset, sizeof(*dst)*count)) { 38226584Sdim for (T *value_ptr = dst, *end = dst + count; value_ptr != end; 39226584Sdim ++value_ptr, offset += sizeof(*dst)) 40226584Sdim *value_ptr = getU<T>(offset_ptr, de, isLittleEndian, Data); 41226584Sdim // Advance the offset 42226584Sdim *offset_ptr = offset; 43226584Sdim // Return a non-NULL pointer to the converted data as an indicator of 44226584Sdim // success 45226584Sdim return dst; 46226584Sdim } 47226584Sdim return NULL; 48226584Sdim} 49226584Sdim 50226584Sdimuint8_t DataExtractor::getU8(uint32_t *offset_ptr) const { 51226584Sdim return getU<uint8_t>(offset_ptr, this, IsLittleEndian, Data.data()); 52226584Sdim} 53226584Sdim 54226584Sdimuint8_t * 55226584SdimDataExtractor::getU8(uint32_t *offset_ptr, uint8_t *dst, uint32_t count) const { 56226584Sdim return getUs<uint8_t>(offset_ptr, dst, count, this, IsLittleEndian, 57226584Sdim Data.data()); 58226584Sdim} 59226584Sdim 60226584Sdim 61226584Sdimuint16_t DataExtractor::getU16(uint32_t *offset_ptr) const { 62226584Sdim return getU<uint16_t>(offset_ptr, this, IsLittleEndian, Data.data()); 63226584Sdim} 64226584Sdim 65226584Sdimuint16_t *DataExtractor::getU16(uint32_t *offset_ptr, uint16_t *dst, 66226584Sdim uint32_t count) const { 67226584Sdim return getUs<uint16_t>(offset_ptr, dst, count, this, IsLittleEndian, 68226584Sdim Data.data()); 69226584Sdim} 70226584Sdim 71226584Sdimuint32_t DataExtractor::getU32(uint32_t *offset_ptr) const { 72226584Sdim return getU<uint32_t>(offset_ptr, this, IsLittleEndian, Data.data()); 73226584Sdim} 74226584Sdim 75226584Sdimuint32_t *DataExtractor::getU32(uint32_t *offset_ptr, uint32_t *dst, 76226584Sdim uint32_t count) const { 77226584Sdim return getUs<uint32_t>(offset_ptr, dst, count, this, IsLittleEndian, 78234353Sdim Data.data()); 79226584Sdim} 80226584Sdim 81226584Sdimuint64_t DataExtractor::getU64(uint32_t *offset_ptr) const { 82226584Sdim return getU<uint64_t>(offset_ptr, this, IsLittleEndian, Data.data()); 83226584Sdim} 84226584Sdim 85226584Sdimuint64_t *DataExtractor::getU64(uint32_t *offset_ptr, uint64_t *dst, 86226584Sdim uint32_t count) const { 87226584Sdim return getUs<uint64_t>(offset_ptr, dst, count, this, IsLittleEndian, 88226584Sdim Data.data()); 89226584Sdim} 90226584Sdim 91226584Sdimuint64_t 92226584SdimDataExtractor::getUnsigned(uint32_t *offset_ptr, uint32_t byte_size) const { 93226584Sdim switch (byte_size) { 94226584Sdim case 1: 95226584Sdim return getU8(offset_ptr); 96226584Sdim case 2: 97226584Sdim return getU16(offset_ptr); 98226584Sdim case 4: 99226584Sdim return getU32(offset_ptr); 100226584Sdim case 8: 101226584Sdim return getU64(offset_ptr); 102226584Sdim } 103226584Sdim llvm_unreachable("getUnsigned unhandled case!"); 104226584Sdim} 105226584Sdim 106226584Sdimint64_t 107226584SdimDataExtractor::getSigned(uint32_t *offset_ptr, uint32_t byte_size) const { 108226584Sdim switch (byte_size) { 109226584Sdim case 1: 110226584Sdim return (int8_t)getU8(offset_ptr); 111226584Sdim case 2: 112226584Sdim return (int16_t)getU16(offset_ptr); 113226584Sdim case 4: 114226584Sdim return (int32_t)getU32(offset_ptr); 115226584Sdim case 8: 116226584Sdim return (int64_t)getU64(offset_ptr); 117226584Sdim } 118226584Sdim llvm_unreachable("getSigned unhandled case!"); 119226584Sdim} 120226584Sdim 121226584Sdimconst char *DataExtractor::getCStr(uint32_t *offset_ptr) const { 122226584Sdim uint32_t offset = *offset_ptr; 123226584Sdim StringRef::size_type pos = Data.find('\0', offset); 124226584Sdim if (pos != StringRef::npos) { 125226584Sdim *offset_ptr = pos + 1; 126226584Sdim return Data.data() + offset; 127226584Sdim } 128226584Sdim return NULL; 129226584Sdim} 130226584Sdim 131226584Sdimuint64_t DataExtractor::getULEB128(uint32_t *offset_ptr) const { 132226584Sdim uint64_t result = 0; 133226584Sdim if (Data.empty()) 134226584Sdim return 0; 135226584Sdim 136226584Sdim unsigned shift = 0; 137226584Sdim uint32_t offset = *offset_ptr; 138226584Sdim uint8_t byte = 0; 139226584Sdim 140226584Sdim while (isValidOffset(offset)) { 141226584Sdim byte = Data[offset++]; 142243830Sdim result |= uint64_t(byte & 0x7f) << shift; 143226584Sdim shift += 7; 144226584Sdim if ((byte & 0x80) == 0) 145226584Sdim break; 146226584Sdim } 147226584Sdim 148226584Sdim *offset_ptr = offset; 149226584Sdim return result; 150226584Sdim} 151226584Sdim 152226584Sdimint64_t DataExtractor::getSLEB128(uint32_t *offset_ptr) const { 153226584Sdim int64_t result = 0; 154226584Sdim if (Data.empty()) 155226584Sdim return 0; 156226584Sdim 157226584Sdim unsigned shift = 0; 158226584Sdim uint32_t offset = *offset_ptr; 159226584Sdim uint8_t byte = 0; 160226584Sdim 161226584Sdim while (isValidOffset(offset)) { 162226584Sdim byte = Data[offset++]; 163243830Sdim result |= uint64_t(byte & 0x7f) << shift; 164226584Sdim shift += 7; 165226584Sdim if ((byte & 0x80) == 0) 166226584Sdim break; 167226584Sdim } 168226584Sdim 169226584Sdim // Sign bit of byte is 2nd high order bit (0x40) 170226584Sdim if (shift < 64 && (byte & 0x40)) 171243830Sdim result |= -(1ULL << shift); 172226584Sdim 173226584Sdim *offset_ptr = offset; 174226584Sdim return result; 175226584Sdim} 176