1/*
2 * Copyright 2012 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Paweł Dziepak, pdziepak@quarnos.org
7 */
8
9
10#include "XDR.h"
11
12#include <stdlib.h>
13#include <string.h>
14
15#include <ByteOrder.h>
16
17
18using namespace XDR;
19
20Stream::Stream(void* buffer, uint32 size)
21	:
22	fBuffer(reinterpret_cast<uint32*>(buffer)),
23	fSize(size),
24	fPosition(0)
25{
26}
27
28
29Stream::~Stream()
30{
31}
32
33
34uint32
35Stream::_PositionToSize() const
36{
37	return fPosition * sizeof(uint32);
38}
39
40
41uint32
42Stream::_RealSize(uint32 size) const
43{
44	uint32 real_size = size;
45	if (real_size % 4 != 0)
46		real_size = ((real_size >> 2) + 1) << 2;
47	return real_size;
48}
49
50
51ReadStream::ReadStream(void* buffer, uint32 size)
52	:
53	Stream(buffer, size),
54	fEOF(false)
55{
56}
57
58
59ReadStream::~ReadStream()
60{
61}
62
63
64int32
65ReadStream::GetInt()
66{
67	if (_PositionToSize() >= fSize) {
68		fEOF = true;
69		return 0;
70	}
71
72	return B_BENDIAN_TO_HOST_INT32(fBuffer[fPosition++]);
73}
74
75
76uint32
77ReadStream::GetUInt()
78{
79	if (_PositionToSize() >= fSize) {
80		fEOF = true;
81		return 0;
82	}
83
84	return B_BENDIAN_TO_HOST_INT32(fBuffer[fPosition++]);
85}
86
87
88int64
89ReadStream::GetHyper()
90{
91	if (_PositionToSize() + sizeof(int64) > fSize) {
92		fEOF = true;
93		return 0;
94	}
95
96	int64* ptr = reinterpret_cast<int64*>(fBuffer + fPosition);
97	fPosition += 2;
98
99	return B_BENDIAN_TO_HOST_INT64(*ptr);
100}
101
102
103uint64
104ReadStream::GetUHyper()
105{
106	if (_PositionToSize() + sizeof(uint64) > fSize) {
107		fEOF = true;
108		return 0;
109	}
110
111	uint64* ptr = reinterpret_cast<uint64*>(fBuffer + fPosition);
112	fPosition += 2;
113
114	return B_BENDIAN_TO_HOST_INT64(*ptr);
115}
116
117
118char*
119ReadStream::GetString()
120{
121	if (_PositionToSize() >= fSize) {
122		fEOF = true;
123		return NULL;
124	}
125
126	uint32 size;
127	const void* ptr = GetOpaque(&size);
128	if (ptr == NULL)
129		return NULL;
130
131	char* str = reinterpret_cast<char*>(malloc(size + 1));
132	if (str == NULL)
133		return NULL;
134
135	memcpy(str, ptr, size);
136	str[size] = 0;
137
138	return str;
139}
140
141
142const void*
143ReadStream::GetOpaque(uint32* size)
144{
145	if (_PositionToSize() >= fSize) {
146		fEOF = true;
147		return NULL;
148	}
149
150	void* ptr = NULL;
151	uint32 s = GetUInt();
152	if (s != 0) {
153		ptr = fBuffer + fPosition;
154		if (_PositionToSize() + s <= fSize)
155			fPosition += _RealSize(s) / sizeof(uint32);
156		else {
157			s = fSize - _PositionToSize();
158			fPosition = fSize;
159		}
160	}
161
162	if (size != NULL)
163		*size = s;
164
165	return ptr;
166}
167
168
169WriteStream::WriteStream()
170	:
171	Stream(malloc(kInitialSize), kInitialSize),
172	fError(B_OK)
173{
174}
175
176
177WriteStream::WriteStream(const WriteStream& x)
178	:
179	Stream(malloc(x.fSize), x.fSize),
180	fError(x.fError)
181{
182	fPosition = x.fPosition;
183	memcpy(fBuffer, x.fBuffer, fSize);
184}
185
186
187WriteStream::~WriteStream()
188{
189	free(fBuffer);
190}
191
192
193void
194WriteStream::Clear()
195{
196	free(fBuffer);
197	fSize = kInitialSize;
198	fBuffer = reinterpret_cast<uint32*>(malloc(fSize));
199	fError = B_OK;
200	fPosition = 0;
201}
202
203
204status_t
205WriteStream::InsertUInt(Stream::Position pos, uint32 x)
206{
207	if (pos * sizeof(uint32) >= fSize) {
208		fError = B_BAD_VALUE;
209		return B_BAD_VALUE;
210	}
211
212	fBuffer[pos] = B_HOST_TO_BENDIAN_INT32(x);
213	return B_OK;
214}
215
216
217status_t
218WriteStream::AddInt(int32 x)
219{
220	status_t err = _CheckResize(sizeof(int32));
221	if (err != B_OK)
222		return err;
223
224	fBuffer[fPosition++] = B_HOST_TO_BENDIAN_INT32(x);
225	return B_OK;
226}
227
228
229status_t
230WriteStream::AddUInt(uint32 x)
231{
232	status_t err = _CheckResize(sizeof(uint32));
233	if (err != B_OK)
234		return err;
235
236	fBuffer[fPosition++] = B_HOST_TO_BENDIAN_INT32(x);
237	return B_OK;
238}
239
240
241status_t
242WriteStream::AddHyper(int64 x)
243{
244	status_t err = _CheckResize(sizeof(int64));
245	if (err != B_OK)
246		return err;
247
248	int64* ptr = reinterpret_cast<int64*>(fBuffer + fPosition);
249	*ptr = B_HOST_TO_BENDIAN_INT64(x);
250	fPosition += 2;
251	return B_OK;
252}
253
254
255status_t
256WriteStream::AddUHyper(uint64 x)
257{
258	status_t err = _CheckResize(sizeof(uint64));
259	if (err != B_OK)
260		return err;
261
262	uint64* ptr = reinterpret_cast<uint64*>(fBuffer + fPosition);
263	*ptr = B_HOST_TO_BENDIAN_INT64(x);
264	fPosition += 2;
265	return B_OK;
266}
267
268
269status_t
270WriteStream::AddString(const char* str, uint32 maxlen)
271{
272	uint32 len = strlen(str);
273	uint32 size = maxlen == 0 ? len : min_c(maxlen, len);
274
275	return AddOpaque(str, size);
276}
277
278
279status_t
280WriteStream::AddOpaque(const void* ptr, uint32 size)
281{
282	uint32 real_size = _RealSize(size);
283	status_t err = _CheckResize(real_size + sizeof(uint32));
284	if (err != B_OK)
285		return err;
286
287	AddUInt(size);
288	memset(fBuffer + fPosition, 0, real_size);
289	memcpy(fBuffer + fPosition, ptr, size);
290	fPosition += real_size / sizeof(int32);
291
292	return B_OK;
293}
294
295
296status_t
297WriteStream::AddOpaque(const WriteStream& stream)
298{
299	return AddOpaque(stream.Buffer(), stream.Size());
300}
301
302
303status_t
304WriteStream::Append(const WriteStream& stream)
305{
306	uint32 size = stream.Size();
307	status_t err = _CheckResize(size);
308	if (err != B_OK)
309		return err;
310
311	memcpy(fBuffer + fPosition, stream.Buffer(), size);
312	fPosition += size / sizeof(int32);
313
314	return B_OK;
315}
316
317
318status_t
319WriteStream::_CheckResize(uint32 size)
320{
321	if (_PositionToSize() + size <= fSize)
322		return B_OK;
323
324	uint32 new_size = max_c(fSize * 2, fPosition * sizeof(uint32) + size);
325
326	void* ptr = realloc(fBuffer, new_size);
327	if (ptr == NULL) {
328		fError = B_NO_MEMORY;
329		return B_NO_MEMORY;
330	}
331
332	fBuffer = reinterpret_cast<uint32*>(ptr);
333	fSize = new_size;
334
335	return B_OK;
336}
337
338