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