BDE 4.39.x 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/// ` https://www.iana.org/time-zones/repository/tz-link.html`) -- and deployed
124/// in a standard 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
259namespace baltzo {
260
261class Zoneinfo;
262
263 // ====================
264 // class DataFileLoader
265 // ====================
266
267/// This component provides a concrete implementation of the `DataLoader`
268/// protocol for loading, into a `Zoneinfo`, the properties of a time zone
269/// defined by an Zoneinfo (TZ Database) binary file located on the file
270/// system.
271///
272/// See @ref baltzo_datafileloader
273class DataFileLoader : public Loader {
274
275 // DATA
276 bsl::string d_rootPath; // root path for time-zone data file
277
278 private:
279 // NOT IMPLEMENTED
281 DataFileLoader& operator=(const DataFileLoader&);
282
283 public:
284 // TYPES
286
287 // TRAITS
290
291 // CLASS METHODS
292
293 /// Return `true` if there currently exists a directory at the specified
294 /// file-system `path` that appears to contain Zoneinfo time-zone
295 /// information files. This method verifies (at a minimum) that `path`
296 /// is a valid directory, and contains files for a subset of common
297 /// time-zone identifiers, but does not *guarantee* `path` is currently
298 /// (or will remain) a correctly configured Zoneinfo database containing
299 /// a complete set of time-zone data.
300 static bool isPlausibleZoneinfoRootPath(const char *path);
301
302 // CREATORS
303
304 /// Create an unconfigured data-file loader. Optionally specify an
305 /// `allocator` (e.g., the address of a `bslma::Allocator` object) to
306 /// supply memory; otherwise, the default allocator is used.
308 explicit DataFileLoader(const allocator_type& allocator);
309
310 /// Destroy this data-file loader.
312
313 // MANIPULATORS
314
315 /// Unconditionally set, to the specified `path`, the root of the
316 /// file-system directory hierarchy from which this loader will read
317 /// Zoneinfo binary time-zone information files.
318 void configureRootPath(const char *path);
319
320 /// Set, to the specified `path`, the root of the file-system directory
321 /// hierarchy from which this loader will read Zoneinfo binary time-zone
322 /// information files. Return 0 on success, and a non-zero value
323 /// (without no effect) if `path` is not a directory that appears to
324 /// contain valid Zoneinfo data, as determined by calling
325 /// `isPlausibleZoneinfoRootPath` on `path`.
326 int configureRootPathIfPlausible(const char *path);
327
328 /// Load into the specified `result` the time-zone information for the
329 /// time zone identified by the specified `timeZoneId`. The `result`
330 /// will have a sentinel transition at 01-01-001, meeting the first two
331 /// requirements for a "well-formed" object (see
332 /// `baltzo::ZoneinfoUtil::isWellFormed` documentation). Return 0 on
333 /// success, and a non-zero value otherwise. A return status of
334 /// `ErrorCode::k_UNSUPPORTED_ID` indicates that `timeZoneId` is not
335 /// recognized. If an error occurs during this operation, `result` will
336 /// be left in a valid, but unspecified state.
337 int loadTimeZone(Zoneinfo *result, const char *timeZoneId)
339
340 /// Load into the specified `result` the time-zone information for the
341 /// time zone identified by the specified `timeZoneId` exactly in
342 /// accordance with the original data. The `result` may not be a
343 /// "well-formed" object (see `baltzo::ZoneinfoUtil::isWellFormed`
344 /// documentation for details). Return 0 on success, and a non-zero
345 /// value otherwise. A return status of `ErrorCode::k_UNSUPPORTED_ID`
346 /// indicates that `timeZoneId` is not recognized. If an error occurs
347 /// during this operation, `result` will be left in a valid, but unspecified state.
348 ///
349 /// \note Note that time zone data files created by
350 /// certain versions of the `zic` time zone compiler will have a
351 /// sentinel transition prior to 01-01-0001 (the first representable
352 /// `Datetime` value) and the `result` will therefore be non-well formed
353 /// (use `loadTimeZone` instead).
354 int loadTimeZoneRaw(Zoneinfo *result, const char *timeZoneId);
355
356 // ACCESSORS
357 int loadTimeZoneFilePath(bsl::string *result,
358 const char *timeZoneId) const;
359 int loadTimeZoneFilePath(std::string *result,
360 const char *timeZoneId) const;
361#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR_STRING
362 int loadTimeZoneFilePath(std::pmr::string *result,
363 const char *timeZoneId) const;
364#endif
365 // Load into the specified 'result' the file-system path to the
366 // Zoneinfo binary data file corresponding to the specified
367 // 'timeZoneId' relative to the configured 'rootPath'. Return 0 on
368 // success, and a non-zero value otherwise. On error, 'result' is left
369 // in a valid, but unspecified state. The behavior is undefined unless
370 // either 'configureRootPath' or 'configureRootPathIfValid' has been
371 // called successfully. Note that this operation does not verify
372 // 'result' refers to a valid file on the file system, or whether the
373 // file (if it exists) contains valid Zoneinfo data.
374
375 /// Return the root of the directory hierarchy from which this loader
376 /// will attempt to load Zoneinfo binary data files.
377 ///
378 /// \pre The behavior is undefined unless either `configureRootPath` has been called or
379 /// `configureRootPathIfValid` has been called successfully.
380 const bsl::string& rootPath() const;
381
382 /// Return `true` if the directory returned by the `rootPath` method
383 /// exists and appears to contain valid Zoneinfo time-zone information
384 /// files, as determined by calling `isPlausibleZoneinfoRootPath` on the
385 /// value returned by the `rootPath` method.
386 bool isRootPathPlausible() const;
387
388 // Aspects
389
390 /// Return the allocator used by this object to supply memory.
391 ///
392 /// \note Note that if no allocator was supplied at construction the default
393 /// allocator in effect at construction is used.
395};
396
397// ============================================================================
398// INLINE DEFINITIONS
399// ============================================================================
400
401 // --------------------
402 // class DataFileLoader
403 // --------------------
404
405// ACCESSORS
406inline
411
412 // Aspects
413
414inline
419
420} // close package namespace
421
422
423#endif
424
425// ----------------------------------------------------------------------------
426// Copyright 2020 Bloomberg Finance L.P.
427//
428// Licensed under the Apache License, Version 2.0 (the "License");
429// you may not use this file except in compliance with the License.
430// You may obtain a copy of the License at
431//
432// http://www.apache.org/licenses/LICENSE-2.0
433//
434// Unless required by applicable law or agreed to in writing, software
435// distributed under the License is distributed on an "AS IS" BASIS,
436// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
437// See the License for the specific language governing permissions and
438// limitations under the License.
439// ----------------------------- END-OF-FILE ----------------------------------
440
441/** @} */
442/** @} */
443/** @} */
Definition baltzo_datafileloader.h:273
int loadTimeZoneFilePath(bsl::string *result, const char *timeZoneId) const
bool isRootPathPlausible() const
Definition baltzo_datafileloader.h:407
int loadTimeZoneRaw(Zoneinfo *result, const char *timeZoneId)
bsl::allocator< char > allocator_type
Definition baltzo_datafileloader.h:285
allocator_type get_allocator() const
Definition baltzo_datafileloader.h:415
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:588
Definition bslstl_string.h:1252
allocator_type get_allocator() const BSLS_KEYWORD_NOEXCEPT
Return the allocator used by this string to supply memory.
Definition bslstl_string.h:7423
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
#define BSLS_KEYWORD_OVERRIDE
Definition bsls_keyword.h:695
Definition baltzo_datafileloader.h:259
Definition bdlat_valuetypefunctions.h:939
Definition bdldfp_decimal.h:5549
Definition bslma_usesbslmaallocator.h:344