Pyrogenesis  trunk
BinarySerializer.h
Go to the documentation of this file.
1 /* Copyright (C) 2021 Wildfire Games.
2  * This file is part of 0 A.D.
3  *
4  * 0 A.D. is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * 0 A.D. is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef INCLUDED_BINARYSERIALIZER
19 #define INCLUDED_BINARYSERIALIZER
20 
21 #include "ISerializer.h"
22 
23 #include "lib/byte_order.h"
24 
26 
27 #include <ostream>
28 #include <streambuf>
29 
30 /**
31  * Wrapper for redirecting ostream writes to CBinarySerializer's impl
32  */
33 template<typename T>
34 class CSerializerStreamBuf : public std::streambuf
35 {
38  char m_Buffer[2048];
39 public:
41  m_SerializerImpl(impl)
42  {
43  setp(m_Buffer, m_Buffer + ARRAY_SIZE(m_Buffer) - 1);
44  }
45 
46 protected:
47  // Override overflow and sync, because older versions of libc++ streams
48  // write strings as individual characters, then xsputn is never called
49  int overflow(int ch)
50  {
51  if (ch == traits_type::eof())
52  return traits_type::not_eof(ch);
53 
54  ENSURE(pptr() <= epptr());
55  *pptr() = ch;
56  pbump(1);
57  sync();
58  return ch;
59  }
60 
61  int sync()
62  {
63  std::ptrdiff_t n = pptr() - pbase();
64  if (n != 0)
65  {
66  pbump(-n);
67  m_SerializerImpl.Put("stream", reinterpret_cast<const u8*> (pbase()), n);
68  }
69  return 0;
70  }
71 
72  std::streamsize xsputn(const char* s, std::streamsize n)
73  {
74  m_SerializerImpl.Put("stream", reinterpret_cast<const u8*> (s), n);
75  return n;
76  }
77 };
78 
79 /**
80  * PutScriptVal implementation details.
81  * (Split out from the main class because it's too big to be inlined.)
82  */
84 {
85 public:
86  CBinarySerializerScriptImpl(const ScriptInterface& scriptInterface, ISerializer& serializer);
88 
89  void ScriptString(const char* name, JS::HandleString string);
90  void HandleScriptVal(JS::HandleValue val);
91 private:
92  static void Trace(JSTracer* trc, void* data);
93 
96 
97  using ObjectTagMap = JS::GCHashMap<JS::Heap<JSObject*>, u32, js::MovableCellHasher<JSObject*>, js::SystemAllocPolicy>;
100  u32 GetScriptBackrefTag(JS::HandleObject obj);
101 };
102 
103 /**
104  * Serialize to a binary stream. T must just implement the Put() method.
105  * (We use this templated approach to allow compiler inlining.)
106  */
107 template <typename T>
109 {
111 public:
112  CBinarySerializer(const ScriptInterface& scriptInterface) :
113  m_ScriptImpl(new CBinarySerializerScriptImpl(scriptInterface, *this)),
114  m_RawStreamBuf(m_Impl),
115  m_RawStream(&m_RawStreamBuf)
116  {
117  }
118 
119  template <typename A>
120  CBinarySerializer(const ScriptInterface& scriptInterface, A& a) :
121  m_ScriptImpl(new CBinarySerializerScriptImpl(scriptInterface, *this)),
122  m_Impl(a),
123  m_RawStreamBuf(m_Impl),
124  m_RawStream(&m_RawStreamBuf)
125  {
126  }
127 
128 protected:
129  /*
130  The Put* implementations here are designed for subclasses
131  that want an efficient, portable, deserializable representation.
132  (Subclasses with different requirements should override these methods.)
133 
134  Numbers are converted to little-endian byte strings, for portability
135  and efficiency.
136 
137  Data is not aligned, for storage efficiency.
138  */
139 
140  virtual void PutNumber(const char* name, uint8_t value)
141  {
142  m_Impl.Put(name, (const u8*)&value, sizeof(uint8_t));
143  }
144 
145  virtual void PutNumber(const char* name, int8_t value)
146  {
147  m_Impl.Put(name, (const u8*)&value, sizeof(int8_t));
148  }
149 
150  virtual void PutNumber(const char* name, uint16_t value)
151  {
152  uint16_t v = to_le16(value);
153  m_Impl.Put(name, (const u8*)&v, sizeof(uint16_t));
154  }
155 
156  virtual void PutNumber(const char* name, int16_t value)
157  {
158  int16_t v = (i16)to_le16((u16)value);
159  m_Impl.Put(name, (const u8*)&v, sizeof(int16_t));
160  }
161 
162  virtual void PutNumber(const char* name, uint32_t value)
163  {
164  uint32_t v = to_le32(value);
165  m_Impl.Put(name, (const u8*)&v, sizeof(uint32_t));
166  }
167 
168  virtual void PutNumber(const char* name, int32_t value)
169  {
170  int32_t v = (i32)to_le32((u32)value);
171  m_Impl.Put(name, (const u8*)&v, sizeof(int32_t));
172  }
173 
174  virtual void PutNumber(const char* name, float value)
175  {
176  m_Impl.Put(name, (const u8*)&value, sizeof(float));
177  }
178 
179  virtual void PutNumber(const char* name, double value)
180  {
181  m_Impl.Put(name, (const u8*)&value, sizeof(double));
182  }
183 
184  virtual void PutNumber(const char* name, fixed value)
185  {
186  int32_t v = (i32)to_le32((u32)value.GetInternalValue());
187  m_Impl.Put(name, (const u8*)&v, sizeof(int32_t));
188  }
189 
190  virtual void PutBool(const char* name, bool value)
191  {
192  NumberU8(name, value ? 1 : 0, 0, 1);
193  }
194 
195  virtual void PutString(const char* name, const std::string& value)
196  {
197  // TODO: maybe should intern strings, particularly to save space with script property names
198  PutNumber("string length", (uint32_t)value.length());
199  m_Impl.Put(name, (u8*)value.data(), value.length());
200  }
201 
202  virtual void PutScriptVal(const char* UNUSED(name), JS::MutableHandleValue value)
203  {
204  m_ScriptImpl->HandleScriptVal(value);
205  }
206 
207  virtual void PutRaw(const char* name, const u8* data, size_t len)
208  {
209  m_Impl.Put(name, data, len);
210  }
211 
212  virtual std::ostream& GetStream()
213  {
214  return m_RawStream;
215  }
216 
217 protected:
219 
220 private:
221  std::unique_ptr<CBinarySerializerScriptImpl> m_ScriptImpl;
222 
224  std::ostream m_RawStream;
225 };
226 
227 #endif // INCLUDED_BINARYSERIALIZER
signed char int8_t
Definition: wposix_types.h:37
A simple fixed-point number class.
Definition: Fixed.h:119
int overflow(int ch)
Definition: BinarySerializer.h:49
CBinarySerializer(const ScriptInterface &scriptInterface, A &a)
Definition: BinarySerializer.h:120
char m_Buffer[2048]
Definition: BinarySerializer.h:38
CSerializerStreamBuf< T > m_RawStreamBuf
Definition: BinarySerializer.h:223
#define UNUSED(param)
mark a function parameter as unused and avoid the corresponding compiler warning. ...
Definition: code_annotation.h:38
uint16_t u16
Definition: types.h:38
Serialization interface; see serialization overview.
Definition: ISerializer.h:120
#define to_le16(x)
Definition: byte_order.h:77
short int16_t
Definition: wposix_types.h:38
virtual void PutNumber(const char *name, int32_t value)
Definition: BinarySerializer.h:168
virtual void PutNumber(const char *name, fixed value)
Definition: BinarySerializer.h:184
virtual void PutNumber(const char *name, float value)
Definition: BinarySerializer.h:174
T GetInternalValue() const
Definition: Fixed.h:135
ISerializer & m_Serializer
Definition: BinarySerializer.h:95
std::ostream m_RawStream
Definition: BinarySerializer.h:224
virtual void PutRaw(const char *name, const u8 *data, size_t len)
Definition: BinarySerializer.h:207
virtual void PutBool(const char *name, bool value)
Definition: BinarySerializer.h:190
uint8_t u8
Definition: types.h:37
#define ARRAY_SIZE(name)
Definition: code_annotation.h:348
PutScriptVal implementation details.
Definition: BinarySerializer.h:83
virtual void PutNumber(const char *name, uint32_t value)
Definition: BinarySerializer.h:162
u32 m_ScriptBackrefsNext
Definition: BinarySerializer.h:99
JS::GCHashMap< JS::Heap< JSObject * >, u32, js::MovableCellHasher< JSObject * >, js::SystemAllocPolicy > ObjectTagMap
Definition: BinarySerializer.h:97
#define ENSURE(expr)
ensure the expression <expr> evaluates to non-zero.
Definition: debug.h:290
uint32_t u32
Definition: types.h:39
std::streamsize xsputn(const char *s, std::streamsize n)
Definition: BinarySerializer.h:72
T & m_SerializerImpl
Definition: BinarySerializer.h:37
virtual void PutString(const char *name, const std::string &value)
Definition: BinarySerializer.h:195
#define to_le32(x)
Definition: byte_order.h:78
unsigned char uint8_t
Definition: wposix_types.h:51
Definition: trace.cpp:144
int sync()
Definition: BinarySerializer.h:61
virtual void PutNumber(const char *name, int8_t value)
Definition: BinarySerializer.h:145
#define T(string_literal)
Definition: secure_crt.cpp:77
ObjectTagMap m_ScriptBackrefTags
Definition: BinarySerializer.h:98
int32_t i32
Definition: types.h:34
NONCOPYABLE(CSerializerStreamBuf)
virtual void PutNumber(const char *name, int16_t value)
Definition: BinarySerializer.h:156
virtual std::ostream & GetStream()
Returns a stream which can be used to serialize data directly.
Definition: BinarySerializer.h:212
const ScriptInterface & m_ScriptInterface
Definition: BinarySerializer.h:94
unsigned int uint32_t
Definition: wposix_types.h:53
T m_Impl
Definition: BinarySerializer.h:218
virtual void PutNumber(const char *name, uint16_t value)
Definition: BinarySerializer.h:150
Abstraction around a SpiderMonkey JS::Realm.
Definition: ScriptInterface.h:71
int16_t i16
Definition: types.h:33
Serialize to a binary stream.
Definition: BinarySerializer.h:108
CBinarySerializer(const ScriptInterface &scriptInterface)
Definition: BinarySerializer.h:112
unsigned short uint16_t
Definition: wposix_types.h:52
Wrapper for redirecting ostream writes to CBinarySerializer&#39;s impl.
Definition: BinarySerializer.h:34
virtual void PutNumber(const char *name, double value)
Definition: BinarySerializer.h:179
virtual void PutScriptVal(const char *name, JS::MutableHandleValue value)
Definition: BinarySerializer.h:202
std::unique_ptr< CBinarySerializerScriptImpl > m_ScriptImpl
Definition: BinarySerializer.h:221
virtual void PutNumber(const char *name, uint8_t value)
Definition: BinarySerializer.h:140
CSerializerStreamBuf(T &impl)
Definition: BinarySerializer.h:40