| //===- LEB128.cpp ---------------------------------------------------------===// |
| // |
| // The MCLinker Project |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| #include <mcld/Support/LEB128.h> |
| |
| namespace mcld { |
| |
| namespace leb128 { |
| |
| //===---------------------- LEB128 Encoding APIs -------------------------===// |
| template<> |
| size_t encode<uint64_t>(ByteType *&pBuf, uint64_t pValue) { |
| size_t size = 0; |
| do { |
| ByteType byte = pValue & 0x7f; |
| pValue >>= 7; |
| if (pValue) |
| byte |= 0x80; |
| *pBuf++ = byte; |
| size++; |
| } while (pValue); |
| |
| return size; |
| } |
| |
| /* |
| * Fast version for encoding 32-bit integer. This unrolls the loop in the |
| * generic version defined above. |
| */ |
| template<> |
| size_t encode<uint32_t>(ByteType *&pBuf, uint32_t pValue) { |
| if ((pValue & ~0x7f) == 0) { |
| *pBuf++ = static_cast<ByteType>(pValue); |
| return 1; |
| } else if ((pValue & ~0x3fff) == 0){ |
| *pBuf++ = static_cast<ByteType>((pValue & 0x7f) | 0x80); |
| *pBuf++ = static_cast<ByteType>((pValue >> 7) & 0x7f); |
| return 2; |
| } else if ((pValue & ~0x1fffff) == 0) { |
| *pBuf++ = static_cast<ByteType>((pValue & 0x7f) | 0x80); |
| *pBuf++ = static_cast<ByteType>(((pValue >> 7) & 0x7f) | 0x80); |
| *pBuf++ = static_cast<ByteType>((pValue >> 14) & 0x7f); |
| return 3; |
| } else if ((pValue & ~0xfffffff) == 0) { |
| *pBuf++ = static_cast<ByteType>((pValue & 0x7f) | 0x80); |
| *pBuf++ = static_cast<ByteType>(((pValue >> 7) & 0x7f) | 0x80); |
| *pBuf++ = static_cast<ByteType>(((pValue >> 14) & 0x7f) | 0x80); |
| *pBuf++ = static_cast<ByteType>((pValue >> 21) & 0x7f); |
| return 4; |
| } else { |
| *pBuf++ = static_cast<ByteType>((pValue & 0x7f) | 0x80); |
| *pBuf++ = static_cast<ByteType>(((pValue >> 7) & 0x7f) | 0x80); |
| *pBuf++ = static_cast<ByteType>(((pValue >> 14) & 0x7f) | 0x80); |
| *pBuf++ = static_cast<ByteType>(((pValue >> 21) & 0x7f) | 0x80); |
| *pBuf++ = static_cast<ByteType>((pValue >> 28) & 0x7f); |
| return 5; |
| } |
| // unreachable |
| } |
| |
| template<> |
| size_t encode<int64_t>(ByteType *&pBuf, int64_t pValue) { |
| size_t size = 0; |
| bool more = true; |
| |
| do { |
| ByteType byte = pValue & 0x7f; |
| pValue >>= 7; |
| |
| if (((pValue == 0) && ((byte & 0x40) == 0)) || |
| ((pValue == -1) && ((byte & 0x40) == 0x40))) |
| more = false; |
| else |
| byte |= 0x80; |
| |
| *pBuf++ = byte; |
| size++; |
| } while (more); |
| |
| return size; |
| } |
| |
| template<> |
| size_t encode<int32_t>(ByteType *&pBuf, int32_t pValue) { |
| return encode<int64_t>(pBuf, static_cast<int64_t>(pValue)); |
| } |
| |
| //===---------------------- LEB128 Decoding APIs -------------------------===// |
| |
| template<> |
| uint64_t decode<uint64_t>(const ByteType *pBuf, size_t &pSize) { |
| uint64_t result = 0; |
| |
| if ((*pBuf & 0x80) == 0) { |
| pSize = 1; |
| return *pBuf; |
| } else if ((*(pBuf + 1) & 0x80) == 0) { |
| pSize = 2; |
| return ((*(pBuf + 1) & 0x7f) << 7) | |
| (*pBuf & 0x7f); |
| } else if ((*(pBuf + 2) & 0x80) == 0) { |
| pSize = 3; |
| return ((*(pBuf + 2) & 0x7f) << 14) | |
| ((*(pBuf + 1) & 0x7f) << 7) | |
| (*pBuf & 0x7f); |
| } else { |
| pSize = 4; |
| result = ((*(pBuf + 3) & 0x7f) << 21) | |
| ((*(pBuf + 2) & 0x7f) << 14) | |
| ((*(pBuf + 1) & 0x7f) << 7) | |
| (*pBuf & 0x7f); |
| } |
| |
| if ((*(pBuf + 3) & 0x80) != 0) { |
| // Large number which is an unusual case. |
| unsigned shift; |
| ByteType byte; |
| |
| // Start the read from the 4th byte. |
| shift = 28; |
| pBuf += 4; |
| do { |
| byte = *pBuf; |
| pBuf++; |
| pSize++; |
| result |= (static_cast<uint64_t>(byte & 0x7f) << shift); |
| shift += 7; |
| } while (byte & 0x80); |
| } |
| |
| return result; |
| } |
| |
| template<> |
| uint64_t decode<uint64_t>(const ByteType *&pBuf) { |
| ByteType byte; |
| uint64_t result; |
| |
| byte = *pBuf++; |
| result = byte & 0x7f; |
| if ((byte & 0x80) == 0) { |
| return result; |
| } else { |
| byte = *pBuf++; |
| result |= ((byte & 0x7f) << 7); |
| if ((byte & 0x80) == 0) { |
| return result; |
| } else { |
| byte = *pBuf++; |
| result |= (byte & 0x7f) << 14; |
| if ((byte & 0x80) == 0) { |
| return result; |
| } else { |
| byte = *pBuf++; |
| result |= (byte & 0x7f) << 21; |
| if ((byte & 0x80) == 0) { |
| return result; |
| } |
| } |
| } |
| } |
| |
| // Large number which is an unusual case. |
| unsigned shift; |
| |
| // Start the read from the 4th byte. |
| shift = 28; |
| do { |
| byte = *pBuf++; |
| result |= (static_cast<uint64_t>(byte & 0x7f) << shift); |
| shift += 7; |
| } while (byte & 0x80); |
| |
| return result; |
| } |
| |
| /* |
| * Signed LEB128 decoding is Similar to the unsigned version but setup the sign |
| * bit if necessary. This is rarely used, therefore we don't provide unrolling |
| * version like decode() to save the code size. |
| */ |
| template<> |
| int64_t decode<int64_t>(const ByteType *pBuf, size_t &pSize) { |
| uint64_t result = 0; |
| ByteType byte; |
| unsigned shift = 0; |
| |
| pSize = 0; |
| do { |
| byte = *pBuf; |
| pBuf++; |
| pSize++; |
| result |= (static_cast<uint64_t>(byte & 0x7f) << shift); |
| shift += 7; |
| } while (byte & 0x80); |
| |
| if ((shift < (8 * sizeof(result))) && (byte & 0x40)) |
| result |= ((static_cast<uint64_t>(-1)) << shift); |
| |
| return result; |
| } |
| |
| template<> |
| int64_t decode<int64_t>(const ByteType *&pBuf) { |
| uint64_t result = 0; |
| ByteType byte; |
| unsigned shift = 0; |
| |
| do { |
| byte = *pBuf; |
| pBuf++; |
| result |= (static_cast<uint64_t>(byte & 0x7f) << shift); |
| shift += 7; |
| } while (byte & 0x80); |
| |
| if ((shift < (8 * sizeof(result))) && (byte & 0x40)) |
| result |= ((static_cast<uint64_t>(-1)) << shift); |
| |
| return result; |
| } |
| |
| } // namespace of leb128 |
| } // namespace of mcld |