r_timezone.cc

Go to the documentation of this file.
00001 ///
00002 /// \file       r_timezone.cc
00003 ///             Record parsing class for the timezone database.
00004 ///
00005 
00006 /*
00007     Copyright (C) 2005-2011, Net Direct Inc. (http://www.netdirect.ca/)
00008     Copyright (C) 2008, Brian Edginton
00009 
00010     This program is free software; you can redistribute it and/or modify
00011     it under the terms of the GNU General Public License as published by
00012     the Free Software Foundation; either version 2 of the License, or
00013     (at your option) any later version.
00014 
00015     This program is distributed in the hope that it will be useful,
00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00018 
00019     See the GNU General Public License in the COPYING file at the
00020     root directory of this project for more details.
00021 */
00022 
00023 #include "r_timezone.h"
00024 #include "record-internal.h"
00025 #include "protostructs.h"
00026 #include "data.h"
00027 #include "time.h"
00028 #include "iconv.h"
00029 #include "debug.h"
00030 #include <ostream>
00031 #include <iomanip>
00032 
00033 using namespace std;
00034 using namespace Barry::Protocol;
00035 
00036 namespace Barry
00037 {
00038 
00039 ///////////////////////////////////////////////////////////////////////////////
00040 // Timezone Class
00041 
00042 // Timezone Field Codes
00043 #define TZFC_INDEX              0x01
00044 #define TZFC_NAME               0x02
00045 #define TZFC_OFFSET             0x03
00046 #define TZFC_DST                0x04
00047 #define TZFC_STARTMONTH         0x06
00048 #define TZFC_ENDMONTH           0x0B
00049 #define TZFC_TZTYPE             0x64
00050 
00051 #define TZFC_END                0xffff
00052 
00053 static FieldLink<Timezone> TimezoneFieldLinks[] = {
00054    { TZFC_NAME,   "Name",        0, 0, &Timezone::TimeZoneName, 0, 0, 0, 0, true },
00055    { TZFC_END,    "End of List", 0, 0, 0, 0, 0, 0, 0, false },
00056 };
00057 
00058 Timezone::Timezone()
00059 {
00060         Clear();
00061 }
00062 
00063 Timezone::~Timezone()
00064 {
00065 }
00066 
00067 const unsigned char* Timezone::ParseField(const unsigned char *begin,
00068                                           const unsigned char *end,
00069                                           const IConverter *ic)
00070 {
00071         const CommonField *field = (const CommonField *) begin;
00072 
00073         // advance and check size
00074         begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
00075         if( begin > end )       // if begin==end, we are ok
00076                 return begin;
00077 
00078         if( !btohs(field->size) )   // if field has no size, something's up
00079                 return begin;
00080 
00081         if( field->type == TZFC_TZTYPE ) {
00082                 if( ( TZType = field->u.uint32 ) != 1 ) {
00083                         throw Error("Timezone::ParseField: Timezone Type is not valid");
00084                 }
00085                 return begin;
00086         }
00087 
00088         // cycle through the type table
00089         for(    FieldLink<Timezone> *b = TimezoneFieldLinks;
00090                 b->type != TZFC_END;
00091                 b++ )
00092         {
00093                 if( b->type == field->type ) {
00094                         if( b->strMember ) {
00095                                 std::string &s = this->*(b->strMember);
00096                                 s = ParseFieldString(field);
00097                                 if( b->iconvNeeded && ic )
00098                                         s = ic->FromBB(s);
00099                                 return begin;   // done!
00100                         }
00101                 }
00102         }
00103 
00104         switch( field->type )
00105         {
00106         case TZFC_INDEX:
00107                 Index = btohl(field->u.uint32);
00108                 return begin;
00109 
00110         case TZFC_OFFSET:
00111                 Offset = btohs(field->u.int16);
00112                 if (Offset < 0) {
00113                         Offset =~ Offset;
00114                         Offset++;
00115                         OffsetFraction = Offset % 60;
00116                         Offset = Offset / 60;
00117                         Left = true;
00118                 } else {
00119                         OffsetFraction = Offset % 60;
00120                         Offset = Offset / 60;
00121                         Left = false;
00122                 }
00123                 return begin;
00124 
00125         case TZFC_DST:
00126                 DSTOffset = btohl(field->u.uint32);
00127                 if (DSTOffset) {
00128                         UseDST = true;
00129                 }
00130                 return begin;
00131 
00132         case TZFC_STARTMONTH:
00133                 StartMonth = btohl(field->u.uint32);
00134                 return begin;
00135 
00136         case TZFC_ENDMONTH:
00137                 EndMonth = btohl(field->u.uint32);
00138                 return begin;
00139         }
00140 
00141         // if still not handled, add to the Unknowns list
00142         UnknownField uf;
00143         uf.type = field->type;
00144         uf.data.assign((const char*)field->u.raw, btohs(field->size));
00145         Unknowns.push_back(uf);
00146 
00147         // return new pointer for next field
00148         return begin;
00149 }
00150 
00151 void Timezone::ParseHeader(const Data &data, size_t &offset)
00152 {
00153         // no header in Task records
00154 }
00155 
00156 void Timezone::ParseFields(const Data &data, size_t &offset, const IConverter *ic)
00157 {
00158         const unsigned char *finish = ParseCommonFields(*this,
00159                 data.GetData() + offset, data.GetData() + data.GetSize(), ic);
00160         offset += finish - (data.GetData() + offset);
00161 }
00162 
00163 void Timezone::Clear()
00164 {
00165         RecType = GetDefaultRecType();
00166         RecordId = 0;
00167 
00168         TZType = 0;
00169         DSTOffset = 0;
00170         Index = 0;
00171         Offset = 0;
00172         OffsetFraction = 0;
00173         StartMonth = -1;
00174         EndMonth = -1;
00175         Left = false;
00176         UseDST = false;
00177 
00178         TimeZoneName.clear();
00179 
00180         Unknowns.clear();
00181 }
00182 
00183 void Timezone::Dump(std::ostream &os) const
00184 {
00185         static const char *month[] = {
00186                         "Jan", "Feb", "Mar", "Apr", "May",
00187                         "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
00188         };
00189 
00190         os << "Task entry: 0x" << setbase(16) << RecordId
00191            << " (" << (unsigned int)RecType << ")\n";
00192 
00193         // cycle through the type table
00194         for(    const FieldLink<Timezone> *b = TimezoneFieldLinks;
00195                 b->type != TZFC_END;
00196                 b++ )
00197         {
00198                 if( b->strMember ) {
00199                         const std::string &s = this->*(b->strMember);
00200                         if( s.size() )
00201                                 os << "       " << b->name << ": " << s << "\n";
00202                 }
00203         }
00204 
00205         os << "      Index: 0x" <<setw(2) << Index << "\n";
00206         os << "     Offset: " << (Left ? "-" : "+") << setbase(10) << Offset << "." << OffsetFraction << "\n";
00207         os << "    Use DST: " << (UseDST ? "true" : "false") << "\n";
00208         if (UseDST) {
00209                 if ((StartMonth > 0) && (StartMonth < 11))
00210                                 os << "Start Month: " << month[StartMonth] << "\n";
00211                 else
00212                                 os << "Start Month: unknown (" << setbase(10) << StartMonth << ")\n";
00213                 if ((EndMonth > 0) && (EndMonth < 11))
00214                         os << "  End Month: " << month[EndMonth] << "\n";
00215                 else
00216                         os << "  End Month: unknown (" << setbase(10) << EndMonth << ")\n";
00217         }
00218 
00219         os << Unknowns;
00220         os << "\n\n";
00221 }
00222 
00223 }