m_desktop.cc

Go to the documentation of this file.
00001 ///
00002 /// \file       m_desktop.cc
00003 ///             Mode class for the Desktop mode
00004 ///
00005 
00006 /*
00007     Copyright (C) 2005-2012, 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 #include "m_desktop.h"
00023 #include "data.h"
00024 #include "protocol.h"
00025 #include "protostructs.h"
00026 #include "packet.h"
00027 #include "endian.h"
00028 #include "error.h"
00029 #include "usbwrap.h"
00030 #include "controller.h"
00031 #include "parser.h"
00032 #include <stdexcept>
00033 #include <sstream>
00034 
00035 #include "debug.h"
00036 
00037 namespace Barry { namespace Mode {
00038 
00039 
00040 ///////////////////////////////////////////////////////////////////////////////
00041 // Desktop Mode class
00042 
00043 Desktop::Desktop(Controller &con)
00044         : Mode(con, Controller::Desktop)
00045         , m_ic(0)
00046 {
00047 }
00048 
00049 Desktop::Desktop(Controller &con, const IConverter &ic)
00050         : Mode(con, Controller::Desktop)
00051         , m_ic(&ic)
00052 {
00053 }
00054 
00055 Desktop::~Desktop()
00056 {
00057 }
00058 
00059 ///////////////////////////////////////////////////////////////////////////////
00060 // protected members
00061 
00062 void Desktop::LoadCommandTable()
00063 {
00064         char rawCommand[] = { 6, 0, 0x0a, 0, 0x40, 0, 0, 1, 0, 0 };
00065 
00066         Data command(rawCommand, sizeof(rawCommand));
00067 
00068         try {
00069                 m_socket->Packet(command, m_response);
00070 
00071                 MAKE_PACKET(rpack, m_response);
00072                 while( rpack->command != SB_COMMAND_DB_DONE ) {
00073                         m_socket->NextRecord(m_response);
00074 
00075                         rpack = (const Protocol::Packet *) m_response.GetData();
00076                         if( rpack->command == SB_COMMAND_DB_DATA && btohs(rpack->size) > 10 ) {
00077                                 // second packet is generally large, and contains
00078                                 // the command table
00079                                 m_commandTable.Clear();
00080                                 m_commandTable.Parse(m_response, 6);
00081                         }
00082                 }
00083 
00084                 ddout(m_commandTable);
00085 
00086         }
00087         catch( Usb::Error & ) {
00088                 eout("Desktop: error getting command table");
00089                 eeout(command, m_response);
00090                 throw;
00091         }
00092 }
00093 
00094 void Desktop::LoadDBDB()
00095 {
00096         DBPacket packet(*this, m_command, m_response);
00097         packet.GetDBDB();
00098 
00099         m_socket->Packet(packet);
00100 
00101         while( packet.Command() != SB_COMMAND_DB_DONE ) {
00102                 if( packet.Command() == SB_COMMAND_DB_DATA ) {
00103                         m_dbdb.Clear();
00104                         m_dbdb.Parse(m_response);
00105                 }
00106 
00107                 // advance!
00108                 m_socket->NextRecord(m_response);
00109         }
00110 }
00111 
00112 void Desktop::OnOpen()
00113 {
00114         // get command table and database database
00115         LoadCommandTable();
00116         LoadDBDB();
00117 }
00118 
00119 ///////////////////////////////////////////////////////////////////////////////
00120 // public API
00121 
00122 //
00123 // GetDBID
00124 //
00125 /// Get numeric database ID by name.
00126 ///
00127 /// \param[in]  name            Name of database, which matches one of the
00128 ///                             names listed in GetDBDB()
00129 ///
00130 /// \exception  Barry::Error
00131 ///             Thrown if name not found.
00132 ///
00133 unsigned int Desktop::GetDBID(const std::string &name) const
00134 {
00135         unsigned int ID = 0;
00136         // FIXME - this needs a better error handler...
00137         if( !m_dbdb.GetDBNumber(name, ID) ) {
00138                 throw Error("Desktop: database name not found: " + name);
00139         }
00140         return ID;
00141 }
00142 
00143 //
00144 // GetDBCommand
00145 //
00146 /// Get database command from command table.  Must call Open()
00147 /// before this.
00148 ///
00149 unsigned int Desktop::GetDBCommand(CommandType ct)
00150 {
00151         unsigned int cmd = 0;
00152         const char *cmdName = "Unknown";
00153 
00154         switch( ct )
00155         {
00156         case DatabaseAccess:
00157                 cmdName = "Database Access";
00158                 cmd = m_commandTable.GetCommand(cmdName);
00159                 break;
00160         default:
00161                 throw std::logic_error("Desktop: unknown command type");
00162         }
00163 
00164         if( cmd == 0 ) {
00165                 std::ostringstream oss;
00166                 oss << "Desktop: unable to get command code: " << cmdName;
00167                 throw Error(oss.str());
00168         }
00169 
00170         return cmd;
00171 }
00172 
00173 void Desktop::SetIConverter(const IConverter &ic)
00174 {
00175         m_ic = &ic;
00176 }
00177 
00178 //
00179 // GetRecordStateTable
00180 //
00181 /// Retrieve the record state table from the handheld device, using the given
00182 /// database ID.  Results will be stored in result, which will be cleared
00183 /// before adding.
00184 ///
00185 void Desktop::GetRecordStateTable(unsigned int dbId, RecordStateTable &result)
00186 {
00187         dout("Database ID: " << dbId);
00188 
00189         // start fresh
00190         result.Clear();
00191 
00192         DBPacket packet(*this, m_command, m_response);
00193         packet.GetRecordStateTable(dbId);
00194 
00195         m_socket->Packet(packet);
00196         result.Parse(m_response);
00197 
00198         // flush the command sequence
00199         while( packet.Command() != SB_COMMAND_DB_DONE )
00200                 m_socket->NextRecord(m_response);
00201 }
00202 
00203 //
00204 // AddRecord
00205 //
00206 /// Adds a record to the specified database.  RecordId is
00207 /// retrieved from build, and duplicate IDs are allowed by the device
00208 /// (i.e. you can have two records with the same ID)
00209 /// but *not* recommended!
00210 //
00211 void Desktop::AddRecord(unsigned int dbId, Builder &build)
00212 {
00213         dout("Database ID: " << dbId);
00214 
00215         DBPacket packet(*this, m_command, m_response);
00216 
00217         if( packet.AddRecord(dbId, build, m_ic) ) {
00218 
00219                 std::ostringstream oss;
00220 
00221                 m_socket->Packet(packet);
00222 
00223                 // successful packet transfer, so check the network return code
00224                 if( packet.Command() != SB_COMMAND_DB_DONE ) {
00225                         oss << "Desktop: device responded with unexpected packet command code: "
00226                             << "0x" << std::hex << packet.Command();
00227                         throw Error(oss.str());
00228                 }
00229 
00230                 if( packet.ReturnCode() != 0 ) {
00231                         oss << "Desktop: device responded with error code (command: "
00232                             << packet.Command() << ", code: "
00233                             << packet.ReturnCode() << ")";
00234                         throw ReturnCodeError(oss.str(), packet.Command(), packet.ReturnCode());
00235                 }
00236         }
00237 }
00238 
00239 //
00240 // GetRecord
00241 //
00242 /// Retrieves a specific record from the specified database.
00243 /// The stateTableIndex comes from the GetRecordStateTable()
00244 /// function.  GetRecord() does not clear the dirty flag.
00245 ///
00246 void Desktop::GetRecord(unsigned int dbId,
00247                            unsigned int stateTableIndex,
00248                            Parser &parser)
00249 {
00250         dout("Database ID: " << dbId);
00251 
00252         std::string dbName;
00253         m_dbdb.GetDBName(dbId, dbName);
00254 
00255         DBPacket packet(*this, m_command, m_response);
00256         packet.GetRecordByIndex(dbId, stateTableIndex);
00257 
00258         m_socket->Packet(packet);
00259 
00260         // perform copious packet checks
00261         if( m_response.GetSize() < SB_PACKET_RESPONSE_HEADER_SIZE ) {
00262                 eeout(m_command, m_response);
00263 
00264                 std::ostringstream oss;
00265                 oss << "Desktop: invalid response packet size of "
00266                     << std::dec << m_response.GetSize();
00267                 eout(oss.str());
00268                 throw Error(oss.str());
00269         }
00270         if( packet.Command() != SB_COMMAND_DB_DATA ) {
00271                 eeout(m_command, m_response);
00272 
00273                 std::ostringstream oss;
00274                 oss << "Desktop: unexpected command of 0x"
00275                     << std::setbase(16) << packet.Command()
00276                     << " instead of expected 0x"
00277                     << std::setbase(16) << (unsigned int)SB_COMMAND_DB_DATA;
00278                 eout(oss.str());
00279                 throw Error(oss.str());
00280         }
00281 
00282         // grab that data
00283         packet.Parse(parser, dbName, m_ic);
00284 
00285         // flush the command sequence
00286         while( packet.Command() != SB_COMMAND_DB_DONE )
00287                 m_socket->NextRecord(m_response);
00288 }
00289 
00290 //
00291 // SetRecord
00292 //
00293 /// Overwrites a specific record in the device as identified by the
00294 /// stateTableIndex.
00295 ///
00296 void Desktop::SetRecord(unsigned int dbId, unsigned int stateTableIndex,
00297                            Builder &build)
00298 {
00299         dout("Database ID: " << dbId << " Index: " << stateTableIndex);
00300 
00301         DBPacket packet(*this, m_command, m_response);
00302 
00303         // write only if builder object has data
00304         if( !packet.SetRecordByIndex(dbId, stateTableIndex, build, m_ic) ) {
00305                 throw std::logic_error("Desktop: no data available in SetRecord");
00306         }
00307 
00308         m_socket->Packet(packet);
00309 
00310         std::ostringstream oss;
00311 
00312         // successful packet transfer, so check the network return code
00313         if( packet.Command() != SB_COMMAND_DB_DONE ) {
00314                 oss << "Desktop: device responded with unexpected packet command code: "
00315                     << "0x" << std::hex << packet.Command();
00316                 throw Error(oss.str());
00317         }
00318 
00319         if( packet.ReturnCode() != 0 ) {
00320                 oss << "Desktop: device responded with error code (command: "
00321                     << packet.Command() << ", code: "
00322                     << packet.ReturnCode() << ")";
00323                 throw ReturnCodeError(oss.str(), packet.Command(), packet.ReturnCode());
00324         }
00325 }
00326 
00327 //
00328 // ClearDirty
00329 //
00330 /// Clears the dirty flag on the specified record in the specified database.
00331 ///
00332 void Desktop::ClearDirty(unsigned int dbId, unsigned int stateTableIndex)
00333 {
00334         dout("Database ID: " << dbId);
00335 
00336         DBPacket packet(*this, m_command, m_response);
00337         packet.SetRecordFlags(dbId, stateTableIndex, 0);
00338 
00339         m_socket->Packet(packet);
00340 
00341         // flush the command sequence
00342         while( packet.Command() != SB_COMMAND_DB_DONE )
00343                 m_socket->NextRecord(m_response);
00344 }
00345 
00346 //
00347 // DeleteRecord
00348 //
00349 /// Deletes the specified record in the specified database.
00350 ///
00351 void Desktop::DeleteRecord(unsigned int dbId, unsigned int stateTableIndex)
00352 {
00353         dout("Database ID: " << dbId);
00354 
00355         DBPacket packet(*this, m_command, m_response);
00356         packet.DeleteRecordByIndex(dbId, stateTableIndex);
00357 
00358         m_socket->Packet(packet);
00359 
00360         // flush the command sequence
00361         while( packet.Command() != SB_COMMAND_DB_DONE )
00362                 m_socket->NextRecord(m_response);
00363 }
00364 
00365 //
00366 // LoadDatabase
00367 //
00368 /// Retrieve a database from the handheld device, using the given parser
00369 /// to parse the resulting data, and optionally store it.
00370 ///
00371 /// See the RecordParser<> template to create a parser object.  The
00372 /// RecordParser<> template allows custom storage based on the type of
00373 /// database record retrieved.  The database ID and the parser Record
00374 /// type must match.
00375 ///
00376 /// \param[in]  dbId            Database Database ID - use GetDBID()
00377 /// \param[out] parser          Parser object which parses the resulting
00378 ///                             protocol data, and optionally stores it in
00379 ///                             a custom fashion.  See the RecordParser<>
00380 ///                             template.
00381 ///
00382 /// \exception  Barry::Error
00383 ///             Thrown on protocol error.
00384 ///
00385 /// \exception  std::logic_error
00386 ///             Thrown if not in Desktop mode.
00387 ///
00388 void Desktop::LoadDatabase(unsigned int dbId, Parser &parser)
00389 {
00390         DBData data;
00391         DBLoader loader(*this);
00392         bool loading = loader.StartDBLoad(dbId, data);
00393         while( loading ) {
00394                 // manual parser call
00395                 parser.ParseRecord(data, m_ic);
00396 
00397                 // advance!
00398                 loading = loader.GetNextRecord(data);
00399         }
00400 }
00401 
00402 void Desktop::ClearDatabase(unsigned int dbId)
00403 {
00404         dout("Database ID: " << dbId);
00405 
00406         DBPacket packet(*this, m_command, m_response);
00407         packet.ClearDatabase(dbId);
00408 
00409         // wait up to a minute here for old, slower devices with lots of data
00410         m_socket->Packet(packet, 60000);
00411         if( packet.ReturnCode() != 0 ) {
00412                 std::ostringstream oss;
00413                 oss << "Desktop: could not clear database: (command: "
00414                     << "0x" << std::hex << packet.Command() << ", code: "
00415                     << "0x" << std::hex << packet.ReturnCode() << ")";
00416                 throw ReturnCodeError(oss.str(), packet.Command(), packet.ReturnCode());
00417         }
00418 
00419         // check response to clear command was successful
00420         if( packet.Command() != SB_COMMAND_DB_DONE ) {
00421                 eeout(m_command, m_response);
00422                 throw Error("Desktop: error clearing database, bad response");
00423         }
00424 }
00425 
00426 void Desktop::SaveDatabase(unsigned int dbId, Builder &builder)
00427 {
00428         dout("Database ID: " << dbId);
00429 
00430         ClearDatabase(dbId);
00431 
00432         DBPacket packet(*this, m_command, m_response);
00433 
00434         // loop until builder object has no more data
00435         bool first = true;
00436         while( packet.AddRecord(dbId, builder, m_ic) ) {
00437                 dout("Database ID: " << dbId);
00438 
00439                 m_socket->Packet(packet, first ? 60000 : -1);
00440                 first = false;
00441 
00442                 std::ostringstream oss;
00443                 // successful packet transfer, so check the network return code
00444                 if( packet.Command() != SB_COMMAND_DB_DONE ) {
00445                         oss << "Desktop: device responded with unexpected packet command code: "
00446                             << "0x" << std::hex << packet.Command();
00447                         throw Error(oss.str());
00448                 }
00449 
00450                 if( packet.ReturnCode() != 0 ) {
00451                         oss << "Desktop: device responded with error code (command: "
00452                             << packet.Command() << ", code: "
00453                             << packet.ReturnCode() << ")";
00454                         throw ReturnCodeError(oss.str(), packet.Command(), packet.ReturnCode());
00455                 }
00456         }
00457 }
00458 
00459 
00460 
00461 //////////////////////////////////////////////////////////////////////////////
00462 // DBLoader class
00463 
00464 struct DBLoaderData
00465 {
00466         DBPacket m_packet;
00467         DBLoaderData(Desktop &desktop, Data &command, Data &response)
00468                 : m_packet(desktop, command, response)
00469         {
00470         }
00471 };
00472 
00473 DBLoader::DBLoader(Desktop &desktop)
00474         : m_desktop(desktop)
00475         , m_loading(false)
00476         , m_loader(new DBLoaderData(desktop, m_send, m_send))
00477 {
00478 }
00479 
00480 DBLoader::~DBLoader()
00481 {
00482         delete m_loader;
00483 }
00484 
00485 bool DBLoader::StartDBLoad(unsigned int dbId, DBData &data)
00486 {
00487         dout("Database ID: " << dbId);
00488 
00489         m_loading = true;
00490         m_desktop.m_dbdb.GetDBName(dbId, m_dbName);
00491 
00492         DBPacket &packet = m_loader->m_packet;
00493         packet.SetNewReceive(data.UseData());
00494         packet.GetRecords(dbId);
00495         m_desktop.m_socket->Packet(packet);
00496 
00497         while( packet.Command() != SB_COMMAND_DB_DONE ) {
00498                 if( packet.Command() == SB_COMMAND_DB_DATA ) {
00499                         packet.ParseMeta(data);
00500                         data.SetDBName(m_dbName);
00501                         return true;
00502                 }
00503 
00504                 // advance! (use the same data block as in packet)
00505                 m_desktop.m_socket->NextRecord(data.UseData());
00506         }
00507 
00508         m_loading = false;
00509         return false;
00510 }
00511 
00512 bool DBLoader::GetNextRecord(DBData &data)
00513 {
00514         if( !m_loading )
00515                 return false;
00516 
00517         DBPacket &packet = m_loader->m_packet;
00518         packet.SetNewReceive(data.UseData());
00519 
00520         do {
00521                 // advance! (use same data as in packet)
00522                 m_desktop.m_socket->NextRecord(data.UseData());
00523 
00524                 if( packet.Command() == SB_COMMAND_DB_DATA ) {
00525                         packet.ParseMeta(data);
00526                         return true;
00527                 }
00528         } while( m_loader->m_packet.Command() != SB_COMMAND_DB_DONE );
00529 
00530         m_loading = false;
00531         return false;
00532 }
00533 
00534 } // namespace Barry::Mode
00535 
00536 
00537 
00538 
00539 
00540 //////////////////////////////////////////////////////////////////////////////
00541 // DeviceBuilder class
00542 
00543 DeviceBuilder::DeviceBuilder(Mode::Desktop &desktop)
00544         : m_started(false)
00545         , m_desktop(desktop)
00546         , m_loader(desktop)
00547 {
00548         Restart();
00549 }
00550 
00551 // searches the dbdb from the desktop to find the dbId,
00552 // returns false if not found, and adds it to the list of
00553 // databases to retrieve if found
00554 bool DeviceBuilder::Add(const std::string &dbname)
00555 {
00556         try {
00557                 DBLabel id(m_desktop.GetDBID(dbname), dbname);
00558                 m_dbIds.push_back(id);
00559                 return true;
00560         }
00561         catch( Barry::Error & ) {
00562                 // GetDBID() throws on error...
00563                 return false;
00564         }
00565 }
00566 
00567 void DeviceBuilder::Add(const Barry::DatabaseDatabase &dbdb)
00568 {
00569         DatabaseDatabase::DatabaseArrayType::const_iterator
00570                 b = dbdb.Databases.begin(),
00571                 e = dbdb.Databases.end();
00572 
00573         for( ; b != e; ++b ) {
00574                 // hmmm, could optimize this and only add ids
00575                 // with RecordCount > 0, but let's stick with this
00576                 // for now... it might flush bugs out of the system
00577                 DBLabel id(b->Number, b->Name);
00578                 m_dbIds.push_back(id);
00579         }
00580 }
00581 
00582 bool DeviceBuilder::BuildRecord(DBData &data,
00583                                 size_t &offset,
00584                                 const IConverter *ic)
00585 {
00586         DBData temp;
00587         if( !FetchRecord(temp, ic) )
00588                 return false;
00589 
00590         // copy the metadata
00591         data.SetVersion(temp.GetVersion());
00592         data.SetDBName(temp.GetDBName());
00593         data.SetIds(temp.GetRecType(), temp.GetUniqueId());
00594         data.SetOffset(offset);
00595 
00596         // copy data from temp into the given offset
00597         size_t tempsize = temp.GetData().GetSize() - temp.GetOffset();
00598         data.UseData().MemCpy(offset,
00599                 temp.GetData().GetData() + temp.GetOffset(), tempsize);
00600         data.UseData().ReleaseBuffer(offset + tempsize);
00601         return true;
00602 }
00603 
00604 bool DeviceBuilder::FetchRecord(DBData &data, const IConverter *ic)
00605 {
00606         bool ret;
00607 
00608         if( !m_dbIds.size() )
00609                 return false;   // nothing to do
00610 
00611         if( !m_started ) {
00612                 m_current = m_dbIds.begin();
00613                 ret = m_loader.StartDBLoad(m_current->id, data);
00614                 m_started = true;
00615         }
00616         else if( m_loader.IsBusy() ) {
00617                 ret = m_loader.GetNextRecord(data);
00618         }
00619         else {
00620                 // don't do anything if we're at the end of our rope
00621                 if( EndOfFile() )
00622                         return false;
00623 
00624                 // advance and check again... m_current always points
00625                 // to our current DB
00626                 ++m_current;
00627                 if( EndOfFile() )
00628                         return false;
00629 
00630                 ret = m_loader.StartDBLoad(m_current->id, data);
00631         }
00632 
00633         // fill in the DBname if successful
00634         if( ret ) {
00635                 data.SetDBName(m_current->name);
00636         }
00637         return ret;
00638 }
00639 
00640 bool DeviceBuilder::EndOfFile() const
00641 {
00642         return m_current == m_dbIds.end();
00643 }
00644 
00645 
00646 
00647 //////////////////////////////////////////////////////////////////////////////
00648 // DeviceParser class
00649 
00650 DeviceParser::DeviceParser(Mode::Desktop &desktop, WriteMode mode)
00651         : m_desktop(desktop)
00652         , m_mode(mode)
00653 {
00654 }
00655 
00656 DeviceParser::~DeviceParser()
00657 {
00658 }
00659 
00660 void DeviceParser::StartDB(const DBData &data, const IConverter *ic)
00661 {
00662         // start fresh
00663         m_rstate.Clear();
00664         m_current_db = data.GetDBName();
00665         if( !m_desktop.GetDBDB().GetDBNumber(m_current_db, m_current_dbid) ) {
00666                 // doh!  This database does not exist in this device
00667                 dout("Database '" << m_current_db << "' does not exist in this device.  Dropping record.");
00668                 m_current_db.clear();
00669                 m_current_dbid = 0;
00670                 return;
00671         }
00672 
00673         // determine mode
00674         WriteMode mode = m_mode;
00675         if( mode == DECIDE_BY_CALLBACK )
00676                 mode = DecideWrite(data);
00677 
00678         switch( mode )
00679         {
00680         case ERASE_ALL_WRITE_ALL:
00681                 m_desktop.ClearDatabase(m_current_dbid);
00682                 WriteNext(data, ic);
00683                 break;
00684 
00685         case INDIVIDUAL_OVERWRITE:
00686         case ADD_BUT_NO_OVERWRITE:
00687         case ADD_WITH_NEW_ID:
00688                 m_desktop.GetRecordStateTable(m_current_dbid, m_rstate);
00689                 WriteNext(data, ic);
00690                 break;
00691 
00692         case DROP_RECORD:
00693                 break;
00694 
00695         case DECIDE_BY_CALLBACK:
00696         default:
00697                 throw std::logic_error("DeviceParser: unknown mode");
00698         }
00699 }
00700 
00701 void DeviceParser::WriteNext(const DBData &data, const IConverter *ic)
00702 {
00703         // determine mode
00704         WriteMode mode = m_mode;
00705         if( mode == DECIDE_BY_CALLBACK )
00706                 mode = DecideWrite(data);
00707 
00708         // create fast copy with our own metadata
00709         DBData local(data.GetVersion(), data.GetDBName(),
00710                 data.GetRecType(), data.GetUniqueId(), data.GetOffset(),
00711                 data.GetData().GetData(), data.GetData().GetSize());
00712         DBDataBuilder dbuild(local);
00713 
00714         RecordStateTable::IndexType index;
00715 
00716         switch( mode )
00717         {
00718         case ERASE_ALL_WRITE_ALL:
00719                 // just do an AddRecord()
00720                 m_desktop.AddRecord(m_current_dbid, dbuild);
00721                 break;
00722 
00723         case INDIVIDUAL_OVERWRITE:
00724                 // search the state table, overwrite existing, and add new
00725                 if( m_rstate.GetIndex(local.GetUniqueId(), &index) ) {
00726                         // found this record ID, use the index
00727                         m_desktop.SetRecord(m_current_dbid, index, dbuild);
00728                 }
00729                 else {
00730                         // new record
00731                         m_desktop.AddRecord(m_current_dbid, dbuild);
00732                 }
00733                 break;
00734 
00735         case ADD_BUT_NO_OVERWRITE:
00736                 if( !m_rstate.GetIndex(local.GetUniqueId()) ) {
00737                         // no such record ID, so safe to add as new
00738                         m_desktop.AddRecord(m_current_dbid, dbuild);
00739                 }
00740                 // else, drop record
00741                 break;
00742 
00743         case ADD_WITH_NEW_ID:
00744                 // use state table to create new id, and add as new
00745                 local.SetIds(local.GetRecType(), m_rstate.MakeNewRecordId());
00746                 m_desktop.AddRecord(m_current_dbid, dbuild);
00747                 break;
00748 
00749         case DROP_RECORD:
00750                 break;
00751 
00752         case DECIDE_BY_CALLBACK:
00753         default:
00754                 throw std::logic_error("DeviceParser: unknown mode");
00755         }
00756 }
00757 
00758 void DeviceParser::ParseRecord(const DBData &data, const IConverter *ic)
00759 {
00760         if( data.GetDBName() == m_current_db ) {
00761                 WriteNext(data, ic);
00762         }
00763         else {
00764                 StartDB(data, ic);
00765         }
00766 }
00767 
00768 } // namespace Barry
00769