00001 /// 00002 /// \file builder.h 00003 /// Virtual protocol packet builder wrapper 00004 /// 00005 00006 /* 00007 Copyright (C) 2005-2012, 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 // Make sure record is valid before building it. 00139 // This can throw Barry::ValidationError 00140 rec.Validate(); 00141 00142 // Build the DBData object 00143 data.SetVersion(DBData::REC_VERSION_1); 00144 data.SetOffset(offset); 00145 data.SetDBName(RecordT::GetDBName()); 00146 data.SetIds(rec.GetRecType(), rec.GetUniqueId()); 00147 rec.BuildHeader(data.UseData(), offset); 00148 rec.BuildFields(data.UseData(), offset, ic); 00149 } 00150 00151 // 00152 // RecordBuilder template class 00153 // 00154 /// Template class for easy creation of specific protocol packet builder 00155 /// objects. This template takes the following template arguments: 00156 /// 00157 /// - RecordT: One of the record classes in record.h 00158 /// - StorageT: A custom storage functor class. An object of this type 00159 /// will be called as a function with empty Record as an 00160 /// argument. The storage class is expected to fill the 00161 /// record object in preparation for building the packet 00162 /// out of that data. These calls happen on the fly as the data 00163 /// is sent to the device over USB, so it should not block forever. 00164 /// 00165 /// Example SaveDatabase() call: 00166 /// 00167 /// <pre> 00168 /// FIXME 00169 /// </pre> 00170 /// 00171 template <class RecordT, class StorageT> 00172 class RecordBuilder : public Builder 00173 { 00174 StorageT *m_storage; 00175 bool m_owned; 00176 bool m_record_loaded; 00177 bool m_end_of_file; 00178 RecordT m_rec; 00179 00180 public: 00181 /// Constructor that references an externally managed storage object. 00182 RecordBuilder(StorageT &storage) 00183 : m_storage(&storage) 00184 , m_owned(false) 00185 , m_record_loaded(false) 00186 , m_end_of_file(false) 00187 { 00188 } 00189 00190 /// Constructor that references a locally managed storage object. 00191 /// The pointer passed in will be stored, and freed when this class 00192 /// is destroyed. It is safe to call this constructor with 00193 /// a 'new'ly created storage object. 00194 RecordBuilder(StorageT *storage) 00195 : m_storage(storage) 00196 , m_owned(true) 00197 , m_record_loaded(false) 00198 , m_end_of_file(false) 00199 { 00200 } 00201 00202 ~RecordBuilder() 00203 { 00204 if( this->m_owned ) 00205 delete m_storage; 00206 } 00207 00208 virtual bool BuildRecord(DBData &data, size_t &offset, 00209 const IConverter *ic) 00210 { 00211 if( m_end_of_file ) 00212 return false; 00213 00214 if( !(*m_storage)(m_rec, *this) ) { 00215 m_end_of_file = true; 00216 return false; 00217 } 00218 00219 SetDBData(m_rec, data, offset, ic); 00220 return true; 00221 } 00222 00223 virtual bool FetchRecord(DBData &data, const IConverter *ic) 00224 { 00225 size_t offset = 0; 00226 return BuildRecord(data, offset, ic); 00227 } 00228 00229 virtual bool EndOfFile() const 00230 { 00231 return m_end_of_file; 00232 } 00233 }; 00234 00235 00236 // 00237 // RecordFetch template class 00238 // 00239 /// Generic record fetch class, to help with using records without 00240 /// builder classes. 00241 /// 00242 template <class RecordT> 00243 class RecordFetch 00244 { 00245 const RecordT &m_rec; 00246 mutable bool m_done; 00247 00248 public: 00249 RecordFetch(const RecordT &rec) : m_rec(rec), m_done(false) {} 00250 bool operator()(RecordT &rec, Builder &) const 00251 { 00252 if( m_done ) 00253 return false; 00254 rec = m_rec; 00255 m_done = true; 00256 return true; 00257 } 00258 }; 00259 00260 00261 } // namespace Barry 00262 00263 #endif 00264
1.7.1