1// RequestUnflattener.cpp
2
3#include <stdlib.h>
4
5#include <ByteOrder.h>
6
7#include "Compatibility.h"
8#include "DebugSupport.h"
9#include "RequestUnflattener.h"
10
11const int32 kMaxSaneStringSize	= 4096;			// 4 KB
12const int32 kMaxSaneDataSize	= 128 * 1024;	// 128 KB
13
14// constructor
15Reader::Reader()
16{
17}
18
19// destructor
20Reader::~Reader()
21{
22}
23
24// Read
25status_t
26Reader::Read(int32 size, void** buffer, bool* mustFree)
27{
28	// check params
29	if (size < 0 || !buffer || !mustFree)
30		return B_BAD_VALUE;
31
32	// deal with size == 0
33	if (size == 0) {
34		*buffer = NULL;
35		*mustFree = false;
36		return B_OK;
37	}
38
39	// allocate the buffer and read
40	*buffer = malloc(size);
41	if (!*buffer)
42		return B_NO_MEMORY;
43	status_t error = Read(*buffer, size);
44	if (error != B_OK) {
45		free(*buffer);
46		return error;
47	}
48	return error;
49}
50
51// Skip
52status_t
53Reader::Skip(int32 size)
54{
55	if (size <= 0)
56		return B_OK;
57
58	if (size > 8)
59		return B_BAD_VALUE;
60
61	char buffer[8];
62	return Read(buffer, size);
63}
64
65
66
67// RequestUnflattener
68
69// constructor
70RequestUnflattener::RequestUnflattener(Reader* reader)
71	: RequestMemberVisitor(),
72	  fReader(reader),
73	  fStatus(B_OK),
74	  fBytesRead(0)
75{
76}
77
78// GetStatus
79status_t
80RequestUnflattener::GetStatus() const
81{
82	return fStatus;
83}
84
85// GetBytesRead
86int32
87RequestUnflattener::GetBytesRead() const
88{
89	return fBytesRead;
90}
91
92// Visit
93void
94RequestUnflattener::Visit(RequestMember* member, bool& data)
95{
96	uint8 netData;
97	if (Read(&netData, 1) == B_OK)
98		data = netData;
99}
100
101// Visit
102void
103RequestUnflattener::Visit(RequestMember* member, int8& data)
104{
105	Read(&data, 1);
106}
107
108// Visit
109void
110RequestUnflattener::Visit(RequestMember* member, uint8& data)
111{
112	Read(&data, 1);
113}
114
115// Visit
116void
117RequestUnflattener::Visit(RequestMember* member, int16& data)
118{
119	if (Read(&data, 2) == B_OK)
120		data = B_BENDIAN_TO_HOST_INT16(data);
121}
122
123// Visit
124void
125RequestUnflattener::Visit(RequestMember* member, uint16& data)
126{
127	if (Read(&data, 2) == B_OK)
128		data = B_BENDIAN_TO_HOST_INT16(data);
129}
130
131// Visit
132void
133RequestUnflattener::Visit(RequestMember* member, int32& data)
134{
135	if (Read(&data, 4) == B_OK)
136		data = B_BENDIAN_TO_HOST_INT32(data);
137}
138
139// Visit
140void
141RequestUnflattener::Visit(RequestMember* member, uint32& data)
142{
143	if (Read(&data, 4) == B_OK)
144		data = B_BENDIAN_TO_HOST_INT32(data);
145}
146
147// Visit
148void
149RequestUnflattener::Visit(RequestMember* member, int64& data)
150{
151	if (Read(&data, 8) == B_OK)
152		data = B_BENDIAN_TO_HOST_INT64(data);
153}
154
155// Visit
156void
157RequestUnflattener::Visit(RequestMember* member, uint64& data)
158{
159	if (Read(&data, 8) == B_OK)
160		data = B_BENDIAN_TO_HOST_INT64(data);
161}
162
163// Visit
164void
165RequestUnflattener::Visit(RequestMember* member, Data& data)
166{
167	void* buffer;
168	int32 size;
169	bool mustFree;
170	if (ReadData(buffer, size, mustFree) != B_OK)
171		return;
172
173	// we can't deal with mustFree buffers currently
174	if (mustFree) {
175		free(buffer);
176		fStatus = B_ERROR;
177		return;
178	}
179
180	data.address = buffer;
181	data.size = size;
182}
183
184// Visit
185void
186RequestUnflattener::Visit(RequestMember* member, StringData& data)
187{
188	void* buffer;
189	int32 size;
190	bool mustFree;
191	if (ReadData(buffer, size, mustFree) != B_OK)
192		return;
193
194	// we can't deal with mustFree buffers currently
195	if (mustFree) {
196		free(buffer);
197		fStatus = B_ERROR;
198		return;
199	}
200
201	data.address = buffer;
202	data.size = size;
203// TODO: Check null termination.
204}
205
206// Visit
207void
208RequestUnflattener::Visit(RequestMember* member, RequestMember& subMember)
209{
210	subMember.ShowAround(this);
211}
212
213// Visit
214void
215RequestUnflattener::Visit(RequestMember* member,
216	FlattenableRequestMember& subMember)
217{
218	if (fStatus != B_OK)
219		return;
220
221	status_t status = subMember.Unflatten(this);
222	if (fStatus == B_OK)
223		fStatus = status;
224}
225
226// Read
227status_t
228RequestUnflattener::Read(void* buffer, int32 size)
229{
230	if (fStatus != B_OK)
231		return fStatus;
232
233	fStatus = fReader->Read(buffer, size);
234	if (fStatus == B_OK)
235		fBytesRead += size;
236
237	return fStatus;
238}
239
240// Read
241status_t
242RequestUnflattener::Read(int32 size, void*& buffer, bool& mustFree)
243{
244	if (fStatus != B_OK)
245		return fStatus;
246
247	fStatus = fReader->Read(size, &buffer, &mustFree);
248	if (fStatus == B_OK)
249		fBytesRead += size;
250
251	return fStatus;
252}
253
254
255// Align
256status_t
257RequestUnflattener::Align(int32 align)
258{
259	if (fStatus != B_OK)
260		return fStatus;
261
262	if (align > 1) {
263		int32 newBytesRead = fBytesRead;
264		if (!(align & 0x3))
265			newBytesRead = (fBytesRead + 3) & ~0x3;
266		else if (!(align & 0x1))
267			newBytesRead = (fBytesRead + 1) & ~0x1;
268
269		if (newBytesRead > fBytesRead) {
270			fStatus = fReader->Skip(newBytesRead - fBytesRead);
271			if (fStatus == B_OK)
272				fBytesRead = newBytesRead;
273		}
274	}
275
276	return fStatus;
277}
278
279// ReadBool
280status_t
281RequestUnflattener::ReadBool(bool& data)
282{
283	return Read(&data, 1);
284}
285
286// ReadInt32
287status_t
288RequestUnflattener::ReadInt32(int32& data)
289{
290	if (Read(&data, 4) == B_OK)
291		data = B_BENDIAN_TO_HOST_INT32(data);
292
293	return fStatus;
294}
295
296
297// ReadData
298status_t
299RequestUnflattener::ReadData(void*& buffer, int32& _size, bool& mustFree)
300{
301	if (fStatus != B_OK)
302		return fStatus;
303
304	// read size
305	int32 size;
306	if (ReadInt32(size) != B_OK)
307		return fStatus;
308
309	// check size for sanity
310	if (size < 0 || size > kMaxSaneDataSize) {
311		fStatus = B_BAD_DATA;
312		return fStatus;
313	}
314
315	// read data
316	if (size > 0) {
317		if (Read(size, buffer, mustFree) != B_OK)
318			return fStatus;
319	} else {
320		buffer = NULL;
321		mustFree = false;
322	}
323
324	_size = size;
325	return fStatus;
326}
327
328// ReadString
329status_t
330RequestUnflattener::ReadString(HashString& string)
331{
332	void* buffer;
333	int32 size;
334	bool mustFree;
335	if (ReadData(buffer, size, mustFree) == B_OK) {
336		if (!string.SetTo((const char*)buffer))
337			fStatus = B_NO_MEMORY;
338
339		if (mustFree)
340			free(buffer);
341	}
342
343	return fStatus;
344}
345
346