BDE 4.14.0 Production release
Loading...
Searching...
No Matches
baltzo_datafileloader.h
Go to the documentation of this file.
1/// @file baltzo_datafileloader.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// baltzo_datafileloader.h -*-C++-*-
8#ifndef INCLUDED_BALTZO_DATAFILELOADER
9#define INCLUDED_BALTZO_DATAFILELOADER
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup baltzo_datafileloader baltzo_datafileloader
15/// @brief Provide a concrete `baltzo::Loader` for Zoneinfo binary files.
16/// @addtogroup bal
17/// @{
18/// @addtogroup baltzo
19/// @{
20/// @addtogroup baltzo_datafileloader
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#baltzo_datafileloader-purpose"> Purpose</a>
25/// * <a href="#baltzo_datafileloader-classes"> Classes </a>
26/// * <a href="#baltzo_datafileloader-description"> Description </a>
27/// * <a href="#baltzo_datafileloader-zoneinfo-files"> Zoneinfo (TZ Database) Files </a>
28/// * <a href="#baltzo_datafileloader-directory-hierarchy"> Directory Hierarchy </a>
29/// * <a href="#baltzo_datafileloader-thread-safety"> Thread Safety </a>
30/// * <a href="#baltzo_datafileloader-usage"> Usage </a>
31/// * <a href="#baltzo_datafileloader-example-1-prologue-creating-a-example-data-file"> Example 1: Prologue: Creating a Example Data File </a>
32/// * <a href="#baltzo_datafileloader-example-2-using-a-baltzo-datafileloader-to-load-a-zoneinfo-file"> Example 2: Using a baltzo::DataFileLoader to Load a Zoneinfo File </a>
33/// * <a href="#baltzo_datafileloader-epilogue-removing-the-created-files"> Epilogue: Removing the Created Files </a>
34///
35/// # Purpose {#baltzo_datafileloader-purpose}
36/// Provide a concrete `baltzo::Loader` for Zoneinfo binary files.
37///
38/// # Classes {#baltzo_datafileloader-classes}
39///
40/// - baltzo::DataFileLoader: concrete `baltzo::Loader` for Zoneinfo binary data
41///
42/// @see baltzo_zoneinfobinaryreader, baltzo_zoneinfoutil
43///
44/// # Description {#baltzo_datafileloader-description}
45/// This component provides a mechanism, `baltzo::DataFileLoader`,
46/// that is a concrete implementation of the `baltzo::Loader` protocol for
47/// loading, into a `baltzo::Zoneinfo` object, the properties of a time zone
48/// described in a Zoneinfo binary database file. The following inheritance
49/// hierarchy diagram shows the classes involved and their methods:
50/// @code
51/// ,----------------------.
52/// ( baltzo::DataFileLoader )
53/// `----------------------'
54/// | ctor
55/// | configureRootPath
56/// | configureRootPathIfPlausible
57/// | loadTimeZoneFilePath
58/// | rootPath
59/// | isRootPathPlausible
60/// V
61/// ,--------------.
62/// ( baltzo::Loader )
63/// `--------------'
64/// dtor
65/// loadTimeZone
66/// @endcode
67/// A `baltzo::DataFileLoader` is supplied a file-system location using the
68/// `configureRootPath` method. This location should correspond to the root
69/// directory of a hierarchy containing Zoneinfo binary data files, where each
70/// Zoneinfo time-zone identifier indicates a relative path from the root
71/// directory to the binary data file containing the information for that time
72/// zone. Accordingly, `baltzo::DataFileLoader` provides a method that, given a
73/// time-zone identifier, will open the corresponding data file (relative to the
74/// root directory tree supplied at construction), and load, into a
75/// `baltzo::Zoneinfo` object, the data from that file.
76///
77/// ## Zoneinfo (TZ Database) Files {#baltzo_datafileloader-zoneinfo-files}
78///
79///
80/// The Zoneinfo database, also referred to as either the TZ database or the
81/// Olson database (after its creator, Arthur Olson), is a standard
82/// public-domain time-zone information distribution used by many software
83/// systems (including a number of Unix variants and the Java Runtime
84/// Environment). Information about the Zoneinfo database can be found online
85/// at `http://www.twinsun.com/tz/tz-link.htm`, including the time-zone rules
86/// for the supported time zones, and source code for the `zic` compiler (for
87/// compiling those rules into the binary representation used by this
88/// component). See @ref baltzo_zoneinfobinaryreader for more information about
89/// the binary file format.
90///
91/// ### Directory Hierarchy {#baltzo_datafileloader-directory-hierarchy}
92///
93///
94/// Zoneinfo database files are typically held in a standard file-system
95/// directory hierarchy. Zoneinfo time-zone identifiers (e.g.,
96/// "America/New_York") serve not only as an identifier, but as a relative path
97/// (using the UNIX file separator, `/`) to the file containing data for the
98/// time zone. So, given a hypothetical root directory "/etc/time_zones", the
99/// time-zone data file for "America/New_York" will be located in
100/// "/etc/time_zones/America/New_York".
101///
102/// ## Thread Safety {#baltzo_datafileloader-thread-safety}
103///
104///
105/// `baltzo::DataFileLoader` is *const* *thread-safe*, meaning that accessors
106/// may be invoked concurrently from different threads, but it is not safe to
107/// access or modify a `baltzo::DataFileLoader` in one thread while another
108/// thread modifies the same object.
109///
110/// ## Usage {#baltzo_datafileloader-usage}
111///
112///
113/// The following examples illustrate how to use a `baltzo::DataFileLoader` to
114/// load the Zoneinfo time-zone data for a time zone.
115///
116/// ### Example 1: Prologue: Creating a Example Data File {#baltzo_datafileloader-example-1-prologue-creating-a-example-data-file}
117///
118///
119/// First we need to create one time-zone data file on which to operate. In
120/// practice, clients should *not* generate data files in this manner. Data
121/// files are typically created using the `zic` compiler -- a publicly available
122/// tool provided as part of the standard Zoneinfo distribution (see
123/// `http://www.twinsun.com/tz/tz-link.htm`) -- and deployed in a standard
124/// directory location (see @ref baltzo_defaultzoneinfocache ).
125///
126/// We start by defining static binary data for "Asia/Bangkok", (chosen because
127/// it is relatively small):
128/// @code
129/// const char ASIA_BANGKOK_DATA[] = {
130/// 0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
131/// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
132/// 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
133/// 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0xa2, 0x6a, 0x67, 0xc4,
134/// 0x01, 0x00, 0x00, 0x5e, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x62, 0x70, 0x00,
135/// 0x04, 0x42, 0x4d, 0x54, 0x00, 0x49, 0x43, 0x54, 0x00, 0x00, 0x00, 0x00,
136/// 0x00, 0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
137/// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
138/// 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
139/// 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0c, 0xff, 0xff, 0xff,
140/// 0xff, 0x56, 0xb6, 0x85, 0xc4, 0xff, 0xff, 0xff, 0xff, 0xa2, 0x6a, 0x67,
141/// 0xc4, 0x01, 0x02, 0x00, 0x00, 0x5e, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x5e,
142/// 0x3c, 0x00, 0x04, 0x00, 0x00, 0x62, 0x70, 0x00, 0x08, 0x4c, 0x4d, 0x54,
143/// 0x00, 0x42, 0x4d, 0x54, 0x00, 0x49, 0x43, 0x54, 0x00, 0x00, 0x00, 0x00,
144/// 0x00, 0x00, 0x00, 0x0a, 0x49, 0x43, 0x54, 0x2d, 0x37, 0x0a
145/// };
146/// @endcode
147/// Then we create a testing sub-directory "test/Asia" that will hold the data
148/// file for Bangkok. Note that "Asia/Bangkok" is the time-zone identifier for
149/// Bangkok and "Asia/Bangkok" also serves as a relative path (from our "./test"
150/// sub-directory) to that data file.
151/// @code
152/// #ifdef BSLS_PLATFORM_OS_WINDOWS
153/// const char *TEST_DIRECTORY = "test\\Asia";
154/// const char *TEST_FILE = "test\\Asia\\Bangkok";
155/// #else
156/// const char *TEST_DIRECTORY = "test/Asia";
157/// const char *TEST_FILE = "test/Asia/Bangkok";
158/// #endif
159/// int rc = bdls::FileUtil::createDirectories(TEST_DIRECTORY, true);
160/// assert(0 == rc);
161/// @endcode
162/// Now we create a file for Bangkok and write the binary time-zone data to that
163/// file.
164/// @code
165/// bsl::ofstream outputFile(TEST_FILE, bsl::ofstream::binary);
166/// assert(outputFile.is_open());
167/// outputFile.write(ASIA_BANGKOK_DATA, sizeof(ASIA_BANGKOK_DATA));
168/// assert(outputFile);
169/// outputFile.close();
170/// @endcode
171/// The file `Bangkok` should now appear in the `Asia` sub-directory, under out
172/// `test` directory.
173///
174/// ### Example 2: Using a baltzo::DataFileLoader to Load a Zoneinfo File {#baltzo_datafileloader-example-2-using-a-baltzo-datafileloader-to-load-a-zoneinfo-file}
175///
176///
177/// In this example we demonstrate how to use a `baltzo::DataFileLoader` to load
178/// a time-zone data file into a `baltzo::Zoneinfo` object. We start by
179/// creating a `baltzo::DataFileLoader` object, `loader`, and configure it with
180/// the relative path "test" which we created in Example 1 (Prologue).
181/// @code
182/// baltzo::DataFileLoader loader;
183/// loader.configureRootPath("test");
184/// @endcode
185/// Then we use the `loadTimeZoneFilePath` method to verify that `loader` will
186/// correctly locate the test data file we've created:
187/// @code
188/// const char *BANGKOK_ID = "Asia/Bangkok";
189/// bsl::string bangkokDataPath;
190/// rc = loader.loadTimeZoneFilePath(&bangkokDataPath, BANGKOK_ID);
191/// assert(0 == rc);
192/// assert(TEST_FILE == bangkokDataPath); // Note 'TEST_FILE' from Example 1.
193/// @endcode
194/// Now we create a `baltzo::Zoneinfo` object, `timeZone`, and load it using
195/// `loader`:
196/// @code
197/// baltzo::Zoneinfo timeZone;
198/// rc = loader.loadTimeZone(&timeZone, BANGKOK_ID);
199/// assert(0 == rc);
200/// @endcode
201/// Finally we confirm that certain properties of the `timezone` object are in
202/// agreement with the properties defined in the binary data (see
203/// @ref baltzo_zoneinfobinaryreader ): (1) That the object's identifier is
204/// "Asia/Bangkok", and (2) the object contains three local time descriptors,
205/// "LMT" (Local Mean Time), "BMT" (Bangkok Mean Time) and "ICT" (Indochina
206/// Time), in that order:
207/// @code
208/// assert(BANGKOK_ID == timeZone.identifier());
209/// baltzo::Zoneinfo::LocalTimeDescriptorConstIterator iterator =
210/// timeZone.descriptorBegin();
211/// assert("LMT" == iterator->description());
212/// ++iterator;
213/// assert("BMT" == iterator->description());
214/// ++iterator;
215/// assert("ICT" == iterator->description());
216/// @endcode
217/// The `timeZone` object can now be use for time-zone calculations. See
218/// @ref baltzo_zoneinfoutil .
219///
220/// #### Epilogue: Removing the Created Files {#baltzo_datafileloader-epilogue-removing-the-created-files}
221///
222///
223/// The file hierarchy we created Example 1 solely for Example 2, is no longer
224/// needed, and is removed by:
225/// @code
226/// int rc = bdls::FileUtil::remove(TEST_DIRECTORY, true);
227/// assert(0 == rc);
228/// @endcode
229/// @}
230/** @} */
231/** @} */
232
233/** @addtogroup bal
234 * @{
235 */
236/** @addtogroup baltzo
237 * @{
238 */
239/** @addtogroup baltzo_datafileloader
240 * @{
241 */
242
243#include <balscm_version.h>
244
245#include <baltzo_loader.h>
246
247#include <bslma_bslallocator.h>
249
251
252#include <bsls_keyword.h>
253#include <bsls_libraryfeatures.h>
254#include <bsls_platform.h>
255
256#include <bsl_string.h>
257
258#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
259# include <bslalg_typetraits.h>
260#endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
261
262
263namespace baltzo {
264
265class Zoneinfo;
266
267 // ====================
268 // class DataFileLoader
269 // ====================
270
271/// This component provides a concrete implementation of the `DataLoader`
272/// protocol for loading, into a `Zoneinfo`, the properties of a time zone
273/// defined by an Zoneinfo (TZ Database) binary file located on the file
274/// system.
275///
276/// See @ref baltzo_datafileloader
277class DataFileLoader : public Loader {
278
279 // DATA
280 bsl::string d_rootPath; // root path for time-zone data file
281
282 private:
283 // NOT IMPLEMENTED
285 DataFileLoader& operator=(const DataFileLoader&);
286
287 public:
288 // TYPES
290
291 // TRAITS
294
295 // CLASS METHODS
296
297 /// Return `true` if there currently exists a directory at the specified
298 /// file-system `path` that appears to contain Zoneinfo time-zone
299 /// information files. This method verifies (at a minimum) that `path`
300 /// is a valid directory, and contains files for a subset of common
301 /// time-zone identifiers, but does not *guarantee* `path` is currently
302 /// (or will remain) a correctly configured Zoneinfo database containing
303 /// a complete set of time-zone data.
304 static bool isPlausibleZoneinfoRootPath(const char *path);
305
306 // CREATORS
307
309 /// Create an unconfigured data-file loader. Optionally specify an
310 /// `allocator` (e.g., the address of a `bslma::Allocator` object) to
311 /// supply memory; otherwise, the default allocator is used.
312 explicit DataFileLoader(const allocator_type& allocator);
313
314 /// Destroy this data-file loader.
316
317 // MANIPULATORS
318
319 /// Unconditionally set, to the specified `path`, the root of the
320 /// file-system directory hierarchy from which this loader will read
321 /// Zoneinfo binary time-zone information files.
322 void configureRootPath(const char *path);
323
324 /// Set, to the specified `path`, the root of the file-system directory
325 /// hierarchy from which this loader will read Zoneinfo binary time-zone
326 /// information files. Return 0 on success, and a non-zero value
327 /// (without no effect) if `path` is not a directory that appears to
328 /// contain valid Zoneinfo data, as determined by calling
329 /// `isPlausibleZoneinfoRootPath` on `path`.
330 int configureRootPathIfPlausible(const char *path);
331
332 /// Load into the specified `result` the time-zone information for the
333 /// time zone identified by the specified `timeZoneId`. The `result`
334 /// will have a sentinel transition at 01-01-001, meeting the first two
335 /// requirements for a "well-formed" object (see
336 /// `baltzo::ZoneinfoUtil::isWellFormed` documentation). Return 0 on
337 /// success, and a non-zero value otherwise. A return status of
338 /// `ErrorCode::k_UNSUPPORTED_ID` indicates that `timeZoneId` is not
339 /// recognized. If an error occurs during this operation, `result` will
340 /// be left in a valid, but unspecified state.
341 int loadTimeZone(Zoneinfo *result, const char *timeZoneId)
343
344 /// Load into the specified `result` the time-zone information for the
345 /// time zone identified by the specified `timeZoneId` exactly in
346 /// accordance with the original data. The `result` may not be a
347 /// "well-formed" object (see `baltzo::ZoneinfoUtil::isWellFormed`
348 /// documentation for details). Return 0 on success, and a non-zero
349 /// value otherwise. A return status of `ErrorCode::k_UNSUPPORTED_ID`
350 /// indicates that `timeZoneId` is not recognized. If an error occurs
351 /// during this operation, `result` will be left in a valid, but
352 /// unspecified state. Note that time zone data files created by
353 /// certain versions of the `zic` time zone compiler will have a
354 /// sentinel transition prior to 01-01-0001 (the first representable
355 /// `Datetime` value) and the `result` will therefore be non-well formed
356 /// (use `loadTimeZone` instead).
357 int loadTimeZoneRaw(Zoneinfo *result, const char *timeZoneId);
358
359 // ACCESSORS
360 int loadTimeZoneFilePath(bsl::string *result,
361 const char *timeZoneId) const;
362 int loadTimeZoneFilePath(std::string *result,
363 const char *timeZoneId) const;
364#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR_STRING
365 int loadTimeZoneFilePath(std::pmr::string *result,
366 const char *timeZoneId) const;
367#endif
368 // Load into the specified 'result' the file-system path to the
369 // Zoneinfo binary data file corresponding to the specified
370 // 'timeZoneId' relative to the configured 'rootPath'. Return 0 on
371 // success, and a non-zero value otherwise. On error, 'result' is left
372 // in a valid, but unspecified state. The behavior is undefined unless
373 // either 'configureRootPath' or 'configureRootPathIfValid' has been
374 // called successfully. Note that this operation does not verify
375 // 'result' refers to a valid file on the file system, or whether the
376 // file (if it exists) contains valid Zoneinfo data.
377
378 /// Return the root of the directory hierarchy from which this loader
379 /// will attempt to load Zoneinfo binary data files. The behavior is
380 /// undefined unless either `configureRootPath` has been called or
381 /// `configureRootPathIfValid` has been called successfully.
382 const bsl::string& rootPath() const;
383
384 /// Return `true` if the directory returned by the `rootPath` method
385 /// exists and appears to contain valid Zoneinfo time-zone information
386 /// files, as determined by calling `isPlausibleZoneinfoRootPath` on the
387 /// value returned by the `rootPath` method.
388 bool isRootPathPlausible() const;
389
390 // Aspects
391
392 /// Return the allocator used by this object to supply memory. Note
393 /// that if no allocator was supplied at construction the default
394 /// allocator in effect at construction is used.
396};
397
398// ============================================================================
399// INLINE DEFINITIONS
400// ============================================================================
401
402 // --------------------
403 // class DataFileLoader
404 // --------------------
405
406// ACCESSORS
407inline
412
413 // Aspects
414
415inline
420
421} // close package namespace
422
423
424#endif
425
426// ----------------------------------------------------------------------------
427// Copyright 2020 Bloomberg Finance L.P.
428//
429// Licensed under the Apache License, Version 2.0 (the "License");
430// you may not use this file except in compliance with the License.
431// You may obtain a copy of the License at
432//
433// http://www.apache.org/licenses/LICENSE-2.0
434//
435// Unless required by applicable law or agreed to in writing, software
436// distributed under the License is distributed on an "AS IS" BASIS,
437// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
438// See the License for the specific language governing permissions and
439// limitations under the License.
440// ----------------------------- END-OF-FILE ----------------------------------
441
442/** @} */
443/** @} */
444/** @} */
Definition baltzo_datafileloader.h:277
int loadTimeZoneFilePath(bsl::string *result, const char *timeZoneId) const
bool isRootPathPlausible() const
Definition baltzo_datafileloader.h:408
int loadTimeZoneRaw(Zoneinfo *result, const char *timeZoneId)
bsl::allocator< char > allocator_type
Definition baltzo_datafileloader.h:289
allocator_type get_allocator() const
Definition baltzo_datafileloader.h:416
static bool isPlausibleZoneinfoRootPath(const char *path)
int loadTimeZone(Zoneinfo *result, const char *timeZoneId) BSLS_KEYWORD_OVERRIDE
BSLMF_NESTED_TRAIT_DECLARATION(DataFileLoader, bslma::UsesBslmaAllocator)
void configureRootPath(const char *path)
DataFileLoader(const allocator_type &allocator)
~DataFileLoader() BSLS_KEYWORD_OVERRIDE
Destroy this data-file loader.
int configureRootPathIfPlausible(const char *path)
const bsl::string & rootPath() const
Definition baltzo_loader.h:266
Definition baltzo_zoneinfo.h:429
Definition bslma_bslallocator.h:580
Definition bslstl_string.h:1281
allocator_type get_allocator() const BSLS_KEYWORD_NOEXCEPT
Return the allocator used by this string to supply memory.
Definition bslstl_string.h:6723
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
#define BSLS_KEYWORD_OVERRIDE
Definition bsls_keyword.h:653
Definition baltzo_datafileloader.h:263
Definition bdlb_printmethods.h:283
Definition bdldfp_decimal.h:5188
Definition bslma_usesbslmaallocator.h:343