1/*
2 * Copyright (C) 2016 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#include <algorithm>
29#include <limits.h>
30#include <wtf/Compiler.h>
31
32// This file contains a bunch of helper functions for decoding LEB numbers.
33// See https://en.wikipedia.org/wiki/LEB128 for more information about the
34// LEB format.
35
36namespace WTF { namespace LEBDecoder {
37
38template<typename T>
39constexpr size_t maxByteLength()
40{
41 const size_t numBits = sizeof(T) * CHAR_BIT;
42 return (numBits - 1) / 7 + 1; // numBits / 7 rounding up.
43}
44
45template<typename T>
46inline bool WARN_UNUSED_RETURN decodeUInt(const uint8_t* bytes, size_t length, size_t& offset, T& result)
47{
48 if (length <= offset)
49 return false;
50 result = 0;
51 unsigned shift = 0;
52 size_t last = std::min(maxByteLength<T>(), length - offset) - 1;
53 for (unsigned i = 0; true; ++i) {
54 uint8_t byte = bytes[offset++];
55 result |= static_cast<T>(byte & 0x7f) << shift;
56 shift += 7;
57 if (!(byte & 0x80))
58 return true;
59 if (i == last)
60 return false;
61 }
62 RELEASE_ASSERT_NOT_REACHED();
63 return true;
64}
65
66template<typename T>
67inline bool WARN_UNUSED_RETURN decodeInt(const uint8_t* bytes, size_t length, size_t& offset, T& result)
68{
69 if (length <= offset)
70 return false;
71 result = 0;
72 unsigned shift = 0;
73 size_t last = std::min(maxByteLength<T>(), length - offset) - 1;
74 uint8_t byte;
75 for (unsigned i = 0; true; ++i) {
76 byte = bytes[offset++];
77 result |= static_cast<T>(byte & 0x7f) << shift;
78 shift += 7;
79 if (!(byte & 0x80))
80 break;
81 if (i == last)
82 return false;
83 }
84
85 using UnsignedT = typename std::make_unsigned<T>::type;
86 const size_t numBits = sizeof(T) * CHAR_BIT;
87 if (shift < numBits && (byte & 0x40))
88 result = static_cast<T>(static_cast<UnsignedT>(result) | (static_cast<UnsignedT>(-1) << shift));
89 return true;
90}
91
92inline bool WARN_UNUSED_RETURN decodeUInt32(const uint8_t* bytes, size_t length, size_t& offset, uint32_t& result)
93{
94 return decodeUInt<uint32_t>(bytes, length, offset, result);
95}
96
97inline bool WARN_UNUSED_RETURN decodeUInt64(const uint8_t* bytes, size_t length, size_t& offset, uint64_t& result)
98{
99 return decodeUInt<uint64_t>(bytes, length, offset, result);
100}
101
102inline bool WARN_UNUSED_RETURN decodeInt32(const uint8_t* bytes, size_t length, size_t& offset, int32_t& result)
103{
104 return decodeInt<int32_t>(bytes, length, offset, result);
105}
106
107inline bool WARN_UNUSED_RETURN decodeInt64(const uint8_t* bytes, size_t length, size_t& offset, int64_t& result)
108{
109 return decodeInt<int64_t>(bytes, length, offset, result);
110}
111
112} } // WTF::LEBDecoder
113