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-2012, 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 #include "ios_state.h"
00031 
00032 #define __DEBUG_MODE__
00033 #include "debug.h"
00034 
00035 using namespace std;
00036 using namespace Barry::Protocol;
00037 
00038 namespace Barry {
00039 
00040 
00041 ///////////////////////////////////////////////////////////////////////////////
00042 // ContentStore class
00043 
00044 // ContentStore field codes
00045 #define CSFC_FILENAME           0x01    // may not always be a complete file,but
00046                                         // a folder name as well
00047 #define CSFC_FOLDER_FLAG        0x05
00048 #define CSFC_FILE_DESCRIPTOR    0x06
00049 #define CSFC_FILE_CONTENT       0x07
00050 
00051 
00052 #define MAX_CONTENT_BLOCK_SIZE  0xfffe
00053 
00054 ContentStore::ContentStore()
00055 {
00056         Clear();
00057 }
00058 
00059 ContentStore::~ContentStore()
00060 {
00061 }
00062 
00063 const unsigned char* ContentStore::ParseField(const unsigned char *begin,
00064                                          const unsigned char *end,
00065                                          const IConverter *ic)
00066 {
00067         const CommonField *field = (const CommonField *) begin;
00068 
00069         // advance and check size
00070         begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
00071         if( begin > end )               // if begin==end, we are ok
00072                 return begin;
00073 
00074         if( !btohs(field->size) )       // if field has no size, something's up
00075                 return begin;
00076 
00077         switch( field->type )
00078         {
00079         case CSFC_FILENAME:
00080                 Filename = ParseFieldString(field);
00081                 return begin;
00082 
00083         case CSFC_FOLDER_FLAG:
00084                 FolderFlag = false;
00085                 {
00086                         // the CSFC_FOLDER_FLAG field seems to always
00087                         // contain the string "folder".. so check for it
00088                         string s = ParseFieldString(field);
00089                         if( s == "folder" ) {
00090                                 FolderFlag = true;
00091                         }
00092                 }
00093                 return begin;
00094 
00095         case CSFC_FILE_CONTENT:
00096                 if( FileSize ) {
00097                         // size already received, append data to FileContent
00098                         FileContent.append((const char*)field->u.raw,
00099                                 btohs(field->size));
00100                 }
00101                 else {
00102                         FileSize = btohll(field->u.uint64);
00103                 }
00104                 return begin;
00105 
00106         case CSFC_FILE_DESCRIPTOR:
00107                 // need to parse this further, but until then, just
00108                 // store it as a chunk of data
00109                 FileDescriptor.assign((const char*)field->u.raw,
00110                         btohs(field->size));
00111                 return begin;
00112         }
00113 
00114         // if still not handled, add to the Unknowns list
00115         UnknownField uf;
00116         uf.type = field->type;
00117         uf.data.assign((const char*)field->u.raw, btohs(field->size));
00118         Unknowns.push_back(uf);
00119 
00120         // return new pointer for next field
00121         return begin;
00122 }
00123 
00124 void ContentStore::ParseHeader(const Data &data, size_t &offset)
00125 {
00126         // no header to parse
00127 }
00128 
00129 void ContentStore::ParseFields(const Data &data, size_t &offset, const IConverter *ic)
00130 {
00131         const unsigned char *finish = ParseCommonFields(*this,
00132                 data.GetData() + offset, data.GetData() + data.GetSize(), ic);
00133         offset += finish - (data.GetData() + offset);
00134 }
00135 
00136 void ContentStore::Validate() const
00137 {
00138 }
00139 
00140 void ContentStore::BuildHeader(Data &data, size_t &offset) const
00141 {
00142 }
00143 
00144 void ContentStore::BuildFields(Data &data, size_t &offset, const IConverter *ic) const
00145 {
00146         data.Zap();
00147 
00148         if( !Filename.size() )
00149                 throw BadData("Content Store must have a name.");
00150 
00151         if( !FolderFlag && !FileContent.size() )
00152                 throw BadData("Content Store item without any data.");
00153 
00154         // Filename
00155         BuildField(data, offset, CSFC_FILENAME, Filename);
00156 
00157         // Folder?
00158         if( FolderFlag ) {
00159                 BuildField(data, offset, CSFC_FOLDER_FLAG, string("folder"));
00160         }
00161         else {
00162                 // write file descriptor first
00163                 BuildField(data, offset, CSFC_FILE_DESCRIPTOR,
00164                         FileDescriptor.data(), FileDescriptor.size());
00165 
00166                 // a normal file... the file content is given:
00167                 //      64 bit size
00168                 //      content in blocks of 0xfffe bytes until done
00169                 // all with the same ID
00170 
00171                 // force the size to actual, and write it first
00172                 uint64_t RealSize = FileContent.size();
00173                 BuildField(data, offset, CSFC_FILE_CONTENT, RealSize);
00174 
00175                 // write data in blocks of 0xfffe bytes
00176                 for( size_t foff = 0; foff < FileContent.size(); ) {
00177                         size_t blocksize = FileContent.size() - foff;
00178                         if( blocksize > MAX_CONTENT_BLOCK_SIZE )
00179                                 blocksize = MAX_CONTENT_BLOCK_SIZE;
00180                         BuildField(data, offset, CSFC_FILE_CONTENT,
00181                                 FileContent.data() + foff, blocksize);
00182 
00183                         // advance
00184                         foff += blocksize;
00185                 }
00186         }
00187 
00188         // and finally save unknowns
00189         UnknownsType::const_iterator
00190                 ub = Unknowns.begin(), ue = Unknowns.end();
00191         for( ; ub != ue; ub++ ) {
00192                 BuildField(data, offset, *ub);
00193         }
00194 
00195         data.ReleaseBuffer(offset);
00196 }
00197 
00198 void ContentStore::Clear()
00199 {
00200         RecType = GetDefaultRecType();
00201         RecordId = 0;
00202 
00203         Filename.clear();
00204         FolderFlag = false;
00205         FileContent.clear();
00206         FileDescriptor.clear();
00207 
00208         Unknowns.clear();
00209 
00210         // internal variables
00211         FileSize = 0;
00212 }
00213 
00214 const FieldHandle<ContentStore>::ListT& ContentStore::GetFieldHandles()
00215 {
00216         static FieldHandle<ContentStore>::ListT fhv;
00217 
00218         if( fhv.size() )
00219                 return fhv;
00220 
00221 #undef CONTAINER_OBJECT_NAME
00222 #define CONTAINER_OBJECT_NAME fhv
00223 
00224 #undef RECORD_CLASS_NAME
00225 #define RECORD_CLASS_NAME ContentStore
00226 
00227         FHP(RecType, "Record Type Code");
00228         FHP(RecordId, "Unique Record ID");
00229 
00230         FHD(Filename, "File or Folder Name", CSFC_FILENAME, true);
00231         FHD(FolderFlag, "Folder Flag", CSFC_FOLDER_FLAG, false);
00232         FHD(FileContent, "File Content", CSFC_FILE_CONTENT, false);
00233         FHD(FileDescriptor, "File Descriptor", CSFC_FILE_DESCRIPTOR, false);
00234 
00235         FHP(Unknowns, "Unknown Fields");
00236 
00237         return fhv;
00238 }
00239 
00240 std::string ContentStore::GetDescription() const
00241 {
00242         return Filename;
00243 }
00244 
00245 void ContentStore::Dump(std::ostream &os) const
00246 {
00247         ios_format_state state(os);
00248 
00249         os.setf(ios::left);
00250         os.fill(' ');
00251 
00252         os << "ContentStore: 0x" << hex << RecordId
00253                 << " (" << (unsigned int)RecType << ")\n";
00254 
00255         os << "       Filename: " << Filename << endl;
00256         os << "         Folder: " << (FolderFlag ? "yes" : "no") << endl;
00257         os << "        BB Size: " << dec << FileSize << endl;
00258         os << "    Actual Size: " << FileContent.size() << endl;
00259         os << "     Descriptor:\n"
00260                 << Data(FileDescriptor.data(), FileDescriptor.size()) << endl;
00261         os << "        Content:\n"
00262                 << Data(FileContent.data(), FileContent.size()) << endl;
00263 
00264         // and finally print unknowns
00265         os << Unknowns;
00266 }
00267 
00268 bool ContentStore::operator<(const ContentStore &other) const
00269 {
00270         return RecordId < other.RecordId;
00271 }
00272 
00273 } // namespace Barry
00274