util/SerializationUtil.cpp (161 lines of code) (raw):

/** * Copyright (c) 2014-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. */ #include <wdt/util/SerializationUtil.h> #include <folly/lang/Bits.h> using folly::ByteRange; using std::string; namespace facebook { namespace wdt { ByteRange makeByteRange(string str) { return ByteRange((uint8_t *)str.data(), str.size()); } ByteRange makeByteRange(char *dest, int64_t sz, int64_t off) { WDT_CHECK_GE(off, 0); WDT_CHECK_GE(sz, 0); WDT_CHECK(dest != nullptr); return ByteRange((uint8_t *)(dest + off), sz - off); } int64_t offset(const folly::ByteRange &newRange, const folly::ByteRange &oldRange) { WDT_CHECK_EQ(newRange.end(), oldRange.end()); return newRange.start() - oldRange.start(); } bool decodeInt32(ByteRange &br, int32_t &res32) { int64_t res64; ByteRange obr = br; bool ok = decodeInt64(br, res64); if (!ok) { return false; } if (res64 > INT32_MAX || res64 < INT32_MIN) { WLOG(ERROR) << "var int32 decoded value " << res64 << " does not fit in a 32 bit number as expected"; br = obr; return false; } res32 = static_cast<int32_t>(res64); return true; } bool decodeInt64(ByteRange &br, int64_t &res) { int64_t pos = 0; bool ret = decodeVarI64((const char *)(br.start()), br.size(), pos, res); if (!ret) { return false; } WDT_CHECK_GE(pos, 1); br.advance(pos); return true; } bool decodeUInt64(ByteRange &br, uint64_t &res) { int64_t pos = 0; bool ret = decodeVarU64((const char *)(br.start()), br.size(), pos, res); if (!ret) { return false; } WDT_CHECK_GE(pos, 1); br.advance(pos); return true; } bool decodeInt64C(ByteRange &br, int64_t &sres) { uint64_t ures; bool ret = decodeUInt64(br, ures); if (!ret) { return false; } if (ures > INT64_MAX) { WLOG(ERROR) << "Decoded as unsigned into signed, too large " << ures; return false; } sres = ures; return true; } bool decodeInt32C(ByteRange &br, int32_t &res32) { int64_t res64; ByteRange obr = br; bool ok = decodeInt64C(br, res64); if (!ok) { return false; } if (res64 > INT32_MAX || res64 < 0) { WLOG(ERROR) << "var int32 decoded value " << res64 << " does not fit in a 31 bit positive number as expected"; br = obr; return false; } res32 = static_cast<int32_t>(res64); return true; } template <typename T> bool decodeIntFixedLength(folly::ByteRange &br, T &res) { if (br.size() < sizeof(T)) { WLOG(ERROR) << "Not enough to read to decode fixed length encoded int"; return false; } res = folly::loadUnaligned<T>(br.start()); res = folly::Endian::little(res); br.advance(sizeof(T)); if (res < 0) { WLOG(ERROR) << "negative int decoded " << res; return false; } return true; } bool decodeInt16FixedLength(folly::ByteRange &br, int16_t &res) { bool success = decodeIntFixedLength<int16_t>(br, res); return success; } bool decodeInt32FixedLength(folly::ByteRange &br, int32_t &res) { return decodeIntFixedLength<int32_t>(br, res); } bool decodeInt64FixedLength(folly::ByteRange &br, int64_t &res) { return decodeIntFixedLength<int64_t>(br, res); } template <typename T> bool encodeIntFixedLength(char *dest, int64_t sz, int64_t &off, const T val) { constexpr int intLen = sizeof(T); if (off + intLen > sz) { WLOG(ERROR) << "Not enough room to encode fixed length int " << val << " off: " << off << " buffer size: " << sz; return false; } folly::storeUnaligned<T>(dest + off, folly::Endian::little(val)); off += intLen; return true; } bool encodeInt16FixedLength(char *dest, int64_t sz, int64_t &off, int16_t val) { return encodeIntFixedLength<int16_t>(dest, sz, off, val); } bool encodeInt32FixedLength(char *dest, int64_t sz, int64_t &off, int32_t val) { return encodeIntFixedLength<int32_t>(dest, sz, off, val); } bool encodeInt64FixedLength(char *dest, int64_t sz, int64_t &off, int64_t val) { return encodeIntFixedLength<int64_t>(dest, sz, off, val); } bool encodeString(char *dest, int64_t sz, int64_t &off, const string &str) { if (!encodeVarU64(dest, sz, off, str.length())) { return false; } const int64_t strLen = str.length(); if ((off + strLen) > sz) { WLOG(ERROR) << "Not enough room to encode \"" << str << "\" in buf of size " << sz; return false; } memcpy(dest + off, str.data(), strLen); off += strLen; return true; } bool decodeString(ByteRange &br, string &str) { uint64_t strLen; if (!decodeUInt64(br, strLen)) { return false; } if (strLen > br.size()) { WLOG(ERROR) << "Not enough room with " << br.size() << " to decode " << strLen; return false; } str.assign((const char *)(br.start()), strLen); br.advance(strLen); return true; } } }