/* * Copyright (c) 2014, Oculus VR, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * */ #include "TableSerializer.h" #include "DS_Table.h" #include "BitStream.h" #include "StringCompressor.h" #include "RakAssert.h" using namespace RakNet; void TableSerializer::SerializeTable(DataStructures::Table *in, RakNet::BitStream *out) { DataStructures::Page *cur = in->GetRows().GetListHead(); const DataStructures::List &columns=in->GetColumns(); SerializeColumns(in, out); out->Write((unsigned)in->GetRows().Size()); unsigned rowIndex; while (cur) { for (rowIndex=0; rowIndex < (unsigned)cur->size; rowIndex++) { SerializeRow(cur->data[rowIndex], cur->keys[rowIndex], columns, out); } cur=cur->next; } } void TableSerializer::SerializeColumns(DataStructures::Table *in, RakNet::BitStream *out) { const DataStructures::List &columns=in->GetColumns(); out->Write((unsigned)columns.Size()); unsigned i; for (i=0; iEncodeString(columns[i].columnName, _TABLE_MAX_COLUMN_NAME_LENGTH, out); out->Write((unsigned char)columns[i].columnType); } } void TableSerializer::SerializeColumns(DataStructures::Table *in, RakNet::BitStream *out, DataStructures::List &skipColumnIndices) { const DataStructures::List &columns=in->GetColumns(); out->Write((unsigned)columns.Size()-skipColumnIndices.Size()); unsigned i; for (i=0; iEncodeString(columns[i].columnName, _TABLE_MAX_COLUMN_NAME_LENGTH, out); out->Write((unsigned char)columns[i].columnType); } } } bool TableSerializer::DeserializeTable(unsigned char *serializedTable, unsigned int dataLength, DataStructures::Table *out) { RakNet::BitStream in((unsigned char*) serializedTable, dataLength, false); return DeserializeTable(&in, out); } bool TableSerializer::DeserializeTable(RakNet::BitStream *in, DataStructures::Table *out) { unsigned rowSize; DeserializeColumns(in,out); if (in->Read(rowSize)==false || rowSize>100000) { RakAssert(0); return false; // Hacker crash prevention } unsigned rowIndex; for (rowIndex=0; rowIndex < rowSize; rowIndex++) { if (DeserializeRow(in, out)==false) return false; } return true; } bool TableSerializer::DeserializeColumns(RakNet::BitStream *in, DataStructures::Table *out) { unsigned columnSize; unsigned char columnType; char columnName[_TABLE_MAX_COLUMN_NAME_LENGTH]; if (in->Read(columnSize)==false || columnSize > 10000) return false; // Hacker crash prevention out->Clear(); unsigned i; for (i=0; iDecodeString(columnName, 32, in); in->Read(columnType); out->AddColumn(columnName, (DataStructures::Table::ColumnType)columnType); } return true; } void TableSerializer::SerializeRow(DataStructures::Table::Row *in, unsigned keyIn, const DataStructures::List &columns, RakNet::BitStream *out) { unsigned cellIndex; out->Write(keyIn); unsigned int columnsSize = columns.Size(); out->Write(columnsSize); for (cellIndex=0; cellIndexWrite(cellIndex); SerializeCell(out, in->cells[cellIndex], columns[cellIndex].columnType); } } void TableSerializer::SerializeRow(DataStructures::Table::Row *in, unsigned keyIn, const DataStructures::List &columns, RakNet::BitStream *out, DataStructures::List &skipColumnIndices) { unsigned cellIndex; out->Write(keyIn); unsigned int numEntries=0; for (cellIndex=0; cellIndexWrite(numEntries); for (cellIndex=0; cellIndexWrite(cellIndex); SerializeCell(out, in->cells[cellIndex], columns[cellIndex].columnType); } } } bool TableSerializer::DeserializeRow(RakNet::BitStream *in, DataStructures::Table *out) { const DataStructures::List &columns=out->GetColumns(); unsigned numEntries; DataStructures::Table::Row *row; unsigned key; if (in->Read(key)==false) return false; row=out->AddRow(key); unsigned int cnt; in->Read(numEntries); for (cnt=0; cntRead(cellIndex); if (DeserializeCell(in, row->cells[cellIndex], columns[cellIndex].columnType)==false) { out->RemoveRow(key); return false; } } return true; } void TableSerializer::SerializeCell(RakNet::BitStream *out, DataStructures::Table::Cell *cell, DataStructures::Table::ColumnType columnType) { out->Write(cell->isEmpty); if (cell->isEmpty==false) { if (columnType==DataStructures::Table::NUMERIC) { out->Write(cell->i); } else if (columnType==DataStructures::Table::STRING) { StringCompressor::Instance()->EncodeString(cell->c, 65535, out); } else if (columnType==DataStructures::Table::POINTER) { out->Write(cell->ptr); } else { // Binary RakAssert(columnType==DataStructures::Table::BINARY); RakAssert(cell->i>0); unsigned binaryLength; binaryLength=(unsigned)cell->i; out->Write(binaryLength); out->WriteAlignedBytes((const unsigned char*) cell->c, (const unsigned int) cell->i); } } } bool TableSerializer::DeserializeCell(RakNet::BitStream *in, DataStructures::Table::Cell *cell, DataStructures::Table::ColumnType columnType) { bool isEmpty=false; double value; void *ptr; char tempString[65535]; cell->Clear(); if (in->Read(isEmpty)==false) return false; if (isEmpty==false) { if (columnType==DataStructures::Table::NUMERIC) { if (in->Read(value)==false) return false; cell->Set(value); } else if (columnType==DataStructures::Table::STRING) { if (StringCompressor::Instance()->DecodeString(tempString, 65535, in)==false) return false; cell->Set(tempString); } else if (columnType==DataStructures::Table::POINTER) { if (in->Read(ptr)==false) return false; cell->SetPtr(ptr); } else { unsigned binaryLength; // Binary RakAssert(columnType==DataStructures::Table::BINARY); if (in->Read(binaryLength)==false || binaryLength > 10000000) return false; // Sanity check to max binary cell of 10 megabytes in->AlignReadToByteBoundary(); if (BITS_TO_BYTES(in->GetNumberOfUnreadBits())<(BitSize_t)binaryLength) return false; cell->Set((char*) in->GetData()+BITS_TO_BYTES(in->GetReadOffset()), (int) binaryLength); in->IgnoreBits(BYTES_TO_BITS((int) binaryLength)); } } return true; } void TableSerializer::SerializeFilterQuery(RakNet::BitStream *in, DataStructures::Table::FilterQuery *query) { StringCompressor::Instance()->EncodeString(query->columnName,_TABLE_MAX_COLUMN_NAME_LENGTH,in,0); in->WriteCompressed(query->columnIndex); in->Write((unsigned char) query->operation); in->Write(query->cellValue->isEmpty); if (query->cellValue->isEmpty==false) { in->Write(query->cellValue->i); in->WriteAlignedBytesSafe((const char*)query->cellValue->c,(const unsigned int)query->cellValue->i,10000000); // Sanity check to max binary cell of 10 megabytes in->Write(query->cellValue->ptr); } } bool TableSerializer::DeserializeFilterQuery(RakNet::BitStream *out, DataStructures::Table::FilterQuery *query) { bool b; RakAssert(query->cellValue); StringCompressor::Instance()->DecodeString(query->columnName,_TABLE_MAX_COLUMN_NAME_LENGTH,out,0); out->ReadCompressed(query->columnIndex); unsigned char op; out->Read(op); query->operation=(DataStructures::Table::FilterQueryType) op; query->cellValue->Clear(); b=out->Read(query->cellValue->isEmpty); if (query->cellValue->isEmpty==false) { // HACK - cellValue->i is used for integer, character, and binary data. However, for character and binary c will be 0. So use that to determine if the data was integer or not. out->Read(query->cellValue->i); unsigned int inputLength; out->ReadAlignedBytesSafeAlloc(&query->cellValue->c,inputLength,10000000); // Sanity check to max binary cell of 10 megabytes if (query->cellValue->c) query->cellValue->i=inputLength; b=out->Read(query->cellValue->ptr); } return b; } void TableSerializer::SerializeFilterQueryList(RakNet::BitStream *in, DataStructures::Table::FilterQuery *query, unsigned int numQueries, unsigned int maxQueries) { (void) maxQueries; in->Write((bool)(query && numQueries>0)); if (query==0 || numQueries<=0) return; RakAssert(numQueries<=maxQueries); in->WriteCompressed(numQueries); unsigned i; for (i=0; i < numQueries; i++) { SerializeFilterQuery(in, query); } } bool TableSerializer::DeserializeFilterQueryList(RakNet::BitStream *out, DataStructures::Table::FilterQuery **query, unsigned int *numQueries, unsigned int maxQueries, int allocateExtraQueries) { bool b, anyQueries=false; out->Read(anyQueries); if (anyQueries==false) { if (allocateExtraQueries<=0) *query=0; else *query=new DataStructures::Table::FilterQuery[allocateExtraQueries]; *numQueries=0; return true; } b=out->ReadCompressed(*numQueries); if (*numQueries>maxQueries) { RakAssert(0); *numQueries=maxQueries; } if (*numQueries==0) return b; *query=new DataStructures::Table::FilterQuery[*numQueries+allocateExtraQueries]; DataStructures::Table::FilterQuery *queryPtr = *query; unsigned i; for (i=0; i < *numQueries; i++) { queryPtr[i].cellValue=new DataStructures::Table::Cell; b=DeserializeFilterQuery(out, queryPtr+i); } return b; } void TableSerializer::DeallocateQueryList(DataStructures::Table::FilterQuery *query, unsigned int numQueries) { if (query==0 || numQueries==0) return; unsigned i; for (i=0; i < numQueries; i++) RakNet::OP_DELETE(query[i].cellValue, _FILE_AND_LINE_); RakNet::OP_DELETE_ARRAY(query, _FILE_AND_LINE_); }