2 /// \file r_timezone.cc
3 /// Record parsing class for the timezone database.
7 Copyright (C) 2005-2013, 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.
24 #include "r_timezone.h"
25 #include "record-internal.h"
26 #include "protostructs.h"
34 #include "ios_state.h"
36 #include "m_desktop.h"
39 using namespace Barry::Protocol
;
44 ///////////////////////////////////////////////////////////////////////////////
47 // TimeZone Field Codes
48 #define TZFC_INDEX 0x01
49 #define TZFC_NAME 0x02
50 #define TZFC_OFFSET 0x03
52 #define TZFC_STARTMONTH 0x06
53 #define TZFC_ENDMONTH 0x0B
54 #define TZFC_TZTYPE 0x64
56 #define TZFC_END 0xffff
58 static FieldLink
<TimeZone
> TimeZoneFieldLinks
[] = {
59 { TZFC_NAME
, N_("Name"), 0, 0, &TimeZone::Name
, 0, 0, 0, 0, true },
60 { TZFC_END
, N_("End of List"), 0, 0, 0, 0, 0, 0, 0, false },
68 TimeZone::TimeZone(int utc_offset
)
72 UTCOffset
= utc_offset
;
75 TimeZone::TimeZone(int hours
, int minutes
)
79 // make sure that minutes are always positive, for our logic
83 // calculate offset in total minutes
84 UTCOffset
= hours
* 60;
95 const unsigned char* TimeZone::ParseField(const unsigned char *begin
,
96 const unsigned char *end
,
99 const CommonField
*field
= (const CommonField
*) begin
;
101 // advance and check size
102 begin
+= COMMON_FIELD_HEADER_SIZE
+ btohs(field
->size
);
103 if( begin
> end
) // if begin==end, we are ok
106 if( !btohs(field
->size
) ) // if field has no size, something's up
109 if( field
->type
== TZFC_TZTYPE
) {
110 if( ( TZType
= field
->u
.uint32
) != 1 ) {
111 throw Error(_("TimeZone::ParseField: TimeZone Type is not valid"));
116 // cycle through the type table
117 for( FieldLink
<TimeZone
> *b
= TimeZoneFieldLinks
;
121 if( b
->type
== field
->type
) {
123 std::string
&s
= this->*(b
->strMember
);
124 s
= ParseFieldString(field
);
125 if( b
->iconvNeeded
&& ic
)
127 return begin
; // done!
132 switch( field
->type
)
135 Index
= btohl(field
->u
.uint32
);
139 UTCOffset
= btohs(field
->u
.int16
);
143 DSTOffset
= btohl(field
->u
.uint32
);
149 case TZFC_STARTMONTH
:
150 StartMonth
= btohl(field
->u
.uint32
);
154 EndMonth
= btohl(field
->u
.uint32
);
158 // if still not handled, add to the Unknowns list
160 uf
.type
= field
->type
;
161 uf
.data
.assign((const char*)field
->u
.raw
, btohs(field
->size
));
162 Unknowns
.push_back(uf
);
164 // return new pointer for next field
168 void TimeZone::ParseHeader(const Data
&data
, size_t &offset
)
170 // no header in Task records
173 void TimeZone::ParseFields(const Data
&data
, size_t &offset
, const IConverter
*ic
)
175 const unsigned char *finish
= ParseCommonFields(*this,
176 data
.GetData() + offset
, data
.GetData() + data
.GetSize(), ic
);
177 offset
+= finish
- (data
.GetData() + offset
);
180 void TimeZone::Validate() const
184 void TimeZone::BuildHeader(Data
&data
, size_t &offset
) const
186 // not yet implemented
189 void TimeZone::BuildFields(Data
&data
, size_t &offset
, const IConverter
*ic
) const
191 // not yet implemented
194 void TimeZone::Clear()
196 RecType
= GetDefaultRecType();
213 const FieldHandle
<TimeZone
>::ListT
& TimeZone::GetFieldHandles()
215 static FieldHandle
<TimeZone
>::ListT fhv
;
220 #undef CONTAINER_OBJECT_NAME
221 #define CONTAINER_OBJECT_NAME fhv
223 #undef RECORD_CLASS_NAME
224 #define RECORD_CLASS_NAME TimeZone
226 FHP(RecType
, _("Record Type Code"));
227 FHP(RecordId
, _("Unique Record ID"));
229 FHD(Name
, _("TimeZone Name"), TZFC_NAME
, true);
230 FHD(Index
, _("Index"), TZFC_INDEX
, false);
231 FHD(UTCOffset
, _("TimeZone Offset in Minutes"), TZFC_OFFSET
, false);
232 FHD(UseDST
, _("Use DST?"), TZFC_DST
, false);
233 FHD(DSTOffset
, _("DST Offset"), TZFC_DST
, false);
234 FHD(StartMonth
, _("Start Month"), TZFC_STARTMONTH
, false);
235 FHD(EndMonth
, _("End Month"), TZFC_ENDMONTH
, false);
236 FHD(TZType
, _("TimeZone Type"), TZFC_TZTYPE
, false);
238 FHP(Unknowns
, _("Unknown Fields"));
243 std::string
TimeZone::GetDescription() const
247 " (" << (UTCOffset
> 0 ? "+" : "")
248 << dec
<< (UTCOffset
/ 60.0) << ")";
252 void TimeZone::Dump(std::ostream
&os
) const
254 ios_format_state
state(os
);
256 static const char *month
[] = {
271 os
<< _("TimeZone entry: ") << "0x" << setbase(16) << RecordId
272 << " (" << (unsigned int)RecType
<< ")\n";
274 // cycle through the type table
275 for( const FieldLink
<TimeZone
> *b
= TimeZoneFieldLinks
;
280 const std::string
&s
= this->*(b
->strMember
);
282 os
<< " " << b
->name
<< ": " << s
<< "\n";
287 Split(&hours
, &minutes
);
289 os
<< _(" Desc: ") << GetDescription() << "\n";
290 os
<< _(" Index: ") << "0x" <<setw(2) << Index
<< "\n";
291 os
<< _(" Type: ") << "0x" <<setw(2) << (unsigned int)TZType
<< "\n";
292 os
<< _(" Offset: ") << setbase(10) << UTCOffset
<< _(" minutes ")
293 << "(" << dec
<< (UTCOffset
/ 60.0) << ")\n";
294 os
<< _(" Split Offset: hours: ")
295 << dec
<< hours
<< _(", minutes: ") << minutes
<< "\n";
296 os
<< _(" Sample TZ: ") << GetTz("E") << "\n";
297 os
<< _(" Use DST: ") << (UseDST
? "true" : "false") << "\n";
299 os
<< _(" DST Offset: ") << setbase(10) << DSTOffset
<< "\n";
300 if ((StartMonth
> 0) && (StartMonth
< 11))
301 os
<< _("Start Month: ") << gettext(month
[StartMonth
]) << "\n";
303 os
<< _("Start Month: unknown (") << setbase(10) << StartMonth
<< ")\n";
304 if ((EndMonth
> 0) && (EndMonth
< 11))
305 os
<< _(" End Month: ") << gettext(month
[EndMonth
]) << "\n";
307 os
<< _(" End Month: unknown (") << setbase(10) << EndMonth
<< ")\n";
315 void TimeZone::Split(int *hours
, int *minutes
) const
317 *hours
= UTCOffset
/ 60;
318 *minutes
= UTCOffset
% 60;
320 *minutes
= -*minutes
;
323 void TimeZone::SplitAbsolute(bool *west
,
325 unsigned int *minutes
) const
327 int tmphours
, tmpminutes
;
328 Split(&tmphours
, &tmpminutes
);
332 tmphours
= -tmphours
;
339 *minutes
= tmpminutes
;
342 std::string
TimeZone::GetTz(const std::string
&prefix
) const
345 Split(&hours
, &minutes
);
347 // TZ variable uses positive for west, and negative for east,
348 // so swap the hour value. Minutes is always positive for
349 // our purposes, so leave it alone.
352 // standard time first
354 oss
<< prefix
<< "ST"
356 << setfill('0') << setw(2) << minutes
359 // daylight saving time next, if available
361 TimeZone
dst(UTCOffset
+ DSTOffset
);
363 dst
.Split(&hours
, &minutes
);
365 // swap again for TZ semantics...
368 oss
<< prefix
<< "DT"
370 << setfill('0') << setw(2) << minutes
373 // assume second Sunday of start month to first Sunday of
374 // end month, since we don't have enough data to be more
376 oss
<< ",M" << (StartMonth
+ 1) << ".2.0";
377 oss
<< ",M" << (EndMonth
+ 1) << ".1.0";
384 ///////////////////////////////////////////////////////////////////////////////
387 TimeZones::TimeZones()
389 const StaticTimeZone
*zones
= GetStaticTimeZoneTable();
390 for( ; zones
->Name
; zones
++ ) {
391 TimeZone
tz(zones
->HourOffset
, zones
->MinOffset
);
392 tz
.Index
= zones
->Code
;
393 tz
.Name
= gettext( zones
->Name
);
394 m_list
.push_back(tz
);
397 sort(begin(), end(), &TimeZone::SortByZone
);
402 TimeZones::ListType
&m_list
;
404 TimeZoneStore(TimeZones::ListType
&list
) : m_list(list
)
408 void operator()(const TimeZone
&rec
)
410 m_list
.push_back(rec
);
414 TimeZones::TimeZones(Barry::Mode::Desktop
&desktop
)
416 unsigned int dbId
= desktop
.GetDBID( TimeZone::GetDBName() );
417 TimeZoneStore
store(m_list
);
418 RecordParser
<TimeZone
, TimeZoneStore
> parser(store
);
420 desktop
.LoadDatabase(dbId
, parser
);
422 sort(begin(), end(), &TimeZone::SortByZone
);
425 bool TimeZones::IsLoadable(Barry::Mode::Desktop
&desktop
)
428 return desktop
.GetDBDB().GetDBNumber(TimeZone::GetDBName(), num
);
431 TimeZones::iterator
TimeZones::Find(int index
)
433 for( iterator i
= begin(), e
= end(); i
!= e
; ++i
)
434 if( i
->Index
== index
)
439 TimeZones::const_iterator
TimeZones::Find(int index
) const
441 return const_cast<TimeZones
*>(this)->Find(index
);
444 TimeZones::iterator
TimeZones::FindByOffset(int utc_offset
)
446 for( iterator i
= begin(), e
= end(); i
!= e
; ++i
)
447 if( i
->UTCOffset
== utc_offset
)
452 TimeZones::const_iterator
TimeZones::FindByOffset(int utc_offset
) const
454 return const_cast<TimeZones
*>(this)->FindByOffset(utc_offset
);
457 void TimeZones::Dump(std::ostream
&os
) const
459 const_iterator b
= begin(), e
= end();
460 for( ; b
!= e
; ++b
) {