lib: fixed parsing of recurring VEVENTS: DAILY and interval support
[barry/progweb.git] / src / record.h
blob7055beae7930297ca1b0b3674b161170fbe2b8d9
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 ///
66 /// If Time contains 0, it is considered invalid/uninitialized when using
67 /// IsValid(). Validity has no affect on comparison operators.
68 struct BXEXPORT TimeT
70 time_t Time;
72 TimeT()
73 : Time(0)
77 explicit TimeT(time_t t)
78 : Time(t)
82 void clear()
84 Time = 0;
87 bool IsValid() const { return Time > 0; }
89 bool operator< (const Barry::TimeT &other) const
91 return Time < other.Time;
94 bool operator== (const Barry::TimeT &other) const
96 return Time == other.Time;
99 bool operator!= (const Barry::TimeT &other) const
101 return !operator==(other);
104 BXEXPORT std::ostream& operator<< (std::ostream &os, const TimeT &t);
106 struct BXEXPORT CommandTableCommand
108 unsigned int Code;
109 std::string Name;
112 class BXEXPORT CommandTable
114 public:
115 typedef CommandTableCommand Command;
116 typedef std::vector<Command> CommandArrayType;
118 CommandArrayType Commands;
120 private:
121 BXLOCAL const unsigned char* ParseField(const unsigned char *begin,
122 const unsigned char *end);
123 public:
124 CommandTable();
125 ~CommandTable();
127 void Parse(const Data &data, size_t offset);
128 void Clear();
130 // returns 0 if unable to find command name, which is safe, since
131 // 0 is a special command that shouldn't be in the table anyway
132 unsigned int GetCommand(const std::string &name) const;
134 void Dump(std::ostream &os) const;
137 BXEXPORT inline std::ostream& operator<< (std::ostream &os, const CommandTable &command) {
138 command.Dump(os);
139 return os;
144 struct BXEXPORT RecordStateTableState
146 unsigned int Index;
147 uint32_t RecordId;
148 bool Dirty;
149 unsigned int RecType;
150 std::string Unknown2;
153 class BXEXPORT RecordStateTable
155 public:
156 typedef RecordStateTableState State;
157 typedef unsigned int IndexType;
158 typedef std::map<IndexType, State> StateMapType;
160 StateMapType StateMap;
162 private:
163 mutable IndexType m_LastNewRecordId;
165 private:
166 BXLOCAL const unsigned char* ParseField(const unsigned char *begin,
167 const unsigned char *end);
169 public:
170 RecordStateTable();
171 ~RecordStateTable();
173 void Parse(const Data &data);
174 void Clear();
176 bool GetIndex(uint32_t RecordId, IndexType *pFoundIndex = 0) const;
177 uint32_t MakeNewRecordId() const;
179 void Dump(std::ostream &os) const;
182 BXEXPORT inline std::ostream& operator<< (std::ostream &os, const RecordStateTable &rst) {
183 rst.Dump(os);
184 return os;
189 struct BXEXPORT DatabaseItem
191 unsigned int Number;
192 unsigned int RecordCount;
193 std::string Name;
196 class BXEXPORT DatabaseDatabase
198 public:
199 typedef DatabaseItem Database;
200 typedef std::vector<Database> DatabaseArrayType;
202 DatabaseArrayType Databases;
204 private:
205 template <class RecordType, class FieldType>
206 void ParseRec(const RecordType &rec, const unsigned char *end);
208 template <class FieldType>
209 const unsigned char* ParseField(const unsigned char *begin,
210 const unsigned char *end);
212 public:
213 DatabaseDatabase();
214 ~DatabaseDatabase();
216 void Parse(const Data &data);
217 void Clear();
219 void SortByName();
220 void SortByRecordCount();
221 unsigned int GetTotalRecordCount() const;
223 // returns true on success, and fills target
224 bool GetDBNumber(const std::string &name, unsigned int &number) const;
225 bool GetDBName(unsigned int number, std::string &name) const;
227 void Dump(std::ostream &os) const;
230 BXEXPORT inline std::ostream& operator<<(std::ostream &os, const DatabaseDatabase &dbdb) {
231 dbdb.Dump(os);
232 return os;
235 struct UnknownData
237 std::string raw_data;
239 const std::string::value_type* data() const { return raw_data.data(); }
240 std::string::size_type size() const { return raw_data.size(); }
241 void assign(const std::string::value_type *s, std::string::size_type n)
242 { raw_data.assign(s, n); }
244 bool operator==(const UnknownData &other) const
246 return raw_data == other.raw_data;
249 bool operator!=(const UnknownData &other) const
251 return !operator==(other);
254 bool operator< (const UnknownData &other) const
256 return raw_data < other.raw_data;
260 struct BXEXPORT UnknownField
262 uint8_t type;
263 UnknownData data;
265 bool operator==(const UnknownField &other) const
267 return type == other.type &&
268 data == other.data;
271 bool operator!=(const UnknownField &other) const
273 return !operator==(other);
276 bool operator< (const UnknownField &other) const
278 return type < other.type && data < other.data;
281 typedef std::vector<UnknownField> UnknownsType;
282 BXEXPORT std::ostream& operator<< (std::ostream &os, const UnknownsType &unknowns);
284 // simple string email type and list... keep this a simple string list,
285 // so it can be reused for other address-like data, like phone numbers.
286 // If you need something more complex, use EmailAddress below or
287 // create a new type.
288 typedef std::string EmailType;
289 class BXEXPORT EmailList : public std::vector<EmailType>
291 public:
292 typedef std::vector<EmailType> base_type;
294 public:
295 using base_type::size;
296 using base_type::begin;
297 using base_type::end;
298 using base_type::at;
299 using base_type::rbegin;
300 using base_type::rend;
301 using base_type::empty;
302 using base_type::resize;
303 using base_type::reserve;
304 using base_type::front;
305 using base_type::back;
306 using base_type::push_back;
307 using base_type::pop_back;
308 using base_type::insert;
309 using base_type::erase;
310 using base_type::swap;
311 using base_type::clear;
312 using base_type::operator=;
313 using base_type::operator[];
315 BXEXPORT std::ostream& operator<< (std::ostream &os, const EmailList &list);
317 // struct, attempting to combine name + email address, for mail
318 struct BXEXPORT EmailAddress
320 std::string Name;
321 std::string Email;
323 EmailAddress()
327 /// Converts "Name <address@host.com>" into Name + Address
328 /// Will also handle just a plain address too.
329 explicit EmailAddress(const std::string &complex_address);
331 void clear()
333 Name.clear();
334 Email.clear();
337 size_t size() const
339 return Name.size() + Email.size();
342 bool operator==(const EmailAddress &other) const
344 return Name == other.Name &&
345 Email == other.Email;
348 bool operator!=(const EmailAddress &other) const
350 return !operator==(other);
353 bool operator< (const EmailAddress &other) const
355 // sort by email only, since not every address has a name
356 return Email < other.Email;
359 BXEXPORT std::ostream& operator<<(std::ostream &os, const EmailAddress &msga);
361 class BXEXPORT EmailAddressList : public std::vector<EmailAddress>
363 public:
364 std::string ToCommaSeparated() const;
365 void AddCommaSeparated(const std::string &list);
368 BXEXPORT std::ostream& operator<<(std::ostream &os, const EmailAddressList &elist);
370 struct BXEXPORT PostalAddress
372 std::string
373 Address1,
374 Address2,
375 Address3,
376 City,
377 Province,
378 PostalCode,
379 Country;
381 std::string GetLabel() const;
382 void Clear();
384 bool HasData() const { return Address1.size() || Address2.size() ||
385 Address3.size() || City.size() || Province.size() ||
386 PostalCode.size() || Country.size(); }
388 bool operator==(const PostalAddress &other) const
390 return Address1 == other.Address1 &&
391 Address2 == other.Address2 &&
392 Address3 == other.Address3 &&
393 City == other.City &&
394 Province == other.Province &&
395 PostalCode == other.PostalCode &&
396 Country == other.Country;
398 bool operator!=(const PostalAddress &other) const
400 return !operator==(other);
402 bool operator< (const PostalAddress &other) const
404 return GetLabel() < other.GetLabel();
407 BXEXPORT std::ostream& operator<<(std::ostream &os, const PostalAddress &msga);
409 struct BXEXPORT Date
411 int Month; // 0 to 11
412 int Day; // 1 to 31
413 int Year; // exact number, eg. 2008
415 Date() : Month(0), Day(0), Year(0) {}
416 explicit Date(const struct tm *timep);
418 bool HasData() const { return Month || Day || Year; }
419 void Clear();
421 void ToTm(struct tm *timep) const;
422 std::string ToYYYYMMDD() const;
423 std::string ToBBString() const; // converts to Blackberry string
424 // format of DD/MM/YYYY
426 bool FromTm(const struct tm *timep);
427 bool FromBBString(const std::string &str);
428 bool FromYYYYMMDD(const std::string &str);
430 bool operator==(const Date &other) const
432 return Month == other.Month &&
433 Day == other.Day &&
434 Year == other.Year;
436 bool operator!=(const Date &other) const
438 return !operator==(other);
440 bool operator< (const Date &other) const
442 // YYYYMMDD as integer
443 unsigned int v1 = Year * 10000 + Month * 100 + Day;
444 unsigned int v2 = other.Year * 10000 + other.Month * 100 + other.Day;
445 return v1 < v2;
448 BXEXPORT std::ostream& operator<<(std::ostream &os, const Date &date);
450 class BXEXPORT CategoryList : public std::vector<std::string>
452 public:
453 /// Parses the given comma delimited category string into
454 /// this CategoryList object, appending each token to the vector.
455 /// Will clear vector beforehand.
456 void CategoryStr2List(const std::string &str);
458 /// Turns the current vectory into a comma delimited category
459 /// string suitable for use in Calendar, Task, and Memo
460 /// protocol values.
461 void CategoryList2Str(std::string &str) const;
463 using std::vector<std::string>::operator=;
465 BXEXPORT std::ostream& operator<<(std::ostream &os, const CategoryList &cl);
469 //////////////////////////////////////////////////////////////////////////////
470 // Generic Field Handles
472 /// \addtogroup GenericFieldHandles
473 /// Generic field handle classes, used to reference and work
474 /// with record members in a flexible, indirect way.
476 /// There are two ways to access device record data. The obvious
477 /// way is to instantiate a record class, such as Contact, and
478 /// access the public data members of that class to read and
479 /// write. If you always work with the same record class, this
480 /// works fine.
482 /// The other way is to have a list of pointers to members.
483 /// For example, you may wish to compare two records, without
484 /// actually caring what data is in each one. You can compare
485 /// at the record class level, with Contact one, two; and then
486 /// if( one == two ), but this will not tell you what field in
487 /// the record changed.
489 /// This last feature is what Generic Field Handles are meant to
490 /// fix. Each record class will contain a GetFieldHandles()
491 /// member function, which will return a list of type
492 /// FieldHandle<T>::ListT (currently a std::vector<>)
493 /// objects, for that specific record. For example, Contact
494 /// would fill the ListT with FieldHandle<Contact> objects.
495 /// Each FieldHandle<> object contains a C++ pointer-to-member,
496 /// which the FieldHandle refers to, as well as a FieldIdentity
497 /// object. The FieldIdentity object contains various identitying
498 /// information, such as the C++ variable name, an English
499 /// (or localized language) display name of the field, suitable
500 /// for user prompts, and other data more useful to the library.
502 /// The FieldHandle<> object has two member functions: Value()
503 /// and Member().
505 /// Value() will call a callback function with the _value_ of
506 /// the variable that FieldHandle<> points to. For example,
507 /// if the FieldHandle<> points to a std::string record member
508 /// variable, then Value() will pass that string value in as
509 /// an argument, along with a reference to the FieldIdentity
510 /// object. Value() requires a callback object and a record
511 /// object to perform this callback.
513 /// Member() will call a callback function/functor with the
514 /// pointer-to-member pointer and the FieldIdentity object.
515 /// This allows the programmer to create a functor with multiple
516 /// record objects, perhaps two objects to compare individual
517 /// fields, and use the pointer-to-member to access the field
518 /// data as needed.
520 /// For now, all data and callbacks are const, meaning that it
521 /// is not possible (without const_casting) to write to the
522 /// record via the pointers-to-members. This design decision
523 /// may need to be revisited someday, depending on its usefulness.
525 /// @{
528 // FieldIdentity
530 /// This class holds data that identifies a given field in a record.
531 /// This is fairly constant data, referenced by the FieldHandle class.
532 /// The information in here should be enough to show the user what kind
533 /// of field this is.
535 struct BXEXPORT FieldIdentity
537 // useful public data
538 const char *Name; // C++ name of field member variable in
539 // record class
540 std::string DisplayName; // localized display name of field
541 // in UTF8
542 // FIXME - should we leave localization
543 // to the application?
545 // subfield detection
546 bool HasSubfields; // true if this field has subfields
547 const char *ParentName; // name of field member variable that
548 // this field is a member of, or NULL
549 // if this field is a member of the
550 // record class.
551 // For example, Contact::PostalAddress
552 // would have HasSubfields == true,
553 // and ParentName == NULL, while all
554 // its subfield strings would have
555 // HasSubfields == false and
556 // ParentName == "WorkAddress" or
557 // "HomeAddress".
558 // The application could then decide
559 // whether to process only main fields,
560 // some of which have subfields,
561 // or only individual subfields.
563 // internal field data
564 int FieldTypeCode; // device type code for this field.
565 // if -1, then this is a conglomerate
566 // C++ field, such as
567 // Contact::PostalAddress, not a device
568 // field.
569 // If -1, then none of the following
570 // fields are valid.
571 const char *Ldif; // matching LDIF field name, or NULL
572 const char *ObjectClass; // matching LDIF object class, or NULL
573 bool IconvNeeded; // if true, the device's data needs to
574 // be passed through an IConverter
576 FieldIdentity(const char *name, const std::string &display_name,
577 int type_code = -1,
578 bool iconvneeded = false,
579 const char *ldif = 0, const char *oclass = 0,
580 bool has_sub = false, const char *parent = 0
582 : Name(name)
583 , DisplayName(display_name)
584 , HasSubfields(has_sub)
585 , ParentName(parent)
586 , FieldTypeCode(type_code)
587 , Ldif(ldif)
588 , ObjectClass(oclass)
589 , IconvNeeded(iconvneeded)
595 // EnumConstants
597 /// This is the base class for the hierarchy of classes to define
598 /// enum record members. This is the base class, which contains the
599 /// common code for creating and defining a list of enum constants for
600 /// a given enum field. The next derived class is EnumFieldBase<RecordT>,
601 /// which defines the virtual API for talking to a given enum field
602 /// in a given record. The next derived class is EnumField<RecordT, EnumT>,
603 /// which implements the pointer-to-member and virtual API for a given
604 /// enum type in a given record class.
606 /// For example, the Bookmark record class has the following enum field:
608 /// <pre>
609 /// enum BrowserIdentityType
610 /// {
611 /// IdentityAuto = 0,
612 /// IdentityBlackBerry,
613 /// IdentityFireFox,
614 /// IdentityInternetExplorer,
615 /// IdentityUnknown
616 /// };
617 /// BrowserIdentityType BrowserIdentity;
618 /// </pre>
620 /// The EnumConstants class will hold a vector of EnumConstant structs
621 /// defining each of the identity constants: Auto, BlackBerry, FireFox,
622 /// InternetExplorer, and Unknown.
624 /// The derived class EnumFieldBase<Bookmark> will define two additional
625 /// pure virtual API calls: GetValue(const Bookmark&) and
626 /// SetValue(Bookmark&, int).
628 /// Finally, the derived class EnumField<Bookmark,Bookmark::BrowserIdentityType>
629 /// will implement the virtual API, and contain a pointer-to-member to
630 /// the Bookmark::BrowserIdentity member field.
632 /// The FieldHandle<Bookmark> class will hold a pointer to
633 /// EnumFieldBase<Bookmark>, which can hold a pointer to a specific
634 /// EnumField<> object, one object for each of Bookmark's enum types,
635 /// of which there are currently 3.
637 class BXEXPORT EnumConstants
639 public:
640 /// This defines one of the enum constants being defined.
641 /// For example, for an enum declaration like:
642 /// enum Mine { A, B, C }; then this struct could contain
643 /// a definition for A, B, or C, but only one at at time.
644 /// All three would be defined by the EnumConstantList.
645 struct EnumConstant
647 const char *Name; //< C++ name of enum constant
648 std::string DisplayName; //< user-friendly name / meaning
649 int Value; //< constant enum value
651 EnumConstant(const char *name, const std::string &display,
652 int value)
653 : Name(name)
654 , DisplayName(display)
655 , Value(value)
660 typedef std::vector<EnumConstant> EnumConstantList;
662 private:
663 EnumConstantList m_constants;
665 public:
666 virtual ~EnumConstants() {}
668 /// Adds a constant definition to the list
669 void AddConstant(const char *name, const std::string &display, int val);
671 /// Returns a vector of EnumConstant objects, describing all enum
672 /// constants valid for this enum field.
673 const EnumConstantList& GetConstantList() const { return m_constants; }
675 /// Returns the EnumConstant for the given value.
676 /// Throws std::logic_error if not found.
677 const EnumConstant& GetConstant(int value) const;
679 /// Returns the constant name (C++ name) based on the given value.
680 /// Throws std::logic_error if not found.
681 const char* GetName(int value) const;
683 /// Returns the display name based on the given value.
684 /// Throws std::logic_error if not found.
685 const std::string& GetDisplayName(int value) const;
687 /// Returns true if the value matches one of the constants in the list.
688 bool IsConstantValid(int value) const;
692 // FieldValueHandlerBase
694 /// This is a pure virtual base class, defining the various types that
695 /// record fields can be. To be able to handle all the types of data
696 /// in all records, override these virtual functions to do with the
697 /// data as you wish.
699 /// All data from the records and fields will be passed in by value.
700 /// i.e. if field is string data, the overloaded std::string handler
701 /// will be called, and a refernce to the string will be passed in.
703 /// The advantage of using this virtual class is that less code will be
704 /// generated by templates. The disadvantage is that this is less flexible.
705 /// You will only get called for one field and record at a time.
706 /// So you can't do comparisons this way.
708 class BXEXPORT FieldValueHandlerBase
710 public:
711 virtual ~FieldValueHandlerBase() {}
713 /// For type std::string
714 virtual void operator()(const std::string &v,
715 const FieldIdentity &id) const = 0;
716 /// For type EmailAddressList
717 virtual void operator()(const EmailAddressList &v,
718 const FieldIdentity &id) const = 0;
719 /// For type Barry::TimeT
720 virtual void operator()(const Barry::TimeT &v,
721 const FieldIdentity &id) const = 0;
722 /// For type uint8_t
723 virtual void operator()(const uint8_t &v,
724 const FieldIdentity &id) const = 0;
725 /// For type uint16_t
726 virtual void operator()(const uint16_t &v,
727 const FieldIdentity &id) const = 0;
728 /// For type uint32_t
729 virtual void operator()(const uint32_t &v,
730 const FieldIdentity &id) const = 0;
731 /// For type uint64_t
732 virtual void operator()(const uint64_t &v,
733 const FieldIdentity &id) const = 0;
734 /// For type bool
735 virtual void operator()(const bool &v,
736 const FieldIdentity &id) const = 0;
737 /// For type int32_t
738 virtual void operator()(const int32_t &v,
739 const FieldIdentity &id) const = 0;
740 /// For type EmailList
741 virtual void operator()(const EmailList &v,
742 const FieldIdentity &id) const = 0;
743 /// For type Date
744 virtual void operator()(const Date &v,
745 const FieldIdentity &id) const = 0;
746 /// For type CategoryList
747 virtual void operator()(const CategoryList &v,
748 const FieldIdentity &id) const = 0;
749 /// For type PostalAddress
750 virtual void operator()(const PostalAddress &v,
751 const FieldIdentity &id) const = 0;
752 /// For type UnknownsType
753 virtual void operator()(const UnknownsType &v,
754 const FieldIdentity &id) const = 0;
758 /// EnumFieldBase<RecordT>
760 template <class RecordT>
761 class EnumFieldBase : public EnumConstants
763 public:
764 /// Return value of enum in rec
765 virtual int GetValue(const RecordT &rec) const = 0;
766 /// Set value of enum in rec
767 /// Throws std::logic_error if value is out of range
768 virtual void SetValue(RecordT &rec, int value) = 0;
772 /// EnumField<RecordT, EnumT>
774 template <class RecordT, class EnumT>
775 class EnumField : public EnumFieldBase<RecordT>
777 EnumT RecordT::* m_mp;
779 public:
780 explicit EnumField(EnumT RecordT::* mp)
781 : m_mp(mp)
785 virtual int GetValue(const RecordT &rec) const
787 return rec.*m_mp;
790 virtual void SetValue(RecordT &rec, int value)
792 if( !this->IsConstantValid(value) )
793 throw std::logic_error("Bad enum value in EnumField");
794 rec.*m_mp = (EnumT) value;
799 // FieldHandle<RecordT>
801 /// This is a template class that handles pointers to members of multiple
802 /// types of data and multiple types of records.
804 /// This class contains a union of all known data pointers in all records.
805 /// Therefore this class can hold a pointer to member of any record class.
807 /// To do something with the field that this FieldHandle<> class refers to,
808 /// call either Value() or Member() with appropriate callback functors.
809 /// Value will pass a reference to the field. You can use an object
810 /// derived from FieldValueHandlerBase here. Member() will pass a pointer
811 /// to member. Your functor will need to contain the record data in order
812 /// to access its data via the pointer to member.
814 /// The template functor callback that you pass into member must be
815 /// capable of this:
817 /// <pre>
818 /// template &lt;class RecordT&gt;
819 /// struct Callback
820 /// {
821 /// RecordT m_rec;
823 /// void operator()(typename FieldHandle<RecordT>::PostalPointer pp,
824 /// const FieldIdentity &id) const
825 /// {
826 /// PostalAddress pa = m_rec.*(pp.m_PostalAddress);
827 /// std::string val = pa.*(pp.m_PostalField);
828 /// ...
829 /// }
831 /// template &lt;class TypeT&gt;
832 /// void operator()(TypeT RecordT::* mp,
833 /// const FieldIdentity &id) const
834 /// {
835 /// TypeT val = m_rec.*mp;
836 /// ...
837 /// }
838 /// };
839 /// </pre>
841 /// You don't have to use a TypeT template, but if you don't, then you must
842 /// support all field types that the record class you're processing uses.
845 template <class RecordT>
846 class FieldHandle
848 public:
849 typedef FieldHandle<RecordT> Self;
850 typedef std::vector<Self> ListT;
852 // Need to use this in the union, so no constructor allowed
853 struct PostalPointer
855 PostalAddress RecordT::* m_PostalAddress;
856 std::string PostalAddress::* m_PostalField;
859 // So use a factory function
860 static PostalPointer MakePostalPointer(PostalAddress RecordT::* p1,
861 std::string PostalAddress::* p2)
863 PostalPointer pp;
864 pp.m_PostalAddress = p1;
865 pp.m_PostalField = p2;
866 return pp;
869 private:
870 union PointerUnion
872 std::string RecordT::* m_string; // index 0
873 EmailAddressList RecordT::* m_EmailAddressList; // 1
874 Barry::TimeT RecordT::* m_time; // 2
875 PostalPointer m_postal; // 3
876 uint8_t RecordT::* m_uint8; // 4
877 uint32_t RecordT::* m_uint32; // 5
878 EmailList RecordT::* m_EmailList; // 6
879 Date RecordT::* m_Date; // 7
880 CategoryList RecordT::* m_CategoryList; // 8
881 // GroupLinksType RecordT::* m_GroupLinksType; // 9
882 UnknownsType RecordT::* m_UnknownsType; // 10
883 bool RecordT::* m_bool; // 11
884 uint64_t RecordT::* m_uint64; // 12
885 uint16_t RecordT::* m_uint16; // 13
886 PostalAddress RecordT::* m_PostalAddress; // 14
887 // used by non-union m_enum below: // 15
888 int32_t RecordT::* m_int32; // 16
891 int m_type_index;
892 PointerUnion m_union;
893 EnumFieldBase<RecordT> *m_enum; // never freed, since this is a
894 // static list, existing to end of
895 // program lifetime
897 FieldIdentity m_id;
899 public:
900 // 0
901 FieldHandle(std::string RecordT::* mp, const FieldIdentity &id)
902 : m_type_index(0)
903 , m_enum(0)
904 , m_id(id)
906 m_union.m_string = mp;
909 // 1
910 FieldHandle(EmailAddressList RecordT::* mp, const FieldIdentity &id)
911 : m_type_index(1)
912 , m_enum(0)
913 , m_id(id)
915 m_union.m_EmailAddressList = mp;
918 // 2
919 FieldHandle(Barry::TimeT RecordT::* mp, const FieldIdentity &id)
920 : m_type_index(2)
921 , m_enum(0)
922 , m_id(id)
924 m_union.m_time = mp;
927 // 3
928 FieldHandle(const PostalPointer &pp, const FieldIdentity &id)
929 : m_type_index(3)
930 , m_enum(0)
931 , m_id(id)
933 m_union.m_postal = pp;
936 // 4
937 FieldHandle(uint8_t RecordT::* mp, const FieldIdentity &id)
938 : m_type_index(4)
939 , m_enum(0)
940 , m_id(id)
942 m_union.m_uint8 = mp;
945 // 5
946 FieldHandle(uint32_t RecordT::* mp, const FieldIdentity &id)
947 : m_type_index(5)
948 , m_enum(0)
949 , m_id(id)
951 m_union.m_uint32 = mp;
954 // 6
955 FieldHandle(EmailList RecordT::* mp, const FieldIdentity &id)
956 : m_type_index(6)
957 , m_enum(0)
958 , m_id(id)
960 m_union.m_EmailList = mp;
963 // 7
964 FieldHandle(Date RecordT::* mp, const FieldIdentity &id)
965 : m_type_index(7)
966 , m_enum(0)
967 , m_id(id)
969 m_union.m_Date = mp;
972 // 8
973 FieldHandle(CategoryList RecordT::* mp, const FieldIdentity &id)
974 : m_type_index(8)
975 , m_enum(0)
976 , m_id(id)
978 m_union.m_CategoryList = mp;
981 // 9
982 // FieldHandle(GroupLinksType RecordT::* mp, const FieldIdentity &id)
983 // : m_type_index(9)
984 // , m_enum(0)
985 // , m_id(id)
986 // {
987 // m_union.m_GroupLinksType = mp;
988 // }
990 // 10
991 FieldHandle(UnknownsType RecordT::* mp, const FieldIdentity &id)
992 : m_type_index(10)
993 , m_enum(0)
994 , m_id(id)
996 m_union.m_UnknownsType = mp;
999 // 11
1000 FieldHandle(bool RecordT::* mp, const FieldIdentity &id)
1001 : m_type_index(11)
1002 , m_enum(0)
1003 , m_id(id)
1005 m_union.m_bool = mp;
1008 // 12
1009 FieldHandle(uint64_t RecordT::* mp, const FieldIdentity &id)
1010 : m_type_index(12)
1011 , m_enum(0)
1012 , m_id(id)
1014 m_union.m_uint64 = mp;
1017 // 13
1018 FieldHandle(uint16_t RecordT::* mp, const FieldIdentity &id)
1019 : m_type_index(13)
1020 , m_enum(0)
1021 , m_id(id)
1023 m_union.m_uint16 = mp;
1026 // 14
1027 FieldHandle(PostalAddress RecordT::* mp, const FieldIdentity &id)
1028 : m_type_index(14)
1029 , m_enum(0)
1030 , m_id(id)
1032 m_union.m_PostalAddress = mp;
1035 // 15
1036 FieldHandle(EnumFieldBase<RecordT> *enum_, const FieldIdentity &id)
1037 : m_type_index(15)
1038 , m_enum(enum_)
1039 , m_id(id)
1043 // 16
1044 FieldHandle(int32_t RecordT::* mp, const FieldIdentity &id)
1045 : m_type_index(16)
1046 , m_enum(0)
1047 , m_id(id)
1049 m_union.m_int32 = mp;
1052 /// Extracts FieldIdentity object from FieldHandle<>
1053 const FieldIdentity& GetIdentity() const { return m_id; }
1055 /// Calls the matching virtual function in FieldValueHandlerBase,
1056 /// passing in the value of the field that this FieldHandle<>
1057 /// refers to, and a referenct to the FieldIdentity object.
1058 /// Caller must pass in a RecordT object as well.
1059 void Value(const FieldValueHandlerBase &vh, const RecordT &rec) const
1061 switch( m_type_index )
1063 case 0:
1064 vh(rec.*(m_union.m_string), m_id);
1065 break;
1066 case 1:
1067 vh(rec.*(m_union.m_EmailAddressList), m_id);
1068 break;
1069 case 2:
1070 vh(rec.*(m_union.m_time), m_id);
1071 break;
1072 case 3:
1073 vh(rec.*(m_union.m_postal.m_PostalAddress).*(m_union.m_postal.m_PostalField), m_id);
1074 break;
1075 case 4:
1076 vh(rec.*(m_union.m_uint8), m_id);
1077 break;
1078 case 5:
1079 vh(rec.*(m_union.m_uint32), m_id);
1080 break;
1081 case 6:
1082 vh(rec.*(m_union.m_EmailList), m_id);
1083 break;
1084 case 7:
1085 vh(rec.*(m_union.m_Date), m_id);
1086 break;
1087 case 8:
1088 vh(rec.*(m_union.m_CategoryList), m_id);
1089 break;
1090 // case 9:
1091 // vh(rec.*(m_union.m_GroupLinksType), m_id);
1092 // break;
1093 case 10:
1094 vh(rec.*(m_union.m_UnknownsType), m_id);
1095 break;
1096 case 11:
1097 vh(rec.*(m_union.m_bool), m_id);
1098 break;
1099 case 12:
1100 vh(rec.*(m_union.m_uint64), m_id);
1101 break;
1102 case 13:
1103 vh(rec.*(m_union.m_uint16), m_id);
1104 break;
1105 case 14:
1106 vh(rec.*(m_union.m_PostalAddress), m_id);
1107 break;
1108 case 15:
1109 vh(m_enum->GetValue(rec), m_id);
1110 break;
1111 case 16:
1112 vh(rec.*(m_union.m_int32), m_id);
1113 break;
1114 default:
1115 throw std::logic_error("Unknown field handle type index");
1119 /// Calls the callback functor with two arguments: the pointer to
1120 /// member that this FieldHandle<> contains, and the FieldIdentity
1121 /// object. It is assumed that the functor will either contain
1122 /// or know where to find one or more records of type RecordT.
1123 template <class CallbackT>
1124 void Member(const CallbackT &func) const
1126 switch( m_type_index )
1128 case 0:
1129 func(m_union.m_string, m_id);
1130 break;
1131 case 1:
1132 func(m_union.m_EmailAddressList, m_id);
1133 break;
1134 case 2:
1135 func(m_union.m_time, m_id);
1136 break;
1137 case 3:
1138 func(m_union.m_postal, m_id);
1139 break;
1140 case 4:
1141 func(m_union.m_uint8, m_id);
1142 break;
1143 case 5:
1144 func(m_union.m_uint32, m_id);
1145 break;
1146 case 6:
1147 func(m_union.m_EmailList, m_id);
1148 break;
1149 case 7:
1150 func(m_union.m_Date, m_id);
1151 break;
1152 case 8:
1153 func(m_union.m_CategoryList, m_id);
1154 break;
1155 // case 9:
1156 // func(m_union.m_GroupLinksType, m_id);
1157 // break;
1158 case 10:
1159 func(m_union.m_UnknownsType, m_id);
1160 break;
1161 case 11:
1162 func(m_union.m_bool, m_id);
1163 break;
1164 case 12:
1165 func(m_union.m_uint64, m_id);
1166 break;
1167 case 13:
1168 func(m_union.m_uint16, m_id);
1169 break;
1170 case 14:
1171 func(m_union.m_PostalAddress, m_id);
1172 break;
1173 case 15:
1174 func(m_enum, m_id);
1175 break;
1176 case 16:
1177 func(m_union.m_int32, m_id);
1178 break;
1179 default:
1180 throw std::logic_error("Unknown field handle type index");
1185 /// Factory function to create a FieldHandle<> object.
1186 template <class RecordT, class TypeT>
1187 FieldHandle<RecordT> MakeFieldHandle(TypeT RecordT::* tp,
1188 const FieldIdentity &id)
1190 return FieldHandle<RecordT>(tp, id);
1193 /// Calls FieldHandle<>::Member() for each defined field for a given record
1194 /// type. Takes a FieldHandle<>::ListT containing FieldHandle<> objects,
1195 /// and calls Member(func) for each one.
1196 template <class HandlesT, class CallbackT>
1197 void ForEachField(const HandlesT &handles, const CallbackT &func)
1199 typename HandlesT::const_iterator
1200 b = handles.begin(),
1201 e = handles.end();
1202 for( ; b != e; ++b ) {
1203 b->Member(func);
1207 /// Calls FieldHandle<>::Value() for each defined field for a given record.
1208 /// Takes a RecordT object and calls Value(vh, rec) for each FieldHandle<>
1209 /// object in the record's FieldHandles set.
1210 template <class RecordT>
1211 void ForEachFieldValue(const RecordT &rec, const FieldValueHandlerBase &vh)
1213 typename FieldHandle<RecordT>::ListT::const_iterator
1214 b = RecordT::GetFieldHandles().begin(),
1215 e = RecordT::GetFieldHandles().end();
1216 for( ; b != e; ++b ) {
1217 b->Value(vh, rec);
1222 // FieldHandle setup macros
1224 // #undef and #define the following macros to override these macros for you:
1226 // CONTAINER_OBJECT_NAME - the new FieldHandles will be .push_back()'d into
1227 // this container
1228 // RECORD_CLASS_NAME - the name of the record class you are defining,
1229 // i.e. Barry::Contact, or Barry::Calendar
1232 // plain field, no connection to device field
1233 #define FHP(name, display) \
1234 CONTAINER_OBJECT_NAME.push_back( \
1235 FieldHandle<RECORD_CLASS_NAME>(&RECORD_CLASS_NAME::name, \
1236 FieldIdentity(#name, display)))
1237 // record field with direct connection to device field, no LDIF data
1238 #define FHD(name, display, type_code, iconv) \
1239 CONTAINER_OBJECT_NAME.push_back( \
1240 FieldHandle<RECORD_CLASS_NAME>(&RECORD_CLASS_NAME::name, \
1241 FieldIdentity(#name, display, type_code, iconv, \
1242 0, 0)))
1243 // record field with direct connection to device field, with LDIF data
1244 #define FHL(name, display, type_code, iconv, ldif, oclass) \
1245 CONTAINER_OBJECT_NAME.push_back( \
1246 FieldHandle<RECORD_CLASS_NAME>(&RECORD_CLASS_NAME::name, \
1247 FieldIdentity(#name, display, type_code, iconv, \
1248 ldif, oclass)))
1249 // a subfield of a conglomerate field, with direct connection to device field,
1250 // with LDIF data
1251 #define FHS(name, subname, display, type, iconv, ldif, oclass) \
1252 CONTAINER_OBJECT_NAME.push_back( \
1253 FieldHandle<RECORD_CLASS_NAME>( \
1254 FieldHandle<RECORD_CLASS_NAME>::MakePostalPointer( \
1255 &RECORD_CLASS_NAME::name, \
1256 &PostalAddress::subname), \
1257 FieldIdentity(#name "::" #subname, display, \
1258 type, iconv, ldif, oclass, \
1259 false, #name)))
1260 // record conglomerate field, which has subfields
1261 #define FHC(name, display) \
1262 CONTAINER_OBJECT_NAME.push_back( \
1263 FieldHandle<RECORD_CLASS_NAME>(&RECORD_CLASS_NAME::name, \
1264 FieldIdentity(#name, display, \
1265 -1, false, 0, 0, true, 0)))
1266 // create a new EnumField<> and add it to the list... use the new_var_name
1267 // to add constants with FHE_CONST below
1268 #define FHE(new_var_name, record_field_type, record_field_name, display) \
1269 EnumField<RECORD_CLASS_NAME, RECORD_CLASS_NAME::record_field_type> \
1270 *new_var_name = new \
1271 EnumField<RECORD_CLASS_NAME, RECORD_CLASS_NAME::record_field_type> \
1272 (&RECORD_CLASS_NAME::record_field_name); \
1273 CONTAINER_OBJECT_NAME.push_back( \
1274 FieldHandle<RECORD_CLASS_NAME>(new_var_name, \
1275 FieldIdentity(#record_field_name, display)))
1276 // same as FHE, but for when RECORD_CLASS_NAME is a template argument
1277 #define FHET(new_var_name, record_field_type, record_field_name, display) \
1278 EnumField<RECORD_CLASS_NAME, typename RECORD_CLASS_NAME::record_field_type> \
1279 *new_var_name = new \
1280 EnumField<RECORD_CLASS_NAME, typename RECORD_CLASS_NAME::record_field_type> \
1281 (&RECORD_CLASS_NAME::record_field_name); \
1282 CONTAINER_OBJECT_NAME.push_back( \
1283 FieldHandle<RECORD_CLASS_NAME>(new_var_name, \
1284 FieldIdentity(#record_field_name, display)))
1285 // add constant to enum created above
1286 #define FHE_CONST(var, name, display) \
1287 var->AddConstant(#name, display, RECORD_CLASS_NAME::name)
1289 /// @}
1291 } // namespace Barry
1294 /// \addtogroup RecordParserClasses
1295 /// Parser and data storage classes. These classes take a
1296 /// Database Database record and convert them into C++ objects.
1297 /// Each of these classes are safe to be used in standard
1298 /// containers, and are meant to be used in conjunction with the
1299 /// RecordParser<> template when calling Controller::LoadDatabase().
1300 /// @{
1301 /// @}
1303 #ifndef __BARRY_LIBRARY_BUILD__
1304 // Include all parser classes, to make it easy for the application to use.
1305 #include "r_calendar.h"
1306 #include "r_calllog.h"
1307 #include "r_bookmark.h"
1308 #include "r_contact.h"
1309 #include "r_cstore.h"
1310 #include "r_memo.h"
1311 #include "r_message.h"
1312 #include "r_servicebook.h"
1313 #include "r_task.h"
1314 #include "r_pin_message.h"
1315 #include "r_saved_message.h"
1316 #include "r_sms.h"
1317 #include "r_folder.h"
1318 #include "r_timezone.h"
1319 #include "r_hhagent.h"
1320 #endif
1322 #endif