menu: added new Keywords tag to .desktop files
[barry.git] / src / record.h
blobe9bc0cdcac6db40edc69c5db8c1692af5b13c190
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-2013, 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 #ifdef WINCE
39 /* The WinCE compiler v14.00.60131 doesn't like using operator= from base classes, so don't
40 * confuse it with a using directive. */
41 #define USE_BASE_ASSIGNMENT_OPERATOR
42 #else
43 #define USE_BASE_ASSIGNMENT_OPERATOR using base_type::operator=;
44 #endif
46 // forward declarations
47 namespace Barry { class Data; }
49 namespace Barry {
52 // NOTE: All classes here must be container-safe! Perhaps add sorting
53 // operators in the future.
57 // stream-based wrapper to avoid printing strings that contain
58 // the \r carriage return characters
59 class BXEXPORT Cr2LfWrapper
61 friend BXEXPORT std::ostream& operator<< (std::ostream &os, const Cr2LfWrapper &str);
62 const std::string &m_str;
63 public:
64 explicit Cr2LfWrapper(const std::string &str)
65 : m_str(str)
69 BXEXPORT std::ostream& operator<< (std::ostream &os, const Cr2LfWrapper &str);
71 /// Struct wrapper for time_t, to make sure that it has its own type,
72 /// for overload purposes. Some systems, like QNX, use a uint32_t typedef.
73 ///
74 /// If Time contains 0, it is considered invalid/uninitialized when using
75 /// IsValid(). Validity has no affect on comparison operators.
76 struct BXEXPORT TimeT
78 time_t Time;
80 TimeT()
81 : Time(0)
85 explicit TimeT(time_t t)
86 : Time(t)
90 void clear()
92 Time = 0;
95 bool IsValid() const { return Time > 0; }
97 bool operator< (const Barry::TimeT &other) const
99 return Time < other.Time;
102 bool operator== (const Barry::TimeT &other) const
104 return Time == other.Time;
107 bool operator!= (const Barry::TimeT &other) const
109 return !operator==(other);
112 BXEXPORT std::ostream& operator<< (std::ostream &os, const TimeT &t);
114 struct BXEXPORT CommandTableCommand
116 unsigned int Code;
117 std::string Name;
120 class BXEXPORT CommandTable
122 public:
123 typedef CommandTableCommand Command;
124 typedef std::vector<Command> CommandArrayType;
126 CommandArrayType Commands;
128 private:
129 BXLOCAL const unsigned char* ParseField(const unsigned char *begin,
130 const unsigned char *end);
131 public:
132 CommandTable();
133 ~CommandTable();
135 void Parse(const Data &data, size_t offset);
136 void Clear();
138 // returns 0 if unable to find command name, which is safe, since
139 // 0 is a special command that shouldn't be in the table anyway
140 unsigned int GetCommand(const std::string &name) const;
142 void Dump(std::ostream &os) const;
145 BXEXPORT inline std::ostream& operator<< (std::ostream &os, const CommandTable &command) {
146 command.Dump(os);
147 return os;
152 struct BXEXPORT RecordStateTableState
154 unsigned int Index;
155 uint32_t RecordId;
156 bool Dirty;
157 unsigned int RecType;
158 std::string Unknown2;
161 class BXEXPORT RecordStateTable
163 public:
164 typedef RecordStateTableState State;
165 typedef unsigned int IndexType;
166 typedef std::map<IndexType, State> StateMapType;
168 StateMapType StateMap;
170 private:
171 mutable IndexType m_LastNewRecordId;
173 private:
174 BXLOCAL const unsigned char* ParseField(const unsigned char *begin,
175 const unsigned char *end);
177 public:
178 RecordStateTable();
179 ~RecordStateTable();
181 void Parse(const Data &data);
182 void Clear();
184 bool GetIndex(uint32_t RecordId, IndexType *pFoundIndex = 0) const;
185 uint32_t MakeNewRecordId() const;
187 void Dump(std::ostream &os) const;
190 BXEXPORT inline std::ostream& operator<< (std::ostream &os, const RecordStateTable &rst) {
191 rst.Dump(os);
192 return os;
197 struct BXEXPORT DatabaseItem
199 unsigned int Number;
200 unsigned int RecordCount;
201 std::string Name;
204 class BXEXPORT DatabaseDatabase
206 public:
207 typedef DatabaseItem Database;
208 typedef std::vector<Database> DatabaseArrayType;
210 DatabaseArrayType Databases;
212 private:
213 template <class RecordType, class FieldType>
214 void ParseRec(const RecordType &rec, const unsigned char *end);
216 template <class FieldType>
217 const unsigned char* ParseField(const unsigned char *begin,
218 const unsigned char *end);
220 public:
221 DatabaseDatabase();
222 ~DatabaseDatabase();
224 void Parse(const Data &data);
225 void Clear();
227 void SortByName();
228 void SortByRecordCount();
229 unsigned int GetTotalRecordCount() const;
231 // returns true on success, and fills target
232 bool GetDBNumber(const std::string &name, unsigned int &number) const;
233 bool GetDBName(unsigned int number, std::string &name) const;
235 void Dump(std::ostream &os) const;
238 BXEXPORT inline std::ostream& operator<<(std::ostream &os, const DatabaseDatabase &dbdb) {
239 dbdb.Dump(os);
240 return os;
243 struct UnknownData
245 std::string raw_data;
247 const std::string::value_type* data() const { return raw_data.data(); }
248 std::string::size_type size() const { return raw_data.size(); }
249 void assign(const std::string::value_type *s, std::string::size_type n)
250 { raw_data.assign(s, n); }
252 bool operator==(const UnknownData &other) const
254 return raw_data == other.raw_data;
257 bool operator!=(const UnknownData &other) const
259 return !operator==(other);
262 bool operator< (const UnknownData &other) const
264 return raw_data < other.raw_data;
268 struct BXEXPORT UnknownField
270 uint8_t type;
271 UnknownData data;
273 bool operator==(const UnknownField &other) const
275 return type == other.type &&
276 data == other.data;
279 bool operator!=(const UnknownField &other) const
281 return !operator==(other);
284 bool operator< (const UnknownField &other) const
286 return type < other.type && data < other.data;
289 typedef std::vector<UnknownField> UnknownsType;
290 BXEXPORT std::ostream& operator<< (std::ostream &os, const UnknownsType &unknowns);
292 // simple string email type and list... keep this a simple string list,
293 // so it can be reused for other address-like data, like phone numbers.
294 // If you need something more complex, use EmailAddress below or
295 // create a new type.
296 typedef std::string EmailType;
297 class BXEXPORT EmailList : public std::vector<EmailType>
299 public:
300 typedef std::vector<EmailType> base_type;
302 public:
303 using base_type::size;
304 using base_type::begin;
305 using base_type::end;
306 using base_type::at;
307 using base_type::rbegin;
308 using base_type::rend;
309 using base_type::empty;
310 using base_type::resize;
311 using base_type::reserve;
312 using base_type::front;
313 using base_type::back;
314 using base_type::push_back;
315 using base_type::pop_back;
316 using base_type::insert;
317 using base_type::erase;
318 using base_type::swap;
319 using base_type::clear;
320 using base_type::operator[];
321 USE_BASE_ASSIGNMENT_OPERATOR
323 BXEXPORT std::ostream& operator<< (std::ostream &os, const EmailList &list);
325 // struct, attempting to combine name + email address, for mail
326 struct BXEXPORT EmailAddress
328 std::string Name;
329 std::string Email;
331 EmailAddress()
335 /// Converts "Name <address@host.com>" into Name + Address
336 /// Will also handle just a plain address too.
337 explicit EmailAddress(const std::string &complex_address);
339 void clear()
341 Name.clear();
342 Email.clear();
345 size_t size() const
347 return Name.size() + Email.size();
350 bool operator==(const EmailAddress &other) const
352 return Name == other.Name &&
353 Email == other.Email;
356 bool operator!=(const EmailAddress &other) const
358 return !operator==(other);
361 bool operator< (const EmailAddress &other) const
363 // sort by email only, since not every address has a name
364 return Email < other.Email;
367 BXEXPORT std::ostream& operator<<(std::ostream &os, const EmailAddress &msga);
369 class BXEXPORT EmailAddressList : public std::vector<EmailAddress>
371 public:
372 std::string ToCommaSeparated() const;
373 void AddCommaSeparated(const std::string &list);
376 BXEXPORT std::ostream& operator<<(std::ostream &os, const EmailAddressList &elist);
378 struct BXEXPORT PostalAddress
380 std::string
381 Address1,
382 Address2,
383 Address3,
384 City,
385 Province,
386 PostalCode,
387 Country;
389 std::string GetLabel() const;
390 void Clear();
392 bool HasData() const { return Address1.size() || Address2.size() ||
393 Address3.size() || City.size() || Province.size() ||
394 PostalCode.size() || Country.size(); }
396 bool operator==(const PostalAddress &other) const
398 return Address1 == other.Address1 &&
399 Address2 == other.Address2 &&
400 Address3 == other.Address3 &&
401 City == other.City &&
402 Province == other.Province &&
403 PostalCode == other.PostalCode &&
404 Country == other.Country;
406 bool operator!=(const PostalAddress &other) const
408 return !operator==(other);
410 bool operator< (const PostalAddress &other) const
412 return GetLabel() < other.GetLabel();
415 BXEXPORT std::ostream& operator<<(std::ostream &os, const PostalAddress &msga);
417 struct BXEXPORT Date
419 int Month; // 0 to 11
420 int Day; // 1 to 31
421 int Year; // exact number, eg. 2008
423 Date() : Month(0), Day(0), Year(0) {}
424 explicit Date(const struct tm *timep);
426 bool HasData() const { return Month || Day || Year; }
427 void Clear();
429 void ToTm(struct tm *timep) const;
430 std::string ToYYYYMMDD() const;
431 std::string ToBBString() const; // converts to Blackberry string
432 // format of DD/MM/YYYY
434 bool FromTm(const struct tm *timep);
435 bool FromBBString(const std::string &str);
436 bool FromYYYYMMDD(const std::string &str);
438 bool operator==(const Date &other) const
440 return Month == other.Month &&
441 Day == other.Day &&
442 Year == other.Year;
444 bool operator!=(const Date &other) const
446 return !operator==(other);
448 bool operator< (const Date &other) const
450 // YYYYMMDD as integer
451 unsigned int v1 = Year * 10000 + Month * 100 + Day;
452 unsigned int v2 = other.Year * 10000 + other.Month * 100 + other.Day;
453 return v1 < v2;
456 BXEXPORT std::ostream& operator<<(std::ostream &os, const Date &date);
458 class BXEXPORT CategoryList : public std::vector<std::string>
460 public:
461 typedef std::vector<std::string> base_type;
463 public:
464 /// Parses the given comma delimited category string into
465 /// this CategoryList object, appending each token to the vector.
466 /// Will clear vector beforehand.
467 void CategoryStr2List(const std::string &str);
469 /// Turns the current vectory into a comma delimited category
470 /// string suitable for use in Calendar, Task, and Memo
471 /// protocol values.
472 void CategoryList2Str(std::string &str) const;
474 USE_BASE_ASSIGNMENT_OPERATOR
476 BXEXPORT std::ostream& operator<<(std::ostream &os, const CategoryList &cl);
480 //////////////////////////////////////////////////////////////////////////////
481 // Generic Field Handles
483 /// \addtogroup GenericFieldHandles
484 /// Generic field handle classes, used to reference and work
485 /// with record members in a flexible, indirect way.
487 /// There are two ways to access device record data. The obvious
488 /// way is to instantiate a record class, such as Contact, and
489 /// access the public data members of that class to read and
490 /// write. If you always work with the same record class, this
491 /// works fine.
493 /// The other way is to have a list of pointers to members.
494 /// For example, you may wish to compare two records, without
495 /// actually caring what data is in each one. You can compare
496 /// at the record class level, with Contact one, two; and then
497 /// if( one == two ), but this will not tell you what field in
498 /// the record changed.
500 /// This last feature is what Generic Field Handles are meant to
501 /// fix. Each record class will contain a GetFieldHandles()
502 /// member function, which will return a list of type
503 /// FieldHandle<T>::ListT (currently a std::vector<>)
504 /// objects, for that specific record. For example, Contact
505 /// would fill the ListT with FieldHandle<Contact> objects.
506 /// Each FieldHandle<> object contains a C++ pointer-to-member,
507 /// which the FieldHandle refers to, as well as a FieldIdentity
508 /// object. The FieldIdentity object contains various identitying
509 /// information, such as the C++ variable name, an English
510 /// (or localized language) display name of the field, suitable
511 /// for user prompts, and other data more useful to the library.
513 /// The FieldHandle<> object has two member functions: Value()
514 /// and Member().
516 /// Value() will call a callback function with the _value_ of
517 /// the variable that FieldHandle<> points to. For example,
518 /// if the FieldHandle<> points to a std::string record member
519 /// variable, then Value() will pass that string value in as
520 /// an argument, along with a reference to the FieldIdentity
521 /// object. Value() requires a callback object and a record
522 /// object to perform this callback.
524 /// Member() will call a callback function/functor with the
525 /// pointer-to-member pointer and the FieldIdentity object.
526 /// This allows the programmer to create a functor with multiple
527 /// record objects, perhaps two objects to compare individual
528 /// fields, and use the pointer-to-member to access the field
529 /// data as needed.
531 /// For now, all data and callbacks are const, meaning that it
532 /// is not possible (without const_casting) to write to the
533 /// record via the pointers-to-members. This design decision
534 /// may need to be revisited someday, depending on its usefulness.
536 /// @{
539 // FieldIdentity
541 /// This class holds data that identifies a given field in a record.
542 /// This is fairly constant data, referenced by the FieldHandle class.
543 /// The information in here should be enough to show the user what kind
544 /// of field this is.
546 struct BXEXPORT FieldIdentity
548 // useful public data
549 const char *Name; // C++ name of field member variable in
550 // record class
551 std::string DisplayName; // localized display name of field
552 // in UTF8
553 // FIXME - should we leave localization
554 // to the application?
556 // subfield detection
557 bool HasSubfields; // true if this field has subfields
558 const char *ParentName; // name of field member variable that
559 // this field is a member of, or NULL
560 // if this field is a member of the
561 // record class.
562 // For example, Contact::PostalAddress
563 // would have HasSubfields == true,
564 // and ParentName == NULL, while all
565 // its subfield strings would have
566 // HasSubfields == false and
567 // ParentName == "WorkAddress" or
568 // "HomeAddress".
569 // The application could then decide
570 // whether to process only main fields,
571 // some of which have subfields,
572 // or only individual subfields.
574 // internal field data
575 int FieldTypeCode; // device type code for this field.
576 // if -1, then this is a conglomerate
577 // C++ field, such as
578 // Contact::PostalAddress, not a device
579 // field.
580 // If -1, then none of the following
581 // fields are valid.
582 const char *Ldif; // matching LDIF field name, or NULL
583 const char *ObjectClass; // matching LDIF object class, or NULL
584 bool IconvNeeded; // if true, the device's data needs to
585 // be passed through an IConverter
587 FieldIdentity(const char *name, const std::string &display_name,
588 int type_code = -1,
589 bool iconvneeded = false,
590 const char *ldif = 0, const char *oclass = 0,
591 bool has_sub = false, const char *parent = 0
593 : Name(name)
594 , DisplayName(display_name)
595 , HasSubfields(has_sub)
596 , ParentName(parent)
597 , FieldTypeCode(type_code)
598 , Ldif(ldif)
599 , ObjectClass(oclass)
600 , IconvNeeded(iconvneeded)
606 // EnumConstants
608 /// This is the base class for the hierarchy of classes to define
609 /// enum record members. This is the base class, which contains the
610 /// common code for creating and defining a list of enum constants for
611 /// a given enum field. The next derived class is EnumFieldBase<RecordT>,
612 /// which defines the virtual API for talking to a given enum field
613 /// in a given record. The next derived class is EnumField<RecordT, EnumT>,
614 /// which implements the pointer-to-member and virtual API for a given
615 /// enum type in a given record class.
617 /// For example, the Bookmark record class has the following enum field:
619 /// <pre>
620 /// enum BrowserIdentityType
621 /// {
622 /// IdentityAuto = 0,
623 /// IdentityBlackBerry,
624 /// IdentityFireFox,
625 /// IdentityInternetExplorer,
626 /// IdentityUnknown
627 /// };
628 /// BrowserIdentityType BrowserIdentity;
629 /// </pre>
631 /// The EnumConstants class will hold a vector of EnumConstant structs
632 /// defining each of the identity constants: Auto, BlackBerry, FireFox,
633 /// InternetExplorer, and Unknown.
635 /// The derived class EnumFieldBase<Bookmark> will define two additional
636 /// pure virtual API calls: GetValue(const Bookmark&) and
637 /// SetValue(Bookmark&, int).
639 /// Finally, the derived class EnumField<Bookmark,Bookmark::BrowserIdentityType>
640 /// will implement the virtual API, and contain a pointer-to-member to
641 /// the Bookmark::BrowserIdentity member field.
643 /// The FieldHandle<Bookmark> class will hold a pointer to
644 /// EnumFieldBase<Bookmark>, which can hold a pointer to a specific
645 /// EnumField<> object, one object for each of Bookmark's enum types,
646 /// of which there are currently 3.
648 class BXEXPORT EnumConstants
650 public:
651 /// This defines one of the enum constants being defined.
652 /// For example, for an enum declaration like:
653 /// enum Mine { A, B, C }; then this struct could contain
654 /// a definition for A, B, or C, but only one at at time.
655 /// All three would be defined by the EnumConstantList.
656 struct EnumConstant
658 const char *Name; //< C++ name of enum constant
659 std::string DisplayName; //< user-friendly name / meaning
660 int Value; //< constant enum value
662 EnumConstant(const char *name, const std::string &display,
663 int value)
664 : Name(name)
665 , DisplayName(display)
666 , Value(value)
671 typedef std::vector<EnumConstant> EnumConstantList;
673 private:
674 EnumConstantList m_constants;
676 public:
677 virtual ~EnumConstants() {}
679 /// Adds a constant definition to the list
680 void AddConstant(const char *name, const std::string &display, int val);
682 /// Returns a vector of EnumConstant objects, describing all enum
683 /// constants valid for this enum field.
684 const EnumConstantList& GetConstantList() const { return m_constants; }
686 /// Returns the EnumConstant for the given value.
687 /// Throws std::logic_error if not found.
688 const EnumConstant& GetConstant(int value) const;
690 /// Returns the constant name (C++ name) based on the given value.
691 /// Throws std::logic_error if not found.
692 const char* GetName(int value) const;
694 /// Returns the display name based on the given value.
695 /// Throws std::logic_error if not found.
696 const std::string& GetDisplayName(int value) const;
698 /// Returns true if the value matches one of the constants in the list.
699 bool IsConstantValid(int value) const;
703 // FieldValueHandlerBase
705 /// This is a pure virtual base class, defining the various types that
706 /// record fields can be. To be able to handle all the types of data
707 /// in all records, override these virtual functions to do with the
708 /// data as you wish.
710 /// All data from the records and fields will be passed in by value.
711 /// i.e. if field is string data, the overloaded std::string handler
712 /// will be called, and a refernce to the string will be passed in.
714 /// The advantage of using this virtual class is that less code will be
715 /// generated by templates. The disadvantage is that this is less flexible.
716 /// You will only get called for one field and record at a time.
717 /// So you can't do comparisons this way.
719 class BXEXPORT FieldValueHandlerBase
721 public:
722 virtual ~FieldValueHandlerBase() {}
724 /// For type std::string
725 virtual void operator()(const std::string &v,
726 const FieldIdentity &id) const = 0;
727 /// For type EmailAddressList
728 virtual void operator()(const EmailAddressList &v,
729 const FieldIdentity &id) const = 0;
730 /// For type Barry::TimeT
731 virtual void operator()(const Barry::TimeT &v,
732 const FieldIdentity &id) const = 0;
733 /// For type uint8_t
734 virtual void operator()(const uint8_t &v,
735 const FieldIdentity &id) const = 0;
736 /// For type uint16_t
737 virtual void operator()(const uint16_t &v,
738 const FieldIdentity &id) const = 0;
739 /// For type uint32_t
740 virtual void operator()(const uint32_t &v,
741 const FieldIdentity &id) const = 0;
742 /// For type uint64_t
743 virtual void operator()(const uint64_t &v,
744 const FieldIdentity &id) const = 0;
745 /// For type bool
746 virtual void operator()(const bool &v,
747 const FieldIdentity &id) const = 0;
748 /// For type int32_t
749 virtual void operator()(const int32_t &v,
750 const FieldIdentity &id) const = 0;
751 /// For type EmailList
752 virtual void operator()(const EmailList &v,
753 const FieldIdentity &id) const = 0;
754 /// For type Date
755 virtual void operator()(const Date &v,
756 const FieldIdentity &id) const = 0;
757 /// For type CategoryList
758 virtual void operator()(const CategoryList &v,
759 const FieldIdentity &id) const = 0;
760 /// For type PostalAddress
761 virtual void operator()(const PostalAddress &v,
762 const FieldIdentity &id) const = 0;
763 /// For type UnknownsType
764 virtual void operator()(const UnknownsType &v,
765 const FieldIdentity &id) const = 0;
769 /// EnumFieldBase<RecordT>
771 template <class RecordT>
772 class EnumFieldBase : public EnumConstants
774 public:
775 /// Return value of enum in rec
776 virtual int GetValue(const RecordT &rec) const = 0;
777 /// Set value of enum in rec
778 /// Throws std::logic_error if value is out of range
779 virtual void SetValue(RecordT &rec, int value) = 0;
783 /// EnumField<RecordT, EnumT>
785 template <class RecordT, class EnumT>
786 class EnumField : public EnumFieldBase<RecordT>
788 EnumT RecordT::* m_mp;
790 public:
791 explicit EnumField(EnumT RecordT::* mp)
792 : m_mp(mp)
796 virtual int GetValue(const RecordT &rec) const
798 return rec.*m_mp;
801 virtual void SetValue(RecordT &rec, int value)
803 if( !this->IsConstantValid(value) )
804 throw std::logic_error("Bad enum value in EnumField");
805 rec.*m_mp = (EnumT) value;
810 // FieldHandle<RecordT>
812 /// This is a template class that handles pointers to members of multiple
813 /// types of data and multiple types of records.
815 /// This class contains a union of all known data pointers in all records.
816 /// Therefore this class can hold a pointer to member of any record class.
818 /// To do something with the field that this FieldHandle<> class refers to,
819 /// call either Value() or Member() with appropriate callback functors.
820 /// Value will pass a reference to the field. You can use an object
821 /// derived from FieldValueHandlerBase here. Member() will pass a pointer
822 /// to member. Your functor will need to contain the record data in order
823 /// to access its data via the pointer to member.
825 /// The template functor callback that you pass into member must be
826 /// capable of this:
828 /// <pre>
829 /// template &lt;class RecordT&gt;
830 /// struct Callback
831 /// {
832 /// RecordT m_rec;
834 /// void operator()(typename FieldHandle<RecordT>::PostalPointer pp,
835 /// const FieldIdentity &id) const
836 /// {
837 /// PostalAddress pa = m_rec.*(pp.m_PostalAddress);
838 /// std::string val = pa.*(pp.m_PostalField);
839 /// ...
840 /// }
842 /// template &lt;class TypeT&gt;
843 /// void operator()(TypeT RecordT::* mp,
844 /// const FieldIdentity &id) const
845 /// {
846 /// TypeT val = m_rec.*mp;
847 /// ...
848 /// }
849 /// };
850 /// </pre>
852 /// You don't have to use a TypeT template, but if you don't, then you must
853 /// support all field types that the record class you're processing uses.
856 template <class RecordT>
857 class FieldHandle
859 public:
860 typedef FieldHandle<RecordT> Self;
861 typedef std::vector<Self> ListT;
863 // Need to use this in the union, so no constructor allowed
864 struct PostalPointer
866 PostalAddress RecordT::* m_PostalAddress;
867 std::string PostalAddress::* m_PostalField;
870 // So use a factory function
871 static PostalPointer MakePostalPointer(PostalAddress RecordT::* p1,
872 std::string PostalAddress::* p2)
874 PostalPointer pp;
875 pp.m_PostalAddress = p1;
876 pp.m_PostalField = p2;
877 return pp;
880 private:
881 union PointerUnion
883 std::string RecordT::* m_string; // index 0
884 EmailAddressList RecordT::* m_EmailAddressList; // 1
885 Barry::TimeT RecordT::* m_time; // 2
886 PostalPointer m_postal; // 3
887 uint8_t RecordT::* m_uint8; // 4
888 uint32_t RecordT::* m_uint32; // 5
889 EmailList RecordT::* m_EmailList; // 6
890 Date RecordT::* m_Date; // 7
891 CategoryList RecordT::* m_CategoryList; // 8
892 // GroupLinksType RecordT::* m_GroupLinksType; // 9
893 UnknownsType RecordT::* m_UnknownsType; // 10
894 bool RecordT::* m_bool; // 11
895 uint64_t RecordT::* m_uint64; // 12
896 uint16_t RecordT::* m_uint16; // 13
897 PostalAddress RecordT::* m_PostalAddress; // 14
898 // used by non-union m_enum below: // 15
899 int32_t RecordT::* m_int32; // 16
902 int m_type_index;
903 PointerUnion m_union;
904 EnumFieldBase<RecordT> *m_enum; // never freed, since this is a
905 // static list, existing to end of
906 // program lifetime
908 FieldIdentity m_id;
910 public:
911 // 0
912 FieldHandle(std::string RecordT::* mp, const FieldIdentity &id)
913 : m_type_index(0)
914 , m_enum(0)
915 , m_id(id)
917 m_union.m_string = mp;
920 // 1
921 FieldHandle(EmailAddressList RecordT::* mp, const FieldIdentity &id)
922 : m_type_index(1)
923 , m_enum(0)
924 , m_id(id)
926 m_union.m_EmailAddressList = mp;
929 // 2
930 FieldHandle(Barry::TimeT RecordT::* mp, const FieldIdentity &id)
931 : m_type_index(2)
932 , m_enum(0)
933 , m_id(id)
935 m_union.m_time = mp;
938 // 3
939 FieldHandle(const PostalPointer &pp, const FieldIdentity &id)
940 : m_type_index(3)
941 , m_enum(0)
942 , m_id(id)
944 m_union.m_postal = pp;
947 // 4
948 FieldHandle(uint8_t RecordT::* mp, const FieldIdentity &id)
949 : m_type_index(4)
950 , m_enum(0)
951 , m_id(id)
953 m_union.m_uint8 = mp;
956 // 5
957 FieldHandle(uint32_t RecordT::* mp, const FieldIdentity &id)
958 : m_type_index(5)
959 , m_enum(0)
960 , m_id(id)
962 m_union.m_uint32 = mp;
965 // 6
966 FieldHandle(EmailList RecordT::* mp, const FieldIdentity &id)
967 : m_type_index(6)
968 , m_enum(0)
969 , m_id(id)
971 m_union.m_EmailList = mp;
974 // 7
975 FieldHandle(Date RecordT::* mp, const FieldIdentity &id)
976 : m_type_index(7)
977 , m_enum(0)
978 , m_id(id)
980 m_union.m_Date = mp;
983 // 8
984 FieldHandle(CategoryList RecordT::* mp, const FieldIdentity &id)
985 : m_type_index(8)
986 , m_enum(0)
987 , m_id(id)
989 m_union.m_CategoryList = mp;
992 // 9
993 // FieldHandle(GroupLinksType RecordT::* mp, const FieldIdentity &id)
994 // : m_type_index(9)
995 // , m_enum(0)
996 // , m_id(id)
997 // {
998 // m_union.m_GroupLinksType = mp;
999 // }
1001 // 10
1002 FieldHandle(UnknownsType RecordT::* mp, const FieldIdentity &id)
1003 : m_type_index(10)
1004 , m_enum(0)
1005 , m_id(id)
1007 m_union.m_UnknownsType = mp;
1010 // 11
1011 FieldHandle(bool RecordT::* mp, const FieldIdentity &id)
1012 : m_type_index(11)
1013 , m_enum(0)
1014 , m_id(id)
1016 m_union.m_bool = mp;
1019 // 12
1020 FieldHandle(uint64_t RecordT::* mp, const FieldIdentity &id)
1021 : m_type_index(12)
1022 , m_enum(0)
1023 , m_id(id)
1025 m_union.m_uint64 = mp;
1028 // 13
1029 FieldHandle(uint16_t RecordT::* mp, const FieldIdentity &id)
1030 : m_type_index(13)
1031 , m_enum(0)
1032 , m_id(id)
1034 m_union.m_uint16 = mp;
1037 // 14
1038 FieldHandle(PostalAddress RecordT::* mp, const FieldIdentity &id)
1039 : m_type_index(14)
1040 , m_enum(0)
1041 , m_id(id)
1043 m_union.m_PostalAddress = mp;
1046 // 15
1047 FieldHandle(EnumFieldBase<RecordT> *enum_, const FieldIdentity &id)
1048 : m_type_index(15)
1049 , m_enum(enum_)
1050 , m_id(id)
1054 // 16
1055 FieldHandle(int32_t RecordT::* mp, const FieldIdentity &id)
1056 : m_type_index(16)
1057 , m_enum(0)
1058 , m_id(id)
1060 m_union.m_int32 = mp;
1063 /// Extracts FieldIdentity object from FieldHandle<>
1064 const FieldIdentity& GetIdentity() const { return m_id; }
1066 /// Calls the matching virtual function in FieldValueHandlerBase,
1067 /// passing in the value of the field that this FieldHandle<>
1068 /// refers to, and a referenct to the FieldIdentity object.
1069 /// Caller must pass in a RecordT object as well.
1070 void Value(const FieldValueHandlerBase &vh, const RecordT &rec) const
1072 switch( m_type_index )
1074 case 0:
1075 vh(rec.*(m_union.m_string), m_id);
1076 break;
1077 case 1:
1078 vh(rec.*(m_union.m_EmailAddressList), m_id);
1079 break;
1080 case 2:
1081 vh(rec.*(m_union.m_time), m_id);
1082 break;
1083 case 3:
1084 vh(rec.*(m_union.m_postal.m_PostalAddress).*(m_union.m_postal.m_PostalField), m_id);
1085 break;
1086 case 4:
1087 vh(rec.*(m_union.m_uint8), m_id);
1088 break;
1089 case 5:
1090 vh(rec.*(m_union.m_uint32), m_id);
1091 break;
1092 case 6:
1093 vh(rec.*(m_union.m_EmailList), m_id);
1094 break;
1095 case 7:
1096 vh(rec.*(m_union.m_Date), m_id);
1097 break;
1098 case 8:
1099 vh(rec.*(m_union.m_CategoryList), m_id);
1100 break;
1101 // case 9:
1102 // vh(rec.*(m_union.m_GroupLinksType), m_id);
1103 // break;
1104 case 10:
1105 vh(rec.*(m_union.m_UnknownsType), m_id);
1106 break;
1107 case 11:
1108 vh(rec.*(m_union.m_bool), m_id);
1109 break;
1110 case 12:
1111 vh(rec.*(m_union.m_uint64), m_id);
1112 break;
1113 case 13:
1114 vh(rec.*(m_union.m_uint16), m_id);
1115 break;
1116 case 14:
1117 vh(rec.*(m_union.m_PostalAddress), m_id);
1118 break;
1119 case 15:
1120 vh(m_enum->GetValue(rec), m_id);
1121 break;
1122 case 16:
1123 vh(rec.*(m_union.m_int32), m_id);
1124 break;
1125 default:
1126 throw std::logic_error("Unknown field handle type index");
1130 /// Calls the callback functor with two arguments: the pointer to
1131 /// member that this FieldHandle<> contains, and the FieldIdentity
1132 /// object. It is assumed that the functor will either contain
1133 /// or know where to find one or more records of type RecordT.
1134 template <class CallbackT>
1135 void Member(const CallbackT &func) const
1137 switch( m_type_index )
1139 case 0:
1140 func(m_union.m_string, m_id);
1141 break;
1142 case 1:
1143 func(m_union.m_EmailAddressList, m_id);
1144 break;
1145 case 2:
1146 func(m_union.m_time, m_id);
1147 break;
1148 case 3:
1149 func(m_union.m_postal, m_id);
1150 break;
1151 case 4:
1152 func(m_union.m_uint8, m_id);
1153 break;
1154 case 5:
1155 func(m_union.m_uint32, m_id);
1156 break;
1157 case 6:
1158 func(m_union.m_EmailList, m_id);
1159 break;
1160 case 7:
1161 func(m_union.m_Date, m_id);
1162 break;
1163 case 8:
1164 func(m_union.m_CategoryList, m_id);
1165 break;
1166 // case 9:
1167 // func(m_union.m_GroupLinksType, m_id);
1168 // break;
1169 case 10:
1170 func(m_union.m_UnknownsType, m_id);
1171 break;
1172 case 11:
1173 func(m_union.m_bool, m_id);
1174 break;
1175 case 12:
1176 func(m_union.m_uint64, m_id);
1177 break;
1178 case 13:
1179 func(m_union.m_uint16, m_id);
1180 break;
1181 case 14:
1182 func(m_union.m_PostalAddress, m_id);
1183 break;
1184 case 15:
1185 func(m_enum, m_id);
1186 break;
1187 case 16:
1188 func(m_union.m_int32, m_id);
1189 break;
1190 default:
1191 throw std::logic_error("Unknown field handle type index");
1196 /// Factory function to create a FieldHandle<> object.
1197 template <class RecordT, class TypeT>
1198 FieldHandle<RecordT> MakeFieldHandle(TypeT RecordT::* tp,
1199 const FieldIdentity &id)
1201 return FieldHandle<RecordT>(tp, id);
1204 /// Calls FieldHandle<>::Member() for each defined field for a given record
1205 /// type. Takes a FieldHandle<>::ListT containing FieldHandle<> objects,
1206 /// and calls Member(func) for each one.
1207 template <class HandlesT, class CallbackT>
1208 void ForEachField(const HandlesT &handles, const CallbackT &func)
1210 typename HandlesT::const_iterator
1211 b = handles.begin(),
1212 e = handles.end();
1213 for( ; b != e; ++b ) {
1214 b->Member(func);
1218 /// Calls FieldHandle<>::Value() for each defined field for a given record.
1219 /// Takes a RecordT object and calls Value(vh, rec) for each FieldHandle<>
1220 /// object in the record's FieldHandles set.
1221 template <class RecordT>
1222 void ForEachFieldValue(const RecordT &rec, const FieldValueHandlerBase &vh)
1224 typename FieldHandle<RecordT>::ListT::const_iterator
1225 b = RecordT::GetFieldHandles().begin(),
1226 e = RecordT::GetFieldHandles().end();
1227 for( ; b != e; ++b ) {
1228 b->Value(vh, rec);
1233 // FieldHandle setup macros
1235 // #undef and #define the following macros to override these macros for you:
1237 // CONTAINER_OBJECT_NAME - the new FieldHandles will be .push_back()'d into
1238 // this container
1239 // RECORD_CLASS_NAME - the name of the record class you are defining,
1240 // i.e. Barry::Contact, or Barry::Calendar
1243 // plain field, no connection to device field
1244 #define FHP(name, display) \
1245 CONTAINER_OBJECT_NAME.push_back( \
1246 FieldHandle<RECORD_CLASS_NAME>(&RECORD_CLASS_NAME::name, \
1247 FieldIdentity(#name, display)))
1248 // record field with direct connection to device field, no LDIF data
1249 #define FHD(name, display, type_code, iconv) \
1250 CONTAINER_OBJECT_NAME.push_back( \
1251 FieldHandle<RECORD_CLASS_NAME>(&RECORD_CLASS_NAME::name, \
1252 FieldIdentity(#name, display, type_code, iconv, \
1253 0, 0)))
1254 // record field with direct connection to device field, with LDIF data
1255 #define FHL(name, display, type_code, iconv, ldif, oclass) \
1256 CONTAINER_OBJECT_NAME.push_back( \
1257 FieldHandle<RECORD_CLASS_NAME>(&RECORD_CLASS_NAME::name, \
1258 FieldIdentity(#name, display, type_code, iconv, \
1259 ldif, oclass)))
1260 // a subfield of a conglomerate field, with direct connection to device field,
1261 // with LDIF data
1262 #define FHS(name, subname, display, type, iconv, ldif, oclass) \
1263 CONTAINER_OBJECT_NAME.push_back( \
1264 FieldHandle<RECORD_CLASS_NAME>( \
1265 FieldHandle<RECORD_CLASS_NAME>::MakePostalPointer( \
1266 &RECORD_CLASS_NAME::name, \
1267 &PostalAddress::subname), \
1268 FieldIdentity(#name "::" #subname, display, \
1269 type, iconv, ldif, oclass, \
1270 false, #name)))
1271 // record conglomerate field, which has subfields
1272 #define FHC(name, display) \
1273 CONTAINER_OBJECT_NAME.push_back( \
1274 FieldHandle<RECORD_CLASS_NAME>(&RECORD_CLASS_NAME::name, \
1275 FieldIdentity(#name, display, \
1276 -1, false, 0, 0, true, 0)))
1277 // create a new EnumField<> and add it to the list... use the new_var_name
1278 // to add constants with FHE_CONST below
1279 #define FHE(new_var_name, record_field_type, record_field_name, display) \
1280 EnumField<RECORD_CLASS_NAME, RECORD_CLASS_NAME::record_field_type> \
1281 *new_var_name = new \
1282 EnumField<RECORD_CLASS_NAME, RECORD_CLASS_NAME::record_field_type> \
1283 (&RECORD_CLASS_NAME::record_field_name); \
1284 CONTAINER_OBJECT_NAME.push_back( \
1285 FieldHandle<RECORD_CLASS_NAME>(new_var_name, \
1286 FieldIdentity(#record_field_name, display)))
1287 // same as FHE, but for when RECORD_CLASS_NAME is a template argument
1288 #define FHET(new_var_name, record_field_type, record_field_name, display) \
1289 EnumField<RECORD_CLASS_NAME, typename RECORD_CLASS_NAME::record_field_type> \
1290 *new_var_name = new \
1291 EnumField<RECORD_CLASS_NAME, typename RECORD_CLASS_NAME::record_field_type> \
1292 (&RECORD_CLASS_NAME::record_field_name); \
1293 CONTAINER_OBJECT_NAME.push_back( \
1294 FieldHandle<RECORD_CLASS_NAME>(new_var_name, \
1295 FieldIdentity(#record_field_name, display)))
1296 // add constant to enum created above
1297 #define FHE_CONST(var, name, display) \
1298 var->AddConstant(#name, display, RECORD_CLASS_NAME::name)
1300 /// @}
1302 } // namespace Barry
1305 /// \addtogroup RecordParserClasses
1306 /// Parser and data storage classes. These classes take a
1307 /// Database Database record and convert them into C++ objects.
1308 /// Each of these classes are safe to be used in standard
1309 /// containers, and are meant to be used in conjunction with the
1310 /// RecordParser<> template when calling Controller::LoadDatabase().
1311 /// @{
1312 /// @}
1314 #ifndef __BARRY_LIBRARY_BUILD__
1315 // Include all parser classes, to make it easy for the application to use.
1316 #include "r_calendar.h"
1317 #include "r_calllog.h"
1318 #include "r_bookmark.h"
1319 #include "r_contact.h"
1320 #include "r_cstore.h"
1321 #include "r_memo.h"
1322 #include "r_message.h"
1323 #include "r_servicebook.h"
1324 #include "r_task.h"
1325 #include "r_pin_message.h"
1326 #include "r_saved_message.h"
1327 #include "r_sms.h"
1328 #include "r_folder.h"
1329 #include "r_timezone.h"
1330 #include "r_hhagent.h"
1331 #endif
1333 #endif