3 /// Virtual protocol packet builder wrapper
7 Copyright (C) 2005-2012, Net Direct Inc. (http://www.netdirect.ca/)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 See the GNU General Public License in the COPYING file at the
19 root directory of this project for more details.
22 #ifndef __BARRY_BUILDER_H__
23 #define __BARRY_BUILDER_H__
31 // This macro can be used to automatically generate code for all known
32 // record types. Just #undef HANDLE_BUILDER, then #define it to whatever
33 // you need, then use ALL_KNOWN_BUILDER_TYPES. See parser.cc for
36 // These are sorted so their GetDBName()'s will display in alphabetical order.
38 #define ALL_KNOWN_BUILDER_TYPES \
39 HANDLE_BUILDER(Contact) \
40 HANDLE_BUILDER(Calendar) \
41 HANDLE_BUILDER(CalendarAll) \
42 HANDLE_BUILDER(ContentStore) \
43 HANDLE_BUILDER(Memo) \
44 HANDLE_BUILDER(Task) \
48 // forward declarations
54 /// Base class for the builder functor hierarchy.
56 /// This defines the API used by the Controller and Packet classes
57 /// for building a raw device record to write to the device.
59 class BXEXPORT Builder
65 /// Called to build the record field data. Store the raw data
66 /// in data, using offset to know where to write. Be sure to
67 /// update offset, and be sure to adjust the size of the data
68 /// packet (possibly with Data::ReleaseBuffer()).
70 /// Returns true if successful, and false if at the end of
71 /// the series. Note that if EndOfFile() is false after
72 /// this function returns false, then there may be another
73 /// series available, which the next call to BuildRecord()
76 virtual bool BuildRecord(DBData
&data
, size_t &offset
,
77 const IConverter
*ic
) = 0;
79 /// Same as BuildRecord, but does not care about any offsets.
80 /// The caller should call DBData::GetOffset() afterward
81 /// to discover if there is an offset to the result.
83 /// This is usually the fastest of the two functions, since
84 /// extra copying may be required if a specific offset is
85 /// given. When building records from Record classes, both
86 /// functions are the same speed. But when building records
87 /// from the device, the device decides the offset, so FetchRecord()
88 /// is faster, since BuildRecord requires a copy to adjust
89 /// to the right offset.
91 /// The caller should use the function that results in the least
92 /// amount of copying for the caller. If the caller doesn't
93 /// care about where the resulting record is in data, use
96 virtual bool FetchRecord(DBData
&data
, const IConverter
*ic
) = 0;
98 /// Sometimes a builder can have multiple databases stored
99 /// in it, so when Build/Fetch returns false, check if there
100 /// is more data with this function. This function is
101 /// not used by database-oriented functions, but by pipe-
102 /// oriented functions.
103 virtual bool EndOfFile() const = 0;
110 /// Wrapper class around a DBData object, to make it easy to pass a DBData
111 /// object into a function or API that requires a builder. The main
112 /// advantage to this is that the Builder API allows for movement of
113 /// data, depending on the required offsets.
115 class BXEXPORT DBDataBuilder
: public Builder
117 const DBData
&m_orig
;
120 explicit DBDataBuilder(const DBData
&orig
);
121 virtual ~DBDataBuilder();
123 virtual bool BuildRecord(DBData
&data
, size_t &offset
,
124 const IConverter
*ic
);
125 virtual bool FetchRecord(DBData
&data
, const IConverter
*ic
);
126 virtual bool EndOfFile() const;
132 /// Contains the proper way to convert a record object into a DBData object.
134 template <class RecordT
>
135 void SetDBData(const RecordT
&rec
, DBData
&data
, size_t &offset
,
136 const IConverter
*ic
)
138 // Make sure record is valid before building it.
139 // This can throw Barry::ValidationError
142 // Build the DBData object
143 data
.SetVersion(DBData::REC_VERSION_1
);
144 data
.SetOffset(offset
);
145 data
.SetDBName(RecordT::GetDBName());
146 data
.SetIds(rec
.GetRecType(), rec
.GetUniqueId());
147 rec
.BuildHeader(data
.UseData(), offset
);
148 rec
.BuildFields(data
.UseData(), offset
, ic
);
152 // RecordBuilder template class
154 /// Template class for easy creation of specific protocol packet builder
155 /// objects. This template takes the following template arguments:
157 /// - RecordT: One of the record classes in record.h
158 /// - StorageT: A custom storage functor class. An object of this type
159 /// will be called as a function with empty Record as an
160 /// argument. The storage class is expected to fill the
161 /// record object in preparation for building the packet
162 /// out of that data. These calls happen on the fly as the data
163 /// is sent to the device over USB, so it should not block forever.
165 /// Example SaveDatabase() call:
171 template <class RecordT
, class StorageT
>
172 class RecordBuilder
: public Builder
176 bool m_record_loaded
;
181 /// Constructor that references an externally managed storage object.
182 RecordBuilder(StorageT
&storage
)
183 : m_storage(&storage
)
185 , m_record_loaded(false)
186 , m_end_of_file(false)
190 /// Constructor that references a locally managed storage object.
191 /// The pointer passed in will be stored, and freed when this class
192 /// is destroyed. It is safe to call this constructor with
193 /// a 'new'ly created storage object.
194 RecordBuilder(StorageT
*storage
)
197 , m_record_loaded(false)
198 , m_end_of_file(false)
208 virtual bool BuildRecord(DBData
&data
, size_t &offset
,
209 const IConverter
*ic
)
214 if( !(*m_storage
)(m_rec
, *this) ) {
215 m_end_of_file
= true;
219 SetDBData(m_rec
, data
, offset
, ic
);
223 virtual bool FetchRecord(DBData
&data
, const IConverter
*ic
)
226 return BuildRecord(data
, offset
, ic
);
229 virtual bool EndOfFile() const
231 return m_end_of_file
;
237 // RecordFetch template class
239 /// Generic record fetch class, to help with using records without
242 template <class RecordT
>
245 const RecordT
&m_rec
;
249 RecordFetch(const RecordT
&rec
) : m_rec(rec
), m_done(false) {}
250 bool operator()(RecordT
&rec
, Builder
&) const