lib: changed Usb::Error exception to deal in libusb_errcode instead of system
[barry/progweb.git] / src / r_cstore.cc
blob7deeabbd380c74f1c83e5954c9ec5d3c3bfd1997
1 ///
2 /// \file r_cstore.cc
3 /// Blackberry database record parser class for
4 /// Content Store records.
5 ///
7 /*
8 Copyright (C) 2010-2011, 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>
30 #include "ios_state.h"
32 #define __DEBUG_MODE__
33 #include "debug.h"
35 using namespace std;
36 using namespace Barry::Protocol;
38 namespace Barry {
41 ///////////////////////////////////////////////////////////////////////////////
42 // ContentStore class
44 // ContentStore field codes
45 #define CSFC_FILENAME 0x01 // may not always be a complete file,but
46 // a folder name as well
47 #define CSFC_FOLDER_FLAG 0x05
48 #define CSFC_FILE_DESCRIPTOR 0x06
49 #define CSFC_FILE_CONTENT 0x07
52 #define MAX_CONTENT_BLOCK_SIZE 0xfffe
54 ContentStore::ContentStore()
56 Clear();
59 ContentStore::~ContentStore()
63 const unsigned char* ContentStore::ParseField(const unsigned char *begin,
64 const unsigned char *end,
65 const IConverter *ic)
67 const CommonField *field = (const CommonField *) begin;
69 // advance and check size
70 begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
71 if( begin > end ) // if begin==end, we are ok
72 return begin;
74 if( !btohs(field->size) ) // if field has no size, something's up
75 return begin;
77 switch( field->type )
79 case CSFC_FILENAME:
80 Filename = ParseFieldString(field);
81 return begin;
83 case CSFC_FOLDER_FLAG:
84 FolderFlag = false;
86 // the CSFC_FOLDER_FLAG field seems to always
87 // contain the string "folder".. so check for it
88 string s = ParseFieldString(field);
89 if( s == "folder" ) {
90 FolderFlag = true;
93 return begin;
95 case CSFC_FILE_CONTENT:
96 if( FileSize ) {
97 // size already received, append data to FileContent
98 FileContent.append((const char*)field->u.raw,
99 btohs(field->size));
101 else {
102 FileSize = btohll(field->u.uint64);
104 return begin;
106 case CSFC_FILE_DESCRIPTOR:
107 // need to parse this further, but until then, just
108 // store it as a chunk of data
109 FileDescriptor.assign((const char*)field->u.raw,
110 btohs(field->size));
111 return begin;
114 // if still not handled, add to the Unknowns list
115 UnknownField uf;
116 uf.type = field->type;
117 uf.data.assign((const char*)field->u.raw, btohs(field->size));
118 Unknowns.push_back(uf);
120 // return new pointer for next field
121 return begin;
124 void ContentStore::ParseHeader(const Data &data, size_t &offset)
126 // no header to parse
129 void ContentStore::ParseFields(const Data &data, size_t &offset, const IConverter *ic)
131 const unsigned char *finish = ParseCommonFields(*this,
132 data.GetData() + offset, data.GetData() + data.GetSize(), ic);
133 offset += finish - (data.GetData() + offset);
136 void ContentStore::BuildHeader(Data &data, size_t &offset) const
140 void ContentStore::BuildFields(Data &data, size_t &offset, const IConverter *ic) const
142 data.Zap();
144 if( !Filename.size() )
145 throw BadData("Content Store must have a name.");
147 if( !FolderFlag && !FileContent.size() )
148 throw BadData("Content Store item without any data.");
150 // Filename
151 BuildField(data, offset, CSFC_FILENAME, Filename);
153 // Folder?
154 if( FolderFlag ) {
155 BuildField(data, offset, CSFC_FOLDER_FLAG, string("folder"));
157 else {
158 // write file descriptor first
159 BuildField(data, offset, CSFC_FILE_DESCRIPTOR,
160 FileDescriptor.data(), FileDescriptor.size());
162 // a normal file... the file content is given:
163 // 64 bit size
164 // content in blocks of 0xfffe bytes until done
165 // all with the same ID
167 // force the size to actual, and write it first
168 uint64_t RealSize = FileContent.size();
169 BuildField(data, offset, CSFC_FILE_CONTENT, RealSize);
171 // write data in blocks of 0xfffe bytes
172 for( size_t foff = 0; foff < FileContent.size(); ) {
173 size_t blocksize = FileContent.size() - foff;
174 if( blocksize > MAX_CONTENT_BLOCK_SIZE )
175 blocksize = MAX_CONTENT_BLOCK_SIZE;
176 BuildField(data, offset, CSFC_FILE_CONTENT,
177 FileContent.data() + foff, blocksize);
179 // advance
180 foff += blocksize;
184 // and finally save unknowns
185 UnknownsType::const_iterator
186 ub = Unknowns.begin(), ue = Unknowns.end();
187 for( ; ub != ue; ub++ ) {
188 BuildField(data, offset, *ub);
191 data.ReleaseBuffer(offset);
194 void ContentStore::Clear()
196 RecType = GetDefaultRecType();
197 RecordId = 0;
199 Filename.clear();
200 FolderFlag = false;
201 FileContent.clear();
202 FileDescriptor.clear();
204 Unknowns.clear();
206 // internal variables
207 FileSize = 0;
210 std::string ContentStore::GetDescription() const
212 return Filename;
215 void ContentStore::Dump(std::ostream &os) const
217 ios_format_state state(os);
219 os.setf(ios::left);
220 os.fill(' ');
222 os << "ContentStore: 0x" << hex << RecordId
223 << " (" << (unsigned int)RecType << ")\n";
225 os << " Filename: " << Filename << endl;
226 os << " Folder: " << (FolderFlag ? "yes" : "no") << endl;
227 os << " BB Size: " << dec << FileSize << endl;
228 os << " Actual Size: " << FileContent.size() << endl;
229 os << " Descriptor:\n"
230 << Data(FileDescriptor.data(), FileDescriptor.size()) << endl;
231 os << " Content:\n"
232 << Data(FileContent.data(), FileContent.size()) << endl;
234 // and finally print unknowns
235 os << Unknowns;
238 bool ContentStore::operator<(const ContentStore &other) const
240 return RecordId < other.RecordId;
243 } // namespace Barry