// RequestUnflattener.cpp #include #include #include "Compatibility.h" #include "DebugSupport.h" #include "RequestUnflattener.h" const int32 kMaxSaneStringSize = 4096; // 4 KB const int32 kMaxSaneDataSize = 128 * 1024; // 128 KB // constructor Reader::Reader() { } // destructor Reader::~Reader() { } // Read status_t Reader::Read(int32 size, void** buffer, bool* mustFree) { // check params if (size < 0 || !buffer || !mustFree) return B_BAD_VALUE; // deal with size == 0 if (size == 0) { *buffer = NULL; *mustFree = false; return B_OK; } // allocate the buffer and read *buffer = malloc(size); if (!*buffer) return B_NO_MEMORY; status_t error = Read(*buffer, size); if (error != B_OK) { free(*buffer); return error; } return error; } // Skip status_t Reader::Skip(int32 size) { if (size <= 0) return B_OK; if (size > 8) return B_BAD_VALUE; char buffer[8]; return Read(buffer, size); } // RequestUnflattener // constructor RequestUnflattener::RequestUnflattener(Reader* reader) : RequestMemberVisitor(), fReader(reader), fStatus(B_OK), fBytesRead(0) { } // GetStatus status_t RequestUnflattener::GetStatus() const { return fStatus; } // GetBytesRead int32 RequestUnflattener::GetBytesRead() const { return fBytesRead; } // Visit void RequestUnflattener::Visit(RequestMember* member, bool& data) { uint8 netData; if (Read(&netData, 1) == B_OK) data = netData; } // Visit void RequestUnflattener::Visit(RequestMember* member, int8& data) { Read(&data, 1); } // Visit void RequestUnflattener::Visit(RequestMember* member, uint8& data) { Read(&data, 1); } // Visit void RequestUnflattener::Visit(RequestMember* member, int16& data) { if (Read(&data, 2) == B_OK) data = B_BENDIAN_TO_HOST_INT16(data); } // Visit void RequestUnflattener::Visit(RequestMember* member, uint16& data) { if (Read(&data, 2) == B_OK) data = B_BENDIAN_TO_HOST_INT16(data); } // Visit void RequestUnflattener::Visit(RequestMember* member, int32& data) { if (Read(&data, 4) == B_OK) data = B_BENDIAN_TO_HOST_INT32(data); } // Visit void RequestUnflattener::Visit(RequestMember* member, uint32& data) { if (Read(&data, 4) == B_OK) data = B_BENDIAN_TO_HOST_INT32(data); } // Visit void RequestUnflattener::Visit(RequestMember* member, int64& data) { if (Read(&data, 8) == B_OK) data = B_BENDIAN_TO_HOST_INT64(data); } // Visit void RequestUnflattener::Visit(RequestMember* member, uint64& data) { if (Read(&data, 8) == B_OK) data = B_BENDIAN_TO_HOST_INT64(data); } // Visit void RequestUnflattener::Visit(RequestMember* member, Data& data) { void* buffer; int32 size; bool mustFree; if (ReadData(buffer, size, mustFree) != B_OK) return; // we can't deal with mustFree buffers currently if (mustFree) { free(buffer); fStatus = B_ERROR; return; } data.address = buffer; data.size = size; } // Visit void RequestUnflattener::Visit(RequestMember* member, StringData& data) { void* buffer; int32 size; bool mustFree; if (ReadData(buffer, size, mustFree) != B_OK) return; // we can't deal with mustFree buffers currently if (mustFree) { free(buffer); fStatus = B_ERROR; return; } data.address = buffer; data.size = size; // TODO: Check null termination. } // Visit void RequestUnflattener::Visit(RequestMember* member, RequestMember& subMember) { subMember.ShowAround(this); } // Visit void RequestUnflattener::Visit(RequestMember* member, FlattenableRequestMember& subMember) { if (fStatus != B_OK) return; status_t status = subMember.Unflatten(this); if (fStatus == B_OK) fStatus = status; } // Read status_t RequestUnflattener::Read(void* buffer, int32 size) { if (fStatus != B_OK) return fStatus; fStatus = fReader->Read(buffer, size); if (fStatus == B_OK) fBytesRead += size; return fStatus; } // Read status_t RequestUnflattener::Read(int32 size, void*& buffer, bool& mustFree) { if (fStatus != B_OK) return fStatus; fStatus = fReader->Read(size, &buffer, &mustFree); if (fStatus == B_OK) fBytesRead += size; return fStatus; } // Align status_t RequestUnflattener::Align(int32 align) { if (fStatus != B_OK) return fStatus; if (align > 1) { int32 newBytesRead = fBytesRead; if (!(align & 0x3)) newBytesRead = (fBytesRead + 3) & ~0x3; else if (!(align & 0x1)) newBytesRead = (fBytesRead + 1) & ~0x1; if (newBytesRead > fBytesRead) { fStatus = fReader->Skip(newBytesRead - fBytesRead); if (fStatus == B_OK) fBytesRead = newBytesRead; } } return fStatus; } // ReadBool status_t RequestUnflattener::ReadBool(bool& data) { return Read(&data, 1); } // ReadInt32 status_t RequestUnflattener::ReadInt32(int32& data) { if (Read(&data, 4) == B_OK) data = B_BENDIAN_TO_HOST_INT32(data); return fStatus; } // ReadData status_t RequestUnflattener::ReadData(void*& buffer, int32& _size, bool& mustFree) { if (fStatus != B_OK) return fStatus; // read size int32 size; if (ReadInt32(size) != B_OK) return fStatus; // check size for sanity if (size < 0 || size > kMaxSaneDataSize) { fStatus = B_BAD_DATA; return fStatus; } // read data if (size > 0) { if (Read(size, buffer, mustFree) != B_OK) return fStatus; } else { buffer = NULL; mustFree = false; } _size = size; return fStatus; } // ReadString status_t RequestUnflattener::ReadString(HashString& string) { void* buffer; int32 size; bool mustFree; if (ReadData(buffer, size, mustFree) == B_OK) { if (!string.SetTo((const char*)buffer)) fStatus = B_NO_MEMORY; if (mustFree) free(buffer); } return fStatus; }