1 //
2 // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 #pragma once
8
9 #include "td/utils/common.h"
10 #include "td/utils/logging.h"
11 #include "td/utils/Slice.h"
12 #include "td/utils/StorerBase.h"
13
14 #include <cstring>
15
16 namespace td {
17
18 class TlStorerUnsafe {
19 unsigned char *buf_;
20
21 public:
TlStorerUnsafe(unsigned char * buf)22 explicit TlStorerUnsafe(unsigned char *buf) : buf_(buf) {
23 }
24
25 TlStorerUnsafe(const TlStorerUnsafe &other) = delete;
26 TlStorerUnsafe &operator=(const TlStorerUnsafe &other) = delete;
27
28 template <class T>
store_binary(const T & x)29 void store_binary(const T &x) {
30 std::memcpy(buf_, &x, sizeof(T));
31 buf_ += sizeof(T);
32 }
33
store_int(int32 x)34 void store_int(int32 x) {
35 store_binary<int32>(x);
36 }
37
store_long(int64 x)38 void store_long(int64 x) {
39 store_binary<int64>(x);
40 }
41
store_slice(Slice slice)42 void store_slice(Slice slice) {
43 std::memcpy(buf_, slice.begin(), slice.size());
44 buf_ += slice.size();
45 }
46
store_storer(const Storer & storer)47 void store_storer(const Storer &storer) {
48 size_t size = storer.store(buf_);
49 buf_ += size;
50 }
51
52 template <class T>
store_string(const T & str)53 void store_string(const T &str) {
54 size_t len = str.size();
55 if (len < 254) {
56 *buf_++ = static_cast<unsigned char>(len);
57 len++;
58 } else if (len < (1 << 24)) {
59 *buf_++ = static_cast<unsigned char>(254);
60 *buf_++ = static_cast<unsigned char>(len & 255);
61 *buf_++ = static_cast<unsigned char>((len >> 8) & 255);
62 *buf_++ = static_cast<unsigned char>(len >> 16);
63 } else if (static_cast<uint64>(len) < (static_cast<uint64>(1) << 32)) {
64 *buf_++ = static_cast<unsigned char>(255);
65 *buf_++ = static_cast<unsigned char>(len & 255);
66 *buf_++ = static_cast<unsigned char>((len >> 8) & 255);
67 *buf_++ = static_cast<unsigned char>((len >> 16) & 255);
68 *buf_++ = static_cast<unsigned char>((len >> 24) & 255);
69 *buf_++ = static_cast<unsigned char>(0);
70 *buf_++ = static_cast<unsigned char>(0);
71 *buf_++ = static_cast<unsigned char>(0);
72 } else {
73 LOG(FATAL) << "String size " << len << " is too big to be stored";
74 }
75 std::memcpy(buf_, str.data(), str.size());
76 buf_ += str.size();
77
78 switch (len & 3) {
79 case 1:
80 *buf_++ = 0;
81 // fallthrough
82 case 2:
83 *buf_++ = 0;
84 // fallthrough
85 case 3:
86 *buf_++ = 0;
87 }
88 }
89
get_buf()90 unsigned char *get_buf() const {
91 return buf_;
92 }
93 };
94
95 class TlStorerCalcLength {
96 size_t length = 0;
97
98 public:
99 TlStorerCalcLength() = default;
100 TlStorerCalcLength(const TlStorerCalcLength &other) = delete;
101 TlStorerCalcLength &operator=(const TlStorerCalcLength &other) = delete;
102
103 template <class T>
store_binary(const T & x)104 void store_binary(const T &x) {
105 length += sizeof(T);
106 }
107
store_int(int32 x)108 void store_int(int32 x) {
109 store_binary<int32>(x);
110 }
111
store_long(int64 x)112 void store_long(int64 x) {
113 store_binary<int64>(x);
114 }
115
store_slice(Slice slice)116 void store_slice(Slice slice) {
117 length += slice.size();
118 }
119
store_storer(const Storer & storer)120 void store_storer(const Storer &storer) {
121 length += storer.size();
122 }
123
124 template <class T>
store_string(const T & str)125 void store_string(const T &str) {
126 size_t add = str.size();
127 if (add < 254) {
128 add += 1;
129 } else if (add < (1 << 24)) {
130 add += 4;
131 } else {
132 add += 8;
133 }
134 add = (add + 3) & -4;
135 length += add;
136 }
137
get_length()138 size_t get_length() const {
139 return length;
140 }
141 };
142
143 template <class T>
tl_calc_length(const T & data)144 size_t tl_calc_length(const T &data) {
145 TlStorerCalcLength storer_calc_length;
146 data.store(storer_calc_length);
147 return storer_calc_length.get_length();
148 }
149
150 template <class T>
151 size_t tl_store_unsafe(const T &data, unsigned char *dst) TD_WARN_UNUSED_RESULT;
152
153 template <class T>
tl_store_unsafe(const T & data,unsigned char * dst)154 size_t tl_store_unsafe(const T &data, unsigned char *dst) {
155 TlStorerUnsafe storer_unsafe(dst);
156 data.store(storer_unsafe);
157 return static_cast<size_t>(storer_unsafe.get_buf() - dst);
158 }
159
160 } // namespace td
161