lib: added record parser for the Content Store database
[barry.git] / src / r_cstore.cc
blob4bb42274fb87cd37627b4a27e72b2d4dab1e225e
1 ///
2 /// \file r_cstore.cc
3 /// Blackberry database record parser class for
4 /// Content Store records.
5 ///
7 /*
8 Copyright (C) 2010, Net Direct Inc. (http://www.netdirect.ca/)
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License in the COPYING file at the
20 root directory of this project for more details.
23 #include "r_cstore.h"
24 #include "record-internal.h"
25 #include "data.h"
27 #include <iostream>
28 #include <sstream>
29 #include <iomanip>
31 #define __DEBUG_MODE__
32 #include "debug.h"
34 using namespace std;
35 using namespace Barry::Protocol;
37 namespace Barry {
40 ///////////////////////////////////////////////////////////////////////////////
41 // ContentStore class
43 // ContentStore field codes
44 #define CSFC_FILENAME 0x01 // may not always be a complete file,but
45 // a folder name as well
46 #define CSFC_FOLDER_FLAG 0x05
47 #define CSFC_FILE_DESCRIPTOR 0x06
48 #define CSFC_FILE_CONTENT 0x07
51 #define MAX_CONTENT_BLOCK_SIZE 0xfffe
53 ContentStore::ContentStore()
55 Clear();
58 ContentStore::~ContentStore()
62 const unsigned char* ContentStore::ParseField(const unsigned char *begin,
63 const unsigned char *end,
64 const IConverter *ic)
66 const CommonField *field = (const CommonField *) begin;
68 // advance and check size
69 begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
70 if( begin > end ) // if begin==end, we are ok
71 return begin;
73 if( !btohs(field->size) ) // if field has no size, something's up
74 return begin;
76 switch( field->type )
78 case CSFC_FILENAME:
79 Filename = ParseFieldString(field);
80 return begin;
82 case CSFC_FOLDER_FLAG:
83 FolderFlag = false;
85 // the CSFC_FOLDER_FLAG field seems to always
86 // contain the string "folder".. so check for it
87 string s = ParseFieldString(field);
88 if( s == "folder" ) {
89 FolderFlag = true;
92 return begin;
94 case CSFC_FILE_CONTENT:
95 if( FileSize ) {
96 // size already received, append data to FileContent
97 FileContent.append((const char*)field->u.raw,
98 btohs(field->size));
100 else {
101 FileSize = btohll(field->u.uint64);
103 return begin;
105 case CSFC_FILE_DESCRIPTOR:
106 // need to parse this further, but until then, just
107 // store it as a chunk of data
108 FileDescriptor.assign((const char*)field->u.raw,
109 btohs(field->size));
110 return begin;
113 // if still not handled, add to the Unknowns list
114 UnknownField uf;
115 uf.type = field->type;
116 uf.data.assign((const char*)field->u.raw, btohs(field->size));
117 Unknowns.push_back(uf);
119 // return new pointer for next field
120 return begin;
123 void ContentStore::ParseHeader(const Data &data, size_t &offset)
125 // no header to parse
128 void ContentStore::ParseFields(const Data &data, size_t &offset, const IConverter *ic)
130 const unsigned char *finish = ParseCommonFields(*this,
131 data.GetData() + offset, data.GetData() + data.GetSize(), ic);
132 offset += finish - (data.GetData() + offset);
135 void ContentStore::BuildHeader(Data &data, size_t &offset) const
139 void ContentStore::BuildFields(Data &data, size_t &offset, const IConverter *ic) const
141 data.Zap();
143 if( !Filename.size() )
144 throw BadData("Content Store must have a name.");
146 if( !FolderFlag && !FileContent.size() )
147 throw BadData("Content Store item without any data.");
149 // Filename
150 BuildField(data, offset, CSFC_FILENAME, Filename);
152 // Folder?
153 if( FolderFlag ) {
154 BuildField(data, offset, CSFC_FOLDER_FLAG, string("folder"));
156 else {
157 // write file descriptor first
158 BuildField(data, offset, CSFC_FILE_DESCRIPTOR,
159 FileDescriptor.data(), FileDescriptor.size());
161 // a normal file... the file content is given:
162 // 64 bit size
163 // content in blocks of 0xfffe bytes until done
164 // all with the same ID
166 // force the size to actual, and write it first
167 uint64_t RealSize = FileContent.size();
168 BuildField(data, offset, CSFC_FILE_CONTENT, RealSize);
170 // write data in blocks of 0xfffe bytes
171 for( size_t foff = 0; foff < FileContent.size(); ) {
172 size_t blocksize = FileContent.size() - foff;
173 if( blocksize > MAX_CONTENT_BLOCK_SIZE )
174 blocksize = MAX_CONTENT_BLOCK_SIZE;
175 BuildField(data, offset, CSFC_FILE_CONTENT,
176 FileContent.data() + foff, blocksize);
178 // advance
179 foff += blocksize;
183 // and finally save unknowns
184 UnknownsType::const_iterator
185 ub = Unknowns.begin(), ue = Unknowns.end();
186 for( ; ub != ue; ub++ ) {
187 BuildField(data, offset, *ub);
190 data.ReleaseBuffer(offset);
193 void ContentStore::Clear()
195 RecType = GetDefaultRecType();
196 RecordId = 0;
198 Filename.clear();
199 FolderFlag = false;
200 FileContent.clear();
201 FileDescriptor.clear();
203 Unknowns.clear();
205 // internal variables
206 FileSize = 0;
209 void ContentStore::Dump(std::ostream &os) const
211 ios::fmtflags oldflags = os.setf(ios::left);
212 char fill = os.fill(' ');
214 os << "ContentStore: 0x" << hex << RecordId
215 << " (" << (unsigned int)RecType << ")\n";
217 os << " Filename: " << Filename << endl;
218 os << " Folder: " << (FolderFlag ? "yes" : "no") << endl;
219 os << " BB Size: " << dec << FileSize << endl;
220 os << " Actual Size: " << FileContent.size() << endl;
221 os << " Descriptor:\n"
222 << Data(FileDescriptor.data(), FileDescriptor.size()) << endl;
223 os << " Content:\n"
224 << Data(FileContent.data(), FileContent.size()) << endl;
226 // and finally print unknowns
227 os << Unknowns;
229 // cleanup the stream
230 os.flags(oldflags);
231 os.fill(fill);
234 bool ContentStore::operator<(const ContentStore &other) const
236 return RecordId < other.RecordId;
239 } // namespace Barry