2 /// \file r_timezone.cc
3 /// Record parsing class for the timezone database.
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"
33 #include "ios_state.h"
35 #include "m_desktop.h"
38 using namespace Barry::Protocol
;
43 ///////////////////////////////////////////////////////////////////////////////
46 // TimeZone Field Codes
47 #define TZFC_INDEX 0x01
48 #define TZFC_NAME 0x02
49 #define TZFC_OFFSET 0x03
51 #define TZFC_STARTMONTH 0x06
52 #define TZFC_ENDMONTH 0x0B
53 #define TZFC_TZTYPE 0x64
55 #define TZFC_END 0xffff
57 static FieldLink
<TimeZone
> TimeZoneFieldLinks
[] = {
58 { TZFC_NAME
, "Name", 0, 0, &TimeZone::Name
, 0, 0, 0, 0, true },
59 { TZFC_END
, "End of List", 0, 0, 0, 0, 0, 0, 0, false },
67 TimeZone::TimeZone(int utc_offset
)
71 UTCOffset
= utc_offset
;
74 TimeZone::TimeZone(int hours
, int minutes
)
78 // make sure that minutes are always positive, for our logic
82 // calculate offset in total minutes
83 UTCOffset
= hours
* 60;
94 const unsigned char* TimeZone::ParseField(const unsigned char *begin
,
95 const unsigned char *end
,
98 const CommonField
*field
= (const CommonField
*) begin
;
100 // advance and check size
101 begin
+= COMMON_FIELD_HEADER_SIZE
+ btohs(field
->size
);
102 if( begin
> end
) // if begin==end, we are ok
105 if( !btohs(field
->size
) ) // if field has no size, something's up
108 if( field
->type
== TZFC_TZTYPE
) {
109 if( ( TZType
= field
->u
.uint32
) != 1 ) {
110 throw Error("TimeZone::ParseField: TimeZone Type is not valid");
115 // cycle through the type table
116 for( FieldLink
<TimeZone
> *b
= TimeZoneFieldLinks
;
120 if( b
->type
== field
->type
) {
122 std::string
&s
= this->*(b
->strMember
);
123 s
= ParseFieldString(field
);
124 if( b
->iconvNeeded
&& ic
)
126 return begin
; // done!
131 switch( field
->type
)
134 Index
= btohl(field
->u
.uint32
);
138 UTCOffset
= btohs(field
->u
.int16
);
142 DSTOffset
= btohl(field
->u
.uint32
);
148 case TZFC_STARTMONTH
:
149 StartMonth
= btohl(field
->u
.uint32
);
153 EndMonth
= btohl(field
->u
.uint32
);
157 // if still not handled, add to the Unknowns list
159 uf
.type
= field
->type
;
160 uf
.data
.assign((const char*)field
->u
.raw
, btohs(field
->size
));
161 Unknowns
.push_back(uf
);
163 // return new pointer for next field
167 void TimeZone::ParseHeader(const Data
&data
, size_t &offset
)
169 // no header in Task records
172 void TimeZone::ParseFields(const Data
&data
, size_t &offset
, const IConverter
*ic
)
174 const unsigned char *finish
= ParseCommonFields(*this,
175 data
.GetData() + offset
, data
.GetData() + data
.GetSize(), ic
);
176 offset
+= finish
- (data
.GetData() + offset
);
179 void TimeZone::Validate() const
183 void TimeZone::BuildHeader(Data
&data
, size_t &offset
) const
185 // not yet implemented
188 void TimeZone::BuildFields(Data
&data
, size_t &offset
, const IConverter
*ic
) const
190 // not yet implemented
193 void TimeZone::Clear()
195 RecType
= GetDefaultRecType();
212 const FieldHandle
<TimeZone
>::ListT
& TimeZone::GetFieldHandles()
214 static FieldHandle
<TimeZone
>::ListT fhv
;
219 #undef CONTAINER_OBJECT_NAME
220 #define CONTAINER_OBJECT_NAME fhv
222 #undef RECORD_CLASS_NAME
223 #define RECORD_CLASS_NAME TimeZone
225 FHP(RecType
, "Record Type Code");
226 FHP(RecordId
, "Unique Record ID");
228 FHD(Name
, "TimeZone Name", TZFC_NAME
, true);
229 FHD(Index
, "Index", TZFC_INDEX
, false);
230 FHD(UTCOffset
, "TimeZone Offset in Minutes", TZFC_OFFSET
, false);
231 FHD(UseDST
, "Use DST?", TZFC_DST
, false);
232 FHD(DSTOffset
, "DST Offset", TZFC_DST
, false);
233 FHD(StartMonth
, "Start Month", TZFC_STARTMONTH
, false);
234 FHD(EndMonth
, "End Month", TZFC_ENDMONTH
, false);
235 FHD(TZType
, "TimeZone Type", TZFC_TZTYPE
, false);
237 FHP(Unknowns
, "Unknown Fields");
242 std::string
TimeZone::GetDescription() const
246 " (" << (UTCOffset
> 0 ? "+" : "")
247 << dec
<< (UTCOffset
/ 60.0) << ")";
251 void TimeZone::Dump(std::ostream
&os
) const
253 ios_format_state
state(os
);
255 static const char *month
[] = {
256 "Jan", "Feb", "Mar", "Apr", "May",
257 "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
260 os
<< "TimeZone entry: 0x" << setbase(16) << RecordId
261 << " (" << (unsigned int)RecType
<< ")\n";
263 // cycle through the type table
264 for( const FieldLink
<TimeZone
> *b
= TimeZoneFieldLinks
;
269 const std::string
&s
= this->*(b
->strMember
);
271 os
<< " " << b
->name
<< ": " << s
<< "\n";
276 Split(&hours
, &minutes
);
278 os
<< " Desc: " << GetDescription() << "\n";
279 os
<< " Index: 0x" <<setw(2) << Index
<< "\n";
280 os
<< " Type: 0x" <<setw(2) << (unsigned int)TZType
<< "\n";
281 os
<< " Offset: " << setbase(10) << UTCOffset
<< " minutes ("
282 << dec
<< (UTCOffset
/ 60.0) << ")\n";
283 os
<< " Split Offset: hours: "
284 << dec
<< hours
<< ", minutes: " << minutes
<< "\n";
285 os
<< " Sample TZ: " << GetTz("E") << "\n";
286 os
<< " Use DST: " << (UseDST
? "true" : "false") << "\n";
288 os
<< " DST Offset: " << setbase(10) << DSTOffset
<< "\n";
289 if ((StartMonth
> 0) && (StartMonth
< 11))
290 os
<< "Start Month: " << month
[StartMonth
] << "\n";
292 os
<< "Start Month: unknown (" << setbase(10) << StartMonth
<< ")\n";
293 if ((EndMonth
> 0) && (EndMonth
< 11))
294 os
<< " End Month: " << month
[EndMonth
] << "\n";
296 os
<< " End Month: unknown (" << setbase(10) << EndMonth
<< ")\n";
304 void TimeZone::Split(int *hours
, int *minutes
) const
306 *hours
= UTCOffset
/ 60;
307 *minutes
= UTCOffset
% 60;
309 *minutes
= -*minutes
;
312 void TimeZone::SplitAbsolute(bool *west
,
314 unsigned int *minutes
) const
316 int tmphours
, tmpminutes
;
317 Split(&tmphours
, &tmpminutes
);
321 tmphours
= -tmphours
;
328 *minutes
= tmpminutes
;
331 std::string
TimeZone::GetTz(const std::string
&prefix
) const
334 Split(&hours
, &minutes
);
336 // TZ variable uses positive for west, and negative for east,
337 // so swap the hour value. Minutes is always positive for
338 // our purposes, so leave it alone.
341 // standard time first
343 oss
<< prefix
<< "ST"
345 << setfill('0') << setw(2) << minutes
348 // daylight saving time next, if available
350 TimeZone
dst(UTCOffset
+ DSTOffset
);
352 dst
.Split(&hours
, &minutes
);
354 // swap again for TZ semantics...
357 oss
<< prefix
<< "DT"
359 << setfill('0') << setw(2) << minutes
362 // assume second Sunday of start month to first Sunday of
363 // end month, since we don't have enough data to be more
365 oss
<< ",M" << (StartMonth
+ 1) << ".2.0";
366 oss
<< ",M" << (EndMonth
+ 1) << ".1.0";
373 ///////////////////////////////////////////////////////////////////////////////
376 TimeZones::TimeZones()
378 const StaticTimeZone
*zones
= GetStaticTimeZoneTable();
379 for( ; zones
->Name
; zones
++ ) {
380 TimeZone
tz(zones
->HourOffset
, zones
->MinOffset
);
381 tz
.Index
= zones
->Code
;
382 tz
.Name
= zones
->Name
;
383 m_list
.push_back(tz
);
386 sort(begin(), end(), &TimeZone::SortByZone
);
391 TimeZones::ListType
&m_list
;
393 TimeZoneStore(TimeZones::ListType
&list
) : m_list(list
)
397 void operator()(const TimeZone
&rec
)
399 m_list
.push_back(rec
);
403 TimeZones::TimeZones(Barry::Mode::Desktop
&desktop
)
405 unsigned int dbId
= desktop
.GetDBID( TimeZone::GetDBName() );
406 TimeZoneStore
store(m_list
);
407 RecordParser
<TimeZone
, TimeZoneStore
> parser(store
);
409 desktop
.LoadDatabase(dbId
, parser
);
411 sort(begin(), end(), &TimeZone::SortByZone
);
414 bool TimeZones::IsLoadable(Barry::Mode::Desktop
&desktop
)
417 return desktop
.GetDBDB().GetDBNumber(TimeZone::GetDBName(), num
);
420 TimeZones::iterator
TimeZones::Find(int index
)
422 for( iterator i
= begin(), e
= end(); i
!= e
; ++i
)
423 if( i
->Index
== index
)
428 TimeZones::const_iterator
TimeZones::Find(int index
) const
430 return const_cast<TimeZones
*>(this)->Find(index
);
433 TimeZones::iterator
TimeZones::FindByOffset(int utc_offset
)
435 for( iterator i
= begin(), e
= end(); i
!= e
; ++i
)
436 if( i
->UTCOffset
== utc_offset
)
441 TimeZones::const_iterator
TimeZones::FindByOffset(int utc_offset
) const
443 return const_cast<TimeZones
*>(this)->FindByOffset(utc_offset
);
446 void TimeZones::Dump(std::ostream
&os
) const
448 const_iterator b
= begin(), e
= end();
449 for( ; b
!= e
; ++b
) {