parser.h

Go to the documentation of this file.
00001 ///
00002 /// \file       parser.h
00003 ///             Virtual parser wrapper
00004 ///
00005 
00006 /*
00007     Copyright (C) 2005-2011, Net Direct Inc. (http://www.netdirect.ca/)
00008 
00009     This program is free software; you can redistribute it and/or modify
00010     it under the terms of the GNU General Public License as published by
00011     the Free Software Foundation; either version 2 of the License, or
00012     (at your option) any later version.
00013 
00014     This program is distributed in the hope that it will be useful,
00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00017 
00018     See the GNU General Public License in the COPYING file at the
00019     root directory of this project for more details.
00020 */
00021 
00022 #ifndef __BARRY_PARSER_H__
00023 #define __BARRY_PARSER_H__
00024 
00025 #include "dll.h"
00026 #include "data.h"
00027 #include "protocol.h"
00028 #include <stdint.h>             // for uint32_t
00029 #include <iosfwd>
00030 #include <map>
00031 
00032 // forward declarations
00033 namespace Barry {
00034         class IConverter;
00035         class Contact;
00036         class Message;
00037         class Calendar;
00038         class CalendarAll;
00039         class CallLog;
00040         class Bookmark;
00041         class ServiceBook;
00042         class Memo;
00043         class Task;
00044         class PINMessage;
00045         class SavedMessage;
00046         class Sms;
00047         class Folder;
00048         class Timezone;
00049         class ContentStore;
00050 }
00051 
00052 //
00053 // This macro can be used to automatically generate code for all known
00054 // record types.  Just #undef HANDLE_PARSER, then #define it to whatever
00055 // you need, then use ALL_KNOWN_PARSER_TYPES.  See parser.cc for
00056 // various examples.
00057 //
00058 // These are sorted so their GetDBName()'s will display in alphabetical order.
00059 //
00060 #define ALL_KNOWN_PARSER_TYPES \
00061         HANDLE_PARSER(Contact) \
00062         HANDLE_PARSER(Bookmark) \
00063         HANDLE_PARSER(Calendar) \
00064         HANDLE_PARSER(CalendarAll) \
00065         HANDLE_PARSER(ContentStore) \
00066         HANDLE_PARSER(Folder) \
00067         HANDLE_PARSER(Memo) \
00068         HANDLE_PARSER(Message) \
00069         HANDLE_PARSER(CallLog) \
00070         HANDLE_PARSER(PINMessage) \
00071         HANDLE_PARSER(SavedMessage) \
00072         HANDLE_PARSER(ServiceBook) \
00073         HANDLE_PARSER(Sms) \
00074         HANDLE_PARSER(Task) \
00075         HANDLE_PARSER(Timezone)
00076 
00077 namespace Barry {
00078 
00079 //
00080 // Parser class
00081 //
00082 /// Base class for the parser hierarchy.
00083 ///
00084 /// This class provides the interface that the Controller class uses
00085 /// to pass raw data it reads from the device.  The Controller, along
00086 /// with the Packet class, calls each of the virtual functions below
00087 /// in the same order.
00088 ///
00089 /// This class is kept as a pure abstract class, in order to make sure
00090 /// that the compiler will catch any API changes, for code derived
00091 /// from it.
00092 ///
00093 class BXEXPORT Parser
00094 {
00095 public:
00096         Parser() {}
00097         virtual ~Parser() {}
00098 
00099         /// Called to parse sub fields in the raw data packet.
00100         virtual void ParseRecord(const DBData &data, const IConverter *ic) = 0;
00101 };
00102 
00103 
00104 //
00105 // NullParser class
00106 //
00107 /// If in debug mode, this class can be used as a null parser.
00108 /// Call Init() and the protocol will be dumped to stdout and
00109 /// no parsing will be done.
00110 ///
00111 /// Do NOT derive your own personal parser classes from this,
00112 /// unless you are perfectly confident that you will catch
00113 /// future API changes on the devel tree without the compiler's
00114 /// help.
00115 ///
00116 class BXEXPORT NullParser : public Parser
00117 {
00118 public:
00119         NullParser() {}
00120         virtual ~NullParser() {}
00121 
00122         virtual void ParseRecord(const DBData &data, const IConverter *ic) {}
00123 };
00124 
00125 //
00126 // HexDumpParser
00127 //
00128 /// Dumps raw hex of the given DBData to the given stream.
00129 ///
00130 /// Do NOT derive your own personal parser classes from this,
00131 /// unless you are perfectly confident that you will catch
00132 /// future API changes on the devel tree without the compiler's
00133 /// help.
00134 ///
00135 class BXEXPORT HexDumpParser : public Parser
00136 {
00137         std::ostream &m_os;
00138         std::string m_last_dbname;
00139 
00140 public:
00141         explicit HexDumpParser(std::ostream &os);
00142 
00143         virtual void ParseRecord(const Barry::DBData &data,
00144                                  const IConverter *ic);
00145 };
00146 
00147 //
00148 // RecordParserBase
00149 //
00150 /// Abstract base class for the following RecordParser template, that exposes
00151 /// some information on the specifics that the record parser can handle.
00152 /// Specifically, it exposes the database name it is able to parse
00153 ///
00154 class BXEXPORT RecordParserBase : public Parser
00155 {
00156 public:
00157         // These functions are always valid, regardless of the
00158         // state of the parser.
00159         virtual const char * GetDBName() const = 0;
00160         virtual uint8_t GetDefaultRecType() const = 0;
00161 
00162         // These functions depend on the parser having just parsed
00163         // a record successfully.
00164         virtual bool IsRecordValid() const = 0;
00165         virtual uint8_t GetRecType() const = 0;
00166         virtual uint32_t GetUniqueId() const = 0;
00167         virtual void Dump(std::ostream &os) const = 0;
00168 };
00169 
00170 
00171 //
00172 // Note: Store classes take parsed Record objects as a functor.
00173 //       Parser classes deal with raw data, while Store classes deal with
00174 //       parsed Record objects.
00175 //
00176 
00177 //
00178 // NullStore
00179 //
00180 /// A Storage class for RecordParser<> that does nothing, for the cases
00181 /// where you only want to dump parsed record data to a stream.
00182 ///
00183 template <class RecordT>
00184 class NullStore
00185 {
00186 public:
00187         void operator() (const RecordT &r)
00188         {
00189         }
00190 };
00191 
00192 //
00193 // DumpStore
00194 //
00195 /// A Storage class for RecordParser<> that dumps the parsed record data
00196 /// to the given stream.
00197 ///
00198 template <class RecordT>
00199 class DumpStore
00200 {
00201         std::ostream &m_os;
00202 
00203 public:
00204         explicit DumpStore(std::ostream &os)
00205                 : m_os(os)
00206         {
00207         }
00208 
00209         void operator() (const RecordT &r)
00210         {
00211                 r.Dump(m_os);
00212         }
00213 };
00214 
00215 //
00216 // RecordParser template class
00217 //
00218 /// Template class for easy creation of specific parser objects.  This template
00219 /// takes the following template arguments:
00220 ///
00221 ///     - RecordT: One of the record parser classes in record.h
00222 ///     - StorageT: A custom storage functor class.  An object of this type
00223 ///             will be called as a function with parsed Record as an
00224 ///             argument.  This happens on the fly as the data is retrieved
00225 ///             from the device over USB, so it should not block forever.
00226 ///
00227 /// Example LoadDatabase() call:
00228 ///
00229 /// <pre>
00230 /// struct StoreContact
00231 /// {
00232 ///     std::vector<Contact> &amp;array;
00233 ///     StoreContact(std::vector<Contact> &amp;a) : array(a) {}
00234 ///     void operator() (const Contact &amp;c)
00235 ///     {
00236 ///         array.push_back(c);
00237 ///     }
00238 /// };
00239 ///
00240 /// Controller con(probeResult);
00241 /// con.OpenMode(Controller::Desktop);
00242 /// std::vector<Contact> contactList;
00243 /// StoreContact storage(contactList);
00244 /// RecordParser<Contact, StoreContact> parser(storage);
00245 /// con.LoadDatabase(con.GetDBID("Address Book"), parser);
00246 /// </pre>
00247 ///
00248 template <class RecordT, class StorageT>
00249 class RecordParser : public RecordParserBase
00250 {
00251         StorageT *m_store;
00252         bool m_owned;
00253         RecordT m_rec;
00254         bool m_record_valid;
00255 
00256 public:
00257         /// Constructor that references an externally managed storage object.
00258         RecordParser(StorageT &storage)
00259                 : m_store(&storage)
00260                 , m_owned(false)
00261                 , m_record_valid(false)
00262         {
00263         }
00264 
00265         /// Constructor that references a locally managed storage object.
00266         /// The pointer passed in will be stored, and freed when this class
00267         /// is destroyed.  It is safe to call this constructor with
00268         /// a 'new'ly created storage object.
00269         RecordParser(StorageT *storage = 0)
00270                 : m_store(storage)
00271                 , m_owned(true)
00272                 , m_record_valid(false)
00273         {
00274         }
00275 
00276         ~RecordParser()
00277         {
00278                 if( this->m_owned )
00279                         delete m_store;
00280         }
00281 
00282         virtual StorageT* GetStore()
00283         {
00284                 return m_store;
00285         }
00286 
00287         virtual const StorageT* GetStore() const
00288         {
00289                 return m_store;
00290         }
00291 
00292         virtual void ParseRecord(const DBData &data, const IConverter *ic)
00293         {
00294                 m_rec = RecordT();
00295                 m_record_valid = false;
00296 
00297                 m_rec.SetIds(data.GetRecType(), data.GetUniqueId());
00298                 size_t offset = data.GetOffset();
00299                 m_rec.ParseHeader(data.GetData(), offset);
00300                 m_rec.ParseFields(data.GetData(), offset, ic);
00301                 m_record_valid = true;
00302 
00303                 if( m_store )
00304                         (*m_store)(m_rec);
00305         }
00306 
00307         //
00308         // RecordParserBase overrides
00309         //
00310 
00311         // These functions are always valid, regardless of the
00312         // state of the parser.
00313         virtual const char * GetDBName() const
00314         {
00315                 return RecordT::GetDBName();
00316         }
00317 
00318         virtual uint8_t GetDefaultRecType() const
00319         {
00320                 return RecordT::GetDefaultRecType();
00321         }
00322 
00323         // These functions depend on the parser having just parsed
00324         // a record successfully.
00325         virtual bool IsRecordValid() const
00326         {
00327                 return m_record_valid;
00328         }
00329 
00330         virtual uint8_t GetRecType() const
00331         {
00332                 return m_rec.GetRecType();
00333         }
00334 
00335         virtual uint32_t GetUniqueId() const
00336         {
00337                 return m_rec.GetUniqueId();
00338         }
00339 
00340         virtual void Dump(std::ostream &os) const
00341         {
00342                 m_rec.Dump(os);
00343         }
00344 };
00345 
00346 //
00347 // AllRecordStore
00348 //
00349 /// Base class with overloaded functor behaviour for all available
00350 /// record classes.  To be used with AllRecordParser.
00351 ///
00352 class BXEXPORT AllRecordStore
00353 {
00354 public:
00355         AllRecordStore() {}
00356         virtual ~AllRecordStore() {}
00357 
00358 #undef HANDLE_PARSER
00359 #define HANDLE_PARSER(tname) \
00360         virtual void operator() (const Barry::tname &) = 0;
00361 
00362         ALL_KNOWN_PARSER_TYPES
00363 };
00364 
00365 //
00366 // MultiRecordParser
00367 //
00368 /// Container parser class that accepts multiple Parser objects
00369 /// (often RecordParser<> objects but they don't have to be) and
00370 /// automatically routes incoming records to the appropriate parser.
00371 /// Note that this container owns *all* Parser objects, and will
00372 /// free them upon destruction.
00373 ///
00374 /// Incoming records that have no matching parser are passed to the
00375 /// default parser object, if one exists, otherwise they are dropped
00376 /// silently.  The default parser object is also owned by the container,
00377 /// and will be freed on destruction.
00378 ///
00379 /// Do NOT derive your own personal parser classes from this,
00380 /// unless you are perfectly confident that you will catch
00381 /// future API changes on the devel tree without the compiler's
00382 /// help.
00383 ///
00384 class BXEXPORT MultiRecordParser : public Parser
00385 {
00386         typedef std::map<std::string, Parser*>                  map_type;
00387 
00388         Parser *m_default;
00389         map_type m_parsers;
00390 
00391 public:
00392         // takes ownership of default_parser!
00393         explicit MultiRecordParser(Parser *default_parser = 0);
00394         ~MultiRecordParser();
00395 
00396         /// Adds given parser to list and takes ownership of it
00397         void Add(const std::string &dbname, Parser *parser);
00398 
00399         /// Adds given parser to list and takes ownership of it
00400         void Add(RecordParserBase *parser);
00401 
00402         /// Creates a RecordParser<> object using the given record
00403         /// type and AllRecordStore.  Does NOT take ownership of the
00404         /// store object, since it can be used multiple times for
00405         /// multiple records.
00406         template <class RecordT>
00407         void Add(AllRecordStore &store)
00408         {
00409                 Add( RecordT::GetDBName(),
00410                         new RecordParser<RecordT, AllRecordStore>(store) );
00411         }
00412 
00413         /// Two helper template functions that create the RecordParser<>
00414         /// automatically based on the function call.  Both pointer and
00415         /// reference versions.
00416         template <class RecordT, class StorageT>
00417         void Add(StorageT *store)
00418         {
00419                 Add( RecordT::GetDBName(),
00420                         new RecordParser<RecordT, StorageT>(store) );
00421         }
00422 
00423         template <class RecordT, class StorageT>
00424         void Add(StorageT &store)
00425         {
00426                 Add( RecordT::GetDBName(),
00427                         new RecordParser<RecordT, StorageT>(store) );
00428         }
00429 
00430         /// Creates a RecordParser<> object for the given database name,
00431         /// using DumpStore<> with the given stream for the output,
00432         /// and adds it to list.
00433         /// Returns false if there is no known Record class for dbname.
00434         bool Add(const std::string &dbname, std::ostream &os);
00435 
00436         /// Creates a RecordParser<> object for the given database name,
00437         /// using the given store object.
00438         /// Returns false if there is no known Record class for dbname.
00439         bool Add(const std::string &dbname, AllRecordStore &store);
00440 
00441         // Parser overrides
00442         virtual void ParseRecord(const DBData &data, const IConverter *ic);
00443 };
00444 
00445 //
00446 // AllRecordDumpStore
00447 //
00448 /// Derived from AllRecordStore, which just calls each record's
00449 /// Dump() member with the given stream.
00450 ///
00451 class BXEXPORT AllRecordDumpStore : public AllRecordStore
00452 {
00453 protected:
00454         std::ostream &m_os;
00455 
00456 public:
00457         explicit AllRecordDumpStore(std::ostream &os)
00458                 : m_os(os)
00459         {
00460         }
00461 
00462 #undef HANDLE_PARSER
00463 #define HANDLE_PARSER(tname) \
00464         virtual void operator() (const Barry::tname &);
00465 
00466         ALL_KNOWN_PARSER_TYPES
00467 };
00468 
00469 //
00470 // AllRecordParser
00471 //
00472 /// Convenience parser that creates a MultiRecordParser with all known
00473 /// record parsers added.  If an AllRecordStore pointer is passed in,
00474 /// this class takes ownership of it, and uses it as the store object
00475 /// for all the RecordParser<> objects it creates.  If not, then
00476 /// a custom DumpStore<> object is created with the given stream
00477 /// for each RecordParser<> added.
00478 ///
00479 /// The default parser object behaves just like MultiRecordParser
00480 ///
00481 /// This class takes ownership of all pointers passed in.
00482 ///
00483 class BXEXPORT AllRecordParser : public MultiRecordParser
00484 {
00485         AllRecordStore *m_store;
00486 
00487 public:
00488         // takes ownership of default_parser and store!
00489         explicit AllRecordParser(std::ostream &os,
00490                 Parser *default_parser = 0,
00491                 AllRecordStore *store = 0);
00492         ~AllRecordParser();
00493 };
00494 
00495 //
00496 // TeeParser
00497 //
00498 /// Sends incoming DBData objects to all the parsers in its list.
00499 /// This parser container does NOT own the parsers added.
00500 ///
00501 class BXEXPORT TeeParser : public Parser
00502 {
00503         typedef std::vector<Parser*>                    parser_list_type;
00504 
00505         parser_list_type m_external_parsers, m_owned_parsers;
00506 
00507 public:
00508         TeeParser();
00509         ~TeeParser();
00510 
00511         /// Adds parser to internal list, and takes ownership of the
00512         /// pointer.
00513         void Add(Parser *p);
00514 
00515         /// Adds parser to internal list.  Does NOT own the parser reference.
00516         void Add(Parser &p);
00517 
00518         void ParseRecord(const DBData &data, const IConverter *ic);
00519 };
00520 
00521 } // namespace Barry
00522 
00523 #endif
00524