r_cstore.cc

Go to the documentation of this file.
00001 ///
00002 /// \file       r_cstore.cc
00003 ///             Blackberry database record parser class for
00004 ///             Content Store records.
00005 ///
00006 
00007 /*
00008     Copyright (C) 2010-2011, Net Direct Inc. (http://www.netdirect.ca/)
00009 
00010     This program is free software; you can redistribute it and/or modify
00011     it under the terms of the GNU General Public License as published by
00012     the Free Software Foundation; either version 2 of the License, or
00013     (at your option) any later version.
00014 
00015     This program is distributed in the hope that it will be useful,
00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00018 
00019     See the GNU General Public License in the COPYING file at the
00020     root directory of this project for more details.
00021 */
00022 
00023 #include "r_cstore.h"
00024 #include "record-internal.h"
00025 #include "data.h"
00026 
00027 #include <iostream>
00028 #include <sstream>
00029 #include <iomanip>
00030 
00031 #define __DEBUG_MODE__
00032 #include "debug.h"
00033 
00034 using namespace std;
00035 using namespace Barry::Protocol;
00036 
00037 namespace Barry {
00038 
00039 
00040 ///////////////////////////////////////////////////////////////////////////////
00041 // ContentStore class
00042 
00043 // ContentStore field codes
00044 #define CSFC_FILENAME           0x01    // may not always be a complete file,but
00045                                         // a folder name as well
00046 #define CSFC_FOLDER_FLAG        0x05
00047 #define CSFC_FILE_DESCRIPTOR    0x06
00048 #define CSFC_FILE_CONTENT       0x07
00049 
00050 
00051 #define MAX_CONTENT_BLOCK_SIZE  0xfffe
00052 
00053 ContentStore::ContentStore()
00054 {
00055         Clear();
00056 }
00057 
00058 ContentStore::~ContentStore()
00059 {
00060 }
00061 
00062 const unsigned char* ContentStore::ParseField(const unsigned char *begin,
00063                                          const unsigned char *end,
00064                                          const IConverter *ic)
00065 {
00066         const CommonField *field = (const CommonField *) begin;
00067 
00068         // advance and check size
00069         begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
00070         if( begin > end )               // if begin==end, we are ok
00071                 return begin;
00072 
00073         if( !btohs(field->size) )       // if field has no size, something's up
00074                 return begin;
00075 
00076         switch( field->type )
00077         {
00078         case CSFC_FILENAME:
00079                 Filename = ParseFieldString(field);
00080                 return begin;
00081 
00082         case CSFC_FOLDER_FLAG:
00083                 FolderFlag = false;
00084                 {
00085                         // the CSFC_FOLDER_FLAG field seems to always
00086                         // contain the string "folder".. so check for it
00087                         string s = ParseFieldString(field);
00088                         if( s == "folder" ) {
00089                                 FolderFlag = true;
00090                         }
00091                 }
00092                 return begin;
00093 
00094         case CSFC_FILE_CONTENT:
00095                 if( FileSize ) {
00096                         // size already received, append data to FileContent
00097                         FileContent.append((const char*)field->u.raw,
00098                                 btohs(field->size));
00099                 }
00100                 else {
00101                         FileSize = btohll(field->u.uint64);
00102                 }
00103                 return begin;
00104 
00105         case CSFC_FILE_DESCRIPTOR:
00106                 // need to parse this further, but until then, just
00107                 // store it as a chunk of data
00108                 FileDescriptor.assign((const char*)field->u.raw,
00109                         btohs(field->size));
00110                 return begin;
00111         }
00112 
00113         // if still not handled, add to the Unknowns list
00114         UnknownField uf;
00115         uf.type = field->type;
00116         uf.data.assign((const char*)field->u.raw, btohs(field->size));
00117         Unknowns.push_back(uf);
00118 
00119         // return new pointer for next field
00120         return begin;
00121 }
00122 
00123 void ContentStore::ParseHeader(const Data &data, size_t &offset)
00124 {
00125         // no header to parse
00126 }
00127 
00128 void ContentStore::ParseFields(const Data &data, size_t &offset, const IConverter *ic)
00129 {
00130         const unsigned char *finish = ParseCommonFields(*this,
00131                 data.GetData() + offset, data.GetData() + data.GetSize(), ic);
00132         offset += finish - (data.GetData() + offset);
00133 }
00134 
00135 void ContentStore::BuildHeader(Data &data, size_t &offset) const
00136 {
00137 }
00138 
00139 void ContentStore::BuildFields(Data &data, size_t &offset, const IConverter *ic) const
00140 {
00141         data.Zap();
00142 
00143         if( !Filename.size() )
00144                 throw BadData("Content Store must have a name.");
00145 
00146         if( !FolderFlag && !FileContent.size() )
00147                 throw BadData("Content Store item without any data.");
00148 
00149         // Filename
00150         BuildField(data, offset, CSFC_FILENAME, Filename);
00151 
00152         // Folder?
00153         if( FolderFlag ) {
00154                 BuildField(data, offset, CSFC_FOLDER_FLAG, string("folder"));
00155         }
00156         else {
00157                 // write file descriptor first
00158                 BuildField(data, offset, CSFC_FILE_DESCRIPTOR,
00159                         FileDescriptor.data(), FileDescriptor.size());
00160 
00161                 // a normal file... the file content is given:
00162                 //      64 bit size
00163                 //      content in blocks of 0xfffe bytes until done
00164                 // all with the same ID
00165 
00166                 // force the size to actual, and write it first
00167                 uint64_t RealSize = FileContent.size();
00168                 BuildField(data, offset, CSFC_FILE_CONTENT, RealSize);
00169 
00170                 // write data in blocks of 0xfffe bytes
00171                 for( size_t foff = 0; foff < FileContent.size(); ) {
00172                         size_t blocksize = FileContent.size() - foff;
00173                         if( blocksize > MAX_CONTENT_BLOCK_SIZE )
00174                                 blocksize = MAX_CONTENT_BLOCK_SIZE;
00175                         BuildField(data, offset, CSFC_FILE_CONTENT,
00176                                 FileContent.data() + foff, blocksize);
00177 
00178                         // advance
00179                         foff += blocksize;
00180                 }
00181         }
00182 
00183         // and finally save unknowns
00184         UnknownsType::const_iterator
00185                 ub = Unknowns.begin(), ue = Unknowns.end();
00186         for( ; ub != ue; ub++ ) {
00187                 BuildField(data, offset, *ub);
00188         }
00189 
00190         data.ReleaseBuffer(offset);
00191 }
00192 
00193 void ContentStore::Clear()
00194 {
00195         RecType = GetDefaultRecType();
00196         RecordId = 0;
00197 
00198         Filename.clear();
00199         FolderFlag = false;
00200         FileContent.clear();
00201         FileDescriptor.clear();
00202 
00203         Unknowns.clear();
00204 
00205         // internal variables
00206         FileSize = 0;
00207 }
00208 
00209 std::string ContentStore::GetDescription() const
00210 {
00211         return Filename;
00212 }
00213 
00214 void ContentStore::Dump(std::ostream &os) const
00215 {
00216         ios::fmtflags oldflags = os.setf(ios::left);
00217         char fill = os.fill(' ');
00218 
00219         os << "ContentStore: 0x" << hex << RecordId
00220                 << " (" << (unsigned int)RecType << ")\n";
00221 
00222         os << "       Filename: " << Filename << endl;
00223         os << "         Folder: " << (FolderFlag ? "yes" : "no") << endl;
00224         os << "        BB Size: " << dec << FileSize << endl;
00225         os << "    Actual Size: " << FileContent.size() << endl;
00226         os << "     Descriptor:\n"
00227                 << Data(FileDescriptor.data(), FileDescriptor.size()) << endl;
00228         os << "        Content:\n"
00229                 << Data(FileContent.data(), FileContent.size()) << endl;
00230 
00231         // and finally print unknowns
00232         os << Unknowns;
00233 
00234         // cleanup the stream
00235         os.flags(oldflags);
00236         os.fill(fill);
00237 }
00238 
00239 bool ContentStore::operator<(const ContentStore &other) const
00240 {
00241         return RecordId < other.RecordId;
00242 }
00243 
00244 } // namespace Barry
00245 

Generated on Tue Mar 1 17:50:16 2011 for Barry by  doxygen 1.5.6