proxygen
Load.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2016-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
18 
19 #include <folly/String.h>
20 #include <folly/io/Cursor.h>
21 
22 using namespace folly;
23 using folly::io::Cursor;
24 
25 namespace folly {
26 namespace bser {
27 static dynamic parseBser(Cursor& curs);
28 
29 template <typename... ARGS>
30 [[noreturn]] static void throwDecodeError(Cursor& curs, ARGS&&... args) {
31  throw BserDecodeError(folly::to<std::string>(
32  std::forward<ARGS>(args)...,
33  " with ",
34  curs.length(),
35  " bytes remaining in cursor"));
36 }
37 
38 static int64_t decodeInt(Cursor& curs) {
39  auto enc = (BserType)curs.read<int8_t>();
40  switch (enc) {
41  case BserType::Int8:
42  return curs.read<int8_t>();
43  case BserType::Int16:
44  return curs.read<int16_t>();
45  case BserType::Int32:
46  return curs.read<int32_t>();
47  case BserType::Int64:
48  return curs.read<int64_t>();
49  default:
51  curs, "invalid integer encoding detected (", (int8_t)enc, ")");
52  }
53 }
54 
56  auto len = decodeInt(curs);
57  std::string str;
58 
59  if (len < 0) {
60  throw std::range_error("string length must not be negative");
61  }
62 
63  // We could use Cursor::readFixedString() here, but we'd like
64  // to throw our own exception with some increased diagnostics.
65  str.resize(len);
66 
67  // The start of the string data, mutable.
68  auto* dest = &str[0];
69 
70  auto pulled = curs.pullAtMost(dest, len);
71  if (pulled != size_t(len)) {
72  // Saw this case when decodeHeader was returning the incorrect length
73  // and we were splitting off too few bytes from the IOBufQueue
75  curs,
76  "no data available while decoding a string, header was "
77  "not decoded properly");
78  }
79 
80  return str;
81 }
82 
83 static dynamic decodeArray(Cursor& curs) {
84  dynamic arr = dynamic::array();
85  auto size = decodeInt(curs);
86  while (size-- > 0) {
87  arr.push_back(parseBser(curs));
88  }
89  return arr;
90 }
91 
92 static dynamic decodeObject(Cursor& curs) {
94  auto size = decodeInt(curs);
95  while (size-- > 0) {
96  if ((BserType)curs.read<int8_t>() != BserType::String) {
97  throwDecodeError(curs, "expected String");
98  }
99  auto key = decodeString(curs);
100  obj[key] = parseBser(curs);
101  }
102  return obj;
103 }
104 
107 
108  // List of property names
109  if ((BserType)curs.read<int8_t>() != BserType::Array) {
110  throw std::runtime_error("Expected array encoding for property names");
111  }
112  auto names = decodeArray(curs);
113 
114  auto size = decodeInt(curs);
115 
116  while (size-- > 0) {
117  dynamic obj = dynamic::object;
118 
119  for (auto& name : names) {
120  auto bytes = curs.peekBytes();
121  if ((BserType)bytes.at(0) == BserType::Skip) {
122  obj[name.getString()] = nullptr;
123  curs.skipAtMost(1);
124  continue;
125  }
126 
127  obj[name.getString()] = parseBser(curs);
128  }
129 
130  arr.push_back(std::move(obj));
131  }
132 
133  return arr;
134 }
135 
136 static dynamic parseBser(Cursor& curs) {
137  switch ((BserType)curs.read<int8_t>()) {
138  case BserType::Int8:
139  return curs.read<int8_t>();
140  case BserType::Int16:
141  return curs.read<int16_t>();
142  case BserType::Int32:
143  return curs.read<int32_t>();
144  case BserType::Int64:
145  return curs.read<int64_t>();
146  case BserType::Real: {
147  double dval;
148  curs.pull((void*)&dval, sizeof(dval));
149  return dval;
150  }
151  case BserType::Null:
152  return nullptr;
153  case BserType::True:
154  return (bool)true;
155  case BserType::False:
156  return (bool)false;
157  case BserType::String:
158  return decodeString(curs);
159  case BserType::Array:
160  return decodeArray(curs);
161  case BserType::Object:
162  return decodeObject(curs);
163  case BserType::Template:
164  return decodeTemplate(curs);
165  case BserType::Skip:
166  throw std::runtime_error(
167  "Skip not valid at this location in the bser stream");
168  default:
169  throw std::runtime_error("invalid bser encoding");
170  }
171 }
172 
173 static size_t decodeHeader(Cursor& curs) {
174  char header[sizeof(kMagic)];
175  curs.pull(header, sizeof(header));
176  if (memcmp(header, kMagic, sizeof(kMagic))) {
177  throw std::runtime_error("invalid BSER magic header");
178  }
179 
180  auto enc = (BserType)curs.peekBytes().at(0);
181  size_t int_size;
182  switch (enc) {
183  case BserType::Int8:
184  int_size = 1;
185  break;
186  case BserType::Int16:
187  int_size = 2;
188  break;
189  case BserType::Int32:
190  int_size = 4;
191  break;
192  case BserType::Int64:
193  int_size = 8;
194  break;
195  default:
196  int_size = 0;
197  }
198 
199  return int_size + 3 /* magic + int type */ + decodeInt(curs);
200 }
201 
202 size_t decodePduLength(const folly::IOBuf* buf) {
203  Cursor curs(buf);
204  return decodeHeader(curs);
205 }
206 
208  Cursor curs(buf);
209 
210  decodeHeader(curs);
211  return parseBser(curs);
212 }
213 
215  auto buf = IOBuf::wrapBuffer(str.data(), str.size());
216  return parseBser(&*buf);
217 }
218 
220  return parseBser(ByteRange((uint8_t*)str.data(), str.size()));
221 }
222 } // namespace bser
223 } // namespace folly
224 
225 /* vim:ts=2:sw=2:et:
226  */
static ObjectMaker object()
Definition: dynamic-inl.h:240
static std::unique_ptr< IOBuf > wrapBuffer(const void *buf, std::size_t capacity)
Definition: IOBuf.cpp:353
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
dest
Definition: upload.py:394
constexpr size_type size() const
Definition: Range.h:431
static dynamic decodeObject(Cursor &curs)
Definition: Load.cpp:92
size_t decodePduLength(const folly::IOBuf *)
Definition: Load.cpp:202
size_t pullAtMost(void *buf, size_t len)
Definition: Cursor.h:407
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
static int64_t decodeInt(Cursor &curs)
Definition: Load.cpp:38
void pull(void *buf, size_t len)
Definition: Cursor.h:418
BserType
Definition: Bser.h:41
const char * name
Definition: http_parser.c:437
static size_t decodeHeader(Cursor &curs)
Definition: Load.cpp:173
constexpr auto size(C const &c) -> decltype(c.size())
Definition: Access.h:45
static void throwDecodeError(Cursor &curs, ARGS &&...args)
Definition: Load.cpp:30
constexpr Iter data() const
Definition: Range.h:446
size_t skipAtMost(size_t len)
Definition: Cursor.h:362
static dynamic decodeArray(Cursor &curs)
Definition: Load.cpp:83
void push_back(dynamic const &)
Definition: dynamic-inl.h:969
size_t length() const
Definition: Cursor.h:118
const char * string
Definition: Conv.cpp:212
Range< const unsigned char * > ByteRange
Definition: Range.h:1163
static void array(EmptyArrayTag)
Definition: dynamic-inl.h:233
value_type & at(size_t i)
Definition: Range.h:628
folly::dynamic parseBser(folly::StringPiece)
Definition: Load.cpp:219
static std::string decodeString(Cursor &curs)
Definition: Load.cpp:55
static dynamic decodeTemplate(Cursor &curs)
Definition: Load.cpp:105
const uint8_t kMagic[2]
Definition: Dump.cpp:28