Changelog update
[public/netxms.git] / src / libnetxms / bytestream.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** NetXMS Foundation Library
4 ** Copyright (C) 2003-2017 Raden Solutions
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU Lesser General Public License as published
8 ** by the Free Software Foundation; either version 3 of the License, or
9 ** (at your option) any later version.
10 **
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
15 **
16 ** You should have received a copy of the GNU Lesser General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 **
20 ** File: bytestream.cpp
21 **
22 **/
23
24 #include "libnetxms.h"
25
26 /**
27 * Create empty byte stream
28 */
29 ByteStream::ByteStream(size_t initial)
30 {
31 m_allocated = initial;
32 m_size = 0;
33 m_pos = 0;
34 m_allocationStep = 4096;
35 m_data = (m_allocated > 0) ? (BYTE *)malloc(m_allocated) : NULL;
36 }
37
38 /**
39 * Create byte stream from existing data
40 */
41 ByteStream::ByteStream(const void *data, size_t size)
42 {
43 m_allocated = size;
44 m_size = size;
45 m_pos = 0;
46 m_allocationStep = 4096;
47 m_data = (m_allocated > 0) ? (BYTE *)nx_memdup(data, size) : NULL;
48 }
49
50 /**
51 * Destructor
52 */
53 ByteStream::~ByteStream()
54 {
55 safe_free(m_data);
56 }
57
58 /**
59 * Write data
60 */
61 void ByteStream::write(const void *data, size_t size)
62 {
63 if (m_pos + size > m_allocated)
64 {
65 m_allocated += std::max(size, m_allocationStep);
66 m_data = (BYTE *)realloc(m_data, m_allocated);
67 }
68 memcpy(&m_data[m_pos], data, size);
69 m_pos += size;
70 if (m_pos > m_size)
71 m_size = m_pos;
72 }
73
74 /**
75 * Write string in UTF-8 prepended with length
76 */
77 void ByteStream::writeString(const TCHAR *s)
78 {
79 #ifdef UNICODE
80 char *utf8str = UTF8StringFromWideString(s);
81 #else
82 char *utf8str = UTF8StringFromMBString(s);
83 #endif
84
85 // write len < 2^15 as 2 bytes and 4 bytes with higher bit set otherwise
86 UINT32 len = (UINT32)strlen(utf8str);
87 if (len < 0x8000)
88 write((UINT16)len);
89 else
90 write(len | 0x80000000);
91
92 write(utf8str, len);
93 free(utf8str);
94 }
95
96 /**
97 * Read data
98 */
99 size_t ByteStream::read(void *buffer, size_t count)
100 {
101 size_t c = std::min(count, m_size - m_pos);
102 if (c > 0)
103 {
104 memcpy(buffer, &m_data[m_pos], c);
105 m_pos += c;
106 }
107 return c;
108 }
109
110 /**
111 * Read 16 bit integer
112 */
113 INT16 ByteStream::readInt16()
114 {
115 if (m_size - m_pos < 2)
116 {
117 m_pos = m_size;
118 return 0;
119 }
120
121 UINT16 n;
122 memcpy(&n, &m_data[m_pos], 2);
123 m_pos += 2;
124 return (INT16)ntohs(n);
125 }
126
127 /**
128 * Read unsigned 16 bit integer
129 */
130 UINT16 ByteStream::readUInt16()
131 {
132 if (m_size - m_pos < 2)
133 {
134 m_pos = m_size;
135 return 0;
136 }
137
138 UINT16 n;
139 memcpy(&n, &m_data[m_pos], 2);
140 m_pos += 2;
141 return ntohs(n);
142 }
143
144 /**
145 * Read 32 bit integer
146 */
147 INT32 ByteStream::readInt32()
148 {
149 if (m_size - m_pos < 4)
150 {
151 m_pos = m_size;
152 return 0;
153 }
154
155 UINT32 n;
156 memcpy(&n, &m_data[m_pos], 4);
157 m_pos += 4;
158 return (INT32)ntohl(n);
159 }
160
161 /**
162 * Read unsigned 32 bit integer
163 */
164 UINT32 ByteStream::readUInt32()
165 {
166 if (m_size - m_pos < 4)
167 {
168 m_pos = m_size;
169 return 0;
170 }
171
172 UINT32 n;
173 memcpy(&n, &m_data[m_pos], 4);
174 m_pos += 4;
175 return ntohl(n);
176 }
177
178 /**
179 * Read 64 bit integer
180 */
181 INT64 ByteStream::readInt64()
182 {
183 if (m_size - m_pos < 8)
184 {
185 m_pos = m_size;
186 return 0;
187 }
188
189 UINT64 n;
190 memcpy(&n, &m_data[m_pos], 8);
191 m_pos += 8;
192 return (INT64)ntohq(n);
193 }
194
195 /**
196 * Read unsigned 64 bit integer
197 */
198 UINT64 ByteStream::readUInt64()
199 {
200 if (m_size - m_pos < 8)
201 {
202 m_pos = m_size;
203 return 0;
204 }
205
206 UINT64 n;
207 memcpy(&n, &m_data[m_pos], 8);
208 m_pos += 8;
209 return ntohq(n);
210 }
211
212 /**
213 * Read double
214 */
215 double ByteStream::readDouble()
216 {
217 if (m_size - m_pos < 8)
218 {
219 m_pos = m_size;
220 return 0;
221 }
222
223 double n;
224 memcpy(&n, &m_data[m_pos], 8);
225 m_pos += 8;
226 return ntohd(n);
227 }
228
229 /**
230 * Read UTF-8 encoded string. Returned string is dynamically allocated and must be freed by caller.
231 */
232 TCHAR *ByteStream::readString()
233 {
234 if (m_size - m_pos < 2)
235 return NULL;
236
237 BYTE b = readByte();
238 m_pos--;
239 size_t len;
240 if (b & 0x80)
241 {
242 // 4 byte length
243 if (m_size - m_pos < 4)
244 return NULL;
245 len = (size_t)(readUInt32() & ~0x80000000);
246 }
247 else
248 {
249 len = (size_t)readInt16();
250 }
251
252 if (m_size - m_pos < len)
253 return NULL;
254
255 TCHAR *s = (TCHAR *)malloc((len + 1) * sizeof(TCHAR));
256 #ifdef UNICODE
257 MultiByteToWideChar(CP_UTF8, 0, (char *)&m_data[m_pos], (int)len, s, (int)len + 1);
258 #else
259 utf8_to_mb((char *)&m_data[m_pos], (int)len, s, (int)len + 1);
260 #endif
261 s[len] = 0;
262 m_pos += len;
263 return s;
264 }
265
266 /**
267 * Save byte stream to file
268 */
269 bool ByteStream::save(int f)
270 {
271 #ifdef _WIN32
272 return _write(f, m_data, (unsigned int)m_size) == (unsigned int)m_size;
273 #else
274 return ::write(f, m_data, (int)m_size) == (int)m_size;
275 #endif
276 }
277
278 /**
279 * Load from file
280 */
281 ByteStream *ByteStream::load(const TCHAR *file)
282 {
283 UINT32 size;
284 BYTE *data = LoadFile(file, &size);
285 if (data == NULL)
286 return NULL;
287 ByteStream *s = new ByteStream(0);
288 s->m_allocated = (size_t)size;
289 s->m_size = (size_t)size;
290 s->m_data = data;
291 return s;
292 }