lib: added some operator<() members to basic record objects
[barry/progweb.git] / src / record.h
blob01546f53c9b278724a0514dc6423bbb983923afa
1 ///
2 /// \file record.h
3 /// Blackberry database record classes. Help translate data
4 /// from data packets to useful structurs, and back.
5 /// This header provides the common types and classes
6 /// used by the general record parser classes in the
7 /// r_*.h files. Only application-safe API stuff goes in
8 /// here. Internal library types go in record-internal.h
9 ///
12 Copyright (C) 2005-2012, Net Direct Inc. (http://www.netdirect.ca/)
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; either version 2 of the License, or
17 (at your option) any later version.
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
23 See the GNU General Public License in the COPYING file at the
24 root directory of this project for more details.
27 #ifndef __BARRY_RECORD_H__
28 #define __BARRY_RECORD_H__
30 #include "dll.h"
31 #include <iosfwd>
32 #include <string>
33 #include <vector>
34 #include <map>
35 #include <stdint.h>
36 #include <stdexcept>
38 // forward declarations
39 namespace Barry { class Data; }
41 namespace Barry {
44 // NOTE: All classes here must be container-safe! Perhaps add sorting
45 // operators in the future.
49 // stream-based wrapper to avoid printing strings that contain
50 // the \r carriage return characters
51 class BXEXPORT Cr2LfWrapper
53 friend std::ostream& operator<< (std::ostream &os, const Cr2LfWrapper &str);
54 const std::string &m_str;
55 public:
56 explicit Cr2LfWrapper(const std::string &str)
57 : m_str(str)
61 BXEXPORT std::ostream& operator<< (std::ostream &os, const Cr2LfWrapper &str);
63 /// Struct wrapper for time_t, to make sure that it has its own type,
64 /// for overload purposes. Some systems, like QNX, use a uint32_t typedef.
65 struct BXEXPORT TimeT
67 time_t Time;
69 TimeT()
70 : Time(0)
74 explicit TimeT(time_t t)
75 : Time(t)
79 void clear()
81 Time = 0;
84 bool operator< (const Barry::TimeT &other) const
86 return Time < other.Time;
89 bool operator== (const Barry::TimeT &other) const
91 return Time == other.Time;
94 bool operator!= (const Barry::TimeT &other) const
96 return !operator==(other);
99 BXEXPORT std::ostream& operator<< (std::ostream &os, const TimeT &t);
101 struct BXEXPORT CommandTableCommand
103 unsigned int Code;
104 std::string Name;
107 class BXEXPORT CommandTable
109 public:
110 typedef CommandTableCommand Command;
111 typedef std::vector<Command> CommandArrayType;
113 CommandArrayType Commands;
115 private:
116 BXLOCAL const unsigned char* ParseField(const unsigned char *begin,
117 const unsigned char *end);
118 public:
119 CommandTable();
120 ~CommandTable();
122 void Parse(const Data &data, size_t offset);
123 void Clear();
125 // returns 0 if unable to find command name, which is safe, since
126 // 0 is a special command that shouldn't be in the table anyway
127 unsigned int GetCommand(const std::string &name) const;
129 void Dump(std::ostream &os) const;
132 BXEXPORT inline std::ostream& operator<< (std::ostream &os, const CommandTable &command) {
133 command.Dump(os);
134 return os;
139 struct BXEXPORT RecordStateTableState
141 unsigned int Index;
142 uint32_t RecordId;
143 bool Dirty;
144 unsigned int RecType;
145 std::string Unknown2;
148 class BXEXPORT RecordStateTable
150 public:
151 typedef RecordStateTableState State;
152 typedef unsigned int IndexType;
153 typedef std::map<IndexType, State> StateMapType;
155 StateMapType StateMap;
157 private:
158 mutable IndexType m_LastNewRecordId;
160 private:
161 BXLOCAL const unsigned char* ParseField(const unsigned char *begin,
162 const unsigned char *end);
164 public:
165 RecordStateTable();
166 ~RecordStateTable();
168 void Parse(const Data &data);
169 void Clear();
171 bool GetIndex(uint32_t RecordId, IndexType *pFoundIndex = 0) const;
172 uint32_t MakeNewRecordId() const;
174 void Dump(std::ostream &os) const;
177 BXEXPORT inline std::ostream& operator<< (std::ostream &os, const RecordStateTable &rst) {
178 rst.Dump(os);
179 return os;
184 struct BXEXPORT DatabaseItem
186 unsigned int Number;
187 unsigned int RecordCount;
188 std::string Name;
191 class BXEXPORT DatabaseDatabase
193 public:
194 typedef DatabaseItem Database;
195 typedef std::vector<Database> DatabaseArrayType;
197 DatabaseArrayType Databases;
199 private:
200 template <class RecordType, class FieldType>
201 void ParseRec(const RecordType &rec, const unsigned char *end);
203 template <class FieldType>
204 const unsigned char* ParseField(const unsigned char *begin,
205 const unsigned char *end);
207 public:
208 DatabaseDatabase();
209 ~DatabaseDatabase();
211 void Parse(const Data &data);
212 void Clear();
214 void SortByName();
215 unsigned int GetTotalRecordCount() const;
217 // returns true on success, and fills target
218 bool GetDBNumber(const std::string &name, unsigned int &number) const;
219 bool GetDBName(unsigned int number, std::string &name) const;
221 void Dump(std::ostream &os) const;
224 BXEXPORT inline std::ostream& operator<<(std::ostream &os, const DatabaseDatabase &dbdb) {
225 dbdb.Dump(os);
226 return os;
229 struct UnknownData
231 std::string raw_data;
233 const std::string::value_type* data() const { return raw_data.data(); }
234 std::string::size_type size() const { return raw_data.size(); }
235 void assign(const std::string::value_type *s, std::string::size_type n)
236 { raw_data.assign(s, n); }
238 bool operator==(const UnknownData &other) const
240 return raw_data == other.raw_data;
243 bool operator!=(const UnknownData &other) const
245 return !operator==(other);
248 bool operator< (const UnknownData &other) const
250 return raw_data < other.raw_data;
254 struct BXEXPORT UnknownField
256 uint8_t type;
257 UnknownData data;
259 bool operator==(const UnknownField &other) const
261 return type == other.type &&
262 data == other.data;
265 bool operator!=(const UnknownField &other) const
267 return !operator==(other);
270 bool operator< (const UnknownField &other) const
272 return type < other.type && data < other.data;
275 typedef std::vector<UnknownField> UnknownsType;
276 BXEXPORT std::ostream& operator<< (std::ostream &os, const UnknownsType &unknowns);
278 // simple string email type and list... keep this a simple string list,
279 // so it can be reused for other address-like data, like phone numbers.
280 // If you need something more complex, use EmailAddress below or
281 // create a new type.
282 typedef std::string EmailType;
283 class BXEXPORT EmailList : public std::vector<EmailType>
285 public:
286 typedef std::vector<EmailType> base_type;
288 public:
289 using base_type::size;
290 using base_type::begin;
291 using base_type::end;
292 using base_type::at;
293 using base_type::rbegin;
294 using base_type::rend;
295 using base_type::empty;
296 using base_type::resize;
297 using base_type::reserve;
298 using base_type::front;
299 using base_type::back;
300 using base_type::push_back;
301 using base_type::pop_back;
302 using base_type::insert;
303 using base_type::erase;
304 using base_type::swap;
305 using base_type::clear;
306 using base_type::operator=;
307 using base_type::operator[];
309 BXEXPORT std::ostream& operator<< (std::ostream &os, const EmailList &list);
311 // struct, attempting to combine name + email address, for mail
312 struct BXEXPORT EmailAddress
314 std::string Name;
315 std::string Email;
317 EmailAddress()
321 /// Converts "Name <address@host.com>" into Name + Address
322 /// Will also handle just a plain address too.
323 explicit EmailAddress(const std::string &complex_address);
325 void clear()
327 Name.clear();
328 Email.clear();
331 size_t size() const
333 return Name.size() + Email.size();
336 bool operator==(const EmailAddress &other) const
338 return Name == other.Name &&
339 Email == other.Email;
342 bool operator!=(const EmailAddress &other) const
344 return !operator==(other);
347 bool operator< (const EmailAddress &other) const
349 // sort by email only, since not every address has a name
350 return Email < other.Email;
353 BXEXPORT std::ostream& operator<<(std::ostream &os, const EmailAddress &msga);
355 class BXEXPORT EmailAddressList : public std::vector<EmailAddress>
357 public:
358 std::string ToCommaSeparated() const;
359 void AddCommaSeparated(const std::string &list);
362 BXEXPORT std::ostream& operator<<(std::ostream &os, const EmailAddressList &elist);
364 struct BXEXPORT PostalAddress
366 std::string
367 Address1,
368 Address2,
369 Address3,
370 City,
371 Province,
372 PostalCode,
373 Country;
375 std::string GetLabel() const;
376 void Clear();
378 bool HasData() const { return Address1.size() || Address2.size() ||
379 Address3.size() || City.size() || Province.size() ||
380 PostalCode.size() || Country.size(); }
382 bool operator==(const PostalAddress &other) const
384 return Address1 == other.Address1 &&
385 Address2 == other.Address2 &&
386 Address3 == other.Address3 &&
387 City == other.City &&
388 Province == other.Province &&
389 PostalCode == other.PostalCode &&
390 Country == other.Country;
392 bool operator!=(const PostalAddress &other) const
394 return !operator==(other);
396 bool operator< (const PostalAddress &other) const
398 return GetLabel() < other.GetLabel();
401 BXEXPORT std::ostream& operator<<(std::ostream &os, const PostalAddress &msga);
403 struct BXEXPORT Date
405 int Month; // 0 to 11
406 int Day; // 1 to 31
407 int Year; // exact number, eg. 2008
409 Date() : Month(0), Day(0), Year(0) {}
410 explicit Date(const struct tm *timep);
412 bool HasData() const { return Month || Day || Year; }
413 void Clear();
415 void ToTm(struct tm *timep) const;
416 std::string ToYYYYMMDD() const;
417 std::string ToBBString() const; // converts to Blackberry string
418 // format of DD/MM/YYYY
420 bool FromTm(const struct tm *timep);
421 bool FromBBString(const std::string &str);
422 bool FromYYYYMMDD(const std::string &str);
424 bool operator==(const Date &other) const
426 return Month == other.Month &&
427 Day == other.Day &&
428 Year == other.Year;
430 bool operator!=(const Date &other) const
432 return !operator==(other);
434 bool operator< (const Date &other) const
436 // YYYYMMDD as integer
437 unsigned int v1 = Year * 10000 + Month * 100 + Day;
438 unsigned int v2 = other.Year * 10000 + other.Month * 100 + other.Day;
439 return v1 < v2;
442 BXEXPORT std::ostream& operator<<(std::ostream &os, const Date &date);
444 class BXEXPORT CategoryList : public std::vector<std::string>
446 public:
447 /// Parses the given comma delimited category string into
448 /// this CategoryList object, appending each token to the vector.
449 /// Will clear vector beforehand.
450 void CategoryStr2List(const std::string &str);
452 /// Turns the current vectory into a comma delimited category
453 /// string suitable for use in Calendar, Task, and Memo
454 /// protocol values.
455 void CategoryList2Str(std::string &str) const;
457 using std::vector<std::string>::operator=;
459 BXEXPORT std::ostream& operator<<(std::ostream &os, const CategoryList &cl);
463 //////////////////////////////////////////////////////////////////////////////
464 // Generic Field Handles
466 /// \addtogroup GenericFieldHandles
467 /// Generic field handle classes, used to reference and work
468 /// with record members in a flexible, indirect way.
470 /// There are two ways to access device record data. The obvious
471 /// way is to instantiate a record class, such as Contact, and
472 /// access the public data members of that class to read and
473 /// write. If you always work with the same record class, this
474 /// works fine.
476 /// The other way is to have a list of pointers to members.
477 /// For example, you may wish to compare two records, without
478 /// actually caring what data is in each one. You can compare
479 /// at the record class level, with Contact one, two; and then
480 /// if( one == two ), but this will not tell you what field in
481 /// the record changed.
483 /// This last feature is what Generic Field Handles are meant to
484 /// fix. Each record class will contain a GetFieldHandles()
485 /// member function, which will return a vector of FieldHandle<>
486 /// objects, for that specific record. For example, Contact
487 /// would fill a vector with FieldHandle<Contact> objects.
488 /// Each FieldHandle<> object contains a C++ pointer-to-member,
489 /// which the FieldHandle refers to, as well as a FieldIdentity
490 /// object. The FieldIdentity object contains various identitying
491 /// information, such as the C++ variable name, an English
492 /// (or localized language) display name of the field, suitable
493 /// for user prompts, and other data more useful to the library.
495 /// The FieldHandle<> object has two member functions: Value()
496 /// and Member().
498 /// Value() will call a callback function with the _value_ of
499 /// the variable that FieldHandle<> points to. For example,
500 /// if the FieldHandle<> points to a std::string record member
501 /// variable, then Value() will pass that string value in as
502 /// an argument, along with a reference to the FieldIdentity
503 /// object. Value() requires a callback object and a record
504 /// object to perform this callback.
506 /// Member() will call a callback function/functor with the
507 /// pointer-to-member pointer and the FieldIdentity object.
508 /// This allows the programmer to create a functor with multiple
509 /// record objects, perhaps two objects to compare individual
510 /// fields, and use the pointer-to-member to access the field
511 /// data as needed.
513 /// For now, all data and callbacks are const, meaning that it
514 /// is not possible (without const_casting) to write to the
515 /// record via the pointers-to-members. This design decision
516 /// may need to be revisited someday, depending on its usefulness.
518 /// @{
521 // FieldIdentity
523 /// This class holds data that identifies a given field in a record.
524 /// This is fairly constant data, referenced by the FieldHandle class.
525 /// The information in here should be enough to show the user what kind
526 /// of field this is.
528 struct BXEXPORT FieldIdentity
530 // useful public data
531 const char *Name; // C++ name of field member variable in
532 // record class
533 std::string DisplayName; // localized display name of field
534 // in UTF8
535 // FIXME - should we leave localization
536 // to the application?
538 // subfield detection
539 bool HasSubfields; // true if this field has subfields
540 const char *ParentName; // name of field member variable that
541 // this field is a member of, or NULL
542 // if this field is a member of the
543 // record class.
544 // For example, Contact::PostalAddress
545 // would have HasSubfields == true,
546 // and ParentName == NULL, while all
547 // its subfield strings would have
548 // HasSubfields == false and
549 // ParentName == "WorkAddress" or
550 // "HomeAddress".
551 // The application could then decide
552 // whether to process only main fields,
553 // some of which have subfields,
554 // or only individual subfields.
556 // internal field data
557 int FieldTypeCode; // device type code for this field.
558 // if -1, then this is a conglomerate
559 // C++ field, such as
560 // Contact::PostalAddress, not a device
561 // field.
562 // If -1, then none of the following
563 // fields are valid.
564 const char *Ldif; // matching LDIF field name, or NULL
565 const char *ObjectClass; // matching LDIF object class, or NULL
566 bool IconvNeeded; // if true, the device's data needs to
567 // be passed through an IConverter
569 FieldIdentity(const char *name, const std::string &display_name,
570 int type_code = -1,
571 bool iconvneeded = false,
572 const char *ldif = 0, const char *oclass = 0,
573 bool has_sub = false, const char *parent = 0
575 : Name(name)
576 , DisplayName(display_name)
577 , HasSubfields(has_sub)
578 , ParentName(parent)
579 , FieldTypeCode(type_code)
580 , Ldif(ldif)
581 , ObjectClass(oclass)
582 , IconvNeeded(iconvneeded)
588 // EnumConstants
590 /// This is the base class for the hierarchy of classes to define
591 /// enum record members. This is the base class, which contains the
592 /// common code for creating and defining a list of enum constants for
593 /// a given enum field. The next derived class is EnumFieldBase<RecordT>,
594 /// which defines the virtual API for talking to a given enum field
595 /// in a given record. The next derived class is EnumField<RecordT, EnumT>,
596 /// which implements the pointer-to-member and virtual API for a given
597 /// enum type in a given record class.
599 /// For example, the Bookmark record class has the following enum field:
601 /// <pre>
602 /// enum BrowserIdentityType
603 /// {
604 /// IdentityAuto = 0,
605 /// IdentityBlackBerry,
606 /// IdentityFireFox,
607 /// IdentityInternetExplorer,
608 /// IdentityUnknown
609 /// };
610 /// BrowserIdentityType BrowserIdentity;
611 /// </pre>
613 /// The EnumConstants class will hold a vector of EnumConstant structs
614 /// defining each of the identity constants: Auto, BlackBerry, FireFox,
615 /// InternetExplorer, and Unknown.
617 /// The derived class EnumFieldBase<Bookmark> will define two additional
618 /// pure virtual API calls: GetValue(const Bookmark&) and
619 /// SetValue(Bookmark&, int).
621 /// Finally, the derived class EnumField<Bookmark,Bookmark::BrowserIdentityType>
622 /// will implement the virtual API, and contain a pointer-to-member to
623 /// the Bookmark::BrowserIdentity member field.
625 /// The FieldHandle<Bookmark> class will hold a pointer to
626 /// EnumFieldBase<Bookmark>, which can hold a pointer to a specific
627 /// EnumField<> object, one object for each of Bookmark's enum types,
628 /// of which there are currently 3.
630 class BXEXPORT EnumConstants
632 public:
633 /// This defines one of the enum constants being defined.
634 /// For example, for an enum declaration like:
635 /// enum Mine { A, B, C }; then this struct could contain
636 /// a definition for A, B, or C, but only one at at time.
637 /// All three would be defined by the EnumConstantList.
638 struct EnumConstant
640 const char *Name; //< C++ name of enum constant
641 std::string DisplayName; //< user-friendly name / meaning
642 int Value; //< constant enum value
644 EnumConstant(const char *name, const std::string &display,
645 int value)
646 : Name(name)
647 , DisplayName(display)
648 , Value(value)
653 typedef std::vector<EnumConstant> EnumConstantList;
655 private:
656 EnumConstantList m_constants;
658 public:
659 virtual ~EnumConstants() {}
661 /// Adds a constant definition to the list
662 void AddConstant(const char *name, const std::string &display, int val);
664 /// Returns a vector of EnumConstant objects, describing all enum
665 /// constants valid for this enum field.
666 const EnumConstantList& GetConstantList() const { return m_constants; }
668 /// Returns the EnumConstant for the given value.
669 /// Throws std::logic_error if not found.
670 const EnumConstant& GetConstant(int value) const;
672 /// Returns the constant name (C++ name) based on the given value.
673 /// Throws std::logic_error if not found.
674 const char* GetName(int value) const;
676 /// Returns the display name based on the given value.
677 /// Throws std::logic_error if not found.
678 const std::string& GetDisplayName(int value) const;
680 /// Returns true if the value matches one of the constants in the list.
681 bool IsConstantValid(int value) const;
685 // FieldValueHandlerBase
687 /// This is a pure virtual base class, defining the various types that
688 /// record fields can be. To be able to handle all the types of data
689 /// in all records, override these virtual functions to do with the
690 /// data as you wish.
692 /// All data from the records and fields will be passed in by value.
693 /// i.e. if field is string data, the overloaded std::string handler
694 /// will be called, and a refernce to the string will be passed in.
696 /// The advantage of using this virtual class is that less code will be
697 /// generated by templates. The disadvantage is that this is less flexible.
698 /// You will only get called for one field and record at a time.
699 /// So you can't do comparisons this way.
701 class BXEXPORT FieldValueHandlerBase
703 public:
704 virtual ~FieldValueHandlerBase() {}
706 /// For type std::string
707 virtual void operator()(const std::string &v,
708 const FieldIdentity &id) const = 0;
709 /// For type EmailAddressList
710 virtual void operator()(const EmailAddressList &v,
711 const FieldIdentity &id) const = 0;
712 /// For type Barry::TimeT
713 virtual void operator()(const Barry::TimeT &v,
714 const FieldIdentity &id) const = 0;
715 /// For type uint8_t
716 virtual void operator()(const uint8_t &v,
717 const FieldIdentity &id) const = 0;
718 /// For type uint16_t
719 virtual void operator()(const uint16_t &v,
720 const FieldIdentity &id) const = 0;
721 /// For type uint32_t
722 virtual void operator()(const uint32_t &v,
723 const FieldIdentity &id) const = 0;
724 /// For type uint64_t
725 virtual void operator()(const uint64_t &v,
726 const FieldIdentity &id) const = 0;
727 /// For type bool
728 virtual void operator()(const bool &v,
729 const FieldIdentity &id) const = 0;
730 /// For type int32_t
731 virtual void operator()(const int32_t &v,
732 const FieldIdentity &id) const = 0;
733 /// For type EmailList
734 virtual void operator()(const EmailList &v,
735 const FieldIdentity &id) const = 0;
736 /// For type Date
737 virtual void operator()(const Date &v,
738 const FieldIdentity &id) const = 0;
739 /// For type CategoryList
740 virtual void operator()(const CategoryList &v,
741 const FieldIdentity &id) const = 0;
742 /// For type PostalAddress
743 virtual void operator()(const PostalAddress &v,
744 const FieldIdentity &id) const = 0;
745 /// For type UnknownsType
746 virtual void operator()(const UnknownsType &v,
747 const FieldIdentity &id) const = 0;
751 /// EnumFieldBase<RecordT>
753 template <class RecordT>
754 class EnumFieldBase : public EnumConstants
756 public:
757 /// Return value of enum in rec
758 virtual int GetValue(const RecordT &rec) const = 0;
759 /// Set value of enum in rec
760 /// Throws std::logic_error if value is out of range
761 virtual void SetValue(RecordT &rec, int value) = 0;
765 /// EnumField<RecordT, EnumT>
767 template <class RecordT, class EnumT>
768 class EnumField : public EnumFieldBase<RecordT>
770 EnumT RecordT::* m_mp;
772 public:
773 explicit EnumField(EnumT RecordT::* mp)
774 : m_mp(mp)
778 virtual int GetValue(const RecordT &rec) const
780 return rec.*m_mp;
783 virtual void SetValue(RecordT &rec, int value)
785 if( !this->IsConstantValid(value) )
786 throw std::logic_error("Bad enum value in EnumField");
787 rec.*m_mp = (EnumT) value;
792 // FieldHandle<RecordT>
794 /// This is a template class that handles pointers to members of multiple
795 /// types of data and multiple types of records.
797 /// This class contains a union of all known data pointers in all records.
798 /// Therefore this class can hold a pointer to member of any record class.
800 /// To do something with the field that this FieldHandle<> class refers to,
801 /// call either Value() or Member() with appropriate callback functors.
802 /// Value will pass a reference to the field. You can use an object
803 /// derived from FieldValueHandlerBase here. Member() will pass a pointer
804 /// to member. Your functor will need to contain the record data in order
805 /// to access its data via the pointer to member.
807 /// The template functor callback that you pass into member must be
808 /// capable of this:
810 /// <pre>
811 /// template &lt;class RecordT&gt;
812 /// struct Callback
813 /// {
814 /// RecordT m_rec;
816 /// void operator()(typename FieldHandle<RecordT>::PostalPointer pp,
817 /// const FieldIdentity &id) const
818 /// {
819 /// PostalAddress pa = m_rec.*(pp.m_PostalAddress);
820 /// std::string val = pa.*(pp.m_PostalField);
821 /// ...
822 /// }
824 /// template &lt;class TypeT&gt;
825 /// void operator()(TypeT RecordT::* mp,
826 /// const FieldIdentity &id) const
827 /// {
828 /// TypeT val = m_rec.*mp;
829 /// ...
830 /// }
831 /// };
832 /// </pre>
834 /// You don't have to use a TypeT template, but if you don't, then you must
835 /// support all field types that the record class you're processing uses.
838 template <class RecordT>
839 class FieldHandle
841 public:
842 // Need to use this in the union, so no constructor allowed
843 struct PostalPointer
845 PostalAddress RecordT::* m_PostalAddress;
846 std::string PostalAddress::* m_PostalField;
849 // So use a factory function
850 static PostalPointer MakePostalPointer(PostalAddress RecordT::* p1,
851 std::string PostalAddress::* p2)
853 PostalPointer pp;
854 pp.m_PostalAddress = p1;
855 pp.m_PostalField = p2;
856 return pp;
859 private:
860 union PointerUnion
862 std::string RecordT::* m_string; // index 0
863 EmailAddressList RecordT::* m_EmailAddressList; // 1
864 Barry::TimeT RecordT::* m_time; // 2
865 PostalPointer m_postal; // 3
866 uint8_t RecordT::* m_uint8; // 4
867 uint32_t RecordT::* m_uint32; // 5
868 EmailList RecordT::* m_EmailList; // 6
869 Date RecordT::* m_Date; // 7
870 CategoryList RecordT::* m_CategoryList; // 8
871 // GroupLinksType RecordT::* m_GroupLinksType; // 9
872 UnknownsType RecordT::* m_UnknownsType; // 10
873 bool RecordT::* m_bool; // 11
874 uint64_t RecordT::* m_uint64; // 12
875 uint16_t RecordT::* m_uint16; // 13
876 PostalAddress RecordT::* m_PostalAddress; // 14
877 // used by non-union m_enum below: // 15
878 int32_t RecordT::* m_int32; // 16
881 int m_type_index;
882 PointerUnion m_union;
883 EnumFieldBase<RecordT> *m_enum; // never freed, since this is a
884 // static list, existing to end of
885 // program lifetime
887 FieldIdentity m_id;
889 public:
890 // 0
891 FieldHandle(std::string RecordT::* mp, const FieldIdentity &id)
892 : m_type_index(0)
893 , m_enum(0)
894 , m_id(id)
896 m_union.m_string = mp;
899 // 1
900 FieldHandle(EmailAddressList RecordT::* mp, const FieldIdentity &id)
901 : m_type_index(1)
902 , m_enum(0)
903 , m_id(id)
905 m_union.m_EmailAddressList = mp;
908 // 2
909 FieldHandle(Barry::TimeT RecordT::* mp, const FieldIdentity &id)
910 : m_type_index(2)
911 , m_enum(0)
912 , m_id(id)
914 m_union.m_time = mp;
917 // 3
918 FieldHandle(const PostalPointer &pp, const FieldIdentity &id)
919 : m_type_index(3)
920 , m_enum(0)
921 , m_id(id)
923 m_union.m_postal = pp;
926 // 4
927 FieldHandle(uint8_t RecordT::* mp, const FieldIdentity &id)
928 : m_type_index(4)
929 , m_enum(0)
930 , m_id(id)
932 m_union.m_uint8 = mp;
935 // 5
936 FieldHandle(uint32_t RecordT::* mp, const FieldIdentity &id)
937 : m_type_index(5)
938 , m_enum(0)
939 , m_id(id)
941 m_union.m_uint32 = mp;
944 // 6
945 FieldHandle(EmailList RecordT::* mp, const FieldIdentity &id)
946 : m_type_index(6)
947 , m_enum(0)
948 , m_id(id)
950 m_union.m_EmailList = mp;
953 // 7
954 FieldHandle(Date RecordT::* mp, const FieldIdentity &id)
955 : m_type_index(7)
956 , m_enum(0)
957 , m_id(id)
959 m_union.m_Date = mp;
962 // 8
963 FieldHandle(CategoryList RecordT::* mp, const FieldIdentity &id)
964 : m_type_index(8)
965 , m_enum(0)
966 , m_id(id)
968 m_union.m_CategoryList = mp;
971 // 9
972 // FieldHandle(GroupLinksType RecordT::* mp, const FieldIdentity &id)
973 // : m_type_index(9)
974 // , m_enum(0)
975 // , m_id(id)
976 // {
977 // m_union.m_GroupLinksType = mp;
978 // }
980 // 10
981 FieldHandle(UnknownsType RecordT::* mp, const FieldIdentity &id)
982 : m_type_index(10)
983 , m_enum(0)
984 , m_id(id)
986 m_union.m_UnknownsType = mp;
989 // 11
990 FieldHandle(bool RecordT::* mp, const FieldIdentity &id)
991 : m_type_index(11)
992 , m_enum(0)
993 , m_id(id)
995 m_union.m_bool = mp;
998 // 12
999 FieldHandle(uint64_t RecordT::* mp, const FieldIdentity &id)
1000 : m_type_index(12)
1001 , m_enum(0)
1002 , m_id(id)
1004 m_union.m_uint64 = mp;
1007 // 13
1008 FieldHandle(uint16_t RecordT::* mp, const FieldIdentity &id)
1009 : m_type_index(13)
1010 , m_enum(0)
1011 , m_id(id)
1013 m_union.m_uint16 = mp;
1016 // 14
1017 FieldHandle(PostalAddress RecordT::* mp, const FieldIdentity &id)
1018 : m_type_index(14)
1019 , m_enum(0)
1020 , m_id(id)
1022 m_union.m_PostalAddress = mp;
1025 // 15
1026 FieldHandle(EnumFieldBase<RecordT> *enum_, const FieldIdentity &id)
1027 : m_type_index(15)
1028 , m_enum(enum_)
1029 , m_id(id)
1033 // 16
1034 FieldHandle(int32_t RecordT::* mp, const FieldIdentity &id)
1035 : m_type_index(16)
1036 , m_enum(0)
1037 , m_id(id)
1039 m_union.m_int32 = mp;
1042 /// Extracts FieldIdentity object from FieldHandle<>
1043 const FieldIdentity& GetIdentity() const { return m_id; }
1045 /// Calls the matching virtual function in FieldValueHandlerBase,
1046 /// passing in the value of the field that this FieldHandle<>
1047 /// refers to, and a referenct to the FieldIdentity object.
1048 /// Caller must pass in a RecordT object as well.
1049 void Value(const FieldValueHandlerBase &vh, const RecordT &rec) const
1051 switch( m_type_index )
1053 case 0:
1054 vh(rec.*(m_union.m_string), m_id);
1055 break;
1056 case 1:
1057 vh(rec.*(m_union.m_EmailAddressList), m_id);
1058 break;
1059 case 2:
1060 vh(rec.*(m_union.m_time), m_id);
1061 break;
1062 case 3:
1063 vh(rec.*(m_union.m_postal.m_PostalAddress).*(m_union.m_postal.m_PostalField), m_id);
1064 break;
1065 case 4:
1066 vh(rec.*(m_union.m_uint8), m_id);
1067 break;
1068 case 5:
1069 vh(rec.*(m_union.m_uint32), m_id);
1070 break;
1071 case 6:
1072 vh(rec.*(m_union.m_EmailList), m_id);
1073 break;
1074 case 7:
1075 vh(rec.*(m_union.m_Date), m_id);
1076 break;
1077 case 8:
1078 vh(rec.*(m_union.m_CategoryList), m_id);
1079 break;
1080 // case 9:
1081 // vh(rec.*(m_union.m_GroupLinksType), m_id);
1082 // break;
1083 case 10:
1084 vh(rec.*(m_union.m_UnknownsType), m_id);
1085 break;
1086 case 11:
1087 vh(rec.*(m_union.m_bool), m_id);
1088 break;
1089 case 12:
1090 vh(rec.*(m_union.m_uint64), m_id);
1091 break;
1092 case 13:
1093 vh(rec.*(m_union.m_uint16), m_id);
1094 break;
1095 case 14:
1096 vh(rec.*(m_union.m_PostalAddress), m_id);
1097 break;
1098 case 15:
1099 vh(m_enum->GetValue(rec), m_id);
1100 break;
1101 case 16:
1102 vh(rec.*(m_union.m_int32), m_id);
1103 break;
1104 default:
1105 throw std::logic_error("Unknown field handle type index");
1109 /// Calls the callback functor with two arguments: the pointer to
1110 /// member that this FieldHandle<> contains, and the FieldIdentity
1111 /// object. It is assumed that the functor will either contain
1112 /// or know where to find one or more records of type RecordT.
1113 template <class CallbackT>
1114 void Member(const CallbackT &func) const
1116 switch( m_type_index )
1118 case 0:
1119 func(m_union.m_string, m_id);
1120 break;
1121 case 1:
1122 func(m_union.m_EmailAddressList, m_id);
1123 break;
1124 case 2:
1125 func(m_union.m_time, m_id);
1126 break;
1127 case 3:
1128 func(m_union.m_postal, m_id);
1129 break;
1130 case 4:
1131 func(m_union.m_uint8, m_id);
1132 break;
1133 case 5:
1134 func(m_union.m_uint32, m_id);
1135 break;
1136 case 6:
1137 func(m_union.m_EmailList, m_id);
1138 break;
1139 case 7:
1140 func(m_union.m_Date, m_id);
1141 break;
1142 case 8:
1143 func(m_union.m_CategoryList, m_id);
1144 break;
1145 // case 9:
1146 // func(m_union.m_GroupLinksType, m_id);
1147 // break;
1148 case 10:
1149 func(m_union.m_UnknownsType, m_id);
1150 break;
1151 case 11:
1152 func(m_union.m_bool, m_id);
1153 break;
1154 case 12:
1155 func(m_union.m_uint64, m_id);
1156 break;
1157 case 13:
1158 func(m_union.m_uint16, m_id);
1159 break;
1160 case 14:
1161 func(m_union.m_PostalAddress, m_id);
1162 break;
1163 case 15:
1164 func(m_enum, m_id);
1165 break;
1166 case 16:
1167 func(m_union.m_int32, m_id);
1168 break;
1169 default:
1170 throw std::logic_error("Unknown field handle type index");
1175 /// Factory function to create a FieldHandle<> object.
1176 template <class RecordT, class TypeT>
1177 FieldHandle<RecordT> MakeFieldHandle(TypeT RecordT::* tp,
1178 const FieldIdentity &id)
1180 return FieldHandle<RecordT>(tp, id);
1183 /// Calls FileHandle<>::Member() for each defined field for a given record type.
1184 /// Takes a vector of FileHandle<> objects, and calls Member(func) for each one.
1185 template <class HandlesT, class CallbackT>
1186 void ForEachField(const HandlesT &handles, const CallbackT &func)
1188 typename HandlesT::const_iterator
1189 b = handles.begin(),
1190 e = handles.end();
1191 for( ; b != e; ++b ) {
1192 b->Member(func);
1196 /// Calls FileHandle<>::Value() for each defined field for a given record.
1197 /// Takes a RecordT object and calls Value(vh, rec) for each FileHandle<>
1198 /// object in the record's FileHandles set.
1199 template <class RecordT>
1200 void ForEachFieldValue(const RecordT &rec, const FieldValueHandlerBase &vh)
1202 typename std::vector<FieldHandle<RecordT> >::const_iterator
1203 b = RecordT::GetFieldHandles().begin(),
1204 e = RecordT::GetFieldHandles().end();
1205 for( ; b != e; ++b ) {
1206 b->Value(vh, rec);
1211 // FieldHandle setup macros
1213 // #undef and #define the following macros to override these macros for you:
1215 // CONTAINER_OBJECT_NAME - the new FieldHandles will be .push_back()'d into
1216 // this container
1217 // RECORD_CLASS_NAME - the name of the record class you are defining,
1218 // i.e. Barry::Contact, or Barry::Calendar
1221 // plain field, no connection to device field
1222 #define FHP(name, display) \
1223 CONTAINER_OBJECT_NAME.push_back( \
1224 FieldHandle<RECORD_CLASS_NAME>(&RECORD_CLASS_NAME::name, \
1225 FieldIdentity(#name, display)))
1226 // record field with direct connection to device field, no LDIF data
1227 #define FHD(name, display, type_code, iconv) \
1228 CONTAINER_OBJECT_NAME.push_back( \
1229 FieldHandle<RECORD_CLASS_NAME>(&RECORD_CLASS_NAME::name, \
1230 FieldIdentity(#name, display, type_code, iconv, \
1231 0, 0)))
1232 // record field with direct connection to device field, with LDIF data
1233 #define FHL(name, display, type_code, iconv, ldif, oclass) \
1234 CONTAINER_OBJECT_NAME.push_back( \
1235 FieldHandle<RECORD_CLASS_NAME>(&RECORD_CLASS_NAME::name, \
1236 FieldIdentity(#name, display, type_code, iconv, \
1237 ldif, oclass)))
1238 // a subfield of a conglomerate field, with direct connection to device field,
1239 // with LDIF data
1240 #define FHS(name, subname, display, type, iconv, ldif, oclass) \
1241 CONTAINER_OBJECT_NAME.push_back( \
1242 FieldHandle<RECORD_CLASS_NAME>( \
1243 FieldHandle<RECORD_CLASS_NAME>::MakePostalPointer( \
1244 &RECORD_CLASS_NAME::name, \
1245 &PostalAddress::subname), \
1246 FieldIdentity(#name "::" #subname, display, \
1247 type, iconv, ldif, oclass, \
1248 false, #name)))
1249 // record conglomerate field, which has subfields
1250 #define FHC(name, display) \
1251 CONTAINER_OBJECT_NAME.push_back( \
1252 FieldHandle<RECORD_CLASS_NAME>(&RECORD_CLASS_NAME::name, \
1253 FieldIdentity(#name, display, \
1254 -1, false, 0, 0, true, 0)))
1255 // create a new EnumField<> and add it to the list... use the new_var_name
1256 // to add constants with FHE_CONST below
1257 #define FHE(new_var_name, record_field_type, record_field_name, display) \
1258 EnumField<RECORD_CLASS_NAME, RECORD_CLASS_NAME::record_field_type> \
1259 *new_var_name = new \
1260 EnumField<RECORD_CLASS_NAME, RECORD_CLASS_NAME::record_field_type> \
1261 (&RECORD_CLASS_NAME::record_field_name); \
1262 CONTAINER_OBJECT_NAME.push_back( \
1263 FieldHandle<RECORD_CLASS_NAME>(new_var_name, \
1264 FieldIdentity(#record_field_name, display)))
1265 // same as FHE, but for when RECORD_CLASS_NAME is a template argument
1266 #define FHET(new_var_name, record_field_type, record_field_name, display) \
1267 EnumField<RECORD_CLASS_NAME, typename RECORD_CLASS_NAME::record_field_type> \
1268 *new_var_name = new \
1269 EnumField<RECORD_CLASS_NAME, typename RECORD_CLASS_NAME::record_field_type> \
1270 (&RECORD_CLASS_NAME::record_field_name); \
1271 CONTAINER_OBJECT_NAME.push_back( \
1272 FieldHandle<RECORD_CLASS_NAME>(new_var_name, \
1273 FieldIdentity(#record_field_name, display)))
1274 // add constant to enum created above
1275 #define FHE_CONST(var, name, display) \
1276 var->AddConstant(#name, display, RECORD_CLASS_NAME::name)
1278 /// @}
1280 } // namespace Barry
1283 /// \addtogroup RecordParserClasses
1284 /// Parser and data storage classes. These classes take a
1285 /// Database Database record and convert them into C++ objects.
1286 /// Each of these classes are safe to be used in standard
1287 /// containers, and are meant to be used in conjunction with the
1288 /// RecordParser<> template when calling Controller::LoadDatabase().
1289 /// @{
1290 /// @}
1292 #ifndef __BARRY_LIBRARY_BUILD__
1293 // Include all parser classes, to make it easy for the application to use.
1294 #include "r_calendar.h"
1295 #include "r_calllog.h"
1296 #include "r_bookmark.h"
1297 #include "r_contact.h"
1298 #include "r_cstore.h"
1299 #include "r_memo.h"
1300 #include "r_message.h"
1301 #include "r_servicebook.h"
1302 #include "r_task.h"
1303 #include "r_pin_message.h"
1304 #include "r_saved_message.h"
1305 #include "r_sms.h"
1306 #include "r_folder.h"
1307 #include "r_timezone.h"
1308 #include "r_hhagent.h"
1309 #endif
1311 #endif