lib: added some operator<() members to basic record objects
[barry/progweb.git] / src / r_timezone.cc
blob1f34a020075c0d45a536ee014ed7f3abbcf97981
1 ///
2 /// \file r_timezone.cc
3 /// Record parsing class for the timezone database.
4 ///
6 /*
7 Copyright (C) 2005-2012, Net Direct Inc. (http://www.netdirect.ca/)
8 Copyright (C) 2008, Brian Edginton
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License in the COPYING file at the
20 root directory of this project for more details.
23 #include "r_timezone.h"
24 #include "record-internal.h"
25 #include "protostructs.h"
26 #include "data.h"
27 #include "time.h"
28 #include "iconv.h"
29 #include "debug.h"
30 #include <iostream>
31 #include <sstream>
32 #include <iomanip>
33 #include "ios_state.h"
35 using namespace std;
36 using namespace Barry::Protocol;
38 namespace Barry
41 ///////////////////////////////////////////////////////////////////////////////
42 // Timezone Class
44 // Timezone Field Codes
45 #define TZFC_INDEX 0x01
46 #define TZFC_NAME 0x02
47 #define TZFC_OFFSET 0x03
48 #define TZFC_DST 0x04
49 #define TZFC_STARTMONTH 0x06
50 #define TZFC_ENDMONTH 0x0B
51 #define TZFC_TZTYPE 0x64
53 #define TZFC_END 0xffff
55 static FieldLink<Timezone> TimezoneFieldLinks[] = {
56 { TZFC_NAME, "Name", 0, 0, &Timezone::Name, 0, 0, 0, 0, true },
57 { TZFC_END, "End of List", 0, 0, 0, 0, 0, 0, 0, false },
60 Timezone::Timezone()
62 Clear();
65 Timezone::Timezone(int utc_offset)
67 Clear();
69 UTCOffset = utc_offset;
72 Timezone::Timezone(int hours, int minutes)
74 Clear();
76 // make sure that minutes are always positive, for our logic
77 if( minutes < 0 )
78 minutes = -minutes;
80 // calculate offset in total minutes
81 UTCOffset = hours * 60;
82 if( hours < 0 )
83 UTCOffset -= minutes;
84 else
85 UTCOffset += minutes;
88 Timezone::~Timezone()
92 const unsigned char* Timezone::ParseField(const unsigned char *begin,
93 const unsigned char *end,
94 const IConverter *ic)
96 const CommonField *field = (const CommonField *) begin;
98 // advance and check size
99 begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
100 if( begin > end ) // if begin==end, we are ok
101 return begin;
103 if( !btohs(field->size) ) // if field has no size, something's up
104 return begin;
106 if( field->type == TZFC_TZTYPE ) {
107 if( ( TZType = field->u.uint32 ) != 1 ) {
108 throw Error("Timezone::ParseField: Timezone Type is not valid");
110 return begin;
113 // cycle through the type table
114 for( FieldLink<Timezone> *b = TimezoneFieldLinks;
115 b->type != TZFC_END;
116 b++ )
118 if( b->type == field->type ) {
119 if( b->strMember ) {
120 std::string &s = this->*(b->strMember);
121 s = ParseFieldString(field);
122 if( b->iconvNeeded && ic )
123 s = ic->FromBB(s);
124 return begin; // done!
129 switch( field->type )
131 case TZFC_INDEX:
132 Index = btohl(field->u.uint32);
133 return begin;
135 case TZFC_OFFSET:
136 UTCOffset = btohs(field->u.int16);
137 return begin;
139 case TZFC_DST:
140 DSTOffset = btohl(field->u.uint32);
141 if (DSTOffset) {
142 UseDST = true;
144 return begin;
146 case TZFC_STARTMONTH:
147 StartMonth = btohl(field->u.uint32);
148 return begin;
150 case TZFC_ENDMONTH:
151 EndMonth = btohl(field->u.uint32);
152 return begin;
155 // if still not handled, add to the Unknowns list
156 UnknownField uf;
157 uf.type = field->type;
158 uf.data.assign((const char*)field->u.raw, btohs(field->size));
159 Unknowns.push_back(uf);
161 // return new pointer for next field
162 return begin;
165 void Timezone::ParseHeader(const Data &data, size_t &offset)
167 // no header in Task records
170 void Timezone::ParseFields(const Data &data, size_t &offset, const IConverter *ic)
172 const unsigned char *finish = ParseCommonFields(*this,
173 data.GetData() + offset, data.GetData() + data.GetSize(), ic);
174 offset += finish - (data.GetData() + offset);
177 void Timezone::BuildHeader(Data &data, size_t &offset) const
179 // not yet implemented
182 void Timezone::BuildFields(Data &data, size_t &offset, const IConverter *ic) const
184 // not yet implemented
187 void Timezone::Clear()
189 RecType = GetDefaultRecType();
190 RecordId = 0;
192 Name.clear();
193 Index = 0;
194 UTCOffset = 0;
196 UseDST = false;
197 DSTOffset = 0;
198 StartMonth = -1;
199 EndMonth = -1;
201 TZType = 0;
203 Unknowns.clear();
206 const std::vector<FieldHandle<Timezone> >& Timezone::GetFieldHandles()
208 static std::vector<FieldHandle<Timezone> > fhv;
210 if( fhv.size() )
211 return fhv;
213 #undef CONTAINER_OBJECT_NAME
214 #define CONTAINER_OBJECT_NAME fhv
216 #undef RECORD_CLASS_NAME
217 #define RECORD_CLASS_NAME Timezone
219 FHP(RecType, "Record Type Code");
220 FHP(RecordId, "Unique Record ID");
222 FHD(Name, "Timezone Name", TZFC_NAME, true);
223 FHD(Index, "Index", TZFC_INDEX, false);
224 FHD(UTCOffset, "Timezone Offset in Minutes", TZFC_OFFSET, false);
225 FHD(UseDST, "Use DST?", TZFC_DST, false);
226 FHD(DSTOffset, "DST Offset", TZFC_DST, false);
227 FHD(StartMonth, "Start Month", TZFC_STARTMONTH, false);
228 FHD(EndMonth, "End Month", TZFC_ENDMONTH, false);
229 FHD(TZType, "Timezone Type", TZFC_TZTYPE, false);
231 FHP(Unknowns, "Unknown Fields");
233 return fhv;
236 std::string Timezone::GetDescription() const
238 ostringstream oss;
239 oss << Name << " (" << dec << (UTCOffset / 60.0) << ")";
240 return oss.str();
243 void Timezone::Dump(std::ostream &os) const
245 ios_format_state state(os);
247 static const char *month[] = {
248 "Jan", "Feb", "Mar", "Apr", "May",
249 "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
252 os << "Timezone entry: 0x" << setbase(16) << RecordId
253 << " (" << (unsigned int)RecType << ")\n";
255 // cycle through the type table
256 for( const FieldLink<Timezone> *b = TimezoneFieldLinks;
257 b->type != TZFC_END;
258 b++ )
260 if( b->strMember ) {
261 const std::string &s = this->*(b->strMember);
262 if( s.size() )
263 os << " " << b->name << ": " << s << "\n";
267 int hours, minutes;
268 Split(&hours, &minutes);
270 os << " Desc: " << GetDescription() << "\n";
271 os << " Index: 0x" <<setw(2) << Index << "\n";
272 os << " Type: 0x" <<setw(2) << (unsigned int)TZType << "\n";
273 os << " Offset: " << setbase(10) << UTCOffset << " minutes ("
274 << dec << (UTCOffset / 60.0) << ")\n";
275 os << " Split Offset: hours: "
276 << dec << hours << ", minutes: " << minutes << "\n";
277 os << " Sample TZ: " << GetTz("E") << "\n";
278 os << " Use DST: " << (UseDST ? "true" : "false") << "\n";
279 if (UseDST) {
280 os << " DST Offset: " << setbase(10) << DSTOffset << "\n";
281 if ((StartMonth > 0) && (StartMonth < 11))
282 os << "Start Month: " << month[StartMonth] << "\n";
283 else
284 os << "Start Month: unknown (" << setbase(10) << StartMonth << ")\n";
285 if ((EndMonth > 0) && (EndMonth < 11))
286 os << " End Month: " << month[EndMonth] << "\n";
287 else
288 os << " End Month: unknown (" << setbase(10) << EndMonth << ")\n";
291 os << Unknowns;
292 os << "\n\n";
296 void Timezone::Split(int *hours, int *minutes) const
298 *hours = UTCOffset / 60;
299 *minutes = UTCOffset % 60;
300 if( *minutes < 0 )
301 *minutes = -*minutes;
304 void Timezone::SplitAbsolute(bool *west,
305 unsigned int *hours,
306 unsigned int *minutes) const
308 int tmphours, tmpminutes;
309 Split(&tmphours, &tmpminutes);
311 if( tmphours < 0 ) {
312 *west = true;
313 tmphours = -tmphours;
315 else {
316 *west = false;
319 *hours = tmphours;
320 *minutes = tmpminutes;
323 std::string Timezone::GetTz(const std::string &prefix) const
325 int hours, minutes;
326 Split(&hours, &minutes);
328 // TZ variable uses positive for west, and negative for east,
329 // so swap the hour value. Minutes is always positive for
330 // our purposes, so leave it alone.
331 hours = -hours;
333 // standard time first
334 ostringstream oss;
335 oss << prefix << "ST"
336 << hours << ":"
337 << setfill('0') << setw(2) << minutes
338 << ":00";
340 // daylight saving time next, if available
341 if( UseDST ) {
342 Timezone dst(UTCOffset + DSTOffset);
344 dst.Split(&hours, &minutes);
346 // swap again for TZ semantics...
347 hours = -hours;
349 oss << prefix << "DT"
350 << hours << ":"
351 << setfill('0') << setw(2) << minutes
352 << ":00";
354 // assume second Sunday of start month to first Sunday of
355 // end month, since we don't have enough data to be more
356 // precise
357 oss << ",M" << (StartMonth + 1) << ".2.0";
358 oss << ",M" << (EndMonth + 1) << ".1.0";
361 return oss.str();
364 } // namespace Barry