00001 /// 00002 /// \file builder.h 00003 /// Virtual protocol packet builder wrapper 00004 /// 00005 00006 /* 00007 Copyright (C) 2005-2011, Net Direct Inc. (http://www.netdirect.ca/) 00008 00009 This program is free software; you can redistribute it and/or modify 00010 it under the terms of the GNU General Public License as published by 00011 the Free Software Foundation; either version 2 of the License, or 00012 (at your option) any later version. 00013 00014 This program is distributed in the hope that it will be useful, 00015 but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 00017 00018 See the GNU General Public License in the COPYING file at the 00019 root directory of this project for more details. 00020 */ 00021 00022 #ifndef __BARRY_BUILDER_H__ 00023 #define __BARRY_BUILDER_H__ 00024 00025 #include "dll.h" 00026 #include "data.h" 00027 #include <stdint.h> 00028 #include <string> 00029 00030 // 00031 // This macro can be used to automatically generate code for all known 00032 // record types. Just #undef HANDLE_BUILDER, then #define it to whatever 00033 // you need, then use ALL_KNOWN_BUILDER_TYPES. See parser.cc for 00034 // various examples. 00035 // 00036 // These are sorted so their GetDBName()'s will display in alphabetical order. 00037 // 00038 #define ALL_KNOWN_BUILDER_TYPES \ 00039 HANDLE_BUILDER(Contact) \ 00040 HANDLE_BUILDER(Calendar) \ 00041 HANDLE_BUILDER(CalendarAll) \ 00042 HANDLE_BUILDER(ContentStore) \ 00043 HANDLE_BUILDER(Memo) \ 00044 HANDLE_BUILDER(Task) \ 00045 00046 namespace Barry { 00047 00048 // forward declarations 00049 class IConverter; 00050 00051 // 00052 // Builder class 00053 // 00054 /// Base class for the builder functor hierarchy. 00055 /// 00056 /// This defines the API used by the Controller and Packet classes 00057 /// for building a raw device record to write to the device. 00058 /// 00059 class BXEXPORT Builder 00060 { 00061 public: 00062 Builder() {} 00063 virtual ~Builder() {} 00064 00065 /// Called to build the record field data. Store the raw data 00066 /// in data, using offset to know where to write. Be sure to 00067 /// update offset, and be sure to adjust the size of the data 00068 /// packet (possibly with Data::ReleaseBuffer()). 00069 /// 00070 /// Returns true if successful, and false if at the end of 00071 /// the series. Note that if EndOfFile() is false after 00072 /// this function returns false, then there may be another 00073 /// series available, which the next call to BuildRecord() 00074 /// will determine. 00075 /// 00076 virtual bool BuildRecord(DBData &data, size_t &offset, 00077 const IConverter *ic) = 0; 00078 00079 /// Same as BuildRecord, but does not care about any offsets. 00080 /// The caller should call DBData::GetOffset() afterward 00081 /// to discover if there is an offset to the result. 00082 /// 00083 /// This is usually the fastest of the two functions, since 00084 /// extra copying may be required if a specific offset is 00085 /// given. When building records from Record classes, both 00086 /// functions are the same speed. But when building records 00087 /// from the device, the device decides the offset, so FetchRecord() 00088 /// is faster, since BuildRecord requires a copy to adjust 00089 /// to the right offset. 00090 /// 00091 /// The caller should use the function that results in the least 00092 /// amount of copying for the caller. If the caller doesn't 00093 /// care about where the resulting record is in data, use 00094 /// FetchRecord(). 00095 /// 00096 virtual bool FetchRecord(DBData &data, const IConverter *ic) = 0; 00097 00098 /// Sometimes a builder can have multiple databases stored 00099 /// in it, so when Build/Fetch returns false, check if there 00100 /// is more data with this function. This function is 00101 /// not used by database-oriented functions, but by pipe- 00102 /// oriented functions. 00103 virtual bool EndOfFile() const = 0; 00104 }; 00105 00106 00107 // 00108 // DBDataBuilder 00109 // 00110 /// Wrapper class around a DBData object, to make it easy to pass a DBData 00111 /// object into a function or API that requires a builder. The main 00112 /// advantage to this is that the Builder API allows for movement of 00113 /// data, depending on the required offsets. 00114 /// 00115 class BXEXPORT DBDataBuilder : public Builder 00116 { 00117 const DBData &m_orig; 00118 00119 public: 00120 explicit DBDataBuilder(const DBData &orig); 00121 virtual ~DBDataBuilder(); 00122 00123 virtual bool BuildRecord(DBData &data, size_t &offset, 00124 const IConverter *ic); 00125 virtual bool FetchRecord(DBData &data, const IConverter *ic); 00126 virtual bool EndOfFile() const; 00127 }; 00128 00129 // 00130 // SetDBData 00131 // 00132 /// Contains the proper way to convert a record object into a DBData object. 00133 /// 00134 template <class RecordT> 00135 void SetDBData(const RecordT &rec, DBData &data, size_t &offset, 00136 const IConverter *ic) 00137 { 00138 data.SetVersion(DBData::REC_VERSION_1); 00139 data.SetOffset(offset); 00140 data.SetDBName(RecordT::GetDBName()); 00141 data.SetIds(rec.GetRecType(), rec.GetUniqueId()); 00142 rec.BuildHeader(data.UseData(), offset); 00143 rec.BuildFields(data.UseData(), offset, ic); 00144 } 00145 00146 // 00147 // RecordBuilder template class 00148 // 00149 /// Template class for easy creation of specific protocol packet builder 00150 /// objects. This template takes the following template arguments: 00151 /// 00152 /// - RecordT: One of the record classes in record.h 00153 /// - StorageT: A custom storage functor class. An object of this type 00154 /// will be called as a function with empty Record as an 00155 /// argument. The storage class is expected to fill the 00156 /// record object in preparation for building the packet 00157 /// out of that data. These calls happen on the fly as the data 00158 /// is sent to the device over USB, so it should not block forever. 00159 /// 00160 /// Example SaveDatabase() call: 00161 /// 00162 /// <pre> 00163 /// FIXME 00164 /// </pre> 00165 /// 00166 template <class RecordT, class StorageT> 00167 class RecordBuilder : public Builder 00168 { 00169 StorageT *m_storage; 00170 bool m_owned; 00171 bool m_record_loaded; 00172 bool m_end_of_file; 00173 RecordT m_rec; 00174 00175 public: 00176 /// Constructor that references an externally managed storage object. 00177 RecordBuilder(StorageT &storage) 00178 : m_storage(&storage) 00179 , m_owned(false) 00180 , m_record_loaded(false) 00181 , m_end_of_file(false) 00182 { 00183 } 00184 00185 /// Constructor that references a locally managed storage object. 00186 /// The pointer passed in will be stored, and freed when this class 00187 /// is destroyed. It is safe to call this constructor with 00188 /// a 'new'ly created storage object. 00189 RecordBuilder(StorageT *storage) 00190 : m_storage(storage) 00191 , m_owned(true) 00192 , m_record_loaded(false) 00193 , m_end_of_file(false) 00194 { 00195 } 00196 00197 ~RecordBuilder() 00198 { 00199 if( this->m_owned ) 00200 delete m_storage; 00201 } 00202 00203 virtual bool BuildRecord(DBData &data, size_t &offset, 00204 const IConverter *ic) 00205 { 00206 if( m_end_of_file ) 00207 return false; 00208 00209 if( !(*m_storage)(m_rec, *this) ) { 00210 m_end_of_file = true; 00211 return false; 00212 } 00213 00214 SetDBData(m_rec, data, offset, ic); 00215 return true; 00216 } 00217 00218 virtual bool FetchRecord(DBData &data, const IConverter *ic) 00219 { 00220 size_t offset = 0; 00221 return BuildRecord(data, offset, ic); 00222 } 00223 00224 virtual bool EndOfFile() const 00225 { 00226 return m_end_of_file; 00227 } 00228 }; 00229 00230 00231 // 00232 // RecordFetch template class 00233 // 00234 /// Generic record fetch class, to help with using records without 00235 /// builder classes. 00236 /// 00237 template <class RecordT> 00238 class RecordFetch 00239 { 00240 const RecordT &m_rec; 00241 mutable bool m_done; 00242 00243 public: 00244 RecordFetch(const RecordT &rec) : m_rec(rec), m_done(false) {} 00245 bool operator()(RecordT &rec, Builder &) const 00246 { 00247 if( m_done ) 00248 return false; 00249 rec = m_rec; 00250 m_done = true; 00251 return true; 00252 } 00253 }; 00254 00255 00256 } // namespace Barry 00257 00258 #endif 00259