Load.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  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. #include <folly/experimental/bser/Bser.h>
  17. #include <folly/String.h>
  18. #include <folly/io/Cursor.h>
  19. using namespace folly;
  20. using folly::io::Cursor;
  21. namespace folly {
  22. namespace bser {
  23. static dynamic parseBser(Cursor& curs);
  24. template <typename... ARGS>
  25. [[noreturn]] static void throwDecodeError(Cursor& curs, ARGS&&... args) {
  26. throw BserDecodeError(folly::to<std::string>(
  27. std::forward<ARGS>(args)...,
  28. " with ",
  29. curs.length(),
  30. " bytes remaining in cursor"));
  31. }
  32. static int64_t decodeInt(Cursor& curs) {
  33. auto enc = (BserType)curs.read<int8_t>();
  34. switch (enc) {
  35. case BserType::Int8:
  36. return curs.read<int8_t>();
  37. case BserType::Int16:
  38. return curs.read<int16_t>();
  39. case BserType::Int32:
  40. return curs.read<int32_t>();
  41. case BserType::Int64:
  42. return curs.read<int64_t>();
  43. default:
  44. throwDecodeError(
  45. curs, "invalid integer encoding detected (", (int8_t)enc, ")");
  46. }
  47. }
  48. static std::string decodeString(Cursor& curs) {
  49. auto len = decodeInt(curs);
  50. std::string str;
  51. if (len < 0) {
  52. throw std::range_error("string length must not be negative");
  53. }
  54. // We could use Cursor::readFixedString() here, but we'd like
  55. // to throw our own exception with some increased diagnostics.
  56. str.resize(len);
  57. // The start of the string data, mutable.
  58. auto* dest = &str[0];
  59. auto pulled = curs.pullAtMost(dest, len);
  60. if (pulled != size_t(len)) {
  61. // Saw this case when decodeHeader was returning the incorrect length
  62. // and we were splitting off too few bytes from the IOBufQueue
  63. throwDecodeError(
  64. curs,
  65. "no data available while decoding a string, header was "
  66. "not decoded properly");
  67. }
  68. return str;
  69. }
  70. static dynamic decodeArray(Cursor& curs) {
  71. dynamic arr = dynamic::array();
  72. auto size = decodeInt(curs);
  73. while (size-- > 0) {
  74. arr.push_back(parseBser(curs));
  75. }
  76. return arr;
  77. }
  78. static dynamic decodeObject(Cursor& curs) {
  79. dynamic obj = dynamic::object;
  80. auto size = decodeInt(curs);
  81. while (size-- > 0) {
  82. if ((BserType)curs.read<int8_t>() != BserType::String) {
  83. throwDecodeError(curs, "expected String");
  84. }
  85. auto key = decodeString(curs);
  86. obj[key] = parseBser(curs);
  87. }
  88. return obj;
  89. }
  90. static dynamic decodeTemplate(Cursor& curs) {
  91. dynamic arr = folly::dynamic::array;
  92. // List of property names
  93. if ((BserType)curs.read<int8_t>() != BserType::Array) {
  94. throw std::runtime_error("Expected array encoding for property names");
  95. }
  96. auto names = decodeArray(curs);
  97. auto size = decodeInt(curs);
  98. while (size-- > 0) {
  99. dynamic obj = dynamic::object;
  100. for (auto& name : names) {
  101. auto bytes = curs.peekBytes();
  102. if ((BserType)bytes.at(0) == BserType::Skip) {
  103. obj[name.getString()] = nullptr;
  104. curs.skipAtMost(1);
  105. continue;
  106. }
  107. obj[name.getString()] = parseBser(curs);
  108. }
  109. arr.push_back(std::move(obj));
  110. }
  111. return arr;
  112. }
  113. static dynamic parseBser(Cursor& curs) {
  114. switch ((BserType)curs.read<int8_t>()) {
  115. case BserType::Int8:
  116. return curs.read<int8_t>();
  117. case BserType::Int16:
  118. return curs.read<int16_t>();
  119. case BserType::Int32:
  120. return curs.read<int32_t>();
  121. case BserType::Int64:
  122. return curs.read<int64_t>();
  123. case BserType::Real: {
  124. double dval;
  125. curs.pull((void*)&dval, sizeof(dval));
  126. return dval;
  127. }
  128. case BserType::Null:
  129. return nullptr;
  130. case BserType::True:
  131. return (bool)true;
  132. case BserType::False:
  133. return (bool)false;
  134. case BserType::String:
  135. return decodeString(curs);
  136. case BserType::Array:
  137. return decodeArray(curs);
  138. case BserType::Object:
  139. return decodeObject(curs);
  140. case BserType::Template:
  141. return decodeTemplate(curs);
  142. case BserType::Skip:
  143. throw std::runtime_error(
  144. "Skip not valid at this location in the bser stream");
  145. default:
  146. throw std::runtime_error("invalid bser encoding");
  147. }
  148. }
  149. static size_t decodeHeader(Cursor& curs) {
  150. char header[sizeof(kMagic)];
  151. curs.pull(header, sizeof(header));
  152. if (memcmp(header, kMagic, sizeof(kMagic))) {
  153. throw std::runtime_error("invalid BSER magic header");
  154. }
  155. auto enc = (BserType)curs.peekBytes().at(0);
  156. size_t int_size;
  157. switch (enc) {
  158. case BserType::Int8:
  159. int_size = 1;
  160. break;
  161. case BserType::Int16:
  162. int_size = 2;
  163. break;
  164. case BserType::Int32:
  165. int_size = 4;
  166. break;
  167. case BserType::Int64:
  168. int_size = 8;
  169. break;
  170. default:
  171. int_size = 0;
  172. }
  173. return int_size + 3 /* magic + int type */ + decodeInt(curs);
  174. }
  175. size_t decodePduLength(const folly::IOBuf* buf) {
  176. Cursor curs(buf);
  177. return decodeHeader(curs);
  178. }
  179. folly::dynamic parseBser(const IOBuf* buf) {
  180. Cursor curs(buf);
  181. decodeHeader(curs);
  182. return parseBser(curs);
  183. }
  184. folly::dynamic parseBser(ByteRange str) {
  185. auto buf = IOBuf::wrapBuffer(str.data(), str.size());
  186. return parseBser(&*buf);
  187. }
  188. folly::dynamic parseBser(StringPiece str) {
  189. return parseBser(ByteRange((uint8_t*)str.data(), str.size()));
  190. }
  191. } // namespace bser
  192. } // namespace folly
  193. /* vim:ts=2:sw=2:et:
  194. */