00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "r_servicebook.h"
00024 #include "record-internal.h"
00025 #include "protocol.h"
00026 #include "protostructs.h"
00027 #include "data.h"
00028 #include "time.h"
00029 #include "error.h"
00030 #include "endian.h"
00031 #include "iconv.h"
00032 #include <ostream>
00033 #include <iomanip>
00034 #include <time.h>
00035 #include <stdexcept>
00036 #include "ios_state.h"
00037
00038 #define __DEBUG_MODE__
00039 #include "debug.h"
00040
00041 using namespace std;
00042 using namespace Barry::Protocol;
00043
00044 namespace Barry {
00045
00046
00047
00048
00049
00050 #define SBFCC_END 0xffff
00051
00052 static FieldLink<ServiceBookConfig> ServiceBookConfigFieldLinks[] = {
00053
00054 { SBFCC_END, "End of List",0, 0, 0, 0, 0 }
00055 };
00056
00057 ServiceBookConfig::ServiceBookConfig()
00058 : Format(0)
00059 {
00060 Clear();
00061 }
00062
00063 ServiceBookConfig::~ServiceBookConfig()
00064 {
00065 }
00066
00067 const unsigned char* ServiceBookConfig::ParseField(const unsigned char *begin,
00068 const unsigned char *end,
00069 const IConverter *ic)
00070 {
00071 const void *raw;
00072 uint16_t size, type;
00073
00074 switch( Format )
00075 {
00076 case 0x01:
00077 case 0x02:
00078 {
00079 const PackedField_02 *field = (const PackedField_02 *) begin;
00080 raw = field->raw;
00081 size = field->size;
00082 type = field->type;
00083 begin += PACKED_FIELD_02_HEADER_SIZE + size;
00084 }
00085 break;
00086
00087 case 0x10:
00088 {
00089 const PackedField_10 *field = (const PackedField_10 *) begin;
00090 raw = field->raw;
00091 size = field->size;
00092 type = field->type;
00093 begin += PACKED_FIELD_10_HEADER_SIZE + size;
00094 }
00095 break;
00096
00097 default:
00098 dout("------> Unknown packed field format: 0x" << std::hex <<
00099 (unsigned int) Format);
00100 throw BadPackedFormat(Format);
00101 return begin + 1;
00102 }
00103
00104
00105
00106 if( begin > end )
00107 return begin;
00108
00109 if( !size )
00110 return begin;
00111
00112
00113 for( FieldLink<ServiceBookConfig> *b = ServiceBookConfigFieldLinks;
00114 b->type != SBFCC_END;
00115 b++ )
00116 {
00117 if( b->type == type ) {
00118 if( b->strMember ) {
00119 std::string &s = this->*(b->strMember);
00120 s = ParseFieldString(raw, size-1);
00121 return begin;
00122 }
00123 }
00124 }
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134 UnknownField uf;
00135 uf.type = type;
00136 uf.data.assign((const char*)raw, size);
00137 Unknowns.push_back(uf);
00138
00139
00140 return begin;
00141 }
00142
00143 void ServiceBookConfig::ParseHeader(const Data &data, size_t &offset)
00144 {
00145 MAKE_RECORD(const Barry::Protocol::ServiceBookConfigField, sbc, data, offset);
00146 offset += SERVICE_BOOK_CONFIG_FIELD_HEADER_SIZE;
00147 if( data.GetSize() >= offset ) {
00148 Format = sbc->format;
00149 }
00150 }
00151
00152 void ServiceBookConfig::ParseFields(const Data &data, size_t &offset, const IConverter *ic)
00153 {
00154 const unsigned char *finish = ParseCommonFields(*this,
00155 data.GetData() + offset, data.GetData() + data.GetSize(), ic);
00156 offset += finish - (data.GetData() + offset);
00157 }
00158
00159 void ServiceBookConfig::Validate() const
00160 {
00161 }
00162
00163 void ServiceBookConfig::BuildHeader(Data &data, size_t &offset) const
00164 {
00165
00166 data.GetBuffer(offset + SERVICE_BOOK_CONFIG_FIELD_HEADER_SIZE);
00167
00168 MAKE_RECORD(Barry::Protocol::ServiceBookConfigField, sbc, data, offset);
00169 sbc->format = Format;
00170
00171 offset += SERVICE_BOOK_CONFIG_FIELD_HEADER_SIZE;
00172 }
00173
00174
00175
00176
00177
00178
00179 void ServiceBookConfig::BuildFields(Data &data, size_t &offset, const IConverter *ic) const
00180 {
00181 throw std::logic_error("ServiceBookConfig::Build not yet implemented");
00182 }
00183
00184 void ServiceBookConfig::Clear()
00185 {
00186 Format = 0;
00187 Unknowns.clear();
00188 }
00189
00190 void ServiceBookConfig::Dump(std::ostream &os) const
00191 {
00192 ios_format_state state(os);
00193
00194 os << " ServiceBookConfig Format: " << setbase(16) << (uint16_t)Format << "\n";
00195
00196
00197 for( const FieldLink<ServiceBookConfig> *b = ServiceBookConfigFieldLinks;
00198 b->type != SBFCC_END;
00199 b++ )
00200 {
00201 if( b->strMember ) {
00202 const std::string &s = this->*(b->strMember);
00203 if( s.size() )
00204 os << " " << b->name << ": " << s << "\n";
00205 }
00206 else if( b->timeMember ) {
00207 TimeT t = this->*(b->timeMember);
00208 if( t.Time> 0 )
00209 os << " " << b->name << ": " << t << "\n";
00210 }
00211 }
00212
00213
00214 os << Unknowns;
00215 os << " ------------------- End of Config Field\n";
00216 }
00217
00218
00219
00220
00221
00222
00223 #define SBFC_OLD_NAME 0x01
00224 #define SBFC_HIDDEN_NAME 0x02
00225 #define SBFC_NAME 0x03
00226 #define SBFC_OLD_UNIQUE_ID 0x06
00227 #define SBFC_UNIQUE_ID 0x07
00228 #define SBFC_CONTENT_ID 0x08
00229 #define SBFC_CONFIG 0x09
00230 #define SBFC_OLD_DESC 0x32
00231 #define SBFC_DESCRIPTION 0x0f
00232 #define SBFC_DSID 0xa1
00233 #define SBFC_BES_DOMAIN 0xa2
00234 #define SBFC_USER_ID 0xa3
00235 #define SBFC_END 0xffff
00236
00237
00238 class ServiceBookData
00239 {
00240 public:
00241 FieldLink<ServiceBook> *m_typeSet;
00242 ServiceBookData(FieldLink<ServiceBook> *typeSet) : m_typeSet(typeSet) {}
00243 };
00244
00245
00246
00247
00248
00249 static FieldLink<ServiceBook> ServiceBookOldFieldLinks[] = {
00250 { SBFC_OLD_NAME, "Old Name", 0, 0, &ServiceBook::Name, 0, 0, 0, 0, true },
00251 { SBFC_OLD_DESC, "Old Desc", 0, 0, &ServiceBook::Description, 0, 0, 0, 0, true },
00252 { SBFC_OLD_UNIQUE_ID, "Old UniqueId", 0, 0, &ServiceBook::UniqueId, 0, 0, 0, 0, false },
00253 { SBFC_END, "End of List", 0, 0, 0, 0, 0, 0, 0, false }
00254 };
00255
00256 static FieldLink<ServiceBook> ServiceBookNewFieldLinks[] = {
00257 { SBFC_NAME, "Name", 0, 0, &ServiceBook::Name, 0, 0, 0, 0, true },
00258 { SBFC_DESCRIPTION, "Description", 0, 0, &ServiceBook::Description, 0, 0, 0, 0, true },
00259 { SBFC_UNIQUE_ID, "UniqueId", 0, 0, &ServiceBook::UniqueId, 0, 0, 0, 0, false },
00260 { SBFC_END, "End of List", 0, 0, 0, 0, 0, 0, 0, false }
00261 };
00262
00263
00264 static FieldLink<ServiceBook> ServiceBookFieldLinks[] = {
00265 { SBFC_HIDDEN_NAME, "Hidden Name",0, 0, &ServiceBook::HiddenName, 0, 0, 0, 0, true },
00266 { SBFC_DSID, "DSID", 0, 0, &ServiceBook::DSID, 0, 0, 0, 0, false },
00267 { SBFC_CONTENT_ID, "ContentId", 0, 0, &ServiceBook::ContentId, 0, 0, 0, 0, false },
00268 { SBFC_BES_DOMAIN, "BES Domain", 0, 0, &ServiceBook::BesDomain, 0, 0, 0, 0, false },
00269 { SBFC_END, "End of List",0, 0, 0, 0, 0, 0, 0, false }
00270 };
00271
00272
00273 static FieldLink<ServiceBook> *ServiceBookLinkTable[] = {
00274 ServiceBookOldFieldLinks,
00275 ServiceBookNewFieldLinks,
00276 0
00277 };
00278
00279 #define FIELDLINK_END 0xffff
00280
00281 template <class RecordT>
00282 FieldLink<RecordT>* ParseFieldByTable(RecordT *rec,
00283 const CommonField *field,
00284 const IConverter *ic,
00285 FieldLink<RecordT> *links)
00286 {
00287
00288 for( FieldLink<RecordT> *b = links; b->type != FIELDLINK_END; b++ ) {
00289 if( b->type == field->type ) {
00290 if( b->strMember ) {
00291 std::string &s = rec->*(b->strMember);
00292 if( s.size() ) {
00293 dout(RecordT::GetDBName() << ": field '" << b->name << "' already has data (" << s << "). Overwriting.");
00294 }
00295 s = ParseFieldString(field);
00296 if( b->iconvNeeded && ic )
00297 s = ic->FromBB(s);
00298 return links;
00299 }
00300 else if( b->timeMember && btohs(field->size) == 4 ) {
00301 TimeT &t = rec->*(b->timeMember);
00302 t.Time = min2time(field->u.min1900);
00303 return links;
00304 }
00305 }
00306 }
00307 return 0;
00308 }
00309
00310 template <class RecordT>
00311 FieldLink<RecordT>* ParseFieldByTable(RecordT *rec,
00312 const CommonField *field,
00313 const IConverter *ic,
00314 FieldLink<RecordT> **b)
00315 {
00316 for( ; *b; b++ ) {
00317 FieldLink<RecordT> *link =
00318 ParseFieldByTable<RecordT>(rec, field, ic, *b);
00319 if( link )
00320 return link;
00321 }
00322 return 0;
00323 }
00324
00325 ServiceBook::ServiceBook()
00326 : m_data( new ServiceBookData(ServiceBookOldFieldLinks) )
00327 , RecordId(0)
00328 {
00329 Clear();
00330 }
00331
00332 ServiceBook::~ServiceBook()
00333 {
00334 }
00335
00336 const unsigned char* ServiceBook::ParseField(const unsigned char *begin,
00337 const unsigned char *end,
00338 const IConverter *ic)
00339 {
00340 const CommonField *field = (const CommonField *) begin;
00341
00342
00343 begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
00344 if( begin > end )
00345 return begin;
00346
00347 if( !btohs(field->size) )
00348 return begin;
00349
00350
00351 FieldLink<ServiceBook> *typeSet =
00352 ParseFieldByTable(this, field, ic, ServiceBookLinkTable);
00353 if( typeSet ) {
00354 if( m_data->m_typeSet && m_data->m_typeSet != typeSet ) {
00355 dout("ServiceBook record has a mix of old and new field types.");
00356 }
00357 m_data->m_typeSet = typeSet;
00358 return begin;
00359 }
00360 else {
00361 if( ParseFieldByTable(this, field, ic, ServiceBookFieldLinks) )
00362 return begin;
00363 }
00364
00365
00366 switch( field->type )
00367 {
00368 case SBFC_CONFIG:
00369 try {
00370 Data config((const void *)field->u.raw, btohs(field->size));
00371 size_t offset = 0;
00372 Config.ParseHeader(config, offset);
00373 Config.ParseFields(config, offset);
00374 return begin;
00375 }
00376 catch( BadPackedFormat & ) {
00377
00378
00379 break;
00380 }
00381 }
00382
00383
00384 UnknownField uf;
00385 uf.type = field->type;
00386 uf.data.assign((const char*)field->u.raw, btohs(field->size));
00387 Unknowns.push_back(uf);
00388
00389
00390 return begin;
00391 }
00392
00393 void ServiceBook::ParseHeader(const Data &data, size_t &offset)
00394 {
00395
00396 }
00397
00398 void ServiceBook::ParseFields(const Data &data, size_t &offset, const IConverter *ic)
00399 {
00400 const unsigned char *finish = ParseCommonFields(*this,
00401 data.GetData() + offset, data.GetData() + data.GetSize(), ic);
00402 offset += finish - (data.GetData() + offset);
00403 }
00404
00405 void ServiceBook::Validate() const
00406 {
00407 Config.Validate();
00408 }
00409
00410 void ServiceBook::BuildHeader(Data &data, size_t &offset) const
00411 {
00412
00413 }
00414
00415
00416
00417
00418
00419
00420 void ServiceBook::BuildFields(Data &data, size_t &offset, const IConverter *ic) const
00421 {
00422 throw std::logic_error("ServiceBook::BuildFields not yet implemented");
00423 }
00424
00425 void ServiceBook::Clear()
00426 {
00427 m_data->m_typeSet = ServiceBookOldFieldLinks;
00428 Unknowns.clear();
00429 Config.Clear();
00430 }
00431
00432 const FieldHandle<ServiceBook>::ListT& ServiceBook::GetFieldHandles()
00433 {
00434 static FieldHandle<ServiceBook>::ListT fhv;
00435
00436 if( fhv.size() )
00437 return fhv;
00438
00439 #undef CONTAINER_OBJECT_NAME
00440 #define CONTAINER_OBJECT_NAME fhv
00441
00442 #undef RECORD_CLASS_NAME
00443 #define RECORD_CLASS_NAME ServiceBook
00444
00445 FHP(RecType, "Record Type Code");
00446 FHP(RecordId, "Unique Record ID");
00447
00448 FHP(Name, "Name");
00449 FHP(HiddenName, "Hidden Name");
00450 FHP(Description, "Description");
00451 FHP(DSID, "DSID");
00452 FHP(BesDomain, "BES Domain");
00453 FHP(UniqueId, "Unique ID");
00454 FHP(ContentId, "Content ID");
00455
00456
00457
00458
00459
00460
00461 FHP(Unknowns, "Unknown Fields");
00462
00463 return fhv;
00464 }
00465
00466 std::string ServiceBook::GetDescription() const
00467 {
00468 return Name;
00469 }
00470
00471 inline void FormatStr(std::ostream &os, const char *name, const std::string &str)
00472 {
00473 ios_format_state state(os);
00474
00475 if( str.size() ) {
00476 os << " " << setw(20) << name;
00477 os << ": " << str << "\n";
00478 }
00479 }
00480
00481 void ServiceBook::Dump(std::ostream &os) const
00482 {
00483 ios_format_state state(os);
00484
00485 os.setf(ios::left);
00486 os.fill(' ');
00487
00488 os << "ServiceBook entry: 0x" << setbase(16) << RecordId
00489 << " (" << (unsigned int)RecType << ")\n";
00490
00491 FormatStr(os, "Name", Name);
00492 FormatStr(os, "Hidden Name", HiddenName);
00493 FormatStr(os, "Description", Description);
00494 FormatStr(os, "DSID", DSID);
00495 FormatStr(os, "Unique ID", UniqueId);
00496 FormatStr(os, "Content ID", ContentId);
00497 FormatStr(os, "(BES) Domain", BesDomain);
00498
00499 os << Config;
00500
00501
00502 os << Unknowns;
00503 }
00504
00505 bool ServiceBook::operator<(const ServiceBook &other) const
00506 {
00507 int cmp = BesDomain.compare(other.BesDomain);
00508 if( cmp == 0 )
00509 cmp = DSID.compare(other.DSID);
00510 if( cmp == 0 )
00511 cmp = Name.compare(other.Name);
00512 if( cmp == 0 )
00513 cmp = UniqueId.compare(other.UniqueId);
00514 return cmp < 0;
00515 }
00516
00517 }
00518