# 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