1
2
3
4
5
6 #include <soulng/util/BinaryWriter.hpp>
7 #include <soulng/util/TextUtils.hpp>
8 #include <soulng/util/Unicode.hpp>
9
10 namespace soulng { namespace util {
11
12 using namespace soulng::unicode;
13
14 BinaryWriter::BinaryWriter(const std::string& fileName_) : fileName(fileName_), file(OpenWrite(fileName.c_str()), fileName, LockKind::write), buffer(), bufp(buffer), bufend(buffer + N), pos(0)
15 {
16 if (!file)
17 {
18 throw std::runtime_error("could not open '" + fileName + "' for writing: " + soulng::util::PlatformStringToUtf8(std::strerror(errno)));
19 }
20 }
21
22 BinaryWriter::~BinaryWriter()
23 {
24 FlushBuffer();
25 }
26
27 void BinaryWriter::Write(bool x)
28 {
29 Write(uint8_t(x));
30 }
31
32 void BinaryWriter::Write(uint8_t x)
33 {
34 if (BufferFull())
35 {
36 FlushBuffer();
37 }
38 *bufp++ = x;
39 ++pos;
40 }
41
42 void BinaryWriter::Write(int8_t x)
43 {
44 Write(static_cast<uint8_t>(x));
45 }
46
47 void BinaryWriter::Write(uint16_t x)
48 {
49 uint8_t b0 = static_cast<uint8_t>(x >> 8);
50 uint8_t b1 = static_cast<uint8_t>(x);
51 Write(b0);
52 Write(b1);
53 }
54
55 void BinaryWriter::Write(int16_t x)
56 {
57 Write(static_cast<uint16_t>(x));
58 }
59
60 void BinaryWriter::Write(uint32_t x)
61 {
62 uint8_t b0 = static_cast<uint8_t>(x >> 24);
63 uint8_t b1 = static_cast<uint8_t>(x >> 16);
64 uint8_t b2 = static_cast<uint8_t>(x >> 8);
65 uint8_t b3 = static_cast<uint8_t>(x);
66 Write(b0);
67 Write(b1);
68 Write(b2);
69 Write(b3);
70 }
71
72 void BinaryWriter::Write(int32_t x)
73 {
74 Write(static_cast<uint32_t>(x));
75 }
76
77 void BinaryWriter::Write(uint64_t x)
78 {
79 uint8_t b0 = static_cast<uint8_t>(x >> 56);
80 uint8_t b1 = static_cast<uint8_t>(x >> 48);
81 uint8_t b2 = static_cast<uint8_t>(x >> 40);
82 uint8_t b3 = static_cast<uint8_t>(x >> 32);
83 uint8_t b4 = static_cast<uint8_t>(x >> 24);
84 uint8_t b5 = static_cast<uint8_t>(x >> 16);
85 uint8_t b6 = static_cast<uint8_t>(x >> 8);
86 uint8_t b7 = static_cast<uint8_t>(x);
87 Write(b0);
88 Write(b1);
89 Write(b2);
90 Write(b3);
91 Write(b4);
92 Write(b5);
93 Write(b6);
94 Write(b7);
95 }
96
97 void BinaryWriter::Write(int64_t x)
98 {
99 Write(static_cast<uint64_t>(x));
100 }
101
102 void BinaryWriter::Write(float x)
103 {
104 uint32_t* u = reinterpret_cast<uint32_t*>(&x);
105 Write(*u);
106 }
107
108 void BinaryWriter::Write(double x)
109 {
110 uint64_t* u = reinterpret_cast<uint64_t*>(&x);
111 Write(*u);
112 }
113
114 void BinaryWriter::Write(char x)
115 {
116 Write(static_cast<uint8_t>(x));
117 }
118
119 void BinaryWriter::Write(char16_t x)
120 {
121 Write(static_cast<uint16_t>(x));
122 }
123
124 void BinaryWriter::Write(char32_t x)
125 {
126 Write(static_cast<uint32_t>(x));
127 }
128
129 void BinaryWriter::Write(const std::string& s)
130 {
131 Write(s, true);
132 }
133
134 void BinaryWriter::Write(const std::string& s, bool writeNull)
135 {
136 for (char c : s)
137 {
138 uint8_t x = static_cast<uint8_t>(c);
139 Write(x);
140 }
141 if (writeNull)
142 {
143 Write(static_cast<uint8_t>(0));
144 }
145 }
146
147 void BinaryWriter::Write(const std::u16string& s)
148 {
149 std::string utf8_str = ToUtf8(s);
150 Write(utf8_str);
151 }
152
153 void BinaryWriter::Write(const std::u32string& s)
154 {
155 std::string utf8_str = ToUtf8(s);
156 Write(utf8_str);
157 }
158
159 void BinaryWriter::WriteULEB128UInt(uint32_t x)
160 {
161 do
162 {
163 uint8_t b = x & 0x7F;
164 x >>= 7;
165 if (x != 0)
166 {
167 b |= 0x80;
168 }
169 Write(b);
170 }
171 while (x != 0);
172 }
173
174 void BinaryWriter::WriteULEB128ULong(uint64_t x)
175 {
176 do
177 {
178 uint8_t b = x & 0x7F;
179 x >>= 7;
180 if (x != 0)
181 {
182 b |= 0x80;
183 }
184 Write(b);
185 }
186 while (x != 0);
187 }
188
189 void BinaryWriter::WriteSLEB128Int(int32_t x)
190 {
191 bool more = true;
192 bool negative = x < 0;
193 while (more)
194 {
195 uint8_t b = x & 0x7F;
196 x >>= 7;
197 if (negative)
198 {
199 x |= ~int32_t(0) << (32 - 7);
200 }
201 if (x == 0 && (b & 0x40) == 0 || x == -1 && (b & 0x40) != 0)
202 {
203 more = false;
204 }
205 else
206 {
207 b |= 0x80;
208 }
209 Write(b);
210 }
211 }
212
213 void BinaryWriter::WriteSLEB128Long(int64_t x)
214 {
215 bool more = true;
216 bool negative = x < 0;
217 while (more)
218 {
219 uint8_t b = x & 0x7F;
220 x >>= 7;
221 if (negative)
222 {
223 x |= ~int64_t(0) << (64 - 7);
224 }
225 if (x == 0 && (b & 0x40) == 0 || x == -1 && (b & 0x40) != 0)
226 {
227 more = false;
228 }
229 else
230 {
231 b |= 0x80;
232 }
233 Write(b);
234 }
235 }
236
237 void BinaryWriter::Write(const boost::uuids::uuid& uuid)
238 {
239 for (boost::uuids::uuid::value_type x : uuid)
240 {
241 Write(x);
242 }
243 }
244
245 void BinaryWriter::Seek(uint32_t pos_)
246 {
247 FlushBuffer();
248 pos = pos_;
249 int result = fseek(file, pos, SEEK_SET);
250 if (result != 0)
251 {
252 throw std::runtime_error("seek failed: " + soulng::util::PlatformStringToUtf8(std::strerror(errno)));
253 }
254 }
255
256 void BinaryWriter::FlushBuffer()
257 {
258 if (bufp != buffer)
259 {
260 size_t n = bufp - buffer;
261 size_t numWritten = fwrite(buffer, 1, n, file);
262 if (numWritten != n)
263 {
264 throw std::runtime_error("could not write to '" + fileName + "': " + soulng::util::PlatformStringToUtf8(std::strerror(errno)));
265 }
266 BufferReset();
267 }
268 }
269
270 } }
271