Home | History | Annotate | Download | only in Support
      1 //===-- DataExtractor.cpp -------------------------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include "llvm/Support/DataExtractor.h"
     11 #include "llvm/Support/ErrorHandling.h"
     12 #include "llvm/Support/Host.h"
     13 #include "llvm/Support/SwapByteOrder.h"
     14 using namespace llvm;
     15 
     16 template <typename T>
     17 static T getU(uint32_t *offset_ptr, const DataExtractor *de,
     18               bool isLittleEndian, const char *Data) {
     19   T val = 0;
     20   uint32_t offset = *offset_ptr;
     21   if (de->isValidOffsetForDataOfSize(offset, sizeof(val))) {
     22     std::memcpy(&val, &Data[offset], sizeof(val));
     23     if (sys::IsLittleEndianHost != isLittleEndian)
     24       sys::swapByteOrder(val);
     25 
     26     // Advance the offset
     27     *offset_ptr += sizeof(val);
     28   }
     29   return val;
     30 }
     31 
     32 template <typename T>
     33 static T *getUs(uint32_t *offset_ptr, T *dst, uint32_t count,
     34                 const DataExtractor *de, bool isLittleEndian, const char *Data){
     35   uint32_t offset = *offset_ptr;
     36 
     37   if (count > 0 && de->isValidOffsetForDataOfSize(offset, sizeof(*dst)*count)) {
     38     for (T *value_ptr = dst, *end = dst + count; value_ptr != end;
     39         ++value_ptr, offset += sizeof(*dst))
     40       *value_ptr = getU<T>(offset_ptr, de, isLittleEndian, Data);
     41     // Advance the offset
     42     *offset_ptr = offset;
     43     // Return a non-NULL pointer to the converted data as an indicator of
     44     // success
     45     return dst;
     46   }
     47   return nullptr;
     48 }
     49 
     50 uint8_t DataExtractor::getU8(uint32_t *offset_ptr) const {
     51   return getU<uint8_t>(offset_ptr, this, IsLittleEndian, Data.data());
     52 }
     53 
     54 uint8_t *
     55 DataExtractor::getU8(uint32_t *offset_ptr, uint8_t *dst, uint32_t count) const {
     56   return getUs<uint8_t>(offset_ptr, dst, count, this, IsLittleEndian,
     57                        Data.data());
     58 }
     59 
     60 
     61 uint16_t DataExtractor::getU16(uint32_t *offset_ptr) const {
     62   return getU<uint16_t>(offset_ptr, this, IsLittleEndian, Data.data());
     63 }
     64 
     65 uint16_t *DataExtractor::getU16(uint32_t *offset_ptr, uint16_t *dst,
     66                                 uint32_t count) const {
     67   return getUs<uint16_t>(offset_ptr, dst, count, this, IsLittleEndian,
     68                         Data.data());
     69 }
     70 
     71 uint32_t DataExtractor::getU32(uint32_t *offset_ptr) const {
     72   return getU<uint32_t>(offset_ptr, this, IsLittleEndian, Data.data());
     73 }
     74 
     75 uint32_t *DataExtractor::getU32(uint32_t *offset_ptr, uint32_t *dst,
     76                                 uint32_t count) const {
     77   return getUs<uint32_t>(offset_ptr, dst, count, this, IsLittleEndian,
     78                         Data.data());
     79 }
     80 
     81 uint64_t DataExtractor::getU64(uint32_t *offset_ptr) const {
     82   return getU<uint64_t>(offset_ptr, this, IsLittleEndian, Data.data());
     83 }
     84 
     85 uint64_t *DataExtractor::getU64(uint32_t *offset_ptr, uint64_t *dst,
     86                                 uint32_t count) const {
     87   return getUs<uint64_t>(offset_ptr, dst, count, this, IsLittleEndian,
     88                         Data.data());
     89 }
     90 
     91 uint64_t
     92 DataExtractor::getUnsigned(uint32_t *offset_ptr, uint32_t byte_size) const {
     93   switch (byte_size) {
     94   case 1:
     95     return getU8(offset_ptr);
     96   case 2:
     97     return getU16(offset_ptr);
     98   case 4:
     99     return getU32(offset_ptr);
    100   case 8:
    101     return getU64(offset_ptr);
    102   }
    103   llvm_unreachable("getUnsigned unhandled case!");
    104 }
    105 
    106 int64_t
    107 DataExtractor::getSigned(uint32_t *offset_ptr, uint32_t byte_size) const {
    108   switch (byte_size) {
    109   case 1:
    110     return (int8_t)getU8(offset_ptr);
    111   case 2:
    112     return (int16_t)getU16(offset_ptr);
    113   case 4:
    114     return (int32_t)getU32(offset_ptr);
    115   case 8:
    116     return (int64_t)getU64(offset_ptr);
    117   }
    118   llvm_unreachable("getSigned unhandled case!");
    119 }
    120 
    121 const char *DataExtractor::getCStr(uint32_t *offset_ptr) const {
    122   uint32_t offset = *offset_ptr;
    123   StringRef::size_type pos = Data.find('\0', offset);
    124   if (pos != StringRef::npos) {
    125     *offset_ptr = pos + 1;
    126     return Data.data() + offset;
    127   }
    128   return nullptr;
    129 }
    130 
    131 uint64_t DataExtractor::getULEB128(uint32_t *offset_ptr) const {
    132   uint64_t result = 0;
    133   if (Data.empty())
    134     return 0;
    135 
    136   unsigned shift = 0;
    137   uint32_t offset = *offset_ptr;
    138   uint8_t byte = 0;
    139 
    140   while (isValidOffset(offset)) {
    141     byte = Data[offset++];
    142     result |= uint64_t(byte & 0x7f) << shift;
    143     shift += 7;
    144     if ((byte & 0x80) == 0)
    145       break;
    146   }
    147 
    148   *offset_ptr = offset;
    149   return result;
    150 }
    151 
    152 int64_t DataExtractor::getSLEB128(uint32_t *offset_ptr) const {
    153   int64_t result = 0;
    154   if (Data.empty())
    155     return 0;
    156 
    157   unsigned shift = 0;
    158   uint32_t offset = *offset_ptr;
    159   uint8_t byte = 0;
    160 
    161   while (isValidOffset(offset)) {
    162     byte = Data[offset++];
    163     result |= uint64_t(byte & 0x7f) << shift;
    164     shift += 7;
    165     if ((byte & 0x80) == 0)
    166       break;
    167   }
    168 
    169   // Sign bit of byte is 2nd high order bit (0x40)
    170   if (shift < 64 && (byte & 0x40))
    171     result |= -(1ULL << shift);
    172 
    173   *offset_ptr = offset;
    174   return result;
    175 }
    176