1/*
2 * Copyright 2009, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *				Scott T. Mansfield, thephantom@mac.com
7 *              Bruno Albuquerque, bga@bug-br.org.br
8 */
9
10#include <ByteOrder.h>
11#include <Message.h>
12#include <TypeConstants.h>
13
14#include "DynamicBuffer.h"
15#include "NetBuffer.h"
16
17#include <new>
18#include <string.h>
19
20BNetBuffer::BNetBuffer(size_t size) :
21	BArchivable(),
22	fInit(B_NO_INIT)
23{
24	fImpl = new (std::nothrow) DynamicBuffer(size);
25	if (fImpl != NULL)
26		fInit = fImpl->InitCheck();
27}
28
29
30BNetBuffer::~BNetBuffer()
31{
32	delete fImpl;
33}
34
35
36BNetBuffer::BNetBuffer(const BNetBuffer& buffer) :
37	BArchivable(),
38	fInit(B_NO_INIT)
39{
40	fImpl = new (std::nothrow) DynamicBuffer(*buffer.GetImpl());
41	if (fImpl != NULL)
42		fInit = fImpl->InitCheck();
43}
44
45
46BNetBuffer::BNetBuffer(BMessage* archive) :
47	BArchivable(),
48	fInit(B_NO_INIT)
49{
50	const unsigned char* bufferPtr;
51	ssize_t bufferSize;
52
53	if (archive->FindData("buffer", B_RAW_TYPE, (const void**)&bufferPtr,
54		&bufferSize) == B_OK) {
55		fImpl = new (std::nothrow) DynamicBuffer(bufferSize);
56		if (fImpl != NULL) {
57			ssize_t result = fImpl->Write(bufferPtr, bufferSize);
58			if (result >= 0)
59				fInit = fImpl->InitCheck();
60			else
61				fInit = result;
62		}
63	}
64}
65
66BNetBuffer&
67BNetBuffer::operator=(const BNetBuffer& buffer)
68{
69	if (&buffer != this) {
70		delete fImpl;
71
72		fImpl = new (std::nothrow) DynamicBuffer(*buffer.GetImpl());
73		if (fImpl != NULL)
74			fInit = fImpl->InitCheck();
75	}
76	return *this;
77}
78
79
80status_t
81BNetBuffer::Archive(BMessage* into, bool deep) const
82{
83	if (fInit != B_OK)
84		return B_NO_INIT;
85
86	status_t result = into->AddData("buffer", B_RAW_TYPE, fImpl->Data(),
87		fImpl->BytesRemaining());
88
89	return result;
90}
91
92
93BArchivable*
94BNetBuffer::Instantiate(BMessage* archive)
95{
96    if (!validate_instantiation(archive, "BNetBuffer"))
97        return NULL;
98
99    BNetBuffer* buffer = new (std::nothrow) BNetBuffer(archive);
100    if (buffer == NULL)
101        return NULL;
102
103    if (buffer->InitCheck() != B_OK) {
104        delete buffer;
105        return NULL;
106    }
107
108    return buffer;
109}
110
111
112status_t
113BNetBuffer::InitCheck()
114{
115	return fInit;
116}
117
118
119status_t
120BNetBuffer::AppendInt8(int8 data)
121{
122	return AppendData((const void*)&data, sizeof(int8));
123}
124
125
126status_t
127BNetBuffer::AppendUint8(uint8 data)
128{
129	return AppendData((const void*)&data, sizeof(int8));
130}
131
132
133status_t
134BNetBuffer::AppendInt16(int16 data)
135{
136	int16 be_data = B_HOST_TO_BENDIAN_INT16(data);
137	return AppendData((const void*)&be_data, sizeof(int16));
138}
139
140
141status_t
142BNetBuffer::AppendUint16(uint16 data)
143{
144	uint16 be_data = B_HOST_TO_BENDIAN_INT16(data);
145	return AppendData((const void*)&be_data, sizeof(uint16));
146}
147
148
149status_t
150BNetBuffer::AppendInt32(int32 data)
151{
152	int32 be_data = B_HOST_TO_BENDIAN_INT32(data);
153	return AppendData((const void*)&be_data, sizeof(int32));
154}
155
156
157status_t
158BNetBuffer::AppendUint32(uint32 data)
159{
160	uint32 be_data = B_HOST_TO_BENDIAN_INT32(data);
161	return AppendData((const void*)&be_data, sizeof(uint32));
162}
163
164
165status_t
166BNetBuffer::AppendFloat(float data)
167{
168	return AppendData((const void*)&data, sizeof(float));
169}
170
171
172status_t
173BNetBuffer::AppendDouble(double data)
174{
175	return AppendData((const void*)&data, sizeof(double));
176}
177
178
179status_t
180BNetBuffer::AppendString(const char* data)
181{
182	return AppendData((const void*)data, strlen(data) + 1);
183}
184
185
186status_t
187BNetBuffer::AppendData(const void* data, size_t size)
188{
189	if (fInit != B_OK)
190		return B_NO_INIT;
191
192	ssize_t bytesWritten = fImpl->Write(data, size);
193	if (bytesWritten < 0)
194		return (status_t)bytesWritten;
195	return (size_t)bytesWritten == size ? B_OK : B_ERROR;
196}
197
198
199#define STACK_BUFFER_SIZE 2048
200
201status_t
202BNetBuffer::AppendMessage(const BMessage& data)
203{
204	char stackFlattenedData[STACK_BUFFER_SIZE];
205
206	ssize_t dataSize = data.FlattenedSize();
207
208	if (dataSize < 0)
209		return dataSize;
210
211	if (dataSize == 0)
212		return B_ERROR;
213
214	status_t result = B_OK;
215
216	if (dataSize > STACK_BUFFER_SIZE) {
217		char* flattenedData = new (std::nothrow) char[dataSize];
218		if (flattenedData == NULL)
219			return B_NO_MEMORY;
220
221		if (data.Flatten(flattenedData, dataSize) == B_OK)
222			result = AppendData((const void*)&flattenedData, dataSize);
223
224		delete[] flattenedData;
225	} else {
226		if (data.Flatten(stackFlattenedData, dataSize) == B_OK)
227			result = AppendData((const void*)&stackFlattenedData, dataSize);
228	}
229
230	return result;
231}
232
233
234status_t
235BNetBuffer::AppendInt64(int64 data)
236{
237	int64 be_data = B_HOST_TO_BENDIAN_INT64(data);
238	return AppendData((const void*)&be_data, sizeof(int64));
239}
240
241
242status_t
243BNetBuffer::AppendUint64(uint64 data)
244{
245	uint64 be_data = B_HOST_TO_BENDIAN_INT64(data);
246	return AppendData((const void*)&be_data, sizeof(uint64));
247}
248
249
250status_t
251BNetBuffer::RemoveInt8(int8& data)
252{
253	return RemoveData((void*)&data, sizeof(int8));
254}
255
256
257status_t
258BNetBuffer::RemoveUint8(uint8& data)
259{
260	return RemoveData((void*)&data, sizeof(uint8));
261}
262
263
264status_t
265BNetBuffer::RemoveInt16(int16& data)
266{
267	int16 be_data;
268	status_t result = RemoveData((void*)&be_data, sizeof(int16));
269	if (result != B_OK)
270		return result;
271
272	data = B_BENDIAN_TO_HOST_INT16(be_data);
273
274	return B_OK;
275}
276
277
278status_t
279BNetBuffer::RemoveUint16(uint16& data)
280{
281	uint16 be_data;
282	status_t result = RemoveData((void*)&be_data, sizeof(uint16));
283	if (result != B_OK)
284		return result;
285
286	data = B_BENDIAN_TO_HOST_INT16(be_data);
287
288	return B_OK;
289}
290
291
292status_t
293BNetBuffer::RemoveInt32(int32& data)
294{
295	int32 be_data;
296	status_t result = RemoveData((void*)&be_data, sizeof(int32));
297	if (result != B_OK)
298		return result;
299
300	data = B_BENDIAN_TO_HOST_INT32(be_data);
301
302	return B_OK;
303}
304
305
306status_t
307BNetBuffer::RemoveUint32(uint32& data)
308{
309	uint32 be_data;
310	status_t result = RemoveData((void*)&be_data, sizeof(uint32));
311	if (result != B_OK)
312		return result;
313
314	data = B_BENDIAN_TO_HOST_INT32(be_data);
315
316	return B_OK;
317}
318
319
320status_t
321BNetBuffer::RemoveFloat(float& data)
322{
323	return RemoveData((void*)&data, sizeof(float));
324}
325
326
327status_t
328BNetBuffer::RemoveDouble(double& data)
329{
330	return RemoveData((void*)&data, sizeof(double));
331}
332
333
334status_t
335BNetBuffer::RemoveString(char* data, size_t size)
336{
337	// TODO(bga): Should we do anything specific to handle the terminating
338	// NULL byte?
339	return RemoveData((void*)data, size);
340}
341
342
343status_t
344BNetBuffer::RemoveData(void* data, size_t size)
345{
346	if (fInit != B_OK)
347		return B_NO_INIT;
348
349	ssize_t bytesRead = fImpl->Read(data, size);
350	if (bytesRead < 0)
351		return (status_t)bytesRead;
352	return (size_t)bytesRead == size ? B_OK : B_BUFFER_OVERFLOW;
353}
354
355
356status_t
357BNetBuffer::RemoveMessage(BMessage& data)
358{
359	if (fInit != B_OK)
360		return B_NO_INIT;
361
362	unsigned char* bufferPtr = fImpl->Data();
363
364	if (*(int32*)bufferPtr != B_MESSAGE_TYPE)
365		return B_ERROR;
366
367	bufferPtr += sizeof(int32);
368	int32 dataSize = *(int32*)bufferPtr;
369
370	char* flattenedData = new (std::nothrow) char[dataSize];
371	if (flattenedData == NULL)
372		return B_NO_MEMORY;
373
374	status_t result = RemoveData(flattenedData, dataSize);
375	if (result == B_OK)
376		result = data.Unflatten(flattenedData);
377
378	delete[] flattenedData;
379
380	return result;
381}
382
383
384status_t
385BNetBuffer::RemoveInt64(int64& data)
386{
387	int64 be_data;
388	status_t result = RemoveData((void*)&be_data, sizeof(int64));
389	if (result != B_OK)
390		return result;
391
392	data = B_BENDIAN_TO_HOST_INT64(be_data);
393
394	return B_OK;
395}
396
397
398status_t
399BNetBuffer::RemoveUint64(uint64& data)
400{
401	uint64 be_data;
402	status_t result = RemoveData((void*)&be_data, sizeof(uint64));
403	if (result != B_OK)
404		return result;
405
406	data = B_BENDIAN_TO_HOST_INT64(be_data);
407
408	return B_OK;
409}
410
411
412unsigned char*
413BNetBuffer::Data() const
414{
415	if (fInit != B_OK)
416		return NULL;
417
418	return fImpl->Data();
419}
420
421
422size_t
423BNetBuffer::Size() const
424{
425	if (fInit != B_OK)
426		return 0;
427
428	return fImpl->Size();
429}
430
431
432size_t
433BNetBuffer::BytesRemaining() const
434{
435	if (fInit != B_OK)
436		return 0;
437
438	return fImpl->BytesRemaining();
439}
440
441
442void
443BNetBuffer::_ReservedBNetBufferFBCCruft1()
444{
445}
446
447
448void
449BNetBuffer::_ReservedBNetBufferFBCCruft2()
450{
451}
452
453
454void
455BNetBuffer::_ReservedBNetBufferFBCCruft3()
456{
457}
458
459
460void
461BNetBuffer::_ReservedBNetBufferFBCCruft4()
462{
463}
464
465
466void
467BNetBuffer::_ReservedBNetBufferFBCCruft5()
468{
469}
470
471
472void
473BNetBuffer::_ReservedBNetBufferFBCCruft6()
474{
475}
476