1 // This code is derived from code distributed as part of Google LevelDB.
2 // The original is available in leveldb as util/coding.cc.
3 // This file was retrieved Jul 15, 2013 by Robert Escriva.
4 
5 // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
6 // Use of this source code is governed by a BSD-style license that can be
7 // found in the LICENSE file. See the AUTHORS file for names of contributors.
8 
9 // C
10 #include <stdlib.h>
11 
12 // e
13 #include "e/varint.h"
14 
15 namespace
16 {
17 
18 const char*
decode_32_fallback(const char * p,const char * limit,uint32_t * value)19 decode_32_fallback(const char* p,
20                    const char* limit,
21                    uint32_t* value)
22 
23 {
24     uint32_t result = 0;
25 
26     for (uint32_t shift = 0; shift <= 28 && p < limit; shift += 7)
27     {
28         uint32_t byte = *(reinterpret_cast<const unsigned char*>(p));
29         p++;
30 
31         if (byte & 128)
32         {
33             // More bytes are present
34             result |= ((byte & 127) << shift);
35         }
36         else
37         {
38             result |= (byte << shift);
39             *value = result;
40             return reinterpret_cast<const char*>(p);
41         }
42     }
43 
44     return NULL;
45 }
46 
47 } // namespace
48 
49 const char*
varint32_decode(const char * p,const char * limit,uint32_t * value)50 e :: varint32_decode(const char* p,
51                      const char* limit,
52                      uint32_t* value)
53 
54 {
55     if (p < limit)
56     {
57         uint32_t result = *(reinterpret_cast<const unsigned char*>(p));
58 
59         if ((result & 128) == 0)
60         {
61             *value = result;
62             return p + 1;
63         }
64     }
65 
66     return decode_32_fallback(p, limit, value);
67 }
68 
69 const char*
varint64_decode(const char * p,const char * limit,uint64_t * value)70 e :: varint64_decode(const char* p, const char* limit, uint64_t* value)
71 {
72     uint64_t result = 0;
73 
74     for (uint32_t shift = 0; shift <= 63 && p < limit; shift += 7)
75     {
76         uint64_t byte = *(reinterpret_cast<const unsigned char*>(p));
77         p++;
78 
79         if (byte & 128)
80         {
81             // More bytes are present
82             result |= ((byte & 127) << shift);
83         }
84         else
85         {
86             result |= (byte << shift);
87             *value = result;
88             return reinterpret_cast<const char*>(p);
89         }
90     }
91 
92     return NULL;
93 }
94 
95 char*
varint32_encode(char * dst,uint32_t v)96 e :: varint32_encode(char* dst, uint32_t v)
97 {
98     // Operate on characters as unsigneds
99     unsigned char* ptr = reinterpret_cast<unsigned char*>(dst);
100     static const int B = 128;
101 
102     if (v < (1<<7))
103     {
104         *(ptr++) = v;
105     }
106     else if (v < (1<<14))
107     {
108         *(ptr++) = v | B;
109         *(ptr++) = v>>7;
110     }
111     else if (v < (1<<21))
112     {
113         *(ptr++) = v | B;
114         *(ptr++) = (v>>7) | B;
115         *(ptr++) = v>>14;
116     }
117     else if (v < (1<<28))
118     {
119         *(ptr++) = v | B;
120         *(ptr++) = (v>>7) | B;
121         *(ptr++) = (v>>14) | B;
122         *(ptr++) = v>>21;
123     }
124     else
125     {
126         *(ptr++) = v | B;
127         *(ptr++) = (v>>7) | B;
128         *(ptr++) = (v>>14) | B;
129         *(ptr++) = (v>>21) | B;
130         *(ptr++) = v>>28;
131     }
132 
133     return reinterpret_cast<char*>(ptr);
134 }
135 
136 char*
varint64_encode(char * dst,uint64_t v)137 e :: varint64_encode(char* dst, uint64_t v)
138 {
139     static const unsigned B = 128;
140     unsigned char* ptr = reinterpret_cast<unsigned char*>(dst);
141 
142     while (v >= B)
143     {
144         *(ptr++) = (v & (B-1)) | B;
145         v >>= 7;
146     }
147 
148     *(ptr++) = static_cast<unsigned char>(v);
149     return reinterpret_cast<char*>(ptr);
150 }
151