OpenCPN Partial API docs
Loading...
Searching...
No Matches
tcmgr.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * Copyright (C) 2010 by David S. Register *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, see <https://www.gnu.org/licenses/>. *
16 **************************************************************************/
17
24#include <wx/wxprec.h>
25#ifndef WX_PRECOMP
26#include <wx/wx.h>
27#endif // precompiled headers
28#include <wx/hashmap.h>
29
30#include <stdlib.h>
31#include <math.h>
32#include <time.h>
33
34#include "model/georef.h"
35#include "model/logger.h"
36
37#include "gui_lib.h"
38#include "dychart.h"
39#include "navutil.h"
40#include "tcmgr.h"
41
43
44//-----------------------------------------------------------------------------------
45// TIDELIB
46//-----------------------------------------------------------------------------------
47
48// Static variables for the TIDELIB
49
50static time_t s_next_epoch = TIDE_BAD_TIME; /* next years newyears */
51static time_t s_this_epoch = TIDE_BAD_TIME; /* this years newyears */
52static int s_this_year = -1;
53
54static double time2dt_tide(time_t t, int deriv, IDX_entry *pIDX);
55static int yearoftimet(time_t t);
56static void happy_new_year(IDX_entry *pIDX, int new_year);
57static void set_epoch(IDX_entry *pIDX, int year);
58
59static double time2tide(time_t t, IDX_entry *pIDX) {
60 return time2dt_tide(t, 0, pIDX);
61}
62
67double BOGUS_amplitude(double mpy, IDX_entry *pIDX) {
68 Station_Data *pmsd = pIDX->pref_sta_data;
69
70 if (!pmsd->have_BOGUS) // || !convert_BOGUS) // Added mgh
71 return (mpy * pIDX->max_amplitude);
72 else {
73 if (mpy >= 0.0)
74 return (sqrt(mpy * pIDX->max_amplitude));
75 else
76 return (-sqrt(-mpy * pIDX->max_amplitude));
77 }
78}
79
80/* Calculate the denormalized tide. */
81double time2atide(time_t t, IDX_entry *pIDX) {
82 return BOGUS_amplitude(time2tide(t, pIDX), pIDX) + pIDX->pref_sta_data->DATUM;
83}
84
85/* Next high tide, low tide, transition of the mark level, or some
86 * combination.
87 * Bit Meaning
88 * 0 low tide
89 * 1 high tide
90 * 2 falling transition
91 * 3 rising transition
92 */
93int next_big_event(time_t *tm, IDX_entry *pIDX) {
94 double p, q;
95 int flags = 0, slope = 0;
96 p = time2atide(*tm, pIDX);
97 *tm += 60;
98 q = time2atide(*tm, pIDX);
99 *tm += 60;
100 if (p < q) slope = 1;
101 while (1) {
102 if ((slope == 1 && q < p) || (slope == 0 && p < q)) {
103 /* Tide event */
104 flags |= (1 << slope);
105 }
106 /* Modes in which to return mark transitions: */
107 /* -text (no -graph) */
108 /* -graph (no -text) */
109 /* -ppm */
110 /* -gif */
111 /* -ps */
112
113 // if (mark && ((text && !graphmode) || (!text && graphmode)
114 // || ppm || gif || ps))
115 // int marklev = 0;
116#if (0)
117 if (0)
118 if ((p > marklev && q <= marklev) || (p < marklev && q >= marklev)) {
119 /* Transition event */
120 if (p < q)
121 flags |= 8;
122 else
123 flags |= 4;
124 if (!(flags & 3)) {
125 /* If we're incredibly unlucky, we could miss a tide event if we
126 * don't check for it here:
127 *
128 * . <---- Value that would be
129 * returned
130 * ----------- Mark level
131 * . .
132 */
133 p = q;
134 q = time2atide(*tm, pIDX);
135 if ((slope == 1 && q < p) || (slope == 0 && p < q)) {
136 /* Tide event */
137 flags |= (1 << slope);
138 }
139 }
140 }
141#endif
142
143 if (flags) {
144 *tm -= 60;
145 /* Don't back up over a transition event, but do back up to where the
146 * tide changed if possible. If they happen at the same
147 * time, then we're off by a minute on the tide, but if we back it up it
148 * will get snagged on the transition event over and over. */
149 if (flags < 4) *tm -= 60;
150 return flags;
151 }
152 p = q;
153 q = time2atide(*tm, pIDX);
154 *tm += 60;
155 }
156}
157
158/* Estimate the normalized mean tide level around a particular time by
159 * summing only the long-term constituents. */
160/* Does not do any blending around year's end. */
161/* This is used only by time2asecondary for finding the mean tide level */
162double time2mean(time_t t, IDX_entry *pIDX) {
163 double tide = 0.0;
164 int a;
165 int new_year = yearoftimet(t);
166 if (pIDX->epoch_year != new_year) happy_new_year(pIDX, new_year);
167
168 for (a = 0; a < pIDX->num_csts; a++) {
169 if (pIDX->m_cst_speeds[a] < 6e-6) {
170 tide += pIDX->m_work_buffer[a] *
171 cos(pIDX->m_cst_speeds[a] * ((long)(t - pIDX->epoch) +
172 pIDX->pref_sta_data->meridian) +
173 pIDX->m_cst_epochs[a][pIDX->epoch_year - pIDX->first_year] -
174 pIDX->pref_sta_data->epoch[a]);
175 }
176 }
177
178 return tide;
179}
180
181/* If offsets are in effect, interpolate the 'corrected' denormalized
182 * tide. The normalized is derived from this, instead of the other way
183 * around, because the application of height offsets requires the
184 * denormalized tide. */
185double time2asecondary(time_t t, IDX_entry *pIDX) {
186 time_t tadj = t + pIDX->station_tz_offset;
187
188 /* Get rid of the normals. */
189 if (!(pIDX->have_offsets)) return time2atide(tadj, pIDX);
190
191 {
192 /* Intervalwidth of 14 (was originally 13) failed on this input:
193 * -location Dublon -hloff +0.0001 -gstart 1997:09:10:00:00 -raw
194 * 1997:09:15:00:00
195 */
196#define intervalwidth 15
197#define stretchfactor 3
198
199 static time_t lowtime = 0, hightime = 0;
200 static double lowlvl, highlvl; /* Normalized tide levels for MIN, MAX */
201 time_t T; /* Adjusted t */
202 double S, Z, HI, HS, magicnum;
203 time_t interval = 3600 * intervalwidth;
204 long difflow, diffhigh;
205 int badlowflag = 0, badhighflag = 0;
206
207 /* Algorithm by Jean-Pierre Lapointe (scipur@collegenotre-dame.qc.ca) */
208 /* as interpreted, munged, and implemented by DWF */
209
210 /* This is the initial guess (average of time offsets) */
211 // T = t - (httimeoff + lttimeoff) / 2;
212 T = tadj - (pIDX->IDX_ht_time_off * 60 + pIDX->IDX_lt_time_off * 60) / 2;
213 /* The usage of an estimate of mean tide level here is to correct
214 * for seasonal changes in tide level. Previously I had simply
215 * used the zero of the tide function as the mean, but this gave bad results
216 * around summer and winter for locations with large seasonal variations. */
217 // printf("-----time2asecondary %ld %ld %d %d\n", t, T,
218 // pIDX->IDX_ht_time_off ,pIDX->IDX_lt_time_off);
219
220 Z = time2mean(T, pIDX);
221 S = time2tide(T, pIDX) - Z;
222
223 /* Find MAX and MIN. I use the highest high tide and the lowest
224 * low tide over a 26 hour period, but I allow the interval to
225 * stretch a lot if necessary to avoid creating discontinuities. The
226 * heuristic used is not perfect but will hopefully be good
227 * enough.
228 *
229 * It is an assumption in the algorithm that the tide level will
230 * be above the mean tide level for MAX and below it for MIN. A
231 * changeover occurs at mean tide level. It would be nice to
232 * always use the two tides that immediately bracket T and to put
233 * the changeover at mid tide instead of always at mean tide
234 * level, since this would eliminate much of the inaccuracy.
235 * Unfortunately if you change the location of the changeover it
236 * causes the tide function to become discontinuous.
237 *
238 * Now that I'm using time2mean, the changeover does move, but so
239 * slowly that it makes no difference.
240 */
241
242 if (lowtime < T)
243 difflow = T - lowtime;
244 else
245 difflow = lowtime - T;
246 if (hightime < T)
247 diffhigh = T - hightime;
248 else
249 diffhigh = hightime - T;
250
251 /* Update MIN? */
252 if (difflow > interval * stretchfactor) badlowflag = 1;
253 if (badlowflag || (difflow > interval && S > 0)) {
254 time_t tt;
255 double tl;
256 tt = T - interval;
257 next_big_event(&tt, pIDX);
258 lowlvl = time2tide(tt, pIDX);
259 lowtime = tt;
260 while (tt < T + interval) {
261 next_big_event(&tt, pIDX);
262 tl = time2tide(tt, pIDX);
263 if (tl < lowlvl && tt < T + interval) {
264 lowlvl = tl;
265 lowtime = tt;
266 }
267 }
268 }
269 /* Update MAX? */
270 if (diffhigh > interval * stretchfactor) badhighflag = 1;
271 if (badhighflag || (diffhigh > interval && S < 0)) {
272 time_t tt;
273 double tl;
274 tt = T - interval;
275 next_big_event(&tt, pIDX);
276 highlvl = time2tide(tt, pIDX);
277 hightime = tt;
278 while (tt < T + interval) {
279 next_big_event(&tt, pIDX);
280 tl = time2tide(tt, pIDX);
281 if (tl > highlvl && tt < T + interval) {
282 highlvl = tl;
283 hightime = tt;
284 }
285 }
286 }
287
288#if 0
289 /* UNFORTUNATELY there are times when the tide level NEVER CROSSES
290 * THE MEAN for extended periods of time. ARRRGH! */
291 if (lowlvl >= 0.0)
292 lowlvl = -1.0;
293 if (highlvl <= 0.0)
294 highlvl = 1.0;
295#endif
296 /* Now that I'm using time2mean, I should be guaranteed to get
297 * an appropriate low and high. */
298
299 /* Improve the initial guess. */
300 if (S > 0)
301 magicnum = 0.5 * S / fabs(highlvl - Z);
302 else
303 magicnum = 0.5 * S / fabs(lowlvl - Z);
304 // T = T - magicnum * (httimeoff - lttimeoff);
305 T = T - (time_t)(magicnum * ((pIDX->IDX_ht_time_off * 60) -
306 (pIDX->IDX_lt_time_off * 60)));
307 HI = time2tide(T, pIDX);
308
309 // Correct the amplitude offsets for BOGUS knot^2 units
310 double ht_off, lt_off;
311 if (pIDX->pref_sta_data->have_BOGUS) {
312 ht_off = pIDX->IDX_ht_off *
313 pIDX->IDX_ht_off; // Square offset in kts to adjust for kts^2
314 lt_off = pIDX->IDX_lt_off * pIDX->IDX_lt_off;
315 } else {
316 ht_off = pIDX->IDX_ht_off;
317 lt_off = pIDX->IDX_lt_off;
318 }
319
320 /* Denormalize and apply the height offsets. */
321 HI = BOGUS_amplitude(HI, pIDX) + pIDX->pref_sta_data->DATUM;
322 {
323 double RH = 1.0, RL = 1.0, HH = 0.0, HL = 0.0;
324 RH = pIDX->IDX_ht_mpy;
325 HH = ht_off;
326 RL = pIDX->IDX_lt_mpy;
327 HL = lt_off;
328
329 /* I patched the usage of RH and RL to avoid big ugly
330 * discontinuities when they are not equal. -- DWF */
331
332 HS = HI * ((RH + RL) / 2 + (RH - RL) * magicnum) + (HH + HL) / 2 +
333 (HH - HL) * magicnum;
334 }
335
336 return HS;
337 }
338}
339
340/*
341 * We will need a function for tidal height as a function of time
342 * which is continuous (and has continuous first and second derivatives)
343 * for all times.
344 *
345 * Since the epochs & multipliers for the tidal constituents change
346 * with the year, the regular time2tide(t) function has small
347 * discontinuities at new years. These discontinuities really
348 * fry the fast root-finders.
349 *
350 * We will eliminate the new-years discontinuities by smoothly
351 * interpolating (or "blending") between the tides calculated with one
352 * year's coefficients, and the tides calculated with the next year's
353 * coefficients.
354 *
355 * i.e. for times near a new years, we will "blend" a tide
356 * as follows:
357 *
358 * tide(t) = tide(year-1, t)
359 * + w((t - t0) / Tblend) * (tide(year,t) - tide(year-1,t))
360 *
361 * Here: t0 is the time of the nearest new-year.
362 * tide(year-1, t) is the tide calculated using the coefficients
363 * for the year just preceding t0.
364 * tide(year, t) is the tide calculated using the coefficients
365 * for the year which starts at t0.
366 * Tblend is the "blending" time scale. This is set by
367 * the macro TIDE_BLEND_TIME, currently one hour.
368 * w(x) is the "blending function", whice varies smoothly
369 * from 0, for x < -1 to 1 for x > 1.
370 *
371 * Derivatives of the blended tide can be evaluated in terms of derivatives
372 * of w(x), tide(year-1, t), and tide(year, t). The blended tide is
373 * guaranteed to have as many continuous derivatives as w(x). */
374
375/* time2dt_tide(time_t t, int n)
376 *
377 * Calculate nth time derivative the normalized tide.
378 *
379 * Notes: This function does not check for changes in year.
380 * This is important to our algorithm, since for times near
381 * new years, we interpolate between the tides calculated
382 * using one years coefficients, and the next years coefficients.
383 *
384 * Except for this detail, time2dt_tide(t,0) should return a value
385 * identical to time2tide(t).
386 */
387double _time2dt_tide(time_t t, int deriv, IDX_entry *pIDX) {
388 double dt_tide = 0.0;
389 int a, b;
390 double term, tempd;
391
392 tempd = M_PI / 2.0 * deriv;
393 for (a = 0; a < pIDX->num_csts; a++) {
394 term = pIDX->m_work_buffer[a] *
395 cos(tempd +
396 pIDX->m_cst_speeds[a] *
397 ((long)(t - pIDX->epoch) + pIDX->pref_sta_data->meridian) +
398 pIDX->m_cst_epochs[a][pIDX->epoch_year - pIDX->first_year] -
399 pIDX->pref_sta_data->epoch[a]);
400 for (b = deriv; b > 0; b--) term *= pIDX->m_cst_speeds[a];
401 dt_tide += term;
402 }
403 return dt_tide;
404}
405
406/* blend_weight (double x, int deriv)
407 *
408 * Returns the value nth derivative of the "blending function" w(x):
409 *
410 * w(x) = 0, for x <= -1
411 *
412 * w(x) = 1/2 + (15/16) x - (5/8) x^3 + (3/16) x^5,
413 * for -1 < x < 1
414 *
415 * w(x) = 1, for x >= 1
416 *
417 * This function has the following desirable properties:
418 *
419 * w(x) is exactly either 0 or 1 for |x| > 1
420 *
421 * w(x), as well as its first two derivatives are continuous for all x.
422 */
423static double blend_weight(double x, int deriv) {
424 double x2 = x * x;
425
426 if (x2 >= 1.0) return deriv == 0 && x > 0.0 ? 1.0 : 0.0;
427
428 switch (deriv) {
429 case 0:
430 return ((3.0 * x2 - 10.0) * x2 + 15.0) * x / 16.0 + 0.5;
431 case 1:
432 return ((x2 - 2.0) * x2 + 1.0) * (15.0 / 16.0);
433 case 2:
434 return (x2 - 1.0) * x * (15.0 / 4.0);
435 }
436 return (0); // mgh+ to get rid of compiler warning
437}
438
439/*
440 * This function does the actual "blending" of the tide
441 * and its derivatives.
442 */
443double blend_tide(time_t t, unsigned int deriv, int first_year, double blend,
444 IDX_entry *pIDX) {
445 double fl[TIDE_MAX_DERIV + 1];
446 double fr[TIDE_MAX_DERIV + 1];
447 double *fp = fl;
448 double w[TIDE_MAX_DERIV + 1];
449 double fact = 1.0;
450 double f;
451 unsigned int n;
452
453 /*
454 * If we are already happy_new_year()ed into one of the two years
455 * of interest, compute that years tide values first.
456 */
457 int year = yearoftimet(t);
458 if (year == first_year + 1)
459 fp = fr;
460 else if (year != first_year)
461 happy_new_year(pIDX, first_year);
462 for (n = 0; n <= deriv; n++) fp[n] = _time2dt_tide(t, n, pIDX);
463
464 /*
465 * Compute tide values for the other year of interest,
466 * and the needed values of w(x) and its derivatives.
467 */
468 if (fp == fl) {
469 happy_new_year(pIDX, first_year + 1);
470 fp = fr;
471 } else {
472 happy_new_year(pIDX, first_year);
473 fp = fl;
474 }
475 for (n = 0; n <= deriv; n++) {
476 fp[n] = _time2dt_tide(t, n, pIDX);
477 w[n] = blend_weight(blend, n);
478 }
479
480 /*
481 * Do the blending.
482 */
483
484 f = fl[deriv];
485 for (n = 0; n <= deriv; n++) {
486 f += fact * w[n] * (fr[deriv - n] - fl[deriv - n]);
487 fact *= (double)(deriv - n) / (n + 1) * (1.0 / TIDE_BLEND_TIME);
488 }
489 printf(" %ld %g %g %g %g\n", (long)t, blend, fr[0], fl[0], f);
490 return f;
491}
492
493static double time2dt_tide(time_t t, int deriv, IDX_entry *pIDX) {
494 int new_year;
495 int yott = yearoftimet(t);
496 new_year = yott;
497
498 /* Make sure our values of next_epoch and epoch are up to date. */
499 if (new_year != s_this_year) {
500 if (new_year + 1 < pIDX->first_year + pIDX->num_epochs) {
501 set_epoch(pIDX, new_year + 1);
502 s_next_epoch = pIDX->epoch;
503 } else
504 s_next_epoch = TIDE_BAD_TIME;
505
506 happy_new_year(pIDX, s_this_year = new_year);
507 s_this_epoch = pIDX->epoch;
508 }
509
510 /*
511 * If we're close to either the previous or the next
512 * new years we must blend the two years tides.
513 */
514 if (t - s_this_epoch <= TIDE_BLEND_TIME && s_this_year > pIDX->first_year)
515 return blend_tide(t, deriv, s_this_year - 1,
516 (double)(t - s_this_epoch) / TIDE_BLEND_TIME, pIDX);
517 else if (s_next_epoch - t <= TIDE_BLEND_TIME &&
518 s_this_year + 1 < pIDX->first_year + pIDX->num_epochs)
519 return blend_tide(t, deriv, s_this_year,
520 -(double)(s_next_epoch - t) / TIDE_BLEND_TIME, pIDX);
521
522 /*
523 * Else, we're far enough from newyears to ignore the blending.
524 */
525 if (pIDX->epoch_year != new_year) happy_new_year(pIDX, new_year);
526
527 return _time2dt_tide(t, deriv, pIDX);
528}
529
530/* Figure out max amplitude over all the years in the node factors table. */
531/* This function by Geoffrey T. Dairiki */
532void figure_max_amplitude(IDX_entry *pIDX) {
533 int i, a;
534
535 if (pIDX->max_amplitude == 0.0) {
536 for (i = 0; i < pIDX->num_nodes; i++) {
537 double year_amp = 0.0;
538
539 for (a = 0; a < pIDX->num_csts; a++)
540 year_amp += pIDX->pref_sta_data->amplitude[a] * pIDX->m_cst_nodes[a][i];
541 if (year_amp > pIDX->max_amplitude) pIDX->max_amplitude = year_amp;
542 }
543 }
544}
545
546/* Figure out normalized multipliers for constituents for a particular year. */
547void figure_multipliers(IDX_entry *pIDX, int year) {
548 int a;
549
550 figure_max_amplitude(pIDX);
551 for (a = 0; a < pIDX->num_csts; a++) {
552 pIDX->m_work_buffer[a] = pIDX->pref_sta_data->amplitude[a] *
553 pIDX->m_cst_nodes[a][year - pIDX->first_year] /
554 pIDX->max_amplitude; // BOGUS_amplitude?
555 }
556}
557
558/* This idiotic function is needed by the new tm2gmt. */
559#define compare_int(a, b) (((int)(a)) - ((int)(b)))
560int compare_tm(struct tm *a, struct tm *b) {
561 int temp;
562 /* printf ("A is %d:%d:%d:%d:%d:%d B is %d:%d:%d:%d:%d:%d\n",
563 * a->tm_year+1900, a->tm_mon+1, a->tm_mday, a->tm_hour,
564 * a->tm_min, a->tm_sec,
565 * b->tm_year+1900, b->tm_mon+1, b->tm_mday, b->tm_hour,
566 * b->tm_min, b->tm_sec); */
567
568 temp = compare_int(a->tm_year, b->tm_year);
569 if (temp) return temp;
570 temp = compare_int(a->tm_mon, b->tm_mon);
571 if (temp) return temp;
572 temp = compare_int(a->tm_mday, b->tm_mday);
573 if (temp) return temp;
574 temp = compare_int(a->tm_hour, b->tm_hour);
575 if (temp) return temp;
576 temp = compare_int(a->tm_min, b->tm_min);
577 if (temp) return temp;
578 return compare_int(a->tm_sec, b->tm_sec);
579}
580
581/* Convert a struct tm in GMT back to a time_t. isdst is ignored, since
582 * it never should have been needed by mktime in the first place.
583 */
584time_t tm2gmt(struct tm *ht) {
585 time_t guess, newguess, thebit;
586 int loopcounter, compare;
587 struct tm *gt;
588
589 guess = 0;
590 loopcounter = (sizeof(time_t) * 8) - 1;
591 thebit = ((time_t)1) << (loopcounter - 1);
592
593 /* For simplicity, I'm going to insist that the time_t we want is
594 * positive. If time_t is signed, skip the sign bit.
595 */
596 if ((signed long)thebit < (time_t)(0)) {
597 /* You can't just shift thebit right because it propagates the sign bit. */
598 loopcounter--;
599 thebit = ((time_t)1) << (loopcounter - 1);
600 }
601
602 for (; loopcounter; loopcounter--) {
603 newguess = guess | thebit;
604 gt = gmtime(&newguess);
605 if (NULL != gt) {
606 compare = compare_tm(gt, ht);
607 if (compare <= 0) guess = newguess;
608 }
609 thebit >>= 1;
610 }
611
612 return guess;
613}
614
615static int yearoftimet(time_t t) { return ((gmtime(&t))->tm_year) + 1900; }
616
617/* Calculate time_t of the epoch. */
618static void set_epoch(IDX_entry *pIDX, int year) {
619 struct tm ht;
620
621 ht.tm_year = year - 1900;
622 ht.tm_sec = ht.tm_min = ht.tm_hour = ht.tm_mon = 0;
623 ht.tm_mday = 1;
624 pIDX->epoch = tm2gmt(&ht);
625}
626
627/* Re-initialize for a different year */
628static void happy_new_year(IDX_entry *pIDX, int new_year) {
629 pIDX->epoch_year = new_year;
630 figure_multipliers(pIDX, new_year);
631 set_epoch(pIDX, new_year);
632}
633
634// TCMgr Implementation
635TCMgr::TCMgr() {}
636
637TCMgr::~TCMgr() { PurgeData(); }
638
639void TCMgr::PurgeData() {
640 m_Combined_IDX_array.clear();
641
642 // Delete all the data sources
643 m_source_array.Clear();
644}
645
646TC_Error_Code TCMgr::LoadDataSources(std::vector<std::string> &sources) {
647 PurgeData();
648
649 // Take a copy of dataset file name array
650 m_sourcefile_array.clear();
651 m_sourcefile_array = sources;
652
653 int num_IDX = 0;
654
655 for (auto src : sources) {
656 TCDataSource *s = new TCDataSource;
657 TC_Error_Code r = s->LoadData(src);
658 if (r != TC_NO_ERROR) {
659 wxString msg;
660 msg.Printf(" Error loading Tide/Currect data source %s ", src.c_str());
661 if (r == TC_FILE_NOT_FOUND)
662 msg += "Error Code: TC_FILE_NOT_FOUND";
663 else {
664 wxString msg1;
665 msg1.Printf("Error code: %d", r);
666 msg += msg1;
667 }
668 wxLogMessage(msg);
669 delete s;
670 } else {
671 m_source_array.Add(s);
672
673 for (int k = 0; k < s->GetMaxIndex(); k++) {
674 IDX_entry *pIDX = s->GetIndexEntry(k);
675 pIDX->IDX_rec_num = num_IDX;
676 num_IDX++;
677 m_Combined_IDX_array.push_back(pIDX);
678 }
679 }
680 }
681
682 bTCMReady = true;
683
684 if (m_Combined_IDX_array.empty())
685 OCPNMessageBox(
686 NULL, _("It seems you have no tide/current harmonic data installed."),
687 _("OpenCPN Info"), wxOK | wxCENTER);
688
689 ScrubCurrentDepths();
690 return TC_NO_ERROR;
691}
692
693void TCMgr::ScrubCurrentDepths() {
694 // Process Current stations reporting values at multiple depths
695 // Identify and mark the shallowest record, as being most usable to OCPN
696 // users
697
698 WX_DECLARE_STRING_HASH_MAP(int, currentDepth_index_hash);
699
700 currentDepth_index_hash hash1;
701
702 for (int i = 1; i < Get_max_IDX() + 1; i++) {
703 IDX_entry *a = (IDX_entry *)GetIDX_entry(i);
704 if (a->IDX_type == 'C') {
705 if (a->current_depth > 0) {
706 int depth_a = a->current_depth;
707
708 // We formulate the hash map with geo-location as the keys
709 // Using "doubles" as hashmap key values is dangerous, especially
710 // cross-platform So, we a printf-ed string of lat/lon for hash key,
711 // This is relatively inefficient. but tolerable in this little used
712 // method.
713
714 wxString key1;
715 key1.Printf("%10.6f %10.6f", a->IDX_lat, a->IDX_lon);
716
717 currentDepth_index_hash::iterator it = hash1.find(key1);
718 if (it == hash1.end()) {
719 // Key not found, needs to be added
720 hash1[key1] = i;
721 } else {
722 // Check the depth value at the referenced index
723 // if less than the current depth, replace the hashmap value
724 IDX_entry *b = (IDX_entry *)GetIDX_entry(it->second);
725 std::string bName(b->IDX_station_name);
726 int depth_b = b->current_depth;
727 if (depth_a < depth_b) {
728 hash1[key1] = i;
729 b->b_skipTooDeep = 1; // mark deeper index to skip display
730 } else {
731 a->b_skipTooDeep = 1; // mark deeper index to skip display
732 }
733 }
734 }
735 }
736 }
737}
738
739const IDX_entry *TCMgr::GetIDX_entry(int index) const {
740 if ((unsigned int)index < m_Combined_IDX_array.size())
741 return m_Combined_IDX_array[index];
742 else
743 return NULL;
744}
745
746bool TCMgr::GetTideOrCurrent(time_t t, int idx, float &tcvalue, float &dir) {
747 // Return a sensible value of 0,0 by default
748 dir = 0;
749 tcvalue = 0;
750
751 // Load up this location data
752 IDX_entry *pIDX = m_Combined_IDX_array[idx]; // point to the index entry
753
754 if (!pIDX) {
755 dir = 0;
756 tcvalue = 0;
757 return false;
758 }
759
760 if (!pIDX->IDX_Useable) {
761 dir = 0;
762 tcvalue = 0;
763 return (false); // no error, but unuseable
764 }
765
766 if (pIDX->pDataSource) {
767 if (pIDX->pDataSource->LoadHarmonicData(pIDX) != TC_NO_ERROR) return false;
768 }
769
770 pIDX->max_amplitude = 0.0; // Force multiplier re-compute
771 int yott = yearoftimet(t);
772
773 happy_new_year(pIDX, yott); // Calculate new multipliers
774
775 // Finally, calculate the tide/current
776
777 double level = time2asecondary(t + (00 * 60), pIDX); // 300. 240
778 if (level >= 0)
779 dir = pIDX->IDX_flood_dir;
780 else
781 dir = pIDX->IDX_ebb_dir;
782
783 tcvalue = level;
784
785 return (true); // Got it!
786}
787
788bool TCMgr::GetTideOrCurrentMeters(time_t t, int idx, float &tcvalue,
789 float &dir) {
790 float val_from_index;
791 bool bret = GetTideOrCurrent(t, idx, val_from_index, dir);
792 if (!bret) return false;
793
794 // Load up this location data
795 IDX_entry *pIDX = m_Combined_IDX_array[idx]; // point to the index entry
796 Station_Data *pmsd = pIDX->pref_sta_data;
797 if (pmsd) {
798 // Convert from station units to meters
799 int unit_c = TCDataFactory::findunit(pmsd->unit);
800 if (unit_c >= 0) {
801 val_from_index *= TCDataFactory::known_units[unit_c].conv_factor;
802 }
803 tcvalue = val_from_index;
804 return true;
805 } else
806 return false;
807}
808
809extern wxDateTime gTimeSource;
810
811bool TCMgr::GetTideOrCurrent15(time_t t_d, int idx, float &tcvalue, float &dir,
812 bool &bnew_val) {
813 int ret;
814 IDX_entry *pIDX = m_Combined_IDX_array[idx]; // point to the index entry
815
816 if (!pIDX) {
817 dir = 0;
818 tcvalue = 0;
819 return false;
820 }
821
822 // Figure out this computer timezone minute offset
823 wxDateTime this_now = gTimeSource; // wxDateTime::Now();
824 if (this_now.IsValid() == false) this_now = wxDateTime::Now();
825 wxDateTime this_gmt = this_now.ToGMT();
826 wxTimeSpan diff = this_gmt.Subtract(this_now);
827 int diff_mins = diff.GetMinutes();
828
829 int station_offset = pIDX->IDX_time_zone;
830 if (this_now.IsDST()) station_offset += 60;
831 int corr_mins = station_offset - diff_mins;
832
833 wxDateTime today_00 = this_now;
834 today_00.ResetTime();
835 int t_today_00 = today_00.GetTicks();
836 int t_today_00_at_station = t_today_00 - (corr_mins * 60);
837
838 int t_at_station =
839 this_gmt.GetTicks() - (station_offset * 60) + (corr_mins * 60);
840
841 int t_mins = (t_at_station - t_today_00_at_station) / 60;
842 int t_15s = t_mins / 15;
843
844 if (pIDX->Valid15) // valid data available
845 {
846 int tref1 = t_today_00_at_station + t_15s * 15 * 60;
847 if (tref1 == pIDX->Valid15) {
848 tcvalue = pIDX->Value15;
849 dir = pIDX->Dir15;
850 bnew_val = false;
851 return pIDX->Ret15;
852 } else {
853 int tref = t_today_00_at_station + t_15s * 15 * 60;
854 ret = GetTideOrCurrent(tref, idx, tcvalue, dir);
855
856 pIDX->Valid15 = tref;
857 pIDX->Value15 = tcvalue;
858 pIDX->Dir15 = dir;
859 pIDX->Ret15 = !(ret == 0);
860 bnew_val = true;
861
862 return !(ret == 0);
863 }
864 }
865
866 else {
867 int tref = t_today_00_at_station + t_15s * 15 * 60;
868 ret = GetTideOrCurrent(tref, idx, tcvalue, dir);
869
870 pIDX->Valid15 = tref;
871 pIDX->Value15 = tcvalue;
872 pIDX->Dir15 = dir;
873 pIDX->Ret15 = !(ret == 0);
874 bnew_val = true;
875 }
876
877 return !(ret == 0);
878}
879
880bool TCMgr::GetTideFlowSens(time_t t, int sch_step, int idx, float &tcvalue_now,
881 float &tcvalue_prev, bool &w_t) {
882 // Return a sensible value of 0 by default
883 tcvalue_now = 0;
884 tcvalue_prev = 0;
885 w_t = false;
886
887 // Load up this location data
888 IDX_entry *pIDX = m_Combined_IDX_array[idx]; // point to the index entry
889
890 if (!pIDX) return false;
891
892 if (!pIDX->IDX_Useable) return false; // no error, but unuseable
893
894 if (pIDX->pDataSource) {
895 if (pIDX->pDataSource->LoadHarmonicData(pIDX) != TC_NO_ERROR) return false;
896 }
897
898 pIDX->max_amplitude = 0.0; // Force multiplier re-compute
899 int yott = yearoftimet(t);
900 happy_new_year(pIDX, yott); // Force new multipliers
901
902 // Finally, process the tide flow sens
903
904 tcvalue_now = time2asecondary(t, pIDX);
905 tcvalue_prev = time2asecondary(t + sch_step, pIDX);
906
907 w_t =
908 tcvalue_now > tcvalue_prev; // w_t = true --> flood , w_t = false --> ebb
909
910 return true;
911}
912
913void TCMgr::GetHightOrLowTide(time_t t, int sch_step_1, int sch_step_2,
914 float tide_val, bool w_t, int idx, float &tcvalue,
915 time_t &tctime) {
916 // Return a sensible value of 0,0 by default
917 tcvalue = 0;
918 tctime = t;
919
920 // Load up this location data
921 IDX_entry *pIDX = m_Combined_IDX_array[idx]; // point to the index entry
922
923 if (!pIDX) return;
924
925 if (!pIDX->IDX_Useable) return; // no error, but unuseable
926
927 if (pIDX->pDataSource) {
928 if (pIDX->pDataSource->LoadHarmonicData(pIDX) != TC_NO_ERROR) return;
929 }
930
931 // Is the cache data reasonably fresh?
932 if (abs(t - pIDX->recent_highlow_calc_time) < 60) {
933 if (w_t) {
934 tcvalue = pIDX->recent_high_level;
935 tctime = pIDX->recent_high_time;
936 } else {
937 tcvalue = pIDX->recent_low_level;
938 tctime = pIDX->recent_low_time;
939 }
940 return;
941 }
942
943 pIDX->max_amplitude = 0.0; // Force multiplier re-compute
944 int yott = yearoftimet(t);
945 happy_new_year(pIDX, yott);
946
947 // Finally, calculate the Hight and low tides
948 double newval = tide_val;
949 double oldval = (w_t) ? newval - 1 : newval + 1;
950 int j = 0;
951 int k = 0;
952 int ttt = 0;
953 while ((newval > oldval) == w_t) // searching each ten minute
954 {
955 j++;
956 oldval = newval;
957 ttt = t + (sch_step_1 * j);
958 newval = time2asecondary(ttt, pIDX);
959 }
960 oldval = (w_t) ? newval - 1 : newval + 1;
961 while ((newval > oldval) == w_t) // searching back each minute
962 {
963 oldval = newval;
964 k++;
965 ttt = t + (sch_step_1 * j) - (sch_step_2 * k);
966 newval = time2asecondary(ttt, pIDX);
967 }
968 tcvalue = newval;
969 tctime = ttt + sch_step_2;
970
971 // Cache the data
972 pIDX->recent_highlow_calc_time = t;
973 if (w_t) {
974 pIDX->recent_high_level = newval;
975 pIDX->recent_high_time = tctime;
976 } else {
977 pIDX->recent_low_level = newval;
978 pIDX->recent_low_time = tctime;
979 }
980}
981
982int TCMgr::GetStationTimeOffset(IDX_entry *pIDX) { return pIDX->IDX_time_zone; }
983
984double TCMgr::GetStationLat(IDX_entry *pIDX) { return pIDX->IDX_lat; }
985
986double TCMgr::GetStationLon(IDX_entry *pIDX) { return pIDX->IDX_lon; }
987
988int TCMgr::GetNextBigEvent(time_t *tm, int idx) {
989 float tcvalue[1];
990 float dir;
991 bool ret;
992 double p, q;
993 int flags = 0, slope = 0;
994 ret = GetTideOrCurrent(*tm, idx, tcvalue[0], dir);
995 p = tcvalue[0];
996 *tm += 60;
997 ret = GetTideOrCurrent(*tm, idx, tcvalue[0], dir);
998 q = tcvalue[0];
999 *tm += 60;
1000 if (p < q) slope = 1;
1001 while (1) {
1002 if ((slope == 1 && q < p) || (slope == 0 && p < q)) {
1003 /* Tide event */
1004 flags |= (1 << slope);
1005 }
1006 if (flags) {
1007 *tm -= 60;
1008 if (flags < 4) *tm -= 60;
1009 return flags;
1010 }
1011 p = q;
1012 ret = GetTideOrCurrent(*tm, idx, tcvalue[0], dir);
1013 if (!ret) return 0; // Harmonics file error, data not available
1014 q = tcvalue[0];
1015 *tm += 60;
1016 }
1017}
1018
1019std::wstring TCMgr::GetTidalEventStr(int station_id, wxDateTime ref_dt,
1020 double lat, double lon, int dt_type) {
1021 IDX_entry *idx = (IDX_entry *)GetIDX_entry(station_id);
1022 time_t dtmtt = ref_dt.FromUTC().GetTicks();
1023 int event = GetNextBigEvent(&dtmtt, station_id);
1024 wxDateTime event_dt = wxDateTime(dtmtt).MakeUTC();
1025
1026 std::wstring event_str;
1027 if (event == 1) {
1028 event_str = _("LW").ToStdWstring();
1029 } else if (event == 2) {
1030 event_str = _("HW").ToStdWstring();
1031 } else {
1032 event_str = _("Unavailable").ToStdWstring();
1033 }
1034
1035 if (event > 0) {
1036 event_str.append(L": ");
1037 event_str.append(
1038 toUsrDateTime(event_dt, dt_type, lon).FormatISOCombined(' '));
1039 }
1040
1041 return event_str;
1042}
1043
1044std::map<double, const IDX_entry *> TCMgr::GetStationsForLL(double xlat,
1045 double xlon) const {
1046 std::map<double, const IDX_entry *> x;
1047 const IDX_entry *lpIDX;
1048
1049 for (int j = 1; j < Get_max_IDX() + 1; j++) {
1050 lpIDX = GetIDX_entry(j);
1051 char type = lpIDX->IDX_type;
1052 wxString locnx(lpIDX->IDX_station_name, wxConvUTF8);
1053
1054 if (type == 't' || type == 'T') {
1055 double brg, dist;
1056 DistanceBearingMercator(xlat, xlon, lpIDX->IDX_lat, lpIDX->IDX_lon, &brg,
1057 &dist);
1058 x.emplace(std::make_pair(dist, lpIDX));
1059 }
1060 }
1061
1062 return x;
1063}
1064
1065int TCMgr::GetStationIDXbyName(const wxString &prefix, double xlat,
1066 double xlon) const {
1067 const IDX_entry *lpIDX;
1068 int jx = 0;
1069 wxString locn;
1070 double distx = 100000.;
1071
1072 int jmax = Get_max_IDX();
1073
1074 for (int j = 1; j < Get_max_IDX() + 1; j++) {
1075 lpIDX = GetIDX_entry(j);
1076 char type = lpIDX->IDX_type; // Entry "TCtcIUu" identifier
1077 wxString locnx(lpIDX->IDX_station_name, wxConvUTF8);
1078
1079 if (((type == 't') || (type == 'T')) // only Tides
1080 && (locnx.StartsWith(prefix))) {
1081 double brg, dist;
1082 DistanceBearingMercator(xlat, xlon, lpIDX->IDX_lat, lpIDX->IDX_lon, &brg,
1083 &dist);
1084 if (dist < distx) {
1085 distx = dist;
1086 jx = j;
1087 }
1088 }
1089 } // end for loop
1090 //} // end if @~~ found in WP
1091 return (jx);
1092}
1093
1094int TCMgr::GetStationIDXbyNameType(const wxString &prefix, double xlat,
1095 double xlon, char type) const {
1096 const IDX_entry *lpIDX;
1097 int jx = 0;
1098 wxString locn;
1099 double distx = 100000.;
1100
1101 // if (prp->m_MarkName.Find("@~~") != wxNOT_FOUND) {
1102 // tide_form = prp->m_MarkName.Mid(prp->m_MarkName.Find("@~~")+3);
1103 int jmax = Get_max_IDX();
1104
1105 for (int j = 1; j < Get_max_IDX() + 1; j++) {
1106 lpIDX = GetIDX_entry(j);
1107 char typep = lpIDX->IDX_type; // Entry "TCtcIUu" identifier
1108 wxString locnx(lpIDX->IDX_station_name, wxConvUTF8);
1109
1110 if ((type == typep) && (locnx.StartsWith(prefix))) {
1111 double brg, dist;
1112 DistanceBearingMercator(xlat, xlon, lpIDX->IDX_lat, lpIDX->IDX_lon, &brg,
1113 &dist);
1114 if (dist < distx) {
1115 distx = dist;
1116 jx = j;
1117 }
1118 }
1119 } // end for loop
1120 return (jx);
1121}
1122
1123/* $Id: tide_db_default.h 1092 2006-11-16 03:02:42Z flaterco $ */
1124
1125// #include "tcd.h"
1126
1127/*****************************************************************************
1128 *
1129 * DISTRIBUTION STATEMENT
1130 *
1131 * This source file is unclassified, distribution unlimited, public
1132 * domain. It is distributed in the hope that it will be useful, but
1133 * WITHOUT ANY WARRANTY; without even the implied warranty of
1134 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1135 *
1136 ******************************************************************************/
1137
1138#define DEFAULT_HEADER_SIZE 4096
1139#define DEFAULT_NUMBER_OF_RECORDS 0
1140#define DEFAULT_LEVEL_UNIT_TYPES 5
1141#define DEFAULT_DIR_UNIT_TYPES 3
1142#define DEFAULT_RESTRICTION_TYPES 2
1143#define DEFAULT_RESTRICTION_BITS 4
1144#define DEFAULT_TZFILES 406
1145#define DEFAULT_TZFILE_BITS 10
1146#define DEFAULT_COUNTRIES 240
1147#define DEFAULT_COUNTRY_BITS 9
1148#define DEFAULT_DATUM_TYPES 61
1149#define DEFAULT_DATUM_BITS 7
1150#define DEFAULT_LEGALESES 1
1151#define DEFAULT_LEGALESE_BITS 4
1152#define DEFAULT_SPEED_SCALE 10000000
1153#define DEFAULT_EQUILIBRIUM_SCALE 100
1154#define DEFAULT_NODE_SCALE 10000
1155#define DEFAULT_AMPLITUDE_BITS 19
1156#define DEFAULT_AMPLITUDE_SCALE 10000
1157#define DEFAULT_EPOCH_BITS 16
1158#define DEFAULT_EPOCH_SCALE 100
1159#define DEFAULT_RECORD_TYPE_BITS 4
1160#define DEFAULT_LATITUDE_BITS 25
1161#define DEFAULT_LATITUDE_SCALE 100000
1162#define DEFAULT_LONGITUDE_BITS 26
1163#define DEFAULT_LONGITUDE_SCALE 100000
1164#define DEFAULT_RECORD_SIZE_BITS 16
1165#define DEFAULT_STATION_BITS 18
1166#define DEFAULT_DATUM_OFFSET_BITS 28
1167#define DEFAULT_DATUM_OFFSET_SCALE 10000
1168#define DEFAULT_DATE_BITS 27
1169#define DEFAULT_MONTHS_ON_STATION_BITS 10
1170#define DEFAULT_CONFIDENCE_VALUE_BITS 4
1171#define DEFAULT_NUMBER_OF_CONSTITUENTS_BITS 8
1172#define DEFAULT_TIME_BITS 13
1173#define DEFAULT_LEVEL_ADD_BITS 17
1174#define DEFAULT_LEVEL_ADD_SCALE 1000
1175#define DEFAULT_LEVEL_MULTIPLY_BITS 16
1176#define DEFAULT_LEVEL_MULTIPLY_SCALE 1000
1177#define DEFAULT_DIRECTION_BITS 9
1178#define DEFAULT_CONSTITUENT_SIZE 10
1179#define DEFAULT_LEVEL_UNIT_SIZE 15
1180#define DEFAULT_DIR_UNIT_SIZE 15
1181#define DEFAULT_RESTRICTION_SIZE 30
1182#define DEFAULT_DATUM_SIZE 70
1183#define DEFAULT_LEGALESE_SIZE 70
1184#define DEFAULT_TZFILE_SIZE 30
1185#define DEFAULT_COUNTRY_SIZE 50
1186
1187/* Stuff for inferring constituents (NAVO short duration tide stations). */
1188
1189#define INFERRED_SEMI_DIURNAL_COUNT 10
1190#define INFERRED_DIURNAL_COUNT 10
1191
1192#ifdef __MSVC__
1193#pragma warning(disable : 4305) // conversion loss, double to float
1194#endif
1195
1196const NV_CHAR *inferred_semi_diurnal[INFERRED_SEMI_DIURNAL_COUNT] = {
1197 "N2", "NU2", "MU2", "2N2", "LDA2", "T2", "R2", "L2", "K2", "KJ2"};
1198const NV_CHAR *inferred_diurnal[INFERRED_DIURNAL_COUNT] = {
1199 "OO1", "M1", "J1", "RHO1", "Q1", "2Q1", "P1", "PI1", "PHI1", "PSI1"};
1200NV_FLOAT32 semi_diurnal_coeff[INFERRED_SEMI_DIURNAL_COUNT] = {
1201 .1759, .0341, .0219, .0235, .0066, .0248, .0035, .0251, .1151, .0064};
1202NV_FLOAT32 diurnal_coeff[INFERRED_DIURNAL_COUNT] = {
1203 .0163, .0209, .0297, .0142, .0730, .0097, .1755, .0103, .0076, .0042};
1204
1205/* These represent M2 and O1. */
1206
1207NV_FLOAT32 coeff[2] = {.9085, .3771};
1208
1209/* The following lookup tables are only used for initialization
1210 * purposes and in the pull-down menus in TideEditor. It should be
1211 * possible to change them without breaking existing TCD files. TCD
1212 * files embed their own lookup tables.
1213 */
1214
1215/* Level unit names */
1216
1217NV_CHAR level_unit[DEFAULT_LEVEL_UNIT_TYPES][DEFAULT_LEVEL_UNIT_SIZE] = {
1218 "Unknown", "feet", "meters", "knots", "knots^2"};
1219
1220/* Direction unit names */
1221
1222NV_CHAR dir_unit[DEFAULT_DIR_UNIT_TYPES][DEFAULT_DIR_UNIT_SIZE] = {
1223 "Unknown", "degrees true", "degrees"};
1224
1225/* Restriction types */
1226
1227NV_CHAR restriction[DEFAULT_RESTRICTION_TYPES][DEFAULT_RESTRICTION_SIZE] = {
1228 "Public Domain", "DoD/DoD Contractors Only"};
1229
1230/* Legaleses */
1231
1232NV_CHAR legalese[DEFAULT_LEGALESES][DEFAULT_LEGALESE_SIZE] = {"NULL"};
1233
1234/* # Datum names */
1235
1236NV_CHAR datum[DEFAULT_DATUM_TYPES][DEFAULT_DATUM_SIZE] = {
1237 "Unknown",
1238 "Mean Sea Level",
1239 "Mean Low Water",
1240 "Mean Lower Low Water",
1241 "Mean High Water",
1242 "Mean Higher High Water",
1243 "Mean Lower High Water",
1244 "Mean Higher Low Water",
1245 "Mean Low Water Springs",
1246 "Mean Lower Low Water Springs",
1247 "Mean Low Water Neaps",
1248 "Mean High Water Neaps",
1249 "Mean High Water Springs",
1250 "Mean Higher High Water Springs",
1251 "Indian Spring Low Water",
1252 "Equatorial Spring Low Water",
1253 "Lowest Normal Low Water",
1254 "Lowest Low Water",
1255 "Lowest Possible Low Water",
1256 "Lowest Astronomical Tide",
1257 "International Great Lakes Datum(1955)",
1258 "Lower Low Water, Large Tide",
1259 "Lowest Normal Tide",
1260 "Higher High Water, Large Tide",
1261 "Mean Water Level",
1262 "Higher High Water, Mean Tide",
1263 "Lower Low Water, Mean Tide",
1264 "Mean Tide Level",
1265 "World Geodetic System (1984)",
1266 "National Geodetic Vertical Datum",
1267 "Gulf Coast Low Water Datum",
1268 "Approximate Level of Mean Sea Level",
1269 "Approximate Level of Mean Low Water",
1270 "Approximate Level of Mean Lower Low Water",
1271 "Approximate Level of Mean High Water",
1272 "Approximate Level of Mean Higher High Water",
1273 "Approximate Level of Mean Lower High Water",
1274 "Approximate Level of Mean Higher Low Water",
1275 "Approximate Level of Mean Low Water Springs",
1276 "Approximate Level of Mean Lower Low Water Springs",
1277 "Approximate Level of Mean Low Water Neaps",
1278 "Approximate Level of Mean High Water Neaps",
1279 "Approximate Level of Mean High Water Springs",
1280 "Approximate Level of Mean Higher High Water Springs",
1281 "Approximate Level of Indian Spring Low Water",
1282 "Approximate Level of Equatorial Spring Low Water",
1283 "Approximate Level of Lowest Normal Low Water",
1284 "Approximate Level of Lowest Low Water",
1285 "Approximate Level of Lowest Possible Low Water",
1286 "Approximate Level of Lowest Astronomical Tide",
1287 "Approximate Level of International Great Lakes Datum (1955)",
1288 "Approximate Level of Lower Low Water, Large Tide",
1289 "Approximate Level of Lowest Normal Tide",
1290 "Approximate Level of Higher High Water, Large Tide",
1291 "Approximate Level of Mean Water Level",
1292 "Approximate Level of Higher High Water, Mean Tide",
1293 "Approximate Level of Lower Low Water, Mean Tide",
1294 "Approximate Level of Mean Tide Level",
1295 "Approximate Level of World Geodetic System (1984)",
1296 "Approximate Level of National Geodetic Vertical Datum",
1297 "Approximate Level of Gulf Coast Low Water Datum"};
1298
1299/* # Country names from ISO 3166-1:1999 2-character country code list */
1300
1301NV_CHAR country[DEFAULT_COUNTRIES][DEFAULT_COUNTRY_SIZE] = {
1302 "Unknown",
1303 "Afghanistan",
1304 "Albania",
1305 "Algeria",
1306 "Andorra",
1307 "Angola",
1308 "Anguilla",
1309 "Antarctica",
1310 "Antigua & Barbuda",
1311 "Argentina",
1312 "Armenia",
1313 "Aruba",
1314 "Australia",
1315 "Austria",
1316 "Azerbaijan",
1317 "Bahamas",
1318 "Bahrain",
1319 "Bangladesh",
1320 "Barbados",
1321 "Belarus",
1322 "Belgium",
1323 "Belize",
1324 "Benin",
1325 "Bermuda",
1326 "Bhutan",
1327 "Bolivia",
1328 "Bosnia & Herzegovina",
1329 "Botswana",
1330 "Bouvet Island",
1331 "Brazil",
1332 "Britain (UK)",
1333 "British Indian Ocean Territory",
1334 "Brunei",
1335 "Bulgaria",
1336 "Burkina Faso",
1337 "Burundi",
1338 "Cambodia",
1339 "Cameroon",
1340 "Canada",
1341 "Cape Verde",
1342 "Cayman Islands",
1343 "Central African Rep.",
1344 "Chad",
1345 "Chile",
1346 "China",
1347 "Christmas Island",
1348 "Cocos (Keeling) Islands",
1349 "Colombia",
1350 "Comoros",
1351 "Congo (Dem. Rep.)",
1352 "Congo (Rep.)",
1353 "Cook Islands",
1354 "Costa Rica",
1355 "Cote d'Ivoire",
1356 "Croatia",
1357 "Cuba",
1358 "Cyprus",
1359 "Czech Republic",
1360 "Denmark",
1361 "Djibouti",
1362 "Dominica",
1363 "Dominican Republic",
1364 "East Timor",
1365 "Ecuador",
1366 "Egypt",
1367 "El Salvador",
1368 "Equatorial Guinea",
1369 "Eritrea",
1370 "Estonia",
1371 "Ethiopia",
1372 "Faeroe Islands",
1373 "Falkland Islands",
1374 "Fiji",
1375 "Finland",
1376 "France",
1377 "French Guiana",
1378 "French Polynesia",
1379 "French Southern & Antarctic Lands",
1380 "Gabon",
1381 "Gambia",
1382 "Georgia",
1383 "Germany",
1384 "Ghana",
1385 "Gibraltar",
1386 "Greece",
1387 "Greenland",
1388 "Grenada",
1389 "Guadeloupe",
1390 "Guam",
1391 "Guatemala",
1392 "Guinea",
1393 "Guinea-Bissau",
1394 "Guyana",
1395 "Haiti",
1396 "Heard Island & McDonald Islands",
1397 "Honduras",
1398 "Hong Kong",
1399 "Hungary",
1400 "Iceland",
1401 "India",
1402 "Indonesia",
1403 "Iran",
1404 "Iraq",
1405 "Ireland",
1406 "Israel",
1407 "Italy",
1408 "Jamaica",
1409 "Japan",
1410 "Jordan",
1411 "Kazakhstan",
1412 "Kenya",
1413 "Kiribati",
1414 "Korea (North)",
1415 "Korea (South)",
1416 "Kuwait",
1417 "Kyrgyzstan",
1418 "Laos",
1419 "Latvia",
1420 "Lebanon",
1421 "Lesotho",
1422 "Liberia",
1423 "Libya",
1424 "Liechtenstein",
1425 "Lithuania",
1426 "Luxembourg",
1427 "Macau",
1428 "Macedonia",
1429 "Madagascar",
1430 "Malawi",
1431 "Malaysia",
1432 "Maldives",
1433 "Mali",
1434 "Malta",
1435 "Marshall Islands",
1436 "Martinique",
1437 "Mauritania",
1438 "Mauritius",
1439 "Mayotte",
1440 "Mexico",
1441 "Micronesia",
1442 "Moldova",
1443 "Monaco",
1444 "Mongolia",
1445 "Montserrat",
1446 "Morocco",
1447 "Mozambique",
1448 "Myanmar (Burma)",
1449 "Namibia",
1450 "Nauru",
1451 "Nepal",
1452 "Netherlands",
1453 "Netherlands Antilles",
1454 "New Caledonia",
1455 "New Zealand",
1456 "Nicaragua",
1457 "Niger",
1458 "Nigeria",
1459 "Niue",
1460 "Norfolk Island",
1461 "Northern Mariana Islands",
1462 "Norway",
1463 "Oman",
1464 "Pakistan",
1465 "Palau",
1466 "Palestine",
1467 "Panama",
1468 "Papua New Guinea",
1469 "Paraguay",
1470 "Peru",
1471 "Philippines",
1472 "Pitcairn",
1473 "Poland",
1474 "Portugal",
1475 "Puerto Rico",
1476 "Qatar",
1477 "Reunion",
1478 "Romania",
1479 "Russia",
1480 "Rwanda",
1481 "Samoa (American)",
1482 "Samoa (Western)",
1483 "San Marino",
1484 "Sao Tome & Principe",
1485 "Saudi Arabia",
1486 "Senegal",
1487 "Seychelles",
1488 "Sierra Leone",
1489 "Singapore",
1490 "Slovakia",
1491 "Slovenia",
1492 "Solomon Islands",
1493 "Somalia",
1494 "South Africa",
1495 "South Georgia & the South Sandwich Islands",
1496 "Spain",
1497 "Sri Lanka",
1498 "St Helena",
1499 "St Kitts & Nevis",
1500 "St Lucia",
1501 "St Pierre & Miquelon",
1502 "St Vincent",
1503 "Sudan",
1504 "Suriname",
1505 "Svalbard & Jan Mayen",
1506 "Swaziland",
1507 "Sweden",
1508 "Switzerland",
1509 "Syria",
1510 "Taiwan",
1511 "Tajikistan",
1512 "Tanzania",
1513 "Thailand",
1514 "Togo",
1515 "Tokelau",
1516 "Tonga",
1517 "Trinidad & Tobago",
1518 "Tunisia",
1519 "Turkey",
1520 "Turkmenistan",
1521 "Turks & Caicos Is",
1522 "Tuvalu",
1523 "Uganda",
1524 "Ukraine",
1525 "United Arab Emirates",
1526 "United States",
1527 "Uruguay",
1528 "US minor outlying islands",
1529 "Uzbekistan",
1530 "Vanuatu",
1531 "Vatican City",
1532 "Venezuela",
1533 "Vietnam",
1534 "Virgin Islands (UK)",
1535 "Virgin Islands (US)",
1536 "Wallis & Futuna",
1537 "Western Sahara",
1538 "Yemen",
1539 "Yugoslavia",
1540 "Zambia",
1541 "Zimbabwe"};
1542
1543/* # Time zones extracted from tzdata2002? . */
1544
1545NV_CHAR tzfile[DEFAULT_TZFILES][DEFAULT_TZFILE_SIZE] = {
1546 "Unknown",
1547 ":Africa/Abidjan",
1548 ":Africa/Accra",
1549 ":Africa/Addis_Ababa",
1550 ":Africa/Algiers",
1551 ":Africa/Asmera",
1552 ":Africa/Bamako",
1553 ":Africa/Bangui",
1554 ":Africa/Banjul",
1555 ":Africa/Bissau",
1556 ":Africa/Blantyre",
1557 ":Africa/Brazzaville",
1558 ":Africa/Bujumbura",
1559 ":Africa/Cairo",
1560 ":Africa/Casablanca",
1561 ":Africa/Ceuta",
1562 ":Africa/Conakry",
1563 ":Africa/Dakar",
1564 ":Africa/Dar_es_Salaam",
1565 ":Africa/Djibouti",
1566 ":Africa/Douala",
1567 ":Africa/El_Aaiun",
1568 ":Africa/Freetown",
1569 ":Africa/Gaborone",
1570 ":Africa/Harare",
1571 ":Africa/Johannesburg",
1572 ":Africa/Kampala",
1573 ":Africa/Khartoum",
1574 ":Africa/Kigali",
1575 ":Africa/Kinshasa",
1576 ":Africa/Lagos",
1577 ":Africa/Libreville",
1578 ":Africa/Lome",
1579 ":Africa/Luanda",
1580 ":Africa/Lubumbashi",
1581 ":Africa/Lusaka",
1582 ":Africa/Malabo",
1583 ":Africa/Maputo",
1584 ":Africa/Maseru",
1585 ":Africa/Mbabane",
1586 ":Africa/Mogadishu",
1587 ":Africa/Monrovia",
1588 ":Africa/Nairobi",
1589 ":Africa/Ndjamena",
1590 ":Africa/Niamey",
1591 ":Africa/Nouakchott",
1592 ":Africa/Ouagadougou",
1593 ":Africa/Porto-Novo",
1594 ":Africa/Sao_Tome",
1595 ":Africa/Timbuktu",
1596 ":Africa/Tripoli",
1597 ":Africa/Tunis",
1598 ":Africa/Windhoek",
1599 ":America/Adak",
1600 ":America/Anchorage",
1601 ":America/Anguilla",
1602 ":America/Antigua",
1603 ":America/Araguaina",
1604 ":America/Aruba",
1605 ":America/Asuncion",
1606 ":America/Atka",
1607 ":America/Barbados",
1608 ":America/Belem",
1609 ":America/Belize",
1610 ":America/Boa_Vista",
1611 ":America/Bogota",
1612 ":America/Boise",
1613 ":America/Buenos_Aires",
1614 ":America/Cambridge_Bay",
1615 ":America/Cancun",
1616 ":America/Caracas",
1617 ":America/Catamarca",
1618 ":America/Cayenne",
1619 ":America/Cayman",
1620 ":America/Chicago",
1621 ":America/Chihuahua",
1622 ":America/Cordoba",
1623 ":America/Costa_Rica",
1624 ":America/Cuiaba",
1625 ":America/Curacao",
1626 ":America/Danmarkshavn",
1627 ":America/Dawson",
1628 ":America/Dawson_Creek",
1629 ":America/Denver",
1630 ":America/Detroit",
1631 ":America/Dominica",
1632 ":America/Edmonton",
1633 ":America/Eirunepe",
1634 ":America/El_Salvador",
1635 ":America/Ensenada",
1636 ":America/Fortaleza",
1637 ":America/Glace_Bay",
1638 ":America/Godthab",
1639 ":America/Goose_Bay",
1640 ":America/Grand_Turk",
1641 ":America/Grenada",
1642 ":America/Guadeloupe",
1643 ":America/Guatemala",
1644 ":America/Guayaquil",
1645 ":America/Guyana",
1646 ":America/Halifax",
1647 ":America/Havana",
1648 ":America/Hermosillo",
1649 ":America/Indiana/Knox",
1650 ":America/Indiana/Marengo",
1651 ":America/Indianapolis",
1652 ":America/Indiana/Vevay",
1653 ":America/Inuvik",
1654 ":America/Iqaluit",
1655 ":America/Jamaica",
1656 ":America/Jujuy",
1657 ":America/Juneau",
1658 ":America/Kentucky/Monticello",
1659 ":America/La_Paz",
1660 ":America/Lima",
1661 ":America/Los_Angeles",
1662 ":America/Louisville",
1663 ":America/Maceio",
1664 ":America/Managua",
1665 ":America/Manaus",
1666 ":America/Martinique",
1667 ":America/Mazatlan",
1668 ":America/Mendoza",
1669 ":America/Menominee",
1670 ":America/Merida",
1671 ":America/Mexico_City",
1672 ":America/Miquelon",
1673 ":America/Monterrey",
1674 ":America/Montevideo",
1675 ":America/Montreal",
1676 ":America/Montserrat",
1677 ":America/Nassau",
1678 ":America/New_York",
1679 ":America/Nipigon",
1680 ":America/Nome",
1681 ":America/Noronha",
1682 ":America/North_Dakota/Center",
1683 ":America/Panama",
1684 ":America/Pangnirtung",
1685 ":America/Paramaribo",
1686 ":America/Phoenix",
1687 ":America/Port-au-Prince",
1688 ":America/Port_of_Spain",
1689 ":America/Porto_Velho",
1690 ":America/Puerto_Rico",
1691 ":America/Rainy_River",
1692 ":America/Rankin_Inlet",
1693 ":America/Recife",
1694 ":America/Regina",
1695 ":America/Rio_Branco",
1696 ":America/Santiago",
1697 ":America/Santo_Domingo",
1698 ":America/Sao_Paulo",
1699 ":America/Scoresbysund",
1700 ":America/Shiprock",
1701 ":America/St_Johns",
1702 ":America/St_Kitts",
1703 ":America/St_Lucia",
1704 ":America/St_Thomas",
1705 ":America/St_Vincent",
1706 ":America/Swift_Current",
1707 ":America/Tegucigalpa",
1708 ":America/Thule",
1709 ":America/Thunder_Bay",
1710 ":America/Tijuana",
1711 ":America/Tortola",
1712 ":America/Vancouver",
1713 ":America/Whitehorse",
1714 ":America/Winnipeg",
1715 ":America/Yakutat",
1716 ":America/Yellowknife",
1717 ":Antarctica/Casey",
1718 ":Antarctica/Davis",
1719 ":Antarctica/DumontDUrville",
1720 ":Antarctica/Mawson",
1721 ":Antarctica/McMurdo",
1722 ":Antarctica/Palmer",
1723 ":Antarctica/South_Pole",
1724 ":Antarctica/Syowa",
1725 ":Antarctica/Vostok",
1726 ":Arctic/Longyearbyen",
1727 ":Asia/Aden",
1728 ":Asia/Almaty",
1729 ":Asia/Amman",
1730 ":Asia/Anadyr",
1731 ":Asia/Aqtau",
1732 ":Asia/Aqtobe",
1733 ":Asia/Ashgabat",
1734 ":Asia/Baghdad",
1735 ":Asia/Bahrain",
1736 ":Asia/Baku",
1737 ":Asia/Bangkok",
1738 ":Asia/Beirut",
1739 ":Asia/Bishkek",
1740 ":Asia/Brunei",
1741 ":Asia/Calcutta",
1742 ":Asia/Choibalsan",
1743 ":Asia/Chongqing",
1744 ":Asia/Colombo",
1745 ":Asia/Damascus",
1746 ":Asia/Dhaka",
1747 ":Asia/Dili",
1748 ":Asia/Dubai",
1749 ":Asia/Dushanbe",
1750 ":Asia/Gaza",
1751 ":Asia/Harbin",
1752 ":Asia/Hong_Kong",
1753 ":Asia/Hovd",
1754 ":Asia/Irkutsk",
1755 ":Asia/Jakarta",
1756 ":Asia/Jayapura",
1757 ":Asia/Jerusalem",
1758 ":Asia/Kabul",
1759 ":Asia/Kamchatka",
1760 ":Asia/Karachi",
1761 ":Asia/Kashgar",
1762 ":Asia/Katmandu",
1763 ":Asia/Krasnoyarsk",
1764 ":Asia/Kuala_Lumpur",
1765 ":Asia/Kuching",
1766 ":Asia/Kuwait",
1767 ":Asia/Macau",
1768 ":Asia/Magadan",
1769 ":Asia/Makassar",
1770 ":Asia/Manila",
1771 ":Asia/Muscat",
1772 ":Asia/Nicosia",
1773 ":Asia/Novosibirsk",
1774 ":Asia/Omsk",
1775 ":Asia/Oral",
1776 ":Asia/Phnom_Penh",
1777 ":Asia/Pontianak",
1778 ":Asia/Pyongyang",
1779 ":Asia/Qatar",
1780 ":Asia/Qyzylorda",
1781 ":Asia/Rangoon",
1782 ":Asia/Riyadh",
1783 ":Asia/Saigon",
1784 ":Asia/Sakhalin",
1785 ":Asia/Samarkand",
1786 ":Asia/Seoul",
1787 ":Asia/Shanghai",
1788 ":Asia/Singapore",
1789 ":Asia/Taipei",
1790 ":Asia/Tashkent",
1791 ":Asia/Tbilisi",
1792 ":Asia/Tehran",
1793 ":Asia/Thimphu",
1794 ":Asia/Tokyo",
1795 ":Asia/Ulaanbaatar",
1796 ":Asia/Urumqi",
1797 ":Asia/Vientiane",
1798 ":Asia/Vladivostok",
1799 ":Asia/Yakutsk",
1800 ":Asia/Yekaterinburg",
1801 ":Asia/Yerevan",
1802 ":Atlantic/Azores",
1803 ":Atlantic/Bermuda",
1804 ":Atlantic/Canary",
1805 ":Atlantic/Cape_Verde",
1806 ":Atlantic/Faeroe",
1807 ":Atlantic/Jan_Mayen",
1808 ":Atlantic/Madeira",
1809 ":Atlantic/Reykjavik",
1810 ":Atlantic/South_Georgia",
1811 ":Atlantic/Stanley",
1812 ":Atlantic/St_Helena",
1813 ":Australia/Adelaide",
1814 ":Australia/Brisbane",
1815 ":Australia/Broken_Hill",
1816 ":Australia/Darwin",
1817 ":Australia/Hobart",
1818 ":Australia/Lindeman",
1819 ":Australia/Lord_Howe",
1820 ":Australia/Melbourne",
1821 ":Australia/Perth",
1822 ":Australia/Sydney",
1823 ":Etc/GMT",
1824 ":Etc/GMT-1",
1825 ":Etc/GMT+1",
1826 ":Etc/GMT-10",
1827 ":Etc/GMT+10",
1828 ":Etc/GMT-11",
1829 ":Etc/GMT+11",
1830 ":Etc/GMT-12",
1831 ":Etc/GMT+12",
1832 ":Etc/GMT-13",
1833 ":Etc/GMT-14",
1834 ":Etc/GMT-2",
1835 ":Etc/GMT+2",
1836 ":Etc/GMT-3",
1837 ":Etc/GMT+3",
1838 ":Etc/GMT-4",
1839 ":Etc/GMT+4",
1840 ":Etc/GMT-5",
1841 ":Etc/GMT+5",
1842 ":Etc/GMT-6",
1843 ":Etc/GMT+6",
1844 ":Etc/GMT-7",
1845 ":Etc/GMT+7",
1846 ":Etc/GMT-8",
1847 ":Etc/GMT+8",
1848 ":Etc/GMT-9",
1849 ":Etc/GMT+9",
1850 ":Etc/UCT",
1851 ":Etc/UTC",
1852 ":Europe/Amsterdam",
1853 ":Europe/Andorra",
1854 ":Europe/Athens",
1855 ":Europe/Belfast",
1856 ":Europe/Belgrade",
1857 ":Europe/Berlin",
1858 ":Europe/Bratislava",
1859 ":Europe/Brussels",
1860 ":Europe/Bucharest",
1861 ":Europe/Budapest",
1862 ":Europe/Chisinau",
1863 ":Europe/Copenhagen",
1864 ":Europe/Dublin",
1865 ":Europe/Gibraltar",
1866 ":Europe/Helsinki",
1867 ":Europe/Istanbul",
1868 ":Europe/Kaliningrad",
1869 ":Europe/Kiev",
1870 ":Europe/Lisbon",
1871 ":Europe/Ljubljana",
1872 ":Europe/London",
1873 ":Europe/Luxembourg",
1874 ":Europe/Madrid",
1875 ":Europe/Malta",
1876 ":Europe/Minsk",
1877 ":Europe/Monaco",
1878 ":Europe/Moscow",
1879 ":Europe/Oslo",
1880 ":Europe/Paris",
1881 ":Europe/Prague",
1882 ":Europe/Riga",
1883 ":Europe/Rome",
1884 ":Europe/Samara",
1885 ":Europe/San_Marino",
1886 ":Europe/Sarajevo",
1887 ":Europe/Simferopol",
1888 ":Europe/Skopje",
1889 ":Europe/Sofia",
1890 ":Europe/Stockholm",
1891 ":Europe/Tallinn",
1892 ":Europe/Tirane",
1893 ":Europe/Uzhgorod",
1894 ":Europe/Vaduz",
1895 ":Europe/Vatican",
1896 ":Europe/Vienna",
1897 ":Europe/Vilnius",
1898 ":Europe/Warsaw",
1899 ":Europe/Zagreb",
1900 ":Europe/Zaporozhye",
1901 ":Europe/Zurich",
1902 ":Indian/Antananarivo",
1903 ":Indian/Chagos",
1904 ":Indian/Christmas",
1905 ":Indian/Cocos",
1906 ":Indian/Comoro",
1907 ":Indian/Kerguelen",
1908 ":Indian/Mahe",
1909 ":Indian/Maldives",
1910 ":Indian/Mauritius",
1911 ":Indian/Mayotte",
1912 ":Indian/Reunion",
1913 ":Pacific/Apia",
1914 ":Pacific/Auckland",
1915 ":Pacific/Chatham",
1916 ":Pacific/Easter",
1917 ":Pacific/Efate",
1918 ":Pacific/Enderbury",
1919 ":Pacific/Fakaofo",
1920 ":Pacific/Fiji",
1921 ":Pacific/Funafuti",
1922 ":Pacific/Galapagos",
1923 ":Pacific/Gambier",
1924 ":Pacific/Guadalcanal",
1925 ":Pacific/Guam",
1926 ":Pacific/Honolulu",
1927 ":Pacific/Johnston",
1928 ":Pacific/Kiritimati",
1929 ":Pacific/Kosrae",
1930 ":Pacific/Kwajalein",
1931 ":Pacific/Majuro",
1932 ":Pacific/Marquesas",
1933 ":Pacific/Midway",
1934 ":Pacific/Nauru",
1935 ":Pacific/Niue",
1936 ":Pacific/Norfolk",
1937 ":Pacific/Noumea",
1938 ":Pacific/Pago_Pago",
1939 ":Pacific/Palau",
1940 ":Pacific/Pitcairn",
1941 ":Pacific/Ponape",
1942 ":Pacific/Port_Moresby",
1943 ":Pacific/Rarotonga",
1944 ":Pacific/Saipan",
1945 ":Pacific/Tahiti",
1946 ":Pacific/Tarawa",
1947 ":Pacific/Tongatapu",
1948 ":Pacific/Truk",
1949 ":Pacific/Wake",
1950 ":Pacific/Wallis",
1951 ":Pacific/Yap"};
1952
1953/* $Id: tide_db.c 3744 2010-08-17 22:34:46Z flaterco $ */
1954
1955// #include "tcd.h"
1956// #include "tide_db_header.h"
1957// #include "tide_db_default.h"
1958
1959/* This should be done with stdbool.h, but VC doesn't have it. */
1960/* Using crappy old int, must be careful not to 'require' a 64-bit value. */
1961#ifndef require
1962#define require(expr) \
1963 { \
1964 int require_expr; \
1965 require_expr = (int)(expr); \
1966 assert(require_expr); \
1967 }
1968#endif
1969
1970#include <stdio.h>
1971#include <stdlib.h>
1972#include <string.h>
1973#include <errno.h>
1974#include <time.h>
1975#include <math.h>
1976#include <ctype.h>
1977#include <assert.h>
1978
1979#ifdef HAVE_UNISTD_H
1980#include <unistd.h>
1981#endif
1982
1983#ifdef HAVE_IO_H
1984#include <io.h>
1985#endif
1986
1987/****************************************************************************
1988
1989 DISTRIBUTION STATEMENT
1990
1991 This source file is unclassified, distribution unlimited, public
1992 domain. It is distributed in the hope that it will be useful, but
1993 WITHOUT ANY WARRANTY; without even the implied warranty of
1994 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1995
1996*****************************************************************************/
1997
1998/* Some of the following commentary is out of date. See the new
1999 documentation in libtcd.html. */
2000
2001/****************************************************************************
2002
2003 Tide Constituent Database API
2004
2005
2006 Author : Jan C. Depner (depnerj@navo.navy.mil)
2007
2008 Date : 08/01/02
2009 (First day of Micro$oft's "Licensing 6" policy - P.T. Barnum was
2010 right!!!)
2011
2012 Purpose : To replace the ASCII/XML formatted harmonic constituent data
2013 files, used in Dave Flater's (http://www.flaterco.com/xtide/)
2014 exceptionally fine open-source XTide program, with a fast,
2015 efficient binary format. In addition, we wanted to replace the
2016 Naval Oceanographic Office's (http://www.navo.navy.mil)
2017 antiquated ASCII format harmonic constituent data file due to
2018 problems with configuration management of the file. The
2019 resulting database will become a Navy OAML (Oceanographic and
2020 Atmospheric Master Library) standard harmonic tide constituent
2021 database.
2022
2023 Design : The following describes the database file and some of the
2024 rationale behind the design.
2025
2026 First question - Why didn't I use PostgreSQL or MySQL? Mostly
2027 portability. What? PostgreSQL runs on everything! Yes, but it doesn't
2028 come installed on everything. This would have meant that the poor,
2029 benighted Micro$oft borgs would have had to actually load a software
2030 package. In addition, the present harmonics/offset files only contain
2031 a total of 6,409 stations. It hardly seemed worth the effort (or overhead)
2032 of a fullblown RDBMS to handle this. Second question - Why binary and not
2033 ASCII or XML? This actually gets into philosophy. At NAVO we have used an
2034 ASCII harmonic constituent file for years (we were founded in 1830 and I
2035 think that that's when they designed the file). We have about fifty
2036 million copies floating around and each one is slightly different. Why?
2037 Because they're ASCII and everyone thinks they know what they're doing so
2038 they tend to modify the file. Same problem with XML, it's still ASCII.
2039 We wanted a file that people weren't going to mess with and that we could
2040 version control. We also wanted a file that was small and fast. This is
2041 very difficult to do with ASCII. The big slowdown with the old format
2042 was I/O and parsing. Third question - will it run on any OS? Hopefully,
2043 yes. After twenty-five years of working with low bidder systems I've
2044 worked on almost every OS known to man. Once you've been bitten by big
2045 endian vs little endian or IEEE floating point format vs VAX floating
2046 point format or byte addressable memory vs word addressable memory or 32
2047 bit word vs 36 bit word vs 48 bit word vs 64 bit word sizes you get the
2048 message. All of the data in the file is stored either as ASCII text or
2049 scaled integers (32 bits or smaller), bit-packed and stuffed into an
2050 unsigned character buffer for I/O. No endian issues, no floating point
2051 issues, no word size issues, no memory mapping issues. I will be testing
2052 this on x86 Linux, HP-UX, and Micro$oft Windoze. By the time you read
2053 this it will be portable to those systems at least.
2054
2055 Now, on to the file layout. As much as I dislike ASCII it is occasionally
2056 handy to be able to see some information about a file without having to
2057 resort to a special purpose program. With that in mind I made the first
2058 part of the header of the file ASCII. The following is an example of the
2059 ASCII portion of the header:
2060
2061 [VERSION] = PFM Software - tide_db V1.00 - 08/01/02
2062 [LAST MODIFIED] = Thu Aug 1 02:46:29 2002
2063 [HEADER SIZE] = 4096
2064 [NUMBER OF RECORDS] = 10652
2065 [START YEAR] = 1970
2066 [NUMBER OF YEARS] = 68
2067 [SPEED BITS] = 31
2068 [SPEED SCALE] = 10000000
2069 [SPEED OFFSET] = -410667
2070 [EQUILIBRIUM BITS] = 16
2071 [EQUILIBRIUM SCALE] = 100
2072 [EQUILIBRIUM OFFSET] = 0
2073 [NODE BITS] = 15
2074 [NODE SCALE] = 10000
2075 [NODE OFFSET] = -3949
2076 [AMPLITUDE BITS] = 19
2077 [AMPLITUDE SCALE] = 10000
2078 [EPOCH BITS] = 16
2079 [EPOCH SCALE] = 100
2080 [RECORD TYPE BITS] = 4
2081 [LATITUDE BITS] = 25
2082 [LATITUDE SCALE] = 100000
2083 [LONGITUDE BITS] = 26
2084 [LONGITUDE SCALE] = 100000
2085 [RECORD SIZE BITS] = 12
2086 [STATION BITS] = 18
2087 [DATUM OFFSET BITS] = 32
2088 [DATUM OFFSET SCALE] = 10000
2089 [DATE BITS] = 27
2090 [MONTHS ON STATION BITS] = 10
2091 [CONFIDENCE VALUE BITS] = 4
2092 [TIME BITS] = 13
2093 [LEVEL ADD BITS] = 16
2094 [LEVEL ADD SCALE] = 100
2095 [LEVEL MULTIPLY BITS] = 16
2096 [LEVEL MULTIPLY SCALE] = 1000
2097 [DIRECTION BITS] = 9
2098 [LEVEL UNIT BITS] = 3
2099 [LEVEL UNIT TYPES] = 6
2100 [LEVEL UNIT SIZE] = 15
2101 [DIRECTION UNIT BITS] = 2
2102 [DIRECTION UNIT TYPES] = 3
2103 [DIRECTION UNIT SIZE] = 15
2104 [RESTRICTION BITS] = 4
2105 [RESTRICTION TYPES] = 2
2106 [RESTRICTION SIZE] = 30
2107 [PEDIGREE BITS] = 6
2108 [PEDIGREE TYPES] = 13
2109 [PEDIGREE SIZE] = 60
2110 [DATUM BITS] = 7
2111 [DATUM TYPES] = 61
2112 [DATUM SIZE] = 70
2113 [CONSTITUENT BITS] = 8
2114 [CONSTITUENTS] = 173
2115 [CONSTITUENT SIZE] = 10
2116 [COUNTRY BITS] = 9
2117 [COUNTRIES] = 240
2118 [COUNTRY SIZE] = 50
2119 [TZFILE BITS] = 10
2120 [TZFILES] = 449
2121 [TZFILE SIZE] = 30
2122 [END OF FILE] = 2585170
2123 [END OF ASCII HEADER DATA]
2124
2125 Most of these values will make sense in the context of the following
2126 description of the rest of the file. Some caveats on the data storage -
2127 if no SCALE is listed for a field, the scale is 1. If no BITS field is
2128 listed, this is a variable length character field and is stored as 8 bit
2129 ASCII characters. If no OFFSET is listed, the offset is 0. Offsets are
2130 scaled. All SIZE fields refer to the maximum length, in characters, of a
2131 variable length character field. Some of the BITS fields are calculated
2132 while others are hardwired (see code). For instance, [DIRECTION BITS] is
2133 hardwired because it is an integer field whose value can only be from 0 to
2134 361 (361 = no direction flag). [NODE BITS], on the other hand, is
2135 calculated on creation by checking the min, max, and range of all of the
2136 node factor values. The number of bits needed is easily calculated by
2137 taking the log of the adjusted, scaled range, dividing by the log of 2 and
2138 adding 1. Immediately following the ASCII portion of the header is a 32
2139 bit checksum of the ASCII portion of the header. Why? Because some
2140 genius always gets the idea that he/she can modify the header with a text
2141 or hex editor. Go figure.
2142
2143 The rest of the header is as follows :
2144
2145 [LEVEL UNIT TYPES] fields of [LEVEL UNIT SIZE] characters, each field
2146 is internally 0 terminated (anything after the zero is garbage)
2147
2148 [DIRECTION UNIT TYPES] fields of [DIRECTION UNIT SIZE] characters, 0
2149 terminated
2150
2151 [RESTRICTION TYPES] fields of [RESTRICTION SIZE] characters, 0
2152 terminated
2153
2154 [PEDIGREE TYPES] fields of [PEDIGREE SIZE] characters, 0 terminated
2155
2156 [TZFILES] fields of [TZFILE SIZE] characters, 0 terminated
2157
2158 [COUNTRIES] fields of [COUNTRY SIZE] characters, 0 terminated
2159
2160 [DATUM TYPES] fields of [DATUM SIZE] characters, 0 terminated
2161
2162 [CONSTITUENTS] fields of [CONSTITUENT SIZE] characters, 0 terminated
2163 Yes, I know, I wasted some space with these fields but I wasn't
2164 worried about a couple of hundred bytes.
2165
2166 [CONSTITUENTS] fields of [SPEED BITS], speed values (scaled and offset)
2167
2168 [CONSTITUENTS] groups of [NUMBER OF YEARS] fields of
2169 [EQUILIBRIUM BITS], equilibrium arguments (scaled and offset)
2170
2171 [CONSTITUENTS] groups of [NUMBER OF YEARS] fields of [NODE BITS], node
2172 factors (scaled and offset)
2173
2174
2175 Finally, the data. At present there are two types of records in the file.
2176 These are reference stations (record type 1) and subordinate stations
2177 (record type 2). Reference stations contain a set of constituents while
2178 subordinate stations contain a number of offsets to be applied to the
2179 reference station that they are associated with. Note that reference
2180 stations (record type 1) may, in actuality, be subordinate stations, albeit
2181 with a set of constituents. All of the records have the following subset
2182 of information stored as the first part of the record:
2183
2184 [RECORD SIZE BITS] - record size in bytes
2185 [RECORD TYPE BITS] - record type (1 or 2)
2186 [LATITUDE BITS] - latitude (degrees, south negative, scaled & offset)
2187 [LONGITUDE BITS] - longitude (degrees, west negative, scaled & offset)
2188 [TZFILE BITS] - index into timezone array (retrieved from header)
2189 variable size - station name, 0 terminated
2190 [STATION BITS] - record number of reference station or -1
2191 [COUNTRY_BITS] index into country array (retrieved from header)
2192 [PEDIGREE BITS] - index into pedigree array (retrieved from header)
2193 variable size - source, 0 terminated
2194 [RESTRICTION BITS] - index into restriction array
2195 variable size - comments, may contain LFs to indicate newline (no CRs)
2196
2197
2198 These are the rest of the fields for record type 1:
2199
2200 [LEVEL UNIT BITS] - index into level units array
2201 [DATUM OFFSET BITS] - datum offset (scaled)
2202 [DATUM BITS] - index into datum name array
2203 [TIME BITS] - time zone offset from GMT0 (meridian, integer +/-HHMM)
2204 [DATE BITS] - expiration date, (integer YYYYMMDD, default is 0)
2205 [MONTHS ON STATION BITS] - months on station
2206 [DATE BITS] - last date on station, default is 0
2207 [CONFIDENCE BITS] - confidence value (TBD)
2208 [CONSTITUENT BITS] - "N", number of constituents for this station
2209
2210 N groups of:
2211 [CONSTITUENT BITS] - constituent number
2212 [AMPLITUDE BITS] - amplitude (scaled & offset)
2213 [EPOCH BITS] - epoch (scaled & offset)
2214
2215
2216 These are the rest of the fields for record type 2:
2217
2218 [LEVEL UNIT BITS] - leveladd units, index into level_units array
2219 [DIRECTION UNIT BITS] - direction units, index into dir_units array
2220 [LEVEL UNIT BITS] - avglevel units, index into level_units array
2221 [TIME BITS] - min timeadd (integer +/-HHMM) or 0
2222 [LEVEL ADD BITS] - min leveladd (scaled) or 0
2223 [LEVEL MULTIPLY BITS] - min levelmultiply (scaled) or 0
2224 [LEVEL ADD BITS] - min avglevel (scaled) or 0
2225 [DIRECTION BITS] - min direction (0-360 or 361 for no direction)
2226 [TIME BITS] - max timeadd (integer +/-HHMM) or 0
2227 [LEVEL ADD BITS] - max leveladd (scaled) or 0
2228 [LEVEL MULTIPLY BITS] - max levelmultiply (scaled) or 0
2229 [LEVEL ADD BITS] - max avglevel (scaled) or 0
2230 [DIRECTION BITS] - max direction (0-360 or 361 for no direction)
2231 [TIME BITS] - floodbegins (integer +/-HHMM) or NULLSLACKOFFSET
2232 [TIME BITS] - ebbbegins (integer +/-HHMM) or NULLSLACKOFFSET
2233
2234
2235 Back to philosophy! When you design a database of any kind the first
2236 thing you should ask yourself is "Self, how am I going to access this
2237 data most of the time?". If you answer yourself out loud you should
2238 consider seeing a shrink. 99 and 44/100ths percent of the time this
2239 database is going to be read to get station data. The other 66/100ths
2240 percent of the time it will be created/modified. Variable length records
2241 are no problem on retrieval. They are no problem to create. They can be
2242 a major pain in the backside if you have to modify/delete them. Since we
2243 shouldn't be doing too much editing of the data (usually just adding
2244 records) this is a pretty fair design. At some point though we are going
2245 to want to modify or delete a record. There are two possibilities here.
2246 We can dump the database to an ASCII file or files using restore_tide_db,
2247 use a text editor to modify them, and then rebuild the database. The
2248 other possibility is to modify the record in place. This is OK if you
2249 don't change a variable length field but what if you want to change the
2250 station name or add a couple of constituents? With the design as is we
2251 have to read the remainder of the file from the end of the record to be
2252 modified, write the modified record, rewrite the remainder of the file,
2253 and then change the end_of_file pointer in the header. So, which fields
2254 are going to be a problem? Changes to station name, source, comments, or
2255 the number of constituents for a station will require a resizing of the
2256 database. Changes to any of the other fields can be done in place. The
2257 worst thing that you can do though is to delete a record. Not just
2258 because the file has to be resized but because it might be a reference
2259 record with subordinate stations. These would have to be deleted as well.
2260 The delete_tide_record function will do just that so make sure you check
2261 before you call it. You might not want to do that.
2262
2263 Another point to note is that when you open the database the records are
2264 indexed at that point. This takes about half a second on a dual 450.
2265 Most applications use the header part of the record very often and
2266 the rest of the record only if they are going to actually produce
2267 predicted tides. For instance, XTide plots all of the stations on a
2268 world map or globe and lists all of the station names. It also needs the
2269 timezone up front. To save re-indexing to get these values I save them
2270 in memory. The only time an application needs to actually read an entire
2271 record is when you want to do the prediction. Otherwise just use
2272 get_partial_tide_record or get_next_partial_tide_record to yank the good
2273 stuff out of memory.
2274
2275 'Nuff said?
2276
2277
2278 See libtcd.html for changelog.
2279
2280*****************************************************************************/
2281
2282/* Maintenance by DWF */
2283
2284/* Function prototypes. */
2285
2286NV_U_INT32 calculate_bits(NV_U_INT32 value);
2287void bit_pack(NV_U_BYTE *, NV_U_INT32, NV_U_INT32, NV_INT32);
2288NV_U_INT32 bit_unpack(NV_U_BYTE *, NV_U_INT32, NV_U_INT32);
2289NV_INT32 signed_bit_unpack(NV_U_BYTE buffer[], NV_U_INT32 start,
2290 NV_U_INT32 numbits);
2291
2292/* Global variables. */
2293
2294typedef struct {
2295 NV_INT32 address;
2296 NV_U_INT32 record_size;
2297 NV_U_INT16 tzfile;
2298 NV_INT32 reference_station;
2299 NV_INT32 lat;
2300 NV_INT32 lon;
2301 NV_U_BYTE record_type;
2302 NV_CHAR *name;
2303} TIDE_INDEX;
2304
2305static FILE *fp = NULL;
2306static TIDE_INDEX *tindex = NULL;
2307static NV_BOOL modified = NVFalse;
2308static NV_INT32 current_record, current_index;
2309static NV_CHAR filename[MONOLOGUE_LENGTH];
2310
2311/*****************************************************************************\
2312 Checked fread and fwrite wrappers
2313 DWF 2007-12-02
2314
2315 Fedora package compiles generate warnings for invoking these
2316 functions without checking the return.
2317\*****************************************************************************/
2318
2319static void chk_fread(void *ptr, size_t size, size_t nmemb, FILE *stream) {
2320 size_t ret;
2321 ret = fread(ptr, size, nmemb, stream);
2322 if (ret != nmemb) {
2323 // LOG_ERROR ("libtcd unexpected error: fread failed\n");
2324 // LOG_ERROR ("nmemb = %lu, got %lu\n", nmemb, ret);
2325 throw std::runtime_error("tcmgr file read exception");
2326 }
2327}
2328
2329static void chk_fwrite(const void *ptr, size_t size, size_t nmemb,
2330 FILE *stream) {
2331 size_t ret;
2332 ret = fwrite(ptr, size, nmemb, stream);
2333 if (ret != nmemb) {
2334 // LOG_ERROR ("libtcd unexpected error: fwrite failed\n");
2335 // LOG_ERROR ("nmemb = %lu, got %lu\n", nmemb, ret);
2336 // LOG_ERROR ("The database is probably corrupt now.\n");
2337 throw std::runtime_error("tcmgr file read exception");
2338 }
2339}
2340
2341/*****************************************************************************\
2342
2343 Function dump_tide_record - prints out all of the fields in the
2344 input tide record
2345
2346 Synopsis dump_tide_record (rec);
2347
2348 TIDE_RECORD *rec pointer to the tide record
2349
2350 Returns void
2351
2352 Author Jan C. Depner
2353 Date 08/01/02
2354
2355 See libtcd.html for changelog.
2356
2357\*****************************************************************************/
2358
2359void dump_tide_record(const TIDE_RECORD *rec) {
2360 NV_U_INT32 i;
2361
2362 assert(rec);
2363
2364 LOG_ERROR("\n\nRecord number = %d\n", rec->header.record_number);
2365 LOG_ERROR("Record size = %u\n", rec->header.record_size);
2366 LOG_ERROR("Record type = %u\n", rec->header.record_type);
2367 LOG_ERROR("Latitude = %f\n", rec->header.latitude);
2368 LOG_ERROR("Longitude = %f\n", rec->header.longitude);
2369 LOG_ERROR("Reference station = %d\n", rec->header.reference_station);
2370 LOG_ERROR("Tzfile = %s\n", get_tzfile(rec->header.tzfile));
2371 LOG_ERROR("Name = %s\n", rec->header.name);
2372
2373 LOG_ERROR("Country = %s\n", get_country(rec->country));
2374 LOG_ERROR("Source = %s\n", rec->source);
2375 LOG_ERROR("Restriction = %s\n", get_restriction(rec->restriction));
2376 LOG_ERROR("Comments = %s\n", rec->comments);
2377 LOG_ERROR("Notes = %s\n", rec->notes);
2378 LOG_ERROR("Legalese = %s\n", get_legalese(rec->legalese));
2379 LOG_ERROR("Station ID context = %s\n", rec->station_id_context);
2380 LOG_ERROR("Station ID = %s\n", rec->station_id);
2381 LOG_ERROR("Date imported = %d\n", rec->date_imported);
2382 LOG_ERROR("Xfields = %s\n", rec->xfields);
2383
2384 LOG_ERROR("Direction units = %s\n", get_dir_units(rec->direction_units));
2385 LOG_ERROR("Min direction = %d\n", rec->min_direction);
2386 LOG_ERROR("Max direction = %d\n", rec->max_direction);
2387 LOG_ERROR("Level units = %s\n", get_level_units(rec->level_units));
2388
2389 if (rec->header.record_type == REFERENCE_STATION) {
2390 LOG_ERROR("Datum offset = %f\n", rec->datum_offset);
2391 LOG_ERROR("Datum = %s\n", get_datum(rec->datum));
2392 LOG_ERROR("Zone offset = %d\n", rec->zone_offset);
2393 LOG_ERROR("Expiration date = %d\n", rec->expiration_date);
2394 LOG_ERROR("Months on station = %d\n", rec->months_on_station);
2395 LOG_ERROR("Last date on station = %d\n", rec->last_date_on_station);
2396 LOG_ERROR("Confidence = %d\n", rec->confidence);
2397 for (i = 0; i < hd.pub.constituents; ++i) {
2398 if (rec->amplitude[i] != 0.0 || rec->epoch[i] != 0.0) {
2399 LOG_ERROR("Amplitude[%d] = %f\n", i, rec->amplitude[i]);
2400 LOG_ERROR("Epoch[%d] = %f\n", i, rec->epoch[i]);
2401 }
2402 }
2403 }
2404
2405 else if (rec->header.record_type == SUBORDINATE_STATION) {
2406 LOG_ERROR("Min time add = %d\n", rec->min_time_add);
2407 LOG_ERROR("Min level add = %f\n", rec->min_level_add);
2408 LOG_ERROR("Min level multiply = %f\n", rec->min_level_multiply);
2409 LOG_ERROR("Max time add = %d\n", rec->max_time_add);
2410 LOG_ERROR("Max level add = %f\n", rec->max_level_add);
2411 LOG_ERROR("Max level multiply = %f\n", rec->max_level_multiply);
2412 LOG_ERROR("Flood begins = %d\n", rec->flood_begins);
2413 LOG_ERROR("Ebb begins = %d\n", rec->ebb_begins);
2414 }
2415}
2416
2417/*****************************************************************************\
2418
2419 Function write_protect - prevent trying to modify TCD files of
2420 an earlier version. Nothing to do with file locking.
2421
2422 David Flater, 2004-10-14.
2423
2424\*****************************************************************************/
2425
2426static void write_protect() {
2427 if (hd.pub.major_rev < LIBTCD_MAJOR_REV) {
2428 LOG_ERROR(
2429 "libtcd error: can't modify TCD files created by earlier version. "
2430 "Use\nrewrite_tide_db to upgrade the TCD file.\n");
2431 exit(-1);
2432 }
2433}
2434
2435/*****************************************************************************\
2436
2437 Function get_country - gets the country field for record "num"
2438
2439 Synopsis get_country (num);
2440
2441 NV_INT32 num tide record number
2442
2443 Returns NV_CHAR * country name (associated with
2444 ISO 3166-1:1999 2-character
2445 country code
2446
2447 Author Jan C. Depner
2448 Date 08/01/02
2449
2450 See libtcd.html for changelog.
2451
2452\*****************************************************************************/
2453
2454const NV_CHAR *get_country(NV_INT32 num) {
2455 if (!fp) {
2456 LOG_ERROR(
2457 "libtcd error: attempt to access database when database not open\n");
2458 exit(-1);
2459 }
2460 if (num >= 0 && num < (NV_INT32)hd.pub.countries) return (hd.country[num]);
2461 return ("Unknown");
2462}
2463
2464/*****************************************************************************\
2465
2466 Function get_tzfile - gets the time zone name for record "num"
2467
2468 Synopsis get_tzfile (num);
2469
2470 NV_INT32 num tide record number
2471
2472 Returns NV_CHAR * time zone name used in TZ variable
2473
2474 Author Jan C. Depner
2475 Date 08/01/02
2476
2477 See libtcd.html for changelog.
2478
2479\*****************************************************************************/
2480
2481const NV_CHAR *get_tzfile(NV_INT32 num) {
2482 if (!fp) {
2483 LOG_ERROR(
2484 "libtcd error: attempt to access database when database not open\n");
2485 exit(-1);
2486 }
2487 if (num >= 0 && num < (NV_INT32)hd.pub.tzfiles) return (hd.tzfile[num]);
2488 return ("Unknown");
2489}
2490
2491/*****************************************************************************\
2492
2493 Function get_station - get the name of the station for record "num"
2494
2495 Synopsis get_station (num);
2496
2497 NV_INT32 num tide record number
2498
2499 Returns NV_CHAR * station name
2500
2501 Author Jan C. Depner
2502 Date 08/01/02
2503
2504 See libtcd.html for changelog.
2505
2506\*****************************************************************************/
2507
2508const NV_CHAR *get_station(NV_INT32 num) {
2509 if (!fp) {
2510 LOG_ERROR(
2511 "libtcd error: attempt to access database when database not open\n");
2512 exit(-1);
2513 }
2514 if (num >= 0 && num < (NV_INT32)hd.pub.number_of_records)
2515 return (tindex[num].name);
2516 return ("Unknown");
2517}
2518
2519/*****************************************************************************\
2520
2521 Function get_constituent - get the constituent name for constituent
2522 number "num"
2523
2524 Synopsis get_constituent (num);
2525
2526 NV_INT32 num constituent number
2527
2528 Returns NV_CHAR * constituent name
2529
2530 Author Jan C. Depner
2531 Date 08/01/02
2532
2533 See libtcd.html for changelog.
2534
2535\*****************************************************************************/
2536
2537const NV_CHAR *get_constituent(NV_INT32 num) {
2538 if (!fp) {
2539 LOG_ERROR(
2540 "libtcd error: attempt to access database when database not open\n");
2541 exit(-1);
2542 }
2543 if (num >= 0 && num < (NV_INT32)hd.pub.constituents)
2544 return (hd.constituent[num]);
2545 return ("Unknown");
2546}
2547
2548/*****************************************************************************\
2549
2550 Function get_level_units - get the level units for level units
2551 number "num"
2552
2553 Synopsis get_level_units (num);
2554
2555 NV_INT32 num level units number
2556
2557 Returns NV_CHAR * units (ex. "meters");
2558
2559 Author Jan C. Depner
2560 Date 08/01/02
2561
2562 See libtcd.html for changelog.
2563
2564\*****************************************************************************/
2565
2566const NV_CHAR *get_level_units(NV_INT32 num) {
2567 if (!fp) {
2568 LOG_ERROR(
2569 "libtcd error: attempt to access database when database not open\n");
2570 exit(-1);
2571 }
2572 if (num >= 0 && num < (NV_INT32)hd.pub.level_unit_types)
2573 return (hd.level_unit[num]);
2574 return ("Unknown");
2575}
2576
2577/*****************************************************************************\
2578
2579 Function get_dir_units - get the direction units for direction
2580 units number "num"
2581
2582 Synopsis get_dir_units (num);
2583
2584 NV_INT32 num direction units number
2585
2586 Returns NV_CHAR * units (ex. "degrees true");
2587
2588 Author Jan C. Depner
2589 Date 08/01/02
2590
2591 See libtcd.html for changelog.
2592
2593\*****************************************************************************/
2594
2595const NV_CHAR *get_dir_units(NV_INT32 num) {
2596 if (!fp) {
2597 LOG_ERROR(
2598 "libtcd error: attempt to access database when database not open\n");
2599 exit(-1);
2600 }
2601 if (num >= 0 && num < (NV_INT32)hd.pub.dir_unit_types)
2602 return (hd.dir_unit[num]);
2603 return ("Unknown");
2604}
2605
2606/*****************************************************************************\
2607
2608 Function get_restriction - gets the restriction description for
2609 restriction number "num"
2610
2611 Synopsis get_restriction (num);
2612
2613 NV_INT32 num restriction number
2614
2615 Returns NV_CHAR * restriction (ex. "PUBLIC DOMAIN");
2616
2617 Author Jan C. Depner
2618 Date 08/01/02
2619
2620 See libtcd.html for changelog.
2621
2622\*****************************************************************************/
2623
2624const NV_CHAR *get_restriction(NV_INT32 num) {
2625 if (!fp) {
2626 LOG_ERROR(
2627 "libtcd error: attempt to access database when database not open\n");
2628 exit(-1);
2629 }
2630 if (num >= 0 && num < (NV_INT32)hd.pub.restriction_types)
2631 return (hd.restriction[num]);
2632 return ("Unknown");
2633}
2634
2635/*****************************************************************************\
2636
2637 Function get_pedigree - gets the pedigree description for pedigree
2638 number "num"
2639
2640 Synopsis get_pedigree (num);
2641
2642 NV_INT32 num pedigree number
2643
2644 Returns NV_CHAR * pedigree description
2645
2646 Author Jan C. Depner
2647 Date 08/01/02
2648
2649 See libtcd.html for changelog.
2650
2651\*****************************************************************************/
2652
2653#ifdef COMPAT114
2654NV_CHAR *get_pedigree(NV_INT32 num) { return "Unknown"; }
2655#endif
2656
2657/*****************************************************************************\
2658
2659 Function get_datum - gets the datum name for datum number "num"
2660
2661 Synopsis get_datum (num);
2662
2663 NV_INT32 num datum number
2664
2665 Returns NV_CHAR * datum name
2666
2667 Author Jan C. Depner
2668 Date 08/01/02
2669
2670 See libtcd.html for changelog.
2671
2672\*****************************************************************************/
2673
2674const NV_CHAR *get_datum(NV_INT32 num) {
2675 if (!fp) {
2676 LOG_ERROR(
2677 "libtcd error: attempt to access database when database not open\n");
2678 exit(-1);
2679 }
2680 if (num >= 0 && num < (NV_INT32)hd.pub.datum_types) return (hd.datum[num]);
2681 return ("Unknown");
2682}
2683
2684/*****************************************************************************\
2685DWF 2004-10-14
2686\*****************************************************************************/
2687const NV_CHAR *get_legalese(NV_INT32 num) {
2688 if (!fp) {
2689 LOG_ERROR(
2690 "libtcd error: attempt to access database when database not open\n");
2691 exit(-1);
2692 }
2693 if (num >= 0 && num < (NV_INT32)hd.pub.legaleses) return (hd.legalese[num]);
2694 return ("Unknown");
2695}
2696
2697/*****************************************************************************\
2698
2699 Function get_speed - gets the speed value for constituent number
2700 "num"
2701
2702 Synopsis get_speed (num);
2703
2704 NV_INT32 num constituent number
2705
2706 Returns NV_FLOAT64 speed
2707
2708 Author Jan C. Depner
2709 Date 08/01/02
2710
2711 See libtcd.html for changelog.
2712
2713\*****************************************************************************/
2714
2715NV_FLOAT64 get_speed(NV_INT32 num) {
2716 if (!fp) {
2717 LOG_ERROR(
2718 "libtcd error: attempt to access database when database not open\n");
2719 exit(-1);
2720 }
2721 assert(num >= 0 && num < (NV_INT32)hd.pub.constituents);
2722 return hd.speed[num];
2723}
2724
2725/*****************************************************************************\
2726
2727 Function get_equilibrium - gets the equilibrium value for
2728 constituent number "num" and year "year"
2729
2730 Synopsis get_equilibrium (num, year);
2731
2732 NV_INT32 num constituent number
2733 NV_INT32 year year
2734
2735 Returns NV_FLOAT32 equilibrium argument
2736
2737 Author Jan C. Depner
2738 Date 08/01/02
2739
2740 See libtcd.html for changelog.
2741
2742\*****************************************************************************/
2743
2744NV_FLOAT32 get_equilibrium(NV_INT32 num, NV_INT32 year) {
2745 if (!fp) {
2746 LOG_ERROR(
2747 "libtcd error: attempt to access database when database not open\n");
2748 exit(-1);
2749 }
2750 assert(num >= 0 && num < (NV_INT32)hd.pub.constituents && year >= 0 &&
2751 year < (NV_INT32)hd.pub.number_of_years);
2752 return hd.equilibrium[num][year];
2753}
2754
2755/*****************************************************************************\
2756 DWF 2004-10-04
2757\*****************************************************************************/
2758NV_FLOAT32 *get_equilibriums(NV_INT32 num) {
2759 if (!fp) {
2760 LOG_ERROR(
2761 "libtcd error: attempt to access database when database not open\n");
2762 exit(-1);
2763 }
2764 assert(num >= 0 && num < (NV_INT32)hd.pub.constituents);
2765 return hd.equilibrium[num];
2766}
2767
2768/*****************************************************************************\
2769
2770 Function get_node_factor - gets the node factor value for
2771 constituent number "num" and year "year"
2772
2773 Synopsis get_node_factor (num, year);
2774
2775 NV_INT32 num constituent number
2776 NV_INT32 year year
2777
2778 Returns NV_FLOAT32 node factor
2779
2780 Author Jan C. Depner
2781 Date 08/01/02
2782
2783 See libtcd.html for changelog.
2784
2785\*****************************************************************************/
2786
2787NV_FLOAT32 get_node_factor(NV_INT32 num, NV_INT32 year) {
2788 if (!fp) {
2789 LOG_ERROR(
2790 "libtcd error: attempt to access database when database not open\n");
2791 exit(-1);
2792 }
2793 assert(num >= 0 && num < (NV_INT32)hd.pub.constituents && year >= 0 &&
2794 year < (NV_INT32)hd.pub.number_of_years);
2795 return hd.node_factor[num][year];
2796}
2797
2798/*****************************************************************************\
2799 DWF 2004-10-04
2800\*****************************************************************************/
2801NV_FLOAT32 *get_node_factors(NV_INT32 num) {
2802 if (!fp) {
2803 LOG_ERROR(
2804 "libtcd error: attempt to access database when database not open\n");
2805 exit(-1);
2806 }
2807 assert(num >= 0 && num < (NV_INT32)hd.pub.constituents);
2808 return hd.node_factor[num];
2809}
2810
2811/*****************************************************************************\
2812
2813 Function get_partial_tide_record - gets "header" portion of record
2814 "num" from the index that is stored in memory. This is
2815 way faster than reading it again and we have to read it
2816 to set up the index. This costs a bit in terms of
2817 memory but most applications use this data far more than
2818 the rest of the record.
2819
2820 Synopsis get_partial_tide_record (num, rec);
2821
2822 NV_INT32 num record number
2823 TIDE_STATION_HEADER *rec header portion of the record
2824
2825 Returns NV_BOOL NVTrue if successful
2826
2827 Author Jan C. Depner
2828 Date 08/01/02
2829
2830 See libtcd.html for changelog.
2831
2832\*****************************************************************************/
2833
2834NV_BOOL get_partial_tide_record(NV_INT32 num, TIDE_STATION_HEADER *rec) {
2835 if (!fp) {
2836 LOG_ERROR(
2837 "libtcd error: attempt to access database when database not open\n");
2838 return NVFalse;
2839 }
2840
2841 if (num < 0 || num >= (NV_INT32)hd.pub.number_of_records) return (NVFalse);
2842
2843 assert(rec);
2844
2845 rec->record_number = num;
2846 rec->record_size = tindex[num].record_size;
2847 rec->record_type = tindex[num].record_type;
2848 rec->latitude = (NV_FLOAT64)tindex[num].lat / hd.latitude_scale;
2849 rec->longitude = (NV_FLOAT64)tindex[num].lon / hd.longitude_scale;
2850 rec->reference_station = tindex[num].reference_station;
2851 rec->tzfile = tindex[num].tzfile;
2852 strcpy(rec->name, tindex[num].name);
2853
2854 current_index = num;
2855
2856 return (NVTrue);
2857}
2858
2859/*****************************************************************************\
2860
2861 Function get_next_partial_tide_record - gets "header" portion of
2862 the next record from the index that is stored in memory.
2863
2864 Synopsis get_next_partial_tide_record (rec);
2865
2866 TIDE_STATION_HEADER *rec header portion of the record
2867
2868 Returns NV_INT32 record number or -1 on failure
2869
2870 Author Jan C. Depner
2871 Date 08/01/02
2872
2873 See libtcd.html for changelog.
2874
2875\*****************************************************************************/
2876
2877NV_INT32 get_next_partial_tide_record(TIDE_STATION_HEADER *rec) {
2878 if (!get_partial_tide_record(current_index + 1, rec)) return (-1);
2879
2880 return (current_index);
2881}
2882
2883/*****************************************************************************\
2884
2885 Function get_nearest_partial_tide_record - gets "header" portion of
2886 the record closest geographically to the input position.
2887
2888 Synopsis get_nearest_partial_tide_record (lat, lon, rec);
2889
2890 NV_FLOAT64 lat latitude
2891 NV_FLOAT64 lon longitude
2892 TIDE_STATION_HEADER *rec header portion of the record
2893
2894 Returns NV_INT32 record number or -1 on failure
2895
2896 Author Jan C. Depner
2897 Date 08/01/02
2898
2899 See libtcd.html for changelog.
2900
2901\*****************************************************************************/
2902
2903NV_INT32 get_nearest_partial_tide_record(NV_FLOAT64 lat, NV_FLOAT64 lon,
2904 TIDE_STATION_HEADER *rec) {
2905 NV_FLOAT64 diff, min_diff, lt, ln;
2906 NV_U_INT32 i, shortest = 0;
2907
2908 min_diff = 999999999.9;
2909 for (i = 0; i < hd.pub.number_of_records; ++i) {
2910 lt = (NV_FLOAT64)tindex[i].lat / hd.latitude_scale;
2911 ln = (NV_FLOAT64)tindex[i].lon / hd.longitude_scale;
2912
2913 diff = sqrt((lat - lt) * (lat - lt) + (lon - ln) * (lon - ln));
2914
2915 if (diff < min_diff) {
2916 min_diff = diff;
2917 shortest = i;
2918 }
2919 }
2920
2921 if (!get_partial_tide_record(shortest, rec)) return (-1);
2922 return (shortest);
2923}
2924
2925/*****************************************************************************\
2926
2927 Function get_time - converts a time string in +/-HH:MM form to an
2928 integer in +/-HHMM form
2929
2930 Synopsis get_time (string);
2931
2932 NV_CHAR *string time string
2933
2934 Returns NV_INT32 time
2935
2936 Author Jan C. Depner
2937 Date 08/01/02
2938
2939 See libtcd.html for changelog.
2940
2941\*****************************************************************************/
2942
2943NV_INT32 get_time(const NV_CHAR *string) {
2944 NV_INT32 hour, minute, hhmm;
2945
2946 assert(string);
2947 sscanf(string, "%d:%d", &hour, &minute);
2948
2949 /* Trying to deal with negative 0 (-00:45). */
2950
2951 if (string[0] == '-') {
2952 if (hour < 0) hour = -hour;
2953
2954 hhmm = -(hour * 100 + minute);
2955 } else {
2956 hhmm = hour * 100 + minute;
2957 }
2958
2959 return (hhmm);
2960}
2961
2962/*****************************************************************************\
2963
2964 Function ret_time - converts a time value in +/-HHMM form to a
2965 time string in +/-HH:MM form
2966
2967 Synopsis ret_time (time);
2968
2969 NV_INT32 time
2970
2971 Returns NV_CHAR * time string
2972
2973 Author Jan C. Depner
2974 Date 08/01/02
2975
2976 See libtcd.html for changelog.
2977
2978\*****************************************************************************/
2979
2980NV_CHAR *ret_time(NV_INT32 time) {
2981 NV_INT32 hour, minute;
2982 static NV_CHAR tname[16];
2983
2984 hour = abs(time) / 100;
2985 assert(hour <= 99999 && hour >= -99999); /* 9 chars: +99999:99 */
2986 minute = abs(time) % 100;
2987
2988 if (time < 0) {
2989 sprintf(tname, "-%02d:%02d", hour, minute);
2990 } else {
2991 sprintf(tname, "+%02d:%02d", hour, minute);
2992 }
2993
2994 return tname;
2995}
2996
2997/*****************************************************************************\
2998 DWF 2004-10-04
2999\*****************************************************************************/
3000NV_CHAR *ret_time_neat(NV_INT32 time) {
3001 NV_INT32 hour, minute;
3002 static NV_CHAR tname[16];
3003
3004 hour = abs(time) / 100;
3005 assert(hour <= 99999 && hour >= -99999); /* 9 chars: +99999:99 */
3006 minute = abs(time) % 100;
3007
3008 if (time < 0)
3009 sprintf(tname, "-%d:%02d", hour, minute);
3010 else if (time > 0)
3011 sprintf(tname, "+%d:%02d", hour, minute);
3012 else
3013 strcpy(tname, "0:00");
3014
3015 return tname;
3016}
3017
3018/*****************************************************************************\
3019 DWF 2004-10-04
3020\*****************************************************************************/
3021NV_CHAR *ret_date(NV_U_INT32 date) {
3022 static NV_CHAR tname[30];
3023 if (!date)
3024 strcpy(tname, "NULL");
3025 else {
3026 unsigned y, m, d;
3027 y = date / 10000;
3028 date %= 10000;
3029 m = date / 100;
3030 d = date % 100;
3031 sprintf(tname, "%4u-%02u-%02u", y, m, d);
3032 }
3033 return tname;
3034}
3035
3036/*****************************************************************************\
3037
3038 Function get_tide_db_header - gets the public portion of the tide
3039 database header
3040
3041 Synopsis get_tide_db_header ();
3042
3043 Returns DB_HEADER_PUBLIC public tide header
3044
3045 Author Jan C. Depner
3046 Date 08/01/02
3047
3048 See libtcd.html for changelog.
3049
3050\*****************************************************************************/
3051
3052DB_HEADER_PUBLIC get_tide_db_header() {
3053 if (!fp) {
3054 LOG_ERROR(
3055 "libtcd error: attempt to access database when database not open\n");
3056 exit(-1);
3057 }
3058 return (hd.pub);
3059}
3060
3061/*****************************************************************************\
3062 DWF 2004-09-30
3063 Prevent buffer overflows for MONOLOGUE_LENGTH strings.
3064\*****************************************************************************/
3065static void boundscheck_monologue(const NV_CHAR *string) {
3066 assert(string);
3067 if (strlen(string) >= MONOLOGUE_LENGTH) {
3068 // LOG_ERROR ("libtcd fatal error: static buffer size exceeded\n");
3069 // LOG_ERROR ("Buffer is size MONOLOGUE_LENGTH (%u)\n",
3070 // MONOLOGUE_LENGTH);
3071 // LOG_ERROR ("String is length %lu\n", strlen(string));
3072 // LOG_ERROR ("The offending string is:\n%s\n", string);
3073 exit(-1);
3074 }
3075}
3076
3077/*****************************************************************************\
3078 DWF 2004-09-30
3079 Prevent buffer overflows for ONELINER_LENGTH strings.
3080\*****************************************************************************/
3081static void boundscheck_oneliner(const NV_CHAR *string) {
3082 assert(string);
3083 if (strlen(string) >= ONELINER_LENGTH) {
3084 // LOG_ERROR ("libtcd fatal error: static buffer size exceeded\n");
3085 // LOG_ERROR ("Buffer is size ONELINER_LENGTH (%u)\n",
3086 // ONELINER_LENGTH);
3087 // LOG_ERROR ("String is length %lu\n", strlen(string));
3088 // LOG_ERROR ("The offending string is:\n%s\n", string);
3089 exit(-1);
3090 }
3091}
3092
3093/*****************************************************************************\
3094
3095 Function clip_string - removes leading and trailing spaces from
3096 search strings.
3097
3098 Synopsis clip_string (string);
3099
3100 NV_CHAR *string search string
3101
3102 Returns NV_CHAR * clipped string
3103
3104 Author Jan C. Depner
3105 Date 09/16/02
3106
3107 See libtcd.html for changelog.
3108
3109\*****************************************************************************/
3110
3111static NV_CHAR *clip_string(const NV_CHAR *string) {
3112 static NV_CHAR new_string[MONOLOGUE_LENGTH];
3113 NV_INT32 i, l, start = -1, end = -1;
3114
3115 boundscheck_monologue(string);
3116 new_string[0] = '\0';
3117
3118 l = (int)strlen(string);
3119 if (l) {
3120 for (i = 0; i < l; ++i) {
3121 if (string[i] != ' ') {
3122 start = i;
3123 break;
3124 }
3125 }
3126 for (i = l - 1; i >= start; --i) {
3127 if (string[i] != ' ' && string[i] != 10 && string[i] != 13) {
3128 end = i;
3129 break;
3130 }
3131 }
3132 if (start > -1 && end > -1 && end >= start) {
3133 strncpy(new_string, string + start, end - start + 1);
3134 new_string[end - start + 1] = '\0';
3135 }
3136 }
3137 return new_string;
3138}
3139
3140/*****************************************************************************\
3141
3142 Function search_station - returns record numbers of all stations
3143 that have the string "string" anywhere in the station
3144 name. This search is case insensitive. When no more
3145 records are found it returns -1;
3146
3147 Synopsis search_station (string);
3148
3149 NV_CHAR *string search string
3150
3151 Returns NV_INT32 record number or -1 when no more
3152 matches
3153
3154 Author Jan C. Depner
3155 Date 08/01/02
3156
3157 See libtcd.html for changelog.
3158
3159\*****************************************************************************/
3160
3161NV_INT32 search_station(const NV_CHAR *string) {
3162 static NV_CHAR last_search[ONELINER_LENGTH];
3163 static NV_U_INT32 j = 0;
3164 NV_U_INT32 i;
3165 NV_CHAR name[ONELINER_LENGTH], search[ONELINER_LENGTH];
3166
3167 if (!fp) {
3168 LOG_ERROR(
3169 "libtcd error: attempt to access database when database not open\n");
3170 return -1;
3171 }
3172
3173 boundscheck_oneliner(string);
3174
3175 for (i = 0; i < strlen(string) + 1; ++i) search[i] = tolower(string[i]);
3176
3177 if (strcmp(search, last_search)) j = 0;
3178
3179 strcpy(last_search, search);
3180
3181 while (j < hd.pub.number_of_records) {
3182 for (i = 0; i < strlen(tindex[j].name) + 1; ++i)
3183 name[i] = tolower(tindex[j].name[i]);
3184
3185 ++j;
3186 if (strstr(name, search)) return (j - 1);
3187 }
3188
3189 j = 0;
3190 return -1;
3191}
3192
3193/*****************************************************************************\
3194
3195 Function find_station - finds the record number of the station
3196 that has name "name"
3197
3198 Synopsis find_station (name);
3199
3200 NV_CHAR *name station name
3201
3202 Returns NV_INT32 record number
3203
3204 Author Jan C. Depner
3205 Date 08/01/02
3206
3207 See libtcd.html for changelog.
3208
3209\*****************************************************************************/
3210
3211NV_INT32 find_station(const NV_CHAR *name) {
3212 NV_U_INT32 i;
3213
3214 if (!fp) {
3215 LOG_ERROR(
3216 "libtcd error: attempt to access database when database not open\n");
3217 return -1;
3218 }
3219
3220 assert(name);
3221 for (i = 0; i < hd.pub.number_of_records; ++i) {
3222 if (!strcmp(name, tindex[i].name)) return (i);
3223 }
3224
3225 return (-1);
3226}
3227
3228/*****************************************************************************\
3229
3230 Function find_tzfile - gets the timezone number (index into
3231 tzfile array) given the tzfile name
3232
3233 Synopsis find_tzfile (name);
3234
3235 NV_CHAR *name tzfile name
3236
3237 Returns NV_INT32 tzfile number
3238
3239 Author Jan C. Depner
3240 Date 08/01/02
3241
3242 See libtcd.html for changelog.
3243
3244\*****************************************************************************/
3245
3246NV_INT32 find_tzfile(const NV_CHAR *name) {
3247 NV_INT32 j;
3248 NV_U_INT32 i;
3249 NV_CHAR *temp;
3250
3251 if (!fp) {
3252 LOG_ERROR(
3253 "libtcd error: attempt to access database when database not open\n");
3254 return -1;
3255 }
3256
3257 temp = clip_string(name);
3258
3259 j = -1;
3260 for (i = 0; i < hd.pub.tzfiles; ++i) {
3261 if (!strcmp(temp, get_tzfile(i))) {
3262 j = i;
3263 break;
3264 }
3265 }
3266
3267 return (j);
3268}
3269
3270/*****************************************************************************\
3271
3272 Function find_country - gets the timezone number (index into
3273 country array) given the country name
3274
3275 Synopsis find_country (name);
3276
3277 NV_CHAR *name country name
3278
3279 Returns NV_INT32 country number
3280
3281 Author Jan C. Depner
3282 Date 08/01/02
3283
3284 See libtcd.html for changelog.
3285
3286\*****************************************************************************/
3287
3288NV_INT32 find_country(const NV_CHAR *name) {
3289 NV_INT32 j;
3290 NV_U_INT32 i;
3291 NV_CHAR *temp;
3292
3293 if (!fp) {
3294 LOG_ERROR(
3295 "libtcd error: attempt to access database when database not open\n");
3296 return -1;
3297 }
3298
3299 temp = clip_string(name);
3300
3301 j = -1;
3302 for (i = 0; i < hd.pub.countries; ++i) {
3303 if (!strcmp(temp, get_country(i))) {
3304 j = i;
3305 break;
3306 }
3307 }
3308
3309 return (j);
3310}
3311
3312/*****************************************************************************\
3313
3314 Function find_level_units - gets the index into the level_units
3315 array given the level units name
3316
3317 Synopsis find_level_units (name);
3318
3319 NV_CHAR *name units name (ex. "meters")
3320
3321 Returns NV_INT32 units number
3322
3323 Author Jan C. Depner
3324 Date 08/01/02
3325
3326 See libtcd.html for changelog.
3327
3328\*****************************************************************************/
3329
3330NV_INT32 find_level_units(const NV_CHAR *name) {
3331 NV_INT32 j;
3332 NV_U_INT32 i;
3333 NV_CHAR *temp;
3334
3335 if (!fp) {
3336 LOG_ERROR(
3337 "libtcd error: attempt to access database when database not open\n");
3338 return -1;
3339 }
3340
3341 temp = clip_string(name);
3342
3343 j = -1;
3344 for (i = 0; i < hd.pub.level_unit_types; ++i) {
3345 if (!strcmp(get_level_units(i), temp)) {
3346 j = i;
3347 break;
3348 }
3349 }
3350
3351 return (j);
3352}
3353
3354/*****************************************************************************\
3355
3356 Function find_dir_units - gets the index into the dir_units
3357 array given the direction units name
3358
3359 Synopsis find_dir_units (name);
3360
3361 NV_CHAR *name units name (ex. "degrees true")
3362
3363 Returns NV_INT32 units number
3364
3365 Author Jan C. Depner
3366 Date 08/01/02
3367
3368 See libtcd.html for changelog.
3369
3370\*****************************************************************************/
3371
3372NV_INT32 find_dir_units(const NV_CHAR *name) {
3373 NV_INT32 j;
3374 NV_U_INT32 i;
3375 NV_CHAR *temp;
3376
3377 if (!fp) {
3378 LOG_ERROR(
3379 "libtcd error: attempt to access database when database not open\n");
3380 return -1;
3381 }
3382
3383 temp = clip_string(name);
3384
3385 j = -1;
3386 for (i = 0; i < hd.pub.dir_unit_types; ++i) {
3387 if (!strcmp(get_dir_units(i), temp)) {
3388 j = i;
3389 break;
3390 }
3391 }
3392
3393 return (j);
3394}
3395
3396/*****************************************************************************\
3397
3398 Function find_pedigree - gets the index into the pedigree array
3399 given the pedigree name
3400
3401 Synopsis find_pedigree (name);
3402
3403 NV_CHAR *name pedigree name
3404
3405 Returns NV_INT32 pedigree number
3406
3407 Author Jan C. Depner
3408 Date 08/01/02
3409
3410 See libtcd.html for changelog.
3411
3412\*****************************************************************************/
3413
3414#ifdef COMPAT114
3415NV_INT32 find_pedigree(const NV_CHAR *name) { return 0; }
3416#endif
3417
3418/*****************************************************************************\
3419
3420 Function find_datum - gets the index into the datum array given the
3421 datum name
3422
3423 Synopsis find_datum (name);
3424
3425 NV_CHAR *name datum name
3426
3427 Returns NV_INT32 datum number
3428
3429 Author Jan C. Depner
3430 Date 08/01/02
3431
3432 See libtcd.html for changelog.
3433
3434\*****************************************************************************/
3435
3436NV_INT32 find_datum(const NV_CHAR *name) {
3437 NV_INT32 j;
3438 NV_U_INT32 i;
3439 NV_CHAR *temp;
3440
3441 if (!fp) {
3442 LOG_ERROR(
3443 "libtcd error: attempt to access database when database not open\n");
3444 return -1;
3445 }
3446
3447 temp = clip_string(name);
3448
3449 j = -1;
3450 for (i = 0; i < hd.pub.datum_types; ++i) {
3451 if (!strcmp(get_datum(i), temp)) {
3452 j = i;
3453 break;
3454 }
3455 }
3456
3457 return (j);
3458}
3459
3460/*****************************************************************************\
3461 DWF 2004-10-14
3462\*****************************************************************************/
3463NV_INT32 find_legalese(const NV_CHAR *name) {
3464 NV_INT32 j;
3465 NV_U_INT32 i;
3466 NV_CHAR *temp;
3467
3468 if (!fp) {
3469 LOG_ERROR(
3470 "libtcd error: attempt to access database when database not open\n");
3471 return -1;
3472 }
3473
3474 temp = clip_string(name);
3475
3476 j = -1;
3477 for (i = 0; i < hd.pub.legaleses; ++i) {
3478 if (!strcmp(get_legalese(i), temp)) {
3479 j = i;
3480 break;
3481 }
3482 }
3483
3484 return (j);
3485}
3486
3487/*****************************************************************************\
3488
3489 Function find_constituent - gets the index into the constituent
3490 arrays for the named constituent.
3491
3492 Synopsis find_constituent (name);
3493
3494 NV_CHAR *name constituent name (ex. M2)
3495
3496 Returns NV_INT32 index into constituent arrays or -1
3497 on failure
3498
3499 Author Jan C. Depner
3500 Date 08/01/02
3501
3502 See libtcd.html for changelog.
3503
3504\*****************************************************************************/
3505
3506NV_INT32 find_constituent(const NV_CHAR *name) {
3507 NV_U_INT32 i;
3508 NV_CHAR *temp;
3509
3510 if (!fp) {
3511 LOG_ERROR(
3512 "libtcd error: attempt to access database when database not open\n");
3513 return -1;
3514 }
3515
3516 temp = clip_string(name);
3517
3518 for (i = 0; i < hd.pub.constituents; ++i) {
3519 if (!strcmp(get_constituent(i), temp)) return (i);
3520 }
3521
3522 return (-1);
3523}
3524
3525/*****************************************************************************\
3526
3527 Function find_restriction - gets the index into the restriction
3528 array given the restriction name
3529
3530 Synopsis find_restriction (name);
3531
3532 NV_CHAR *name restriction name
3533
3534 Returns NV_INT32 restriction number
3535
3536 Author Jan C. Depner
3537 Date 08/01/02
3538
3539 See libtcd.html for changelog.
3540
3541\*****************************************************************************/
3542
3543NV_INT32 find_restriction(const NV_CHAR *name) {
3544 NV_INT32 j;
3545 NV_U_INT32 i;
3546 NV_CHAR *temp;
3547
3548 if (!fp) {
3549 LOG_ERROR(
3550 "libtcd error: attempt to access database when database not open\n");
3551 return -1;
3552 }
3553
3554 temp = clip_string(name);
3555
3556 j = -1;
3557 for (i = 0; i < hd.pub.restriction_types; ++i) {
3558 if (!strcmp(get_restriction(i), temp)) {
3559 j = i;
3560 break;
3561 }
3562 }
3563 return (j);
3564}
3565
3566/*****************************************************************************\
3567
3568 Function set_speed - sets the speed value for constituent "num"
3569
3570 Synopsis set_speed (num, value);
3571
3572 NV_INT32 num constituent number
3573 NV_FLOAT64 value speed value
3574
3575 Returns void
3576
3577 Author Jan C. Depner
3578 Date 08/01/02
3579
3580 See libtcd.html for changelog.
3581
3582\*****************************************************************************/
3583
3584void set_speed(NV_INT32 num, NV_FLOAT64 value) {
3585 if (!fp) {
3586 LOG_ERROR(
3587 "libtcd error: attempt to access database when database not open\n");
3588 exit(-1);
3589 }
3590 write_protect();
3591 assert(num >= 0 && num < (NV_INT32)hd.pub.constituents);
3592 if (value < 0.0) {
3593 LOG_ERROR("libtcd set_speed: somebody tried to set a negative speed (%f)\n",
3594 value);
3595 exit(-1);
3596 }
3597 hd.speed[num] = value;
3598 modified = NVTrue;
3599}
3600
3601/*****************************************************************************\
3602
3603 Function set_equilibrium - sets the equilibrium argument for
3604 constituent "num" and year "year"
3605
3606 Synopsis set_equilibrium (num, year, value);
3607
3608 NV_INT32 num constituent number
3609 NV_INT32 year year
3610 NV_FLOAT64 value equilibrium argument
3611
3612 Returns void
3613
3614 Author Jan C. Depner
3615 Date 08/01/02
3616
3617 See libtcd.html for changelog.
3618
3619\*****************************************************************************/
3620
3621void set_equilibrium(NV_INT32 num, NV_INT32 year, NV_FLOAT32 value) {
3622 if (!fp) {
3623 LOG_ERROR(
3624 "libtcd error: attempt to access database when database not open\n");
3625 exit(-1);
3626 }
3627 write_protect();
3628 assert(num >= 0 && num < (NV_INT32)hd.pub.constituents && year >= 0 &&
3629 year < (NV_INT32)hd.pub.number_of_years);
3630 hd.equilibrium[num][year] = value;
3631 modified = NVTrue;
3632}
3633
3634/*****************************************************************************\
3635
3636 Function set_node_factor - sets the node factor for constituent
3637 "num" and year "year"
3638
3639 Synopsis set_node_factor (num, year, value);
3640
3641 NV_INT32 num constituent number
3642 NV_INT32 year year
3643 NV_FLOAT64 value node factor
3644
3645 Returns void
3646
3647 Author Jan C. Depner
3648 Date 08/01/02
3649
3650 See libtcd.html for changelog.
3651
3652\*****************************************************************************/
3653
3654void set_node_factor(NV_INT32 num, NV_INT32 year, NV_FLOAT32 value) {
3655 if (!fp) {
3656 LOG_ERROR(
3657 "libtcd error: attempt to access database when database not open\n");
3658 exit(-1);
3659 }
3660 write_protect();
3661 assert(num >= 0 && num < (NV_INT32)hd.pub.constituents && year >= 0 &&
3662 year < (NV_INT32)hd.pub.number_of_years);
3663 if (value <= 0.0) {
3664 LOG_ERROR(
3665 "libtcd set_node_factor: somebody tried to set a negative or zero node "
3666 "factor (%f)\n",
3667 value);
3668 exit(-1);
3669 }
3670 hd.node_factor[num][year] = value;
3671 modified = NVTrue;
3672}
3673
3674/*****************************************************************************\
3675
3676 Function add_pedigree - adds a new pedigree to the database
3677
3678 Synopsis add_pedigree (name, db);
3679
3680 NV_CHAR *name new pedigree string
3681 DB_HEADER_PUBLIC *db modified header
3682
3683 Returns NV_INT32 new pedigree index
3684
3685 Author Jan C. Depner
3686 Date 09/20/02
3687
3688 See libtcd.html for changelog.
3689
3690\*****************************************************************************/
3691
3692#ifdef COMPAT114
3693NV_INT32 add_pedigree(const NV_CHAR *name, const DB_HEADER_PUBLIC *db) {
3694 return 0;
3695}
3696#endif
3697
3698/*****************************************************************************\
3699
3700 Function add_tzfile - adds a new tzfile to the database
3701
3702 Synopsis add_tzfile (name, db);
3703
3704 NV_CHAR *name new tzfile string
3705 DB_HEADER_PUBLIC *db modified header
3706
3707 Returns NV_INT32 new tzfile index
3708
3709 Author Jan C. Depner
3710 Date 09/20/02
3711
3712 See libtcd.html for changelog.
3713
3714\*****************************************************************************/
3715
3716NV_INT32 add_tzfile(const NV_CHAR *name, DB_HEADER_PUBLIC *db) {
3717 NV_CHAR *c_name;
3718
3719 if (!fp) {
3720 LOG_ERROR(
3721 "libtcd error: attempt to access database when database not open\n");
3722 exit(-1);
3723 }
3724 write_protect();
3725
3726 assert(name);
3727 if (strlen(name) + 1 > hd.tzfile_size) {
3728 LOG_ERROR("libtcd error: tzfile exceeds size limit (%u).\n",
3729 hd.tzfile_size);
3730 LOG_ERROR("The offending input is: %s\n", name);
3731 exit(-1);
3732 }
3733
3734 if (hd.pub.tzfiles == hd.max_tzfiles) {
3735 LOG_ERROR("You have exceeded the maximum number of tzfile types!\n");
3736 LOG_ERROR("You cannot add any new tzfile types.\n");
3737 LOG_ERROR("Modify the DEFAULT_TZFILE_BITS and rebuild the database.\n");
3738 exit(-1);
3739 }
3740
3741 c_name = clip_string(name);
3742
3743 hd.tzfile[hd.pub.tzfiles] =
3744 (NV_CHAR *)calloc(strlen(c_name) + 1, sizeof(NV_CHAR));
3745
3746 if (hd.tzfile[hd.pub.tzfiles] == NULL) {
3747 perror("Allocating new tzfile string");
3748 exit(-1);
3749 }
3750
3751 strcpy(hd.tzfile[hd.pub.tzfiles++], c_name);
3752 if (db) *db = hd.pub;
3753 modified = NVTrue;
3754 return (hd.pub.tzfiles - 1);
3755}
3756
3757/*****************************************************************************\
3758
3759 Function add_country - adds a new country to the database
3760
3761 Synopsis add_country (name, db);
3762
3763 NV_CHAR *name new country string
3764 DB_HEADER_PUBLIC *db modified header
3765
3766 Returns NV_INT32 new country index
3767
3768 Author Jan C. Depner
3769 Date 09/20/02
3770
3771 See libtcd.html for changelog.
3772
3773\*****************************************************************************/
3774
3775NV_INT32 add_country(const NV_CHAR *name, DB_HEADER_PUBLIC *db) {
3776 NV_CHAR *c_name;
3777
3778 if (!fp) {
3779 LOG_ERROR(
3780 "libtcd error: attempt to access database when database not open\n");
3781 exit(-1);
3782 }
3783 write_protect();
3784
3785 assert(name);
3786 if (strlen(name) + 1 > hd.country_size) {
3787 LOG_ERROR("libtcd error: country exceeds size limit (%u).\n",
3788 hd.country_size);
3789 LOG_ERROR("The offending input is: %s\n", name);
3790 exit(-1);
3791 }
3792
3793 if (hd.pub.countries == hd.max_countries) {
3794 LOG_ERROR("You have exceeded the maximum number of country names!\n");
3795 LOG_ERROR("You cannot add any new country names.\n");
3796 LOG_ERROR("Modify the DEFAULT_COUNTRY_BITS and rebuild the database.\n");
3797 exit(-1);
3798 }
3799
3800 c_name = clip_string(name);
3801
3802 hd.country[hd.pub.countries] =
3803 (NV_CHAR *)calloc(strlen(c_name) + 1, sizeof(NV_CHAR));
3804
3805 if (hd.country[hd.pub.countries] == NULL) {
3806 perror("Allocating new country string");
3807 exit(-1);
3808 }
3809
3810 strcpy(hd.country[hd.pub.countries++], c_name);
3811 if (db) *db = hd.pub;
3812 modified = NVTrue;
3813 return (hd.pub.countries - 1);
3814}
3815
3816/*****************************************************************************\
3817
3818 Function add_datum - adds a new datum to the database
3819
3820 Synopsis add_datum (name, db);
3821
3822 NV_CHAR *name new datum string
3823 DB_HEADER_PUBLIC *db modified header
3824
3825 Returns NV_INT32 new datum index
3826
3827 Author Jan C. Depner
3828 Date 09/20/02
3829
3830 See libtcd.html for changelog.
3831
3832\*****************************************************************************/
3833
3834NV_INT32 add_datum(const NV_CHAR *name, DB_HEADER_PUBLIC *db) {
3835 NV_CHAR *c_name;
3836
3837 if (!fp) {
3838 LOG_ERROR(
3839 "libtcd error: attempt to access database when database not open\n");
3840 exit(-1);
3841 }
3842 write_protect();
3843
3844 assert(name);
3845 if (strlen(name) + 1 > hd.datum_size) {
3846 LOG_ERROR("libtcd error: datum exceeds size limit (%u).\n", hd.datum_size);
3847 LOG_ERROR("The offending input is: %s\n", name);
3848 exit(-1);
3849 }
3850
3851 if (hd.pub.datum_types == hd.max_datum_types) {
3852 LOG_ERROR("You have exceeded the maximum number of datum types!\n");
3853 LOG_ERROR("You cannot add any new datum types.\n");
3854 LOG_ERROR("Modify the DEFAULT_DATUM_BITS and rebuild the database.\n");
3855 exit(-1);
3856 }
3857
3858 c_name = clip_string(name);
3859
3860 hd.datum[hd.pub.datum_types] =
3861 (NV_CHAR *)calloc(strlen(c_name) + 1, sizeof(NV_CHAR));
3862
3863 if (hd.datum[hd.pub.datum_types] == NULL) {
3864 perror("Allocating new datum string");
3865 exit(-1);
3866 }
3867
3868 strcpy(hd.datum[hd.pub.datum_types++], c_name);
3869 if (db) *db = hd.pub;
3870 modified = NVTrue;
3871 return (hd.pub.datum_types - 1);
3872}
3873
3874/*****************************************************************************\
3875 DWF 2004-10-14
3876\*****************************************************************************/
3877NV_INT32 add_legalese(const NV_CHAR *name, DB_HEADER_PUBLIC *db) {
3878 NV_CHAR *c_name;
3879
3880 if (!fp) {
3881 LOG_ERROR(
3882 "libtcd error: attempt to access database when database not open\n");
3883 exit(-1);
3884 }
3885 write_protect();
3886
3887 assert(name);
3888 if (strlen(name) + 1 > hd.legalese_size) {
3889 LOG_ERROR("libtcd error: legalese exceeds size limit (%u).\n",
3890 hd.legalese_size);
3891 LOG_ERROR("The offending input is: %s\n", name);
3892 exit(-1);
3893 }
3894
3895 if (hd.pub.legaleses == hd.max_legaleses) {
3896 LOG_ERROR("You have exceeded the maximum number of legaleses!\n");
3897 LOG_ERROR("You cannot add any new legaleses.\n");
3898 LOG_ERROR("Modify the DEFAULT_LEGALESE_BITS and rebuild the database.\n");
3899 exit(-1);
3900 }
3901
3902 c_name = clip_string(name);
3903
3904 hd.legalese[hd.pub.legaleses] =
3905 (NV_CHAR *)calloc(strlen(c_name) + 1, sizeof(NV_CHAR));
3906
3907 if (hd.legalese[hd.pub.legaleses] == NULL) {
3908 perror("Allocating new legalese string");
3909 exit(-1);
3910 }
3911
3912 strcpy(hd.legalese[hd.pub.legaleses++], c_name);
3913 if (db) *db = hd.pub;
3914 modified = NVTrue;
3915 return (hd.pub.legaleses - 1);
3916}
3917
3918/*****************************************************************************\
3919
3920 Function add_restriction - adds a new restriction to the database
3921
3922 Synopsis add_restriction (name, db);
3923
3924 NV_CHAR *name new restriction string
3925 DB_HEADER_PUBLIC *db modified header
3926
3927 Returns NV_INT32 new restriction index
3928
3929 Author Jan C. Depner
3930 Date 09/20/02
3931
3932 See libtcd.html for changelog.
3933
3934\*****************************************************************************/
3935
3936NV_INT32 add_restriction(const NV_CHAR *name, DB_HEADER_PUBLIC *db) {
3937 NV_CHAR *c_name;
3938
3939 if (!fp) {
3940 LOG_ERROR(
3941 "libtcd error: attempt to access database when database not open\n");
3942 exit(-1);
3943 }
3944 write_protect();
3945
3946 assert(name);
3947 if (strlen(name) + 1 > hd.restriction_size) {
3948 LOG_ERROR("libtcd error: restriction exceeds size limit (%u).\n",
3949 hd.restriction_size);
3950 LOG_ERROR("The offending input is: %s\n", name);
3951 exit(-1);
3952 }
3953
3954 if (hd.pub.restriction_types == hd.max_restriction_types) {
3955 LOG_ERROR("You have exceeded the maximum number of restriction types!\n");
3956 LOG_ERROR("You cannot add any new restriction types.\n");
3957 LOG_ERROR(
3958 "Modify the DEFAULT_RESTRICTION_BITS and rebuild the database.\n");
3959 exit(-1);
3960 }
3961
3962 c_name = clip_string(name);
3963
3964 hd.restriction[hd.pub.restriction_types] =
3965 (NV_CHAR *)calloc(strlen(c_name) + 1, sizeof(NV_CHAR));
3966
3967 if (hd.restriction[hd.pub.restriction_types] == NULL) {
3968 perror("Allocating new restriction string");
3969 exit(-1);
3970 }
3971
3972 strcpy(hd.restriction[hd.pub.restriction_types++], c_name);
3973 if (db) *db = hd.pub;
3974 modified = NVTrue;
3975 return (hd.pub.restriction_types - 1);
3976}
3977
3978/*****************************************************************************\
3979 DWF 2004-10-04
3980\*****************************************************************************/
3981NV_INT32 find_or_add_restriction(const NV_CHAR *name, DB_HEADER_PUBLIC *db) {
3982 NV_INT32 ret;
3983 ret = find_restriction(name);
3984 if (ret < 0) ret = add_restriction(name, db);
3985 assert(ret >= 0);
3986 return ret;
3987}
3988
3989/*****************************************************************************\
3990 DWF 2004-10-04
3991\*****************************************************************************/
3992NV_INT32 find_or_add_tzfile(const NV_CHAR *name, DB_HEADER_PUBLIC *db) {
3993 NV_INT32 ret;
3994 ret = find_tzfile(name);
3995 if (ret < 0) ret = add_tzfile(name, db);
3996 assert(ret >= 0);
3997 return ret;
3998}
3999
4000/*****************************************************************************\
4001 DWF 2004-10-04
4002\*****************************************************************************/
4003NV_INT32 find_or_add_country(const NV_CHAR *name, DB_HEADER_PUBLIC *db) {
4004 NV_INT32 ret;
4005 ret = find_country(name);
4006 if (ret < 0) ret = add_country(name, db);
4007 assert(ret >= 0);
4008 return ret;
4009}
4010
4011/*****************************************************************************\
4012 DWF 2004-10-04
4013\*****************************************************************************/
4014NV_INT32 find_or_add_datum(const NV_CHAR *name, DB_HEADER_PUBLIC *db) {
4015 NV_INT32 ret;
4016 ret = find_datum(name);
4017 if (ret < 0) ret = add_datum(name, db);
4018 assert(ret >= 0);
4019 return ret;
4020}
4021
4022/*****************************************************************************\
4023 DWF 2004-10-14
4024\*****************************************************************************/
4025NV_INT32 find_or_add_legalese(const NV_CHAR *name, DB_HEADER_PUBLIC *db) {
4026 NV_INT32 ret;
4027 ret = find_legalese(name);
4028 if (ret < 0) ret = add_legalese(name, db);
4029 assert(ret >= 0);
4030 return ret;
4031}
4032
4033/*****************************************************************************\
4034
4035 Function check_simple - checks tide record to see if it is a
4036 "simple" subordinate station.
4037
4038 Synopsis check_simple (rec);
4039
4040 TIDE_RECORD rec tide record
4041
4042 Returns NV_BOOL NVTrue if "simple"
4043
4044 Author Jan C. Depner
4045 Date 08/01/02
4046
4047 See libtcd.html for changelog.
4048
4049 "Simplified" type 2 records were done away with 2003-03-27 per the
4050 discussion in http://www.flaterco.com/xtide/tcd_notes.html. This
4051 function is now of interest only in restore_tide_db, which uses it
4052 to determine which XML format to output. Deprecated here, moved
4053 to restore_tide_db.
4054
4055\*****************************************************************************/
4056
4057#ifdef COMPAT114
4058NV_BOOL check_simple(TIDE_RECORD rec) {
4059 if (rec.max_time_add == rec.min_time_add &&
4060 rec.max_level_add == rec.min_level_add &&
4061 rec.max_level_multiply == rec.min_level_multiply &&
4062 rec.max_avg_level == 0 && rec.min_avg_level == 0 &&
4063 rec.max_direction == 361 && rec.min_direction == 361 &&
4064 rec.flood_begins == NULLSLACKOFFSET && rec.ebb_begins == NULLSLACKOFFSET)
4065 return (NVTrue);
4066
4067 return (NVFalse);
4068}
4069#endif
4070
4071/*****************************************************************************\
4072
4073 Function header_checksum - compute the checksum for the ASCII
4074 portion of the database header
4075
4076 Synopsis header_checksum ();
4077
4078 Returns NV_U_INT32 checksum value
4079
4080 Author Jan C. Depner
4081 Date 08/01/02
4082
4083 See libtcd.html for changelog.
4084
4085\*****************************************************************************/
4086
4087static NV_U_INT32 header_checksum() {
4088 NV_U_INT32 checksum, i, save_pos;
4089 NV_U_BYTE *buf;
4090 NV_U_INT32 crc_table[256] = {
4091 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
4092 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
4093 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
4094 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
4095 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
4096 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
4097 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
4098 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
4099 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
4100 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
4101 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
4102 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
4103 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
4104 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
4105 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
4106 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
4107 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
4108 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
4109 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
4110 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
4111 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
4112 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
4113 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
4114 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
4115 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
4116 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
4117 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
4118 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
4119 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
4120 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
4121 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
4122 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
4123 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
4124 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
4125 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
4126 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
4127 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
4128 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
4129 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
4130 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
4131 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
4132 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
4133 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D};
4134
4135 if (!fp) {
4136 LOG_ERROR(
4137 "libtcd error: attempt to access database when database not open\n");
4138 exit(-1);
4139 }
4140
4141 save_pos = ftell(fp);
4142
4143 fseek(fp, 0, SEEK_SET);
4144
4145 if ((buf = (NV_U_BYTE *)calloc(hd.header_size, sizeof(NV_U_BYTE))) == NULL) {
4146 perror("Allocating checksum buffer");
4147 exit(-1);
4148 }
4149
4150 checksum = ~0;
4151
4152 assert(hd.header_size > 0);
4153 chk_fread(buf, hd.header_size, 1, fp);
4154 for (i = 0; i < (NV_U_INT32)hd.header_size; ++i) {
4155 checksum = crc_table[(checksum ^ buf[i]) & 0xff] ^ (checksum >> 8);
4156 }
4157 checksum ^= ~0;
4158
4159 free(buf);
4160
4161 fseek(fp, save_pos, SEEK_SET);
4162
4163 return (checksum);
4164}
4165
4166/*****************************************************************************\
4167
4168 Function old_header_checksum - compute the old-style checksum for
4169 the ASCII portion of the database header just in case this
4170 is a pre 1.02 file.
4171
4172 Synopsis old_header_checksum ();
4173
4174 Returns NV_U_INT32 checksum value
4175
4176 Author Jan C. Depner
4177 Date 11/15/02
4178
4179\*****************************************************************************/
4180
4181#ifdef COMPAT114
4182static NV_U_INT32 old_header_checksum() {
4183 NV_U_INT32 checksum, i, save_pos;
4184 NV_U_BYTE *buf;
4185
4186 if (!fp) {
4187 LOG_ERROR(
4188 "libtcd error: attempt to access database when database not open\n");
4189 exit(-1);
4190 }
4191
4192 save_pos = ftell(fp);
4193
4194 checksum = 0;
4195
4196 fseek(fp, 0, SEEK_SET);
4197
4198 if ((buf = (NV_U_BYTE *)calloc(hd.header_size, sizeof(NV_U_BYTE))) == NULL) {
4199 perror("Allocating checksum buffer");
4200 exit(-1);
4201 }
4202
4203 chk_fread(buf, hd.header_size, 1, fp);
4204
4205 for (i = 0; i < hd.header_size; ++i) checksum += buf[i];
4206
4207 free(buf);
4208
4209 fseek(fp, save_pos, SEEK_SET);
4210
4211 return (checksum);
4212}
4213#endif
4214
4215/*****************************************************************************\
4216 DWF 2004-10-01
4217 Get current time in preferred format.
4218\*****************************************************************************/
4219static NV_CHAR *curtime() {
4220 static NV_CHAR buf[ONELINER_LENGTH];
4221 time_t t = time(NULL);
4222 require(strftime(buf, ONELINER_LENGTH, "%Y-%m-%d %H:%M %Z", localtime(&t)) >
4223 0);
4224 return buf;
4225}
4226
4227/*****************************************************************************\
4228 DWF 2004-10-15
4229 Calculate bytes for number of bits.
4230\*****************************************************************************/
4231static NV_U_INT32 bits2bytes(NV_U_INT32 nbits) {
4232 if (nbits % 8) return nbits / 8 + 1;
4233 return nbits / 8;
4234}
4235
4236/*****************************************************************************\
4237
4238 Function write_tide_db_header - writes the database header to the
4239 file
4240
4241 Synopsis write_tide_db_header ();
4242
4243 Returns void
4244
4245 Author Jan C. Depner
4246 Date 08/01/02
4247
4248 See libtcd.html for changelog.
4249
4250\*****************************************************************************/
4251
4252static void write_tide_db_header() {
4253 NV_U_INT32 i, size, pos;
4254 NV_INT32 start, temp_int;
4255 static NV_CHAR zero = 0;
4256 NV_U_BYTE *buf, checksum_c[4];
4257
4258 if (!fp) {
4259 LOG_ERROR(
4260 "libtcd error: attempt to access database when database not open\n");
4261 exit(-1);
4262 }
4263 write_protect();
4264
4265 fseek(fp, 0, SEEK_SET);
4266
4267 fprintf(fp, "[VERSION] = %s\n", LIBTCD_VERSION);
4268 fprintf(fp, "[MAJOR REV] = %u\n", LIBTCD_MAJOR_REV);
4269 fprintf(fp, "[MINOR REV] = %u\n", LIBTCD_MINOR_REV);
4270
4271 fprintf(fp, "[LAST MODIFIED] = %s\n", curtime());
4272
4273 fprintf(fp, "[HEADER SIZE] = %u\n", hd.header_size);
4274 fprintf(fp, "[NUMBER OF RECORDS] = %u\n", hd.pub.number_of_records);
4275
4276 fprintf(fp, "[START YEAR] = %d\n", hd.pub.start_year);
4277 fprintf(fp, "[NUMBER OF YEARS] = %u\n", hd.pub.number_of_years);
4278
4279 fprintf(fp, "[SPEED BITS] = %u\n", hd.speed_bits);
4280 fprintf(fp, "[SPEED SCALE] = %u\n", hd.speed_scale);
4281 fprintf(fp, "[SPEED OFFSET] = %d\n", hd.speed_offset);
4282 fprintf(fp, "[EQUILIBRIUM BITS] = %u\n", hd.equilibrium_bits);
4283 fprintf(fp, "[EQUILIBRIUM SCALE] = %u\n", hd.equilibrium_scale);
4284 fprintf(fp, "[EQUILIBRIUM OFFSET] = %d\n", hd.equilibrium_offset);
4285 fprintf(fp, "[NODE BITS] = %u\n", hd.node_bits);
4286 fprintf(fp, "[NODE SCALE] = %u\n", hd.node_scale);
4287 fprintf(fp, "[NODE OFFSET] = %d\n", hd.node_offset);
4288 fprintf(fp, "[AMPLITUDE BITS] = %u\n", hd.amplitude_bits);
4289 fprintf(fp, "[AMPLITUDE SCALE] = %u\n", hd.amplitude_scale);
4290 fprintf(fp, "[EPOCH BITS] = %u\n", hd.epoch_bits);
4291 fprintf(fp, "[EPOCH SCALE] = %u\n", hd.epoch_scale);
4292
4293 fprintf(fp, "[RECORD TYPE BITS] = %u\n", hd.record_type_bits);
4294 fprintf(fp, "[LATITUDE BITS] = %u\n", hd.latitude_bits);
4295 fprintf(fp, "[LATITUDE SCALE] = %u\n", hd.latitude_scale);
4296 fprintf(fp, "[LONGITUDE BITS] = %u\n", hd.longitude_bits);
4297 fprintf(fp, "[LONGITUDE SCALE] = %u\n", hd.longitude_scale);
4298 fprintf(fp, "[RECORD SIZE BITS] = %u\n", hd.record_size_bits);
4299
4300 fprintf(fp, "[STATION BITS] = %u\n", hd.station_bits);
4301
4302 fprintf(fp, "[DATUM OFFSET BITS] = %u\n", hd.datum_offset_bits);
4303 fprintf(fp, "[DATUM OFFSET SCALE] = %u\n", hd.datum_offset_scale);
4304 fprintf(fp, "[DATE BITS] = %u\n", hd.date_bits);
4305 fprintf(fp, "[MONTHS ON STATION BITS] = %u\n", hd.months_on_station_bits);
4306 fprintf(fp, "[CONFIDENCE VALUE BITS] = %u\n", hd.confidence_value_bits);
4307
4308 fprintf(fp, "[TIME BITS] = %u\n", hd.time_bits);
4309 fprintf(fp, "[LEVEL ADD BITS] = %u\n", hd.level_add_bits);
4310 fprintf(fp, "[LEVEL ADD SCALE] = %u\n", hd.level_add_scale);
4311 fprintf(fp, "[LEVEL MULTIPLY BITS] = %u\n", hd.level_multiply_bits);
4312 fprintf(fp, "[LEVEL MULTIPLY SCALE] = %u\n", hd.level_multiply_scale);
4313 fprintf(fp, "[DIRECTION BITS] = %u\n", hd.direction_bits);
4314
4315 fprintf(fp, "[LEVEL UNIT BITS] = %u\n", hd.level_unit_bits);
4316 fprintf(fp, "[LEVEL UNIT TYPES] = %u\n", hd.pub.level_unit_types);
4317 fprintf(fp, "[LEVEL UNIT SIZE] = %u\n", hd.level_unit_size);
4318
4319 fprintf(fp, "[DIRECTION UNIT BITS] = %u\n", hd.dir_unit_bits);
4320 fprintf(fp, "[DIRECTION UNIT TYPES] = %u\n", hd.pub.dir_unit_types);
4321 fprintf(fp, "[DIRECTION UNIT SIZE] = %u\n", hd.dir_unit_size);
4322
4323 fprintf(fp, "[RESTRICTION BITS] = %u\n", hd.restriction_bits);
4324 fprintf(fp, "[RESTRICTION TYPES] = %u\n", hd.pub.restriction_types);
4325 fprintf(fp, "[RESTRICTION SIZE] = %u\n", hd.restriction_size);
4326
4327 fprintf(fp, "[DATUM BITS] = %u\n", hd.datum_bits);
4328 fprintf(fp, "[DATUM TYPES] = %u\n", hd.pub.datum_types);
4329 fprintf(fp, "[DATUM SIZE] = %u\n", hd.datum_size);
4330
4331 fprintf(fp, "[LEGALESE BITS] = %u\n", hd.legalese_bits);
4332 fprintf(fp, "[LEGALESE TYPES] = %u\n", hd.pub.legaleses);
4333 fprintf(fp, "[LEGALESE SIZE] = %u\n", hd.legalese_size);
4334
4335 fprintf(fp, "[CONSTITUENT BITS] = %u\n", hd.constituent_bits);
4336 fprintf(fp, "[CONSTITUENTS] = %u\n", hd.pub.constituents);
4337 fprintf(fp, "[CONSTITUENT SIZE] = %u\n", hd.constituent_size);
4338
4339 fprintf(fp, "[TZFILE BITS] = %u\n", hd.tzfile_bits);
4340 fprintf(fp, "[TZFILES] = %u\n", hd.pub.tzfiles);
4341 fprintf(fp, "[TZFILE SIZE] = %u\n", hd.tzfile_size);
4342
4343 fprintf(fp, "[COUNTRY BITS] = %u\n", hd.country_bits);
4344 fprintf(fp, "[COUNTRIES] = %u\n", hd.pub.countries);
4345 fprintf(fp, "[COUNTRY SIZE] = %u\n", hd.country_size);
4346
4347 fprintf(fp, "[END OF FILE] = %u\n", hd.end_of_file);
4348 fprintf(fp, "[END OF ASCII HEADER DATA]\n");
4349
4350 /* Fill the remainder of the [HEADER SIZE] ASCII header with zeroes. */
4351
4352 start = ftell(fp);
4353 assert(start >= 0);
4354 for (i = start; i < hd.header_size; ++i) chk_fwrite(&zero, 1, 1, fp);
4355 fflush(fp);
4356
4357 /* Compute and save the checksum. */
4358
4359 bit_pack(checksum_c, 0, 32, header_checksum());
4360 chk_fwrite(checksum_c, 4, 1, fp);
4361
4362 /* NOTE : Using strcpy for character strings (no endian issue). */
4363
4364 /* Write level units. */
4365
4366 pos = 0;
4367 size = hd.pub.level_unit_types * hd.level_unit_size;
4368
4369 if ((buf = (NV_U_BYTE *)calloc(size, sizeof(NV_U_BYTE))) == NULL) {
4370 perror("Allocating unit write buffer");
4371 exit(-1);
4372 }
4373 memset(buf, 0, size);
4374
4375 for (i = 0; i < hd.pub.level_unit_types; ++i) {
4376 assert(strlen(hd.level_unit[i]) + 1 <= hd.level_unit_size);
4377 strcpy((NV_CHAR *)&buf[pos], hd.level_unit[i]);
4378 pos += hd.level_unit_size;
4379 }
4380
4381 chk_fwrite(buf, pos, 1, fp);
4382 free(buf);
4383
4384 /* Write direction units. */
4385
4386 pos = 0;
4387 size = hd.pub.dir_unit_types * hd.dir_unit_size;
4388
4389 if ((buf = (NV_U_BYTE *)calloc(size, sizeof(NV_U_BYTE))) == NULL) {
4390 perror("Allocating unit write buffer");
4391 exit(-1);
4392 }
4393 memset(buf, 0, size);
4394
4395 for (i = 0; i < hd.pub.dir_unit_types; ++i) {
4396 assert(strlen(hd.dir_unit[i]) + 1 <= hd.dir_unit_size);
4397 strcpy((NV_CHAR *)&buf[pos], hd.dir_unit[i]);
4398 pos += hd.dir_unit_size;
4399 }
4400
4401 chk_fwrite(buf, pos, 1, fp);
4402 free(buf);
4403
4404 /* Write restrictions. */
4405
4406 pos = 0;
4407 size = hd.max_restriction_types * hd.restriction_size;
4408
4409 if ((buf = (NV_U_BYTE *)calloc(size, sizeof(NV_U_BYTE))) == NULL) {
4410 perror("Allocating restriction write buffer");
4411 exit(-1);
4412 }
4413 memset(buf, 0, size);
4414
4415 for (i = 0; i < hd.max_restriction_types; ++i) {
4416 if (i == hd.pub.restriction_types) break;
4417 assert(strlen(hd.restriction[i]) + 1 <= hd.restriction_size);
4418 strcpy((NV_CHAR *)&buf[pos], hd.restriction[i]);
4419 pos += hd.restriction_size;
4420 }
4421 memcpy(&buf[pos], "__END__", 7);
4422
4423 chk_fwrite(buf, size, 1, fp);
4424 free(buf);
4425
4426 /* Write tzfiles. */
4427
4428 pos = 0;
4429 size = hd.max_tzfiles * hd.tzfile_size;
4430
4431 if ((buf = (NV_U_BYTE *)calloc(size, sizeof(NV_U_BYTE))) == NULL) {
4432 perror("Allocating tzfile write buffer");
4433 exit(-1);
4434 }
4435 memset(buf, 0, size);
4436
4437 for (i = 0; i < hd.max_tzfiles; ++i) {
4438 if (i == hd.pub.tzfiles) break;
4439 assert(strlen(hd.tzfile[i]) + 1 <= hd.tzfile_size);
4440 strcpy((NV_CHAR *)&buf[pos], hd.tzfile[i]);
4441 pos += hd.tzfile_size;
4442 }
4443 memcpy(&buf[pos], "__END__", 7);
4444
4445 chk_fwrite(buf, size, 1, fp);
4446 free(buf);
4447
4448 /* Write countries. */
4449
4450 pos = 0;
4451 size = hd.max_countries * hd.country_size;
4452
4453 if ((buf = (NV_U_BYTE *)calloc(size, sizeof(NV_U_BYTE))) == NULL) {
4454 perror("Allocating country write buffer");
4455 exit(-1);
4456 }
4457 memset(buf, 0, size);
4458
4459 for (i = 0; i < hd.max_countries; ++i) {
4460 if (i == hd.pub.countries) break;
4461 assert(strlen(hd.country[i]) + 1 <= hd.country_size);
4462 strcpy((NV_CHAR *)&buf[pos], hd.country[i]);
4463 pos += hd.country_size;
4464 }
4465 memcpy(&buf[pos], "__END__", 7);
4466
4467 chk_fwrite(buf, size, 1, fp);
4468 free(buf);
4469
4470 /* Write datums. */
4471
4472 pos = 0;
4473 size = hd.max_datum_types * hd.datum_size;
4474
4475 if ((buf = (NV_U_BYTE *)calloc(size, sizeof(NV_U_BYTE))) == NULL) {
4476 perror("Allocating datum write buffer");
4477 exit(-1);
4478 }
4479 memset(buf, 0, size);
4480
4481 for (i = 0; i < hd.max_datum_types; ++i) {
4482 if (i == hd.pub.datum_types) break;
4483 assert(strlen(hd.datum[i]) + 1 <= hd.datum_size);
4484 strcpy((NV_CHAR *)&buf[pos], hd.datum[i]);
4485 pos += hd.datum_size;
4486 }
4487 memcpy(&buf[pos], "__END__", 7);
4488
4489 chk_fwrite(buf, size, 1, fp);
4490 free(buf);
4491
4492 /* Write legaleses. */
4493
4494 pos = 0;
4495 size = hd.max_legaleses * hd.legalese_size;
4496
4497 if ((buf = (NV_U_BYTE *)calloc(size, sizeof(NV_U_BYTE))) == NULL) {
4498 perror("Allocating legalese write buffer");
4499 exit(-1);
4500 }
4501 memset(buf, 0, size);
4502
4503 for (i = 0; i < hd.max_legaleses; ++i) {
4504 if (i == hd.pub.legaleses) break;
4505 assert(strlen(hd.legalese[i]) + 1 <= hd.legalese_size);
4506 strcpy((NV_CHAR *)&buf[pos], hd.legalese[i]);
4507 pos += hd.legalese_size;
4508 }
4509 memcpy(&buf[pos], "__END__", 7);
4510
4511 chk_fwrite(buf, size, 1, fp);
4512 free(buf);
4513
4514 /* Write constituent names. */
4515
4516 pos = 0;
4517 size = hd.pub.constituents * hd.constituent_size;
4518
4519 if ((buf = (NV_U_BYTE *)calloc(size, sizeof(NV_U_BYTE))) == NULL) {
4520 perror("Allocating constituent write buffer");
4521 exit(-1);
4522 }
4523 memset(buf, 0, size);
4524
4525 for (i = 0; i < hd.pub.constituents; ++i) {
4526 assert(strlen(hd.constituent[i]) + 1 <= hd.constituent_size);
4527 strcpy((NV_CHAR *)&buf[pos], hd.constituent[i]);
4528 pos += hd.constituent_size;
4529 }
4530
4531 chk_fwrite(buf, pos, 1, fp);
4532 free(buf);
4533
4534 /* NOTE : Using bit_pack for integers. */
4535
4536 /* Write speeds. */
4537
4538 pos = 0;
4539 size = bits2bytes(hd.pub.constituents * hd.speed_bits);
4540
4541 if ((buf = (NV_U_BYTE *)calloc(size, sizeof(NV_U_BYTE))) == NULL) {
4542 perror("Allocating speed write buffer");
4543 exit(-1);
4544 }
4545 memset(buf, 0, size);
4546
4547 for (i = 0; i < hd.pub.constituents; ++i) {
4548 temp_int = NINT(hd.speed[i] * hd.speed_scale) - hd.speed_offset;
4549 assert(temp_int >= 0);
4550 bit_pack(buf, pos, hd.speed_bits, temp_int);
4551 pos += hd.speed_bits;
4552 }
4553
4554 chk_fwrite(buf, size, 1, fp);
4555 free(buf);
4556
4557 /* Write equilibrium arguments. */
4558
4559 pos = 0;
4560 size = bits2bytes(hd.pub.constituents * hd.pub.number_of_years *
4561 hd.equilibrium_bits);
4562
4563 if ((buf = (NV_U_BYTE *)calloc(size, sizeof(NV_U_BYTE))) == NULL) {
4564 perror("Allocating equilibrium write buffer");
4565 exit(-1);
4566 }
4567 memset(buf, 0, size);
4568
4569 for (i = 0; i < hd.pub.constituents; ++i) {
4570 NV_U_INT32 j;
4571 for (j = 0; j < hd.pub.number_of_years; ++j) {
4572 temp_int = NINT(hd.equilibrium[i][j] * hd.equilibrium_scale) -
4573 hd.equilibrium_offset;
4574 assert(temp_int >= 0);
4575 bit_pack(buf, pos, hd.equilibrium_bits, temp_int);
4576 pos += hd.equilibrium_bits;
4577 }
4578 }
4579
4580 chk_fwrite(buf, size, 1, fp);
4581 free(buf);
4582
4583 /* Write node factors. */
4584
4585 pos = 0;
4586 size =
4587 bits2bytes(hd.pub.constituents * hd.pub.number_of_years * hd.node_bits);
4588
4589 if ((buf = (NV_U_BYTE *)calloc(size, sizeof(NV_U_BYTE))) == NULL) {
4590 perror("Allocating node write buffer");
4591 exit(-1);
4592 }
4593 memset(buf, 0, size);
4594
4595 for (i = 0; i < hd.pub.constituents; ++i) {
4596 NV_U_INT32 j;
4597 for (j = 0; j < hd.pub.number_of_years; ++j) {
4598 temp_int = NINT(hd.node_factor[i][j] * hd.node_scale) - hd.node_offset;
4599 assert(temp_int >= 0);
4600 bit_pack(buf, pos, hd.node_bits, temp_int);
4601 pos += hd.node_bits;
4602 }
4603 }
4604
4605 chk_fwrite(buf, size, 1, fp);
4606 free(buf);
4607}
4608
4609/*****************************************************************************\
4610
4611 Function unpack_string - Safely unpack a string into a
4612 fixed-length buffer.
4613
4614 Synopsis unpack_string (buf, bufsize, pos, outbuf, outbuflen, desc);
4615
4616 NV_U_BYTE *buf input buffer
4617 NV_U_INT32 bufsize size of input buffer in bytes
4618 NV_U_INT32 *pos current bit-position in buf
4619 (in-out parameter)
4620 NV_CHAR *outbuf fixed-length string-buffer
4621 NV_U_INT32 outbuflen size of outbuf in bytes
4622 NV_CHAR *desc description of the field being
4623 unpacked for use in warning
4624 messages when truncation occurs
4625
4626 Returns void
4627
4628 Author David Flater
4629 Date 2004-09-30
4630
4631 pos will be left at the start of the next field even if the string
4632 gets truncated.
4633
4634\*****************************************************************************/
4635
4636static void unpack_string(NV_U_BYTE *buf, NV_U_INT32 bufsize, NV_U_INT32 *pos,
4637 NV_CHAR *outbuf, NV_U_INT32 outbuflen,
4638 const NV_CHAR *desc) {
4639 NV_U_INT32 i;
4640 NV_CHAR c = 'x';
4641 assert(buf);
4642 assert(pos);
4643 assert(outbuf);
4644 assert(desc);
4645 assert(outbuflen);
4646 --outbuflen;
4647 bufsize <<= 3;
4648 for (i = 0; c; ++i) {
4649 assert(*pos < bufsize); /* Catch unterminated strings */
4650 c = bit_unpack(buf, *pos, 8);
4651 (*pos) += 8;
4652 if (i < outbuflen) {
4653 outbuf[i] = c;
4654 } else if (i == outbuflen) {
4655 outbuf[i] = '\0';
4656 if (c) {
4657 LOG_ERROR("libtcd warning: truncating overlong %s\n", desc);
4658 LOG_ERROR("The offending string starts with:\n%s\n", outbuf);
4659 }
4660 }
4661 }
4662}
4663
4664/*****************************************************************************\
4665
4666 Function unpack_partial_tide_record - unpacks the "header" portion
4667 of a tide record from the supplied buffer
4668
4669 Synopsis unpack_partial_tide_record (buf, rec, pos);
4670
4671 NV_U_BYTE *buf input buffer
4672 NV_U_INT32 bufsize size of input buffer in bytes
4673 TIDE_RECORD *rec tide record
4674 NV_U_INT32 *pos final position in buffer after
4675 unpacking the header
4676
4677 Returns void
4678
4679 Author Jan C. Depner
4680 Date 08/01/02
4681
4682 See libtcd.html for changelog.
4683
4684\*****************************************************************************/
4685
4686static void unpack_partial_tide_record(NV_U_BYTE *buf, NV_U_INT32 bufsize,
4687 TIDE_RECORD *rec, NV_U_INT32 *pos) {
4688 NV_INT32 temp_int;
4689
4690 assert(buf);
4691 assert(rec);
4692 assert(pos);
4693
4694 *pos = 0;
4695
4696 rec->header.record_size = bit_unpack(buf, *pos, hd.record_size_bits);
4697 *pos += hd.record_size_bits;
4698
4699 rec->header.record_type = bit_unpack(buf, *pos, hd.record_type_bits);
4700 *pos += hd.record_type_bits;
4701
4702 temp_int = signed_bit_unpack(buf, *pos, hd.latitude_bits);
4703 rec->header.latitude = (NV_FLOAT64)temp_int / hd.latitude_scale;
4704 *pos += hd.latitude_bits;
4705
4706 temp_int = signed_bit_unpack(buf, *pos, hd.longitude_bits);
4707 rec->header.longitude = (NV_FLOAT64)temp_int / hd.longitude_scale;
4708 *pos += hd.longitude_bits;
4709
4710 /* This ordering doesn't match everywhere else but there's no technical
4711 reason to change it from its V1 ordering. */
4712
4713 rec->header.tzfile = bit_unpack(buf, *pos, hd.tzfile_bits);
4714 *pos += hd.tzfile_bits;
4715
4716 unpack_string(buf, bufsize, pos, rec->header.name, ONELINER_LENGTH,
4717 "station name");
4718
4719 rec->header.reference_station = signed_bit_unpack(buf, *pos, hd.station_bits);
4720 *pos += hd.station_bits;
4721
4722 assert(*pos <= bufsize * 8);
4723}
4724
4725/*****************************************************************************\
4726
4727 Function read_partial_tide_record - reads the "header" portion
4728 of a tide record from the database. This is used to index
4729 the database on opening.
4730
4731 Synopsis read_partial_tide_record (num, rec);
4732
4733 NV_INT32 num record number
4734 TIDE_RECORD *rec tide record
4735
4736 Returns NV_INT32 record number read
4737
4738 Author Jan C. Depner
4739 Date 08/01/02
4740
4741 See libtcd.html for changelog.
4742
4743\*****************************************************************************/
4744
4745static NV_INT32 read_partial_tide_record(NV_INT32 num, TIDE_RECORD *rec) {
4746 NV_U_BYTE *buf;
4747 NV_U_INT32 maximum_possible_size, pos;
4748
4749 if (!fp) {
4750 LOG_ERROR(
4751 "libtcd error: attempt to access database when database not open\n");
4752 exit(-1);
4753 }
4754
4755 assert(rec);
4756
4757 /* Read just the record size, record type, position, time zone, and
4758 name. */
4759
4760 maximum_possible_size = hd.record_size_bits + hd.record_type_bits +
4761 hd.latitude_bits + hd.longitude_bits +
4762 hd.tzfile_bits + (ONELINER_LENGTH * 8) +
4763 hd.station_bits;
4764 maximum_possible_size = bits2bytes(maximum_possible_size);
4765
4766 if ((buf = (NV_U_BYTE *)calloc(maximum_possible_size, sizeof(NV_U_BYTE))) ==
4767 NULL) {
4768 perror("Allocating partial tide record buffer");
4769 exit(-1);
4770 }
4771
4772 current_record = num;
4773 fseek(fp, tindex[num].address, SEEK_SET);
4774 /* DWF 2007-12-02: This is the one place where a short read would not
4775 necessarily mean catastrophe. We don't know how long the partial
4776 record actually is yet, and it's possible that the full record will
4777 be shorter than maximum_possible_size. */
4778 size_t size = fread(buf, 1, maximum_possible_size, fp);
4779 unpack_partial_tide_record(buf, size, rec, &pos);
4780 free(buf);
4781 return (num);
4782}
4783
4784/*****************************************************************************\
4785
4786 Function read_tide_db_header - reads the tide database header
4787
4788 Synopsis read_tide_db_header ();
4789
4790 Returns NV_BOOL NVTrue if header is correct
4791
4792 Author Jan C. Depner
4793 Date 08/01/02
4794
4795 See libtcd.html for changelog.
4796
4797\*****************************************************************************/
4798
4799static NV_BOOL read_tide_db_header() {
4800 NV_INT32 temp_int;
4801 NV_CHAR varin[ONELINER_LENGTH], *info;
4802 NV_U_INT32 utemp, i, j, pos, size, key_count;
4803 NV_U_BYTE *buf, checksum_c[5];
4804 TIDE_RECORD rec;
4805
4806 if (!fp) {
4807 LOG_ERROR(
4808 "libtcd error: attempt to access database when database not open\n");
4809 exit(-1);
4810 }
4811
4812 strcpy(hd.pub.version, "NO VERSION");
4813
4814 /* Compute the number of key phrases there are to match. */
4815 key_count = sizeof(keys) / sizeof(KEY);
4816
4817 /* Zero out the header structure. */
4818 memset(&hd, 0, sizeof(hd));
4819
4820 /* Handle the ASCII header data. */
4821 while (fgets(varin, sizeof(varin), fp) != NULL) {
4822 if (strlen(varin) == ONELINER_LENGTH - 1) {
4823 if (varin[ONELINER_LENGTH - 2] != '\n') {
4824 LOG_ERROR("libtcd error: header line too long, begins with:\n");
4825 LOG_ERROR("%s\n", varin);
4826 LOG_ERROR("in file %s\n", filename);
4827 LOG_ERROR("Configured limit is %u\n", ONELINER_LENGTH - 1);
4828 fclose(fp);
4829 return NVFalse;
4830 }
4831 }
4832
4833 if (strstr(varin, "[END OF ASCII HEADER DATA]")) break;
4834
4835 /* All other lines must be field = value */
4836 info = strchr(varin, '=');
4837 if (!info) {
4838 LOG_ERROR("libtcd error: invalid tide db header line:\n");
4839 LOG_ERROR("%s", varin);
4840 LOG_ERROR("in file %s\n", filename);
4841 fclose(fp);
4842 return NVFalse;
4843 }
4844 ++info;
4845
4846 /* Scan the fields per "keys" defined in tide_db_header.h. */
4847 for (i = 0; i < key_count; ++i) {
4848 if (strstr(varin, keys[i].keyphrase)) {
4849 if (!strcmp(keys[i].datatype, "cstr"))
4850 strcpy((char *)keys[i].address.cstr, clip_string(info));
4851 else if (!strcmp(keys[i].datatype, "i32")) {
4852 if (sscanf(info, "%d", keys[i].address.i32) != 1) {
4853 LOG_ERROR("libtcd error: invalid tide db header line:\n");
4854 LOG_ERROR("%s", varin);
4855 LOG_ERROR("in file %s\n", filename);
4856 fclose(fp);
4857 return NVFalse;
4858 }
4859 } else if (!strcmp(keys[i].datatype, "ui32")) {
4860 if (sscanf(info, "%u", keys[i].address.ui32) != 1) {
4861 LOG_ERROR("libtcd error: invalid tide db header line:\n");
4862 LOG_ERROR("%s", varin);
4863 LOG_ERROR("in file %s\n", filename);
4864 fclose(fp);
4865 return NVFalse;
4866 }
4867 } else
4868 assert(0);
4869 }
4870 }
4871 }
4872
4873 /* We didn't get a valid version string. */
4874
4875 if (!strcmp(hd.pub.version, "NO VERSION")) {
4876 LOG_ERROR("libtcd error: no version found in tide db header\n");
4877 LOG_ERROR("in file %s\n", filename);
4878 fclose(fp);
4879 return NVFalse;
4880 }
4881
4882 /* If no major or minor rev, they're 0 (pre-1.99) */
4883 if (hd.pub.major_rev > LIBTCD_MAJOR_REV) {
4884 LOG_ERROR(
4885 "libtcd error: major revision in TCD file (%u) exceeds major revision "
4886 "of\n",
4887 hd.pub.major_rev);
4888 LOG_ERROR("libtcd (%u). You must upgrade libtcd to read this file.\n",
4889 LIBTCD_MAJOR_REV);
4890 fclose(fp);
4891 return NVFalse;
4892 }
4893
4894 /* Move to end of ASCII header. */
4895 fseek(fp, hd.header_size, SEEK_SET);
4896
4897 /* Read and check the checksum. */
4898
4899 chk_fread(checksum_c, 4, 1, fp);
4900 utemp = bit_unpack(checksum_c, 0, 32);
4901
4902 if (utemp != header_checksum()) {
4903#ifdef COMPAT114
4904 if (utemp != old_header_checksum()) {
4905 LOG_ERROR("libtcd error: header checksum error in file %s\n", filename);
4906 LOG_ERROR(
4907 "Someone may have modified the ASCII portion of the header (don't do that),\n\
4908or it may just be corrupt.\n");
4909 fclose(fp);
4910 return NVFalse;
4911 }
4912#else
4913 LOG_ERROR("libtcd error: header checksum error in file %s\n", filename);
4914 LOG_ERROR(
4915 "Someone may have modified the ASCII portion of the header (don't do that),\n\
4916or it may be an ancient pre-version-1.02 TCD file, or it may just be corrupt.\n\
4917Pre-version-1.02 TCD files can be read by building libtcd with COMPAT114\n\
4918defined.\n");
4919 fclose(fp);
4920 return NVFalse;
4921#endif
4922 }
4923 fseek(fp, hd.header_size + 4, SEEK_SET);
4924
4925 /* Set the max possible restriction types based on the number of bits
4926 used. */
4927
4928 hd.max_restriction_types = NINT(pow(2.0, (NV_FLOAT64)hd.restriction_bits));
4929
4930 /* Set the max possible tzfiles based on the number of bits used. */
4931
4932 hd.max_tzfiles = NINT(pow(2.0, (NV_FLOAT64)hd.tzfile_bits));
4933
4934 /* Set the max possible countries based on the number of bits used. */
4935
4936 hd.max_countries = NINT(pow(2.0, (NV_FLOAT64)hd.country_bits));
4937
4938 /* Set the max possible datum types based on the number of bits
4939 used. */
4940
4941 hd.max_datum_types = NINT(pow(2.0, (NV_FLOAT64)hd.datum_bits));
4942
4943 /* Set the max possible legaleses based on the number of bits
4944 used. */
4945
4946 if (hd.pub.major_rev < 2)
4947 hd.max_legaleses = 1;
4948 else
4949 hd.max_legaleses = NINT(pow(2.0, (NV_FLOAT64)hd.legalese_bits));
4950
4951 /* NOTE : Using strcpy for character strings (no endian issue). */
4952
4953 /* Read level units. */
4954
4955 hd.level_unit =
4956 (NV_CHAR **)calloc(hd.pub.level_unit_types, sizeof(NV_CHAR *));
4957
4958 if ((buf = (NV_U_BYTE *)calloc(hd.level_unit_size, sizeof(NV_U_BYTE))) ==
4959 NULL) {
4960 perror("Allocating level unit read buffer");
4961 exit(-1);
4962 }
4963
4964 for (i = 0; i < hd.pub.level_unit_types; ++i) {
4965 chk_fread(buf, hd.level_unit_size, 1, fp);
4966 hd.level_unit[i] =
4967 (NV_CHAR *)calloc(strlen((char *)buf) + 1, sizeof(NV_CHAR));
4968 strcpy(hd.level_unit[i], (NV_CHAR *)buf);
4969 }
4970 free(buf);
4971
4972 /* Read direction units. */
4973
4974 hd.dir_unit = (NV_CHAR **)calloc(hd.pub.dir_unit_types, sizeof(NV_CHAR *));
4975
4976 if ((buf = (NV_U_BYTE *)calloc(hd.dir_unit_size, sizeof(NV_U_BYTE))) ==
4977 NULL) {
4978 perror("Allocating dir unit read buffer");
4979 exit(-1);
4980 }
4981
4982 for (i = 0; i < hd.pub.dir_unit_types; ++i) {
4983 chk_fread(buf, hd.dir_unit_size, 1, fp);
4984 hd.dir_unit[i] =
4985 (NV_CHAR *)calloc(strlen((char *)buf) + 1, sizeof(NV_CHAR));
4986 strcpy(hd.dir_unit[i], (NV_CHAR *)buf);
4987 }
4988 free(buf);
4989
4990 /* Read restrictions. */
4991
4992 utemp = ftell(fp);
4993 hd.restriction =
4994 (NV_CHAR **)calloc(hd.max_restriction_types, sizeof(NV_CHAR *));
4995
4996 if ((buf = (NV_U_BYTE *)calloc(hd.restriction_size, sizeof(NV_U_BYTE))) ==
4997 NULL) {
4998 perror("Allocating restriction read buffer");
4999 exit(-1);
5000 }
5001
5002 hd.pub.restriction_types = 0;
5003 for (i = 0; i < hd.max_restriction_types; ++i) {
5004 chk_fread(buf, hd.restriction_size, 1, fp);
5005 if (!strcmp((char *)buf, "__END__")) {
5006 hd.pub.restriction_types = i;
5007 break;
5008 }
5009 hd.restriction[i] =
5010 (NV_CHAR *)calloc(strlen((char *)buf) + 1, sizeof(NV_CHAR));
5011 strcpy(hd.restriction[i], (NV_CHAR *)buf);
5012 }
5013 free(buf);
5014 fseek(fp, utemp + hd.max_restriction_types * hd.restriction_size, SEEK_SET);
5015
5016 /* Skip pedigrees. */
5017 if (hd.pub.major_rev < 2)
5018 fseek(fp, hd.pedigree_size * NINT(pow(2.0, (NV_FLOAT64)hd.pedigree_bits)),
5019 SEEK_CUR);
5020 hd.pub.pedigree_types = 1;
5021
5022 /* Read tzfiles. */
5023
5024 utemp = ftell(fp);
5025 hd.tzfile = (NV_CHAR **)calloc(hd.max_tzfiles, sizeof(NV_CHAR *));
5026
5027 if ((buf = (NV_U_BYTE *)calloc(hd.tzfile_size, sizeof(NV_U_BYTE))) == NULL) {
5028 perror("Allocating tzfile read buffer");
5029 exit(-1);
5030 }
5031
5032 hd.pub.tzfiles = 0;
5033 for (i = 0; i < hd.max_tzfiles; ++i) {
5034 chk_fread(buf, hd.tzfile_size, 1, fp);
5035 if (!strcmp((char *)buf, "__END__")) {
5036 hd.pub.tzfiles = i;
5037 break;
5038 }
5039 hd.tzfile[i] = (NV_CHAR *)calloc(strlen((char *)buf) + 1, sizeof(NV_CHAR));
5040 strcpy(hd.tzfile[i], (NV_CHAR *)buf);
5041 }
5042 free(buf);
5043 fseek(fp, utemp + hd.max_tzfiles * hd.tzfile_size, SEEK_SET);
5044
5045 /* Read countries. */
5046
5047 utemp = ftell(fp);
5048 hd.country = (NV_CHAR **)calloc(hd.max_countries, sizeof(NV_CHAR *));
5049
5050 if ((buf = (NV_U_BYTE *)calloc(hd.country_size, sizeof(NV_U_BYTE))) == NULL) {
5051 perror("Allocating country read buffer");
5052 exit(-1);
5053 }
5054
5055 hd.pub.countries = 0;
5056 for (i = 0; i < hd.max_countries; ++i) {
5057 chk_fread(buf, hd.country_size, 1, fp);
5058 if (!strcmp((char *)buf, "__END__")) {
5059 hd.pub.countries = i;
5060 break;
5061 }
5062 hd.country[i] = (NV_CHAR *)calloc(strlen((char *)buf) + 1, sizeof(NV_CHAR));
5063 strcpy(hd.country[i], (NV_CHAR *)buf);
5064 }
5065 free(buf);
5066 fseek(fp, utemp + hd.max_countries * hd.country_size, SEEK_SET);
5067
5068 /* Read datums. */
5069
5070 utemp = ftell(fp);
5071 hd.datum = (NV_CHAR **)calloc(hd.max_datum_types, sizeof(NV_CHAR *));
5072
5073 if ((buf = (NV_U_BYTE *)calloc(hd.datum_size, sizeof(NV_U_BYTE))) == NULL) {
5074 perror("Allocating datum read buffer");
5075 exit(-1);
5076 }
5077
5078 hd.pub.datum_types = 0;
5079 for (i = 0; i < hd.max_datum_types; ++i) {
5080 chk_fread(buf, hd.datum_size, 1, fp);
5081 if (!strcmp((char *)buf, "__END__")) {
5082 hd.pub.datum_types = i;
5083 break;
5084 }
5085 hd.datum[i] = (NV_CHAR *)calloc(strlen((char *)buf) + 1, sizeof(NV_CHAR));
5086 strcpy(hd.datum[i], (NV_CHAR *)buf);
5087 }
5088 free(buf);
5089 fseek(fp, utemp + hd.max_datum_types * hd.datum_size, SEEK_SET);
5090
5091 /* Read legaleses. */
5092
5093 if (hd.pub.major_rev < 2) {
5094 hd.legalese = (NV_CHAR **)malloc(sizeof(NV_CHAR *));
5095 assert(hd.legalese != NULL);
5096 hd.legalese[0] = (NV_CHAR *)malloc(5 * sizeof(NV_CHAR));
5097 assert(hd.legalese[0] != NULL);
5098 strcpy(hd.legalese[0], "NULL");
5099 hd.pub.legaleses = 1;
5100 } else {
5101 utemp = ftell(fp);
5102 hd.legalese = (NV_CHAR **)calloc(hd.max_legaleses, sizeof(NV_CHAR *));
5103
5104 if ((buf = (NV_U_BYTE *)calloc(hd.legalese_size, sizeof(NV_U_BYTE))) ==
5105 NULL) {
5106 perror("Allocating legalese read buffer");
5107 exit(-1);
5108 }
5109
5110 hd.pub.legaleses = 0;
5111 for (i = 0; i < hd.max_legaleses; ++i) {
5112 chk_fread(buf, hd.legalese_size, 1, fp);
5113 if (!strcmp((char *)buf, "__END__")) {
5114 hd.pub.legaleses = i;
5115 break;
5116 }
5117 hd.legalese[i] =
5118 (NV_CHAR *)calloc(strlen((char *)buf) + 1, sizeof(NV_CHAR));
5119 strcpy(hd.legalese[i], (NV_CHAR *)buf);
5120 }
5121 free(buf);
5122 fseek(fp, utemp + hd.max_legaleses * hd.legalese_size, SEEK_SET);
5123 }
5124
5125 /* Read constituent names. */
5126
5127 hd.constituent = (NV_CHAR **)calloc(hd.pub.constituents, sizeof(NV_CHAR *));
5128
5129 if ((buf = (NV_U_BYTE *)calloc(hd.constituent_size, sizeof(NV_U_BYTE))) ==
5130 NULL) {
5131 perror("Allocating constituent read buffer");
5132 exit(-1);
5133 }
5134
5135 for (i = 0; i < hd.pub.constituents; ++i) {
5136 chk_fread(buf, hd.constituent_size, 1, fp);
5137 hd.constituent[i] =
5138 (NV_CHAR *)calloc(strlen((char *)buf) + 1, sizeof(NV_CHAR));
5139 strcpy(hd.constituent[i], (NV_CHAR *)buf);
5140 }
5141 free(buf);
5142
5143 if (hd.speed_offset < 0 || hd.equilibrium_offset < 0 || hd.node_offset < 0) {
5144 LOG_ERROR("libtcd WARNING: File: %s\n", filename);
5145 LOG_ERROR(
5146 "WARNING: This TCD file was created by a pre-version-1.11 libtcd.\n\
5147Versions of libtcd prior to 1.11 contained a serious bug that can result\n\
5148in overflows in the speeds, equilibrium arguments, or node factors. This\n\
5149database should be rebuilt from the original data if possible.\n");
5150 }
5151
5152 /* NOTE: Using bit_unpack to get integers. */
5153
5154 /* Read speeds. */
5155
5156 hd.speed = (NV_FLOAT64 *)calloc(hd.pub.constituents, sizeof(NV_FLOAT64));
5157
5158 pos = 0;
5159 /* wasted byte bug in V1 */
5160 if (hd.pub.major_rev < 2)
5161 size = ((hd.pub.constituents * hd.speed_bits) / 8) + 1;
5162 else
5163 size = bits2bytes(hd.pub.constituents * hd.speed_bits);
5164
5165 if ((buf = (NV_U_BYTE *)calloc(size, sizeof(NV_U_BYTE))) == NULL) {
5166 perror("Allocating speed read buffer");
5167 exit(-1);
5168 }
5169
5170 chk_fread(buf, size, 1, fp);
5171
5172 for (i = 0; i < hd.pub.constituents; ++i) {
5173 temp_int = bit_unpack(buf, pos, hd.speed_bits);
5174 hd.speed[i] = (NV_FLOAT64)(temp_int + hd.speed_offset) / hd.speed_scale;
5175 pos += hd.speed_bits;
5176 assert(hd.speed[i] >= 0.0);
5177 }
5178 free(buf);
5179
5180 /* Read equilibrium arguments. */
5181
5182 hd.equilibrium =
5183 (NV_FLOAT32 **)calloc(hd.pub.constituents, sizeof(NV_FLOAT32 *));
5184
5185 for (i = 0; i < hd.pub.constituents; ++i) {
5186 hd.equilibrium[i] =
5187 (NV_FLOAT32 *)calloc(hd.pub.number_of_years, sizeof(NV_FLOAT32));
5188 }
5189
5190 pos = 0;
5191 /* wasted byte bug in V1 */
5192 if (hd.pub.major_rev < 2)
5193 size =
5194 ((hd.pub.constituents * hd.pub.number_of_years * hd.equilibrium_bits) /
5195 8) +
5196 1;
5197 else
5198 size = bits2bytes(hd.pub.constituents * hd.pub.number_of_years *
5199 hd.equilibrium_bits);
5200
5201 if ((buf = (NV_U_BYTE *)calloc(size, sizeof(NV_U_BYTE))) == NULL) {
5202 perror("Allocating equilibrium read buffer");
5203 exit(-1);
5204 }
5205
5206 chk_fread(buf, size, 1, fp);
5207
5208 for (i = 0; i < hd.pub.constituents; ++i) {
5209 for (j = 0; j < hd.pub.number_of_years; ++j) {
5210 temp_int = bit_unpack(buf, pos, hd.equilibrium_bits);
5211 hd.equilibrium[i][j] =
5212 (NV_FLOAT32)(temp_int + hd.equilibrium_offset) / hd.equilibrium_scale;
5213 pos += hd.equilibrium_bits;
5214 }
5215 }
5216 free(buf);
5217
5218 /* Read node factors. */
5219
5220 hd.node_factor =
5221 (NV_FLOAT32 **)calloc(hd.pub.constituents, sizeof(NV_FLOAT32 *));
5222
5223 for (i = 0; i < hd.pub.constituents; ++i) {
5224 hd.node_factor[i] =
5225 (NV_FLOAT32 *)calloc(hd.pub.number_of_years, sizeof(NV_FLOAT32));
5226 }
5227
5228 pos = 0;
5229 /* wasted byte bug in V1 */
5230 if (hd.pub.major_rev < 2)
5231 size =
5232 ((hd.pub.constituents * hd.pub.number_of_years * hd.node_bits) / 8) + 1;
5233 else
5234 size =
5235 bits2bytes(hd.pub.constituents * hd.pub.number_of_years * hd.node_bits);
5236
5237 if ((buf = (NV_U_BYTE *)calloc(size, sizeof(NV_U_BYTE))) == NULL) {
5238 perror("Allocating node read buffer");
5239 exit(-1);
5240 }
5241
5242 chk_fread(buf, size, 1, fp);
5243
5244 for (i = 0; i < hd.pub.constituents; ++i) {
5245 for (j = 0; j < hd.pub.number_of_years; ++j) {
5246 temp_int = bit_unpack(buf, pos, hd.node_bits);
5247 hd.node_factor[i][j] =
5248 (NV_FLOAT32)(temp_int + hd.node_offset) / hd.node_scale;
5249 pos += hd.node_bits;
5250 assert(hd.node_factor[i][j] > 0.0);
5251 }
5252 }
5253 free(buf);
5254
5255 /* Read the header portion of all of the records in the file and save
5256 the record size, address, and name. */
5257
5258 /* DWF added test for zero 2003-11-16 -- happens on create new db */
5259 if (hd.pub.number_of_records) {
5260 if ((tindex = (TIDE_INDEX *)calloc(hd.pub.number_of_records,
5261 sizeof(TIDE_INDEX))) == NULL) {
5262 perror("Allocating tide index");
5263 exit(-1);
5264 }
5265 /* Set the first address to be immediately after the header */
5266 tindex[0].address = ftell(fp);
5267 } else
5268 tindex = NULL; /* May as well be explicit... */
5269
5270 for (i = 0; i < hd.pub.number_of_records; ++i) {
5271 /* Set the address for the next record so that
5272 read_partial_tide_record will know where to go. */
5273
5274 if (i) tindex[i].address = tindex[i - 1].address + rec.header.record_size;
5275
5276 read_partial_tide_record(i, &rec);
5277
5278 /* Save the header info in the index. */
5279
5280 tindex[i].record_size = rec.header.record_size;
5281 tindex[i].record_type = rec.header.record_type;
5282 tindex[i].reference_station = rec.header.reference_station;
5283 assert(rec.header.tzfile >= 0);
5284 tindex[i].tzfile = rec.header.tzfile;
5285 tindex[i].lat = NINT(rec.header.latitude * hd.latitude_scale);
5286 tindex[i].lon = NINT(rec.header.longitude * hd.longitude_scale);
5287
5288 if ((tindex[i].name = (NV_CHAR *)calloc(strlen(rec.header.name) + 1,
5289 sizeof(NV_CHAR))) == NULL) {
5290 perror("Allocating index name memory");
5291 exit(-1);
5292 }
5293
5294 strcpy(tindex[i].name, rec.header.name);
5295 }
5296
5297 current_record = -1;
5298 current_index = -1;
5299
5300 return (NVTrue);
5301}
5302
5303/*****************************************************************************\
5304
5305 Function open_tide_db - opens the tide database
5306
5307 Synopsis open_tide_db (file);
5308
5309 NV_CHAR *file database file name
5310
5311 Returns NV_BOOL NVTrue if file opened
5312
5313 Author Jan C. Depner
5314 Date 08/01/02
5315
5316 See libtcd.html for changelog.
5317
5318\*****************************************************************************/
5319
5320NV_BOOL open_tide_db(const NV_CHAR *file) {
5321 assert(file);
5322 current_record = -1;
5323 current_index = -1;
5324 if (fp) {
5325 if (!strcmp(file, filename) && !modified)
5326 return NVTrue;
5327 else
5328 close_tide_db();
5329 }
5330 if ((fp = fopen(file, "rb+")) == NULL) {
5331 if ((fp = fopen(file, "rb")) == NULL) return (NVFalse);
5332 }
5333 boundscheck_monologue(file);
5334 strcpy(filename, file);
5335 return (read_tide_db_header());
5336}
5337
5338/*****************************************************************************\
5339
5340 Function close_tide_db - closes the tide database
5341
5342 Synopsis close_tide_db ();
5343
5344 Returns void
5345
5346 Author Jan C. Depner
5347 Date 08/01/02
5348
5349 See libtcd.html for changelog.
5350
5351 If the global modified flag is true, the database header is rewritten
5352 before the database is closed. The modified flag is then cleared.
5353
5354\*****************************************************************************/
5355
5356void close_tide_db() {
5357 NV_U_INT32 i;
5358
5359 if (!fp) {
5360 LOG_ERROR("libtcd warning: close_tide_db called when no database open\n");
5361 return;
5362 }
5363
5364 /* If we've changed something in the file, write the header to reset
5365 the last modified time. */
5366
5367 if (modified) write_tide_db_header();
5368
5369 /* Free all of the temporary memory. */
5370
5371 assert(hd.constituent);
5372 for (i = 0; i < hd.pub.constituents; ++i) {
5373 if (hd.constituent[i] != NULL) free(hd.constituent[i]);
5374 }
5375 free(hd.constituent);
5376 hd.constituent = NULL;
5377
5378 if (hd.speed != NULL) free(hd.speed);
5379
5380 assert(hd.equilibrium);
5381 for (i = 0; i < hd.pub.constituents; ++i) {
5382 if (hd.equilibrium[i] != NULL) free(hd.equilibrium[i]);
5383 }
5384 free(hd.equilibrium);
5385 hd.equilibrium = NULL;
5386
5387 assert(hd.node_factor);
5388 for (i = 0; i < hd.pub.constituents; ++i) {
5389 if (hd.node_factor[i] != NULL) free(hd.node_factor[i]);
5390 }
5391 free(hd.node_factor);
5392 hd.node_factor = NULL;
5393
5394 assert(hd.level_unit);
5395 for (i = 0; i < hd.pub.level_unit_types; ++i) {
5396 if (hd.level_unit[i] != NULL) free(hd.level_unit[i]);
5397 }
5398 free(hd.level_unit);
5399 hd.level_unit = NULL;
5400
5401 assert(hd.dir_unit);
5402 for (i = 0; i < hd.pub.dir_unit_types; ++i) {
5403 if (hd.dir_unit[i] != NULL) free(hd.dir_unit[i]);
5404 }
5405 free(hd.dir_unit);
5406 hd.dir_unit = NULL;
5407
5408 assert(hd.restriction);
5409 for (i = 0; i < hd.max_restriction_types; ++i) {
5410 if (hd.restriction[i] != NULL) free(hd.restriction[i]);
5411 }
5412 free(hd.restriction);
5413 hd.restriction = NULL;
5414
5415 assert(hd.legalese);
5416 for (i = 0; i < hd.max_legaleses; ++i) {
5417 if (hd.legalese[i] != NULL) free(hd.legalese[i]);
5418 }
5419 free(hd.legalese);
5420 hd.legalese = NULL;
5421
5422 assert(hd.tzfile);
5423 for (i = 0; i < hd.max_tzfiles; ++i) {
5424 if (hd.tzfile[i] != NULL) free(hd.tzfile[i]);
5425 }
5426 free(hd.tzfile);
5427 hd.tzfile = NULL;
5428
5429 assert(hd.country);
5430 for (i = 0; i < hd.max_countries; ++i) {
5431 if (hd.country[i] != NULL) free(hd.country[i]);
5432 }
5433 free(hd.country);
5434 hd.country = NULL;
5435
5436 assert(hd.datum);
5437 for (i = 0; i < hd.max_datum_types; ++i) {
5438 if (hd.datum[i] != NULL) free(hd.datum[i]);
5439 }
5440 free(hd.datum);
5441 hd.datum = NULL;
5442
5443 /* tindex will still be null on create_tide_db */
5444 if (tindex) {
5445 for (i = 0; i < hd.pub.number_of_records; ++i) {
5446 if (tindex[i].name) free(tindex[i].name);
5447 }
5448 free(tindex);
5449 tindex = NULL;
5450 }
5451
5452 fclose(fp);
5453 fp = NULL;
5454 modified = NVFalse;
5455
5456 /* Don't nullify the filename; there are places in the code where
5457 open_tide_db (filename) is invoked after close_tide_db(). This
5458 does not break the cache logic in open_tide_db because tindex
5459 is still nullified. */
5460}
5461
5462/*****************************************************************************\
5463
5464 Function create_tide_db - creates the tide database
5465
5466 Synopsis create_tide_db (file, constituents, constituent, speed,
5467 start_year, num_years, equilibrium, node_factor);
5468
5469 NV_CHAR *file database file name
5470 NV_U_INT32 constituents number of constituents
5471 NV_CHAR *constituent[] constituent names
5472 NV_FLOAT64 *speed speed values
5473 NV_INT32 start_year start year
5474 NV_U_INT32 num_years number of years
5475 NV_FLOAT32 *equilibrium[] equilibrium arguments
5476 NV_FLOAT32 *node_factor[] node factors
5477
5478 Returns NV_BOOL NVTrue if file created
5479
5480 Author Jan C. Depner
5481 Date 08/01/02
5482
5483 See libtcd.html for changelog.
5484
5485\*****************************************************************************/
5486
5487NV_BOOL create_tide_db(const NV_CHAR *file, NV_U_INT32 constituents,
5488 NV_CHAR const *const constituent[],
5489 const NV_FLOAT64 *speed, NV_INT32 start_year,
5490 NV_U_INT32 num_years,
5491 NV_FLOAT32 const *const equilibrium[],
5492 NV_FLOAT32 const *const node_factor[]) {
5493 NV_U_INT32 i, j;
5494 NV_FLOAT64 min_value, max_value;
5495 NV_INT32 temp_int;
5496
5497 /* Validate input */
5498 assert(file);
5499 assert(constituent);
5500 assert(speed);
5501 assert(equilibrium);
5502 assert(node_factor);
5503 for (i = 0; i < constituents; ++i) {
5504 if (speed[i] < 0.0) {
5505 LOG_ERROR(
5506 "libtcd create_tide_db: somebody tried to set a negative speed "
5507 "(%f)\n",
5508 speed[i]);
5509 return NVFalse;
5510 }
5511 for (j = 0; j < num_years; ++j) {
5512 if (node_factor[i][j] <= 0.0) {
5513 LOG_ERROR(
5514 "libtcd create_tide_db: somebody tried to set a negative or zero "
5515 "node factor (%f)\n",
5516 node_factor[i][j]);
5517 return NVFalse;
5518 }
5519 }
5520 }
5521
5522 if (fp) close_tide_db();
5523
5524 if ((fp = fopen(file, "wb+")) == NULL) {
5525 perror(file);
5526 return (NVFalse);
5527 }
5528
5529 /* Zero out the header structure. */
5530
5531 memset(&hd, 0, sizeof(hd));
5532
5533 hd.pub.major_rev = LIBTCD_MAJOR_REV;
5534 hd.pub.minor_rev = LIBTCD_MINOR_REV;
5535
5536 hd.header_size = DEFAULT_HEADER_SIZE;
5537 hd.pub.number_of_records = DEFAULT_NUMBER_OF_RECORDS;
5538
5539 hd.pub.start_year = start_year;
5540 hd.pub.number_of_years = num_years;
5541
5542 hd.pub.constituents = constituents;
5543
5544 /* Constituent names. */
5545
5546 hd.constituent = (NV_CHAR **)calloc(hd.pub.constituents, sizeof(NV_CHAR *));
5547 for (i = 0; i < hd.pub.constituents; ++i) {
5548 hd.constituent[i] =
5549 (NV_CHAR *)calloc(strlen(constituent[i]) + 1, sizeof(NV_CHAR));
5550 strcpy(hd.constituent[i], constituent[i]);
5551 }
5552
5553 /* A constituent count is stored with each reference station record,
5554 and it uses constituent_bits, so we need to be able to store
5555 the count itself (not just the values 0..count-1). */
5556 hd.constituent_bits = calculate_bits(hd.pub.constituents);
5557
5558 /* Set all of the speed attributes. */
5559
5560 hd.speed = (NV_FLOAT64 *)calloc(hd.pub.constituents, sizeof(NV_FLOAT64));
5561
5562 hd.speed_scale = DEFAULT_SPEED_SCALE;
5563 min_value = 99999999.0;
5564 max_value = -99999999.0;
5565 for (i = 0; i < hd.pub.constituents; ++i) {
5566 if (speed[i] < min_value) min_value = speed[i];
5567 if (speed[i] > max_value) max_value = speed[i];
5568
5569 hd.speed[i] = speed[i];
5570 }
5571
5572 /* DWF fixed sign reversal 2003-11-16 */
5573 /* DWF harmonized rounding with the way it is done in write_tide_db_header
5574 2007-01-22 */
5575 hd.speed_offset = (NINT(min_value * hd.speed_scale));
5576 temp_int = NINT(max_value * hd.speed_scale) - hd.speed_offset;
5577 assert(temp_int >= 0);
5578 hd.speed_bits = calculate_bits((NV_U_INT32)temp_int);
5579 /* Generally 31. With signed ints we don't have any bits to spare. */
5580 assert(hd.speed_bits < 32);
5581
5582 /* Set all of the equilibrium attributes. */
5583
5584 hd.equilibrium =
5585 (NV_FLOAT32 **)calloc(hd.pub.constituents, sizeof(NV_FLOAT32 *));
5586
5587 hd.equilibrium_scale = DEFAULT_EQUILIBRIUM_SCALE;
5588 min_value = 99999999.0;
5589 max_value = -99999999.0;
5590 for (i = 0; i < hd.pub.constituents; ++i) {
5591 hd.equilibrium[i] =
5592 (NV_FLOAT32 *)calloc(hd.pub.number_of_years, sizeof(NV_FLOAT32));
5593 for (j = 0; j < hd.pub.number_of_years; ++j) {
5594 if (equilibrium[i][j] < min_value) min_value = equilibrium[i][j];
5595 if (equilibrium[i][j] > max_value) max_value = equilibrium[i][j];
5596
5597 hd.equilibrium[i][j] = equilibrium[i][j];
5598 }
5599 }
5600
5601 /* DWF fixed sign reversal 2003-11-16 */
5602 /* DWF harmonized rounding with the way it is done in write_tide_db_header
5603 2007-01-22 */
5604 hd.equilibrium_offset = (NINT(min_value * hd.equilibrium_scale));
5605 temp_int = NINT(max_value * hd.equilibrium_scale) - hd.equilibrium_offset;
5606 assert(temp_int >= 0);
5607 hd.equilibrium_bits = calculate_bits((NV_U_INT32)temp_int);
5608
5609 /* Set all of the node factor attributes. */
5610
5611 hd.node_factor =
5612 (NV_FLOAT32 **)calloc(hd.pub.constituents, sizeof(NV_FLOAT32 *));
5613
5614 hd.node_scale = DEFAULT_NODE_SCALE;
5615 min_value = 99999999.0;
5616 max_value = -99999999.0;
5617 for (i = 0; i < hd.pub.constituents; ++i) {
5618 hd.node_factor[i] =
5619 (NV_FLOAT32 *)calloc(hd.pub.number_of_years, sizeof(NV_FLOAT32));
5620 for (j = 0; j < hd.pub.number_of_years; ++j) {
5621 if (node_factor[i][j] < min_value) min_value = node_factor[i][j];
5622 if (node_factor[i][j] > max_value) max_value = node_factor[i][j];
5623
5624 hd.node_factor[i][j] = node_factor[i][j];
5625 }
5626 }
5627
5628 /* DWF fixed sign reversal 2003-11-16 */
5629 /* DWF harmonized rounding with the way it is done in write_tide_db_header
5630 2007-01-22 */
5631 hd.node_offset = (NINT(min_value * hd.node_scale));
5632 temp_int = NINT(max_value * hd.node_scale) - hd.node_offset;
5633 assert(temp_int >= 0);
5634 hd.node_bits = calculate_bits((NV_U_INT32)temp_int);
5635
5636 /* Default city. */
5637
5638 hd.amplitude_bits = DEFAULT_AMPLITUDE_BITS;
5639 hd.amplitude_scale = DEFAULT_AMPLITUDE_SCALE;
5640 hd.epoch_bits = DEFAULT_EPOCH_BITS;
5641 hd.epoch_scale = DEFAULT_EPOCH_SCALE;
5642
5643 hd.record_type_bits = DEFAULT_RECORD_TYPE_BITS;
5644 hd.latitude_bits = DEFAULT_LATITUDE_BITS;
5645 hd.latitude_scale = DEFAULT_LATITUDE_SCALE;
5646 hd.longitude_bits = DEFAULT_LONGITUDE_BITS;
5647 hd.longitude_scale = DEFAULT_LONGITUDE_SCALE;
5648 hd.record_size_bits = DEFAULT_RECORD_SIZE_BITS;
5649
5650 hd.station_bits = DEFAULT_STATION_BITS;
5651
5652 hd.datum_offset_bits = DEFAULT_DATUM_OFFSET_BITS;
5653 hd.datum_offset_scale = DEFAULT_DATUM_OFFSET_SCALE;
5654 hd.date_bits = DEFAULT_DATE_BITS;
5655 hd.months_on_station_bits = DEFAULT_MONTHS_ON_STATION_BITS;
5656 hd.confidence_value_bits = DEFAULT_CONFIDENCE_VALUE_BITS;
5657
5658 hd.time_bits = DEFAULT_TIME_BITS;
5659 hd.level_add_bits = DEFAULT_LEVEL_ADD_BITS;
5660 hd.level_add_scale = DEFAULT_LEVEL_ADD_SCALE;
5661 hd.level_multiply_bits = DEFAULT_LEVEL_MULTIPLY_BITS;
5662 hd.level_multiply_scale = DEFAULT_LEVEL_MULTIPLY_SCALE;
5663 hd.direction_bits = DEFAULT_DIRECTION_BITS;
5664
5665 hd.constituent_size = DEFAULT_CONSTITUENT_SIZE;
5666 hd.level_unit_size = DEFAULT_LEVEL_UNIT_SIZE;
5667 hd.dir_unit_size = DEFAULT_DIR_UNIT_SIZE;
5668 hd.restriction_size = DEFAULT_RESTRICTION_SIZE;
5669 hd.tzfile_size = DEFAULT_TZFILE_SIZE;
5670 hd.country_size = DEFAULT_COUNTRY_SIZE;
5671 hd.datum_size = DEFAULT_DATUM_SIZE;
5672 hd.legalese_size = DEFAULT_LEGALESE_SIZE;
5673
5674 /* Level units. */
5675
5676 hd.pub.level_unit_types = DEFAULT_LEVEL_UNIT_TYPES;
5677 hd.level_unit_bits = calculate_bits(hd.pub.level_unit_types - 1);
5678
5679 hd.level_unit =
5680 (NV_CHAR **)calloc(hd.pub.level_unit_types, sizeof(NV_CHAR *));
5681 for (i = 0; i < hd.pub.level_unit_types; ++i) {
5682 hd.level_unit[i] =
5683 (NV_CHAR *)calloc(strlen(level_unit[i]) + 1, sizeof(NV_CHAR));
5684 strcpy(hd.level_unit[i], level_unit[i]);
5685 }
5686
5687 /* Direction units. */
5688
5689 hd.pub.dir_unit_types = DEFAULT_DIR_UNIT_TYPES;
5690 hd.dir_unit_bits = calculate_bits(hd.pub.dir_unit_types - 1);
5691
5692 hd.dir_unit = (NV_CHAR **)calloc(hd.pub.dir_unit_types, sizeof(NV_CHAR *));
5693 for (i = 0; i < hd.pub.dir_unit_types; ++i) {
5694 hd.dir_unit[i] =
5695 (NV_CHAR *)calloc(strlen(dir_unit[i]) + 1, sizeof(NV_CHAR));
5696 strcpy(hd.dir_unit[i], dir_unit[i]);
5697 }
5698
5699 /* Restrictions. */
5700
5701 hd.restriction_bits = DEFAULT_RESTRICTION_BITS;
5702 hd.max_restriction_types = NINT(pow(2.0, (NV_FLOAT64)hd.restriction_bits));
5703 hd.pub.restriction_types = DEFAULT_RESTRICTION_TYPES;
5704
5705 hd.restriction =
5706 (NV_CHAR **)calloc(hd.max_restriction_types, sizeof(NV_CHAR *));
5707 for (i = 0; i < hd.max_restriction_types; ++i) {
5708 if (i == hd.pub.restriction_types) break;
5709
5710 hd.restriction[i] =
5711 (NV_CHAR *)calloc(strlen(restriction[i]) + 1, sizeof(NV_CHAR));
5712 strcpy(hd.restriction[i], restriction[i]);
5713 }
5714
5715 /* Legaleses. */
5716
5717 hd.legalese_bits = DEFAULT_LEGALESE_BITS;
5718 hd.max_legaleses = NINT(pow(2.0, (NV_FLOAT64)hd.legalese_bits));
5719 hd.pub.legaleses = DEFAULT_LEGALESES;
5720
5721 hd.legalese = (NV_CHAR **)calloc(hd.max_legaleses, sizeof(NV_CHAR *));
5722 for (i = 0; i < hd.max_legaleses; ++i) {
5723 if (i == hd.pub.legaleses) break;
5724
5725 hd.legalese[i] =
5726 (NV_CHAR *)calloc(strlen(legalese[i]) + 1, sizeof(NV_CHAR));
5727 strcpy(hd.legalese[i], legalese[i]);
5728 }
5729
5730 /* Tzfiles. */
5731
5732 hd.tzfile_bits = DEFAULT_TZFILE_BITS;
5733 hd.max_tzfiles = NINT(pow(2.0, (NV_FLOAT64)hd.tzfile_bits));
5734 hd.pub.tzfiles = DEFAULT_TZFILES;
5735
5736 hd.tzfile = (NV_CHAR **)calloc(hd.max_tzfiles, sizeof(NV_CHAR *));
5737 for (i = 0; i < hd.max_tzfiles; ++i) {
5738 if (i == hd.pub.tzfiles) break;
5739
5740 hd.tzfile[i] = (NV_CHAR *)calloc(strlen(tzfile[i]) + 1, sizeof(NV_CHAR));
5741 strcpy(hd.tzfile[i], tzfile[i]);
5742 }
5743
5744 /* Countries. */
5745
5746 hd.country_bits = DEFAULT_COUNTRY_BITS;
5747 hd.max_countries = NINT(pow(2.0, (NV_FLOAT64)hd.country_bits));
5748 hd.pub.countries = DEFAULT_COUNTRIES;
5749
5750 hd.country = (NV_CHAR **)calloc(hd.max_countries, sizeof(NV_CHAR *));
5751 for (i = 0; i < hd.max_countries; ++i) {
5752 if (i == hd.pub.countries) break;
5753
5754 hd.country[i] = (NV_CHAR *)calloc(strlen(country[i]) + 1, sizeof(NV_CHAR));
5755 strcpy(hd.country[i], country[i]);
5756 }
5757
5758 /* Datums. */
5759
5760 hd.datum_bits = DEFAULT_DATUM_BITS;
5761 hd.max_datum_types = NINT(pow(2.0, (NV_FLOAT64)hd.datum_bits));
5762 hd.pub.datum_types = DEFAULT_DATUM_TYPES;
5763
5764 hd.datum = (NV_CHAR **)calloc(hd.max_datum_types, sizeof(NV_CHAR *));
5765 for (i = 0; i < hd.max_datum_types; ++i) {
5766 if (i == hd.pub.datum_types) break;
5767
5768 hd.datum[i] = (NV_CHAR *)calloc(strlen(datum[i]) + 1, sizeof(NV_CHAR));
5769 strcpy(hd.datum[i], datum[i]);
5770 }
5771
5772 /* Write the header to the file and close. */
5773
5774 modified = NVTrue;
5775 close_tide_db();
5776
5777 /* Re-open it and read the header from the file. */
5778
5779 i = (open_tide_db(file));
5780
5781 /* Set the correct end of file position since the one in the header is
5782 set to 0. */
5783 hd.end_of_file = ftell(fp);
5784 /* DWF 2004-08-15: if the original program exits without adding any
5785 records, that doesn't help! Rewrite the header with correct
5786 end_of_file. */
5787 write_tide_db_header();
5788
5789 return (i);
5790}
5791
5792/*****************************************************************************\
5793 DWF 2004-10-13
5794 Used in check_tide_record.
5795\*****************************************************************************/
5796static NV_BOOL check_date(NV_U_INT32 date) {
5797 if (date) {
5798 unsigned m, d;
5799 date %= 10000;
5800 m = date / 100;
5801 d = date % 100;
5802 if (m < 1 || m > 12 || d < 1 || d > 31) return NVFalse;
5803 }
5804 return NVTrue;
5805}
5806
5807/*****************************************************************************\
5808 DWF 2004-10-13
5809 Returns true iff a record is valid enough to write. Reports all problems
5810 to LOG_ERROR. The checks are not designed to be airtight (e.g., if you
5811 use 360 degrees instead of 0 we'll let it slide).
5812
5813 Mild side effects may occur:
5814 Note that the units-to-level-units COMPAT114 trick is wedged in here.
5815\*****************************************************************************/
5816static NV_BOOL check_tide_record(TIDE_RECORD *rec) {
5817 NV_U_INT32 i;
5818 NV_BOOL ret = NVTrue;
5819
5820 if (!rec) {
5821 LOG_ERROR("libtcd error: null pointer passed to check_tide_record\n");
5822 return NVFalse;
5823 }
5824
5825 /* These are all static fields--if a buffer overflow has occurred on one
5826 of these, other fields might be invalid, but the problem started here. */
5827 boundscheck_oneliner(rec->header.name);
5828 boundscheck_oneliner(rec->source);
5829 boundscheck_monologue(rec->comments);
5830 boundscheck_monologue(rec->notes);
5831 boundscheck_oneliner(rec->station_id_context);
5832 boundscheck_oneliner(rec->station_id);
5833 boundscheck_monologue(rec->xfields);
5834
5835#ifdef COMPAT114
5836 if (rec->header.record_type == REFERENCE_STATION && rec->units > 0)
5837 rec->level_units = rec->units;
5838#endif
5839
5840 if (rec->header.latitude < -90.0 || rec->header.latitude > 90.0 ||
5841 rec->header.longitude < -180.0 || rec->header.longitude > 180.0) {
5842 LOG_ERROR("libtcd error: bad coordinates in tide record\n");
5843 ret = NVFalse;
5844 }
5845
5846 if (rec->header.tzfile < 0 ||
5847 rec->header.tzfile >= (NV_INT32)hd.pub.tzfiles) {
5848 LOG_ERROR("libtcd error: bad tzfile in tide record\n");
5849 ret = NVFalse;
5850 }
5851
5852 if (rec->header.name[0] == '\0') {
5853 LOG_ERROR("libtcd error: null name in tide record\n");
5854 ret = NVFalse;
5855 }
5856
5857 if (rec->country < 0 || rec->country >= (NV_INT32)hd.pub.countries) {
5858 LOG_ERROR("libtcd error: bad country in tide record\n");
5859 ret = NVFalse;
5860 }
5861
5862 if (rec->restriction >= hd.pub.restriction_types) {
5863 LOG_ERROR("libtcd error: bad restriction in tide record\n");
5864 ret = NVFalse;
5865 }
5866
5867 if (rec->legalese >= hd.pub.legaleses) {
5868 LOG_ERROR("libtcd error: bad legalese in tide record\n");
5869 ret = NVFalse;
5870 }
5871
5872 if (!check_date(rec->date_imported)) {
5873 LOG_ERROR("libtcd error: bad date_imported in tide record\n");
5874 ret = NVFalse;
5875 }
5876
5877 if (rec->direction_units >= hd.pub.dir_unit_types) {
5878 LOG_ERROR("libtcd error: bad direction_units in tide record\n");
5879 ret = NVFalse;
5880 }
5881
5882 if (rec->min_direction < 0 || rec->min_direction > 361) {
5883 LOG_ERROR("libtcd error: min_direction out of range in tide record\n");
5884 ret = NVFalse;
5885 }
5886
5887 if (rec->max_direction < 0 || rec->max_direction > 361) {
5888 LOG_ERROR("libtcd error: max_direction out of range in tide record\n");
5889 ret = NVFalse;
5890 }
5891
5892 if (rec->level_units >= hd.pub.level_unit_types) {
5893 LOG_ERROR("libtcd error: bad units in tide record\n");
5894 ret = NVFalse;
5895 }
5896
5897 switch (rec->header.record_type) {
5898 case REFERENCE_STATION:
5899 if (rec->header.reference_station != -1) {
5900 LOG_ERROR("libtcd error: type 1 record, reference_station != -1\n");
5901 ret = NVFalse;
5902 }
5903
5904 if (rec->datum_offset < -13421.7728 || rec->datum_offset > 13421.7727) {
5905 LOG_ERROR("libtcd error: datum_offset out of range in tide record\n");
5906 ret = NVFalse;
5907 }
5908
5909 if (rec->datum < 0 || rec->datum >= (NV_INT32)hd.pub.datum_types) {
5910 LOG_ERROR("libtcd error: bad datum in tide record\n");
5911 ret = NVFalse;
5912 }
5913
5914 if (rec->zone_offset < -4096 || rec->zone_offset > 4095 ||
5915 rec->zone_offset % 100 >= 60) {
5916 LOG_ERROR("libtcd error: bad zone_offset in tide record\n");
5917 ret = NVFalse;
5918 }
5919
5920 if (!check_date(rec->expiration_date)) {
5921 LOG_ERROR("libtcd error: bad expiration_date in tide record\n");
5922 ret = NVFalse;
5923 }
5924
5925 if (rec->months_on_station > 1023) {
5926 LOG_ERROR(
5927 "libtcd error: months_on_station out of range in tide record\n");
5928 ret = NVFalse;
5929 }
5930
5931 if (!check_date(rec->last_date_on_station)) {
5932 LOG_ERROR("libtcd error: bad last_date_on_station in tide record\n");
5933 ret = NVFalse;
5934 }
5935
5936 if (rec->confidence > 15) {
5937 LOG_ERROR("libtcd error: confidence out of range in tide record\n");
5938 ret = NVFalse;
5939 }
5940
5941 /* Only issue each error once. */
5942 for (i = 0; i < hd.pub.constituents; ++i) {
5943 if (rec->amplitude[i] < 0.0 || rec->amplitude[i] > 52.4287) {
5944 LOG_ERROR(
5945 "libtcd error: constituent amplitude out of range in tide "
5946 "record\n");
5947 ret = NVFalse;
5948 break;
5949 }
5950 }
5951 for (i = 0; i < hd.pub.constituents; ++i) {
5952 if (rec->epoch[i] < 0.0 || rec->epoch[i] > 360.0) {
5953 LOG_ERROR(
5954 "libtcd error: constituent epoch out of range in tide record\n");
5955 ret = NVFalse;
5956 break;
5957 }
5958 }
5959
5960 break;
5961
5962 case SUBORDINATE_STATION:
5963 if (rec->header.reference_station < 0 ||
5964 rec->header.reference_station >= (NV_INT32)hd.pub.number_of_records) {
5965 LOG_ERROR("libtcd error: bad reference_station in tide record\n");
5966 ret = NVFalse;
5967 }
5968
5969 if (rec->min_time_add < -4096 || rec->min_time_add > 4095 ||
5970 rec->min_time_add % 100 >= 60) {
5971 LOG_ERROR("libtcd error: bad min_time_add in tide record\n");
5972 ret = NVFalse;
5973 }
5974
5975 if (rec->min_level_add < -65.536 || rec->min_level_add > 65.535) {
5976 LOG_ERROR("libtcd error: min_level_add out of range in tide record\n");
5977 ret = NVFalse;
5978 }
5979
5980 if (rec->min_level_multiply < 0.0 || rec->min_level_multiply > 65.535) {
5981 LOG_ERROR(
5982 "libtcd error: min_level_multiply out of range in tide record\n");
5983 ret = NVFalse;
5984 }
5985
5986 if (rec->max_time_add < -4096 || rec->max_time_add > 4095 ||
5987 rec->max_time_add % 100 >= 60) {
5988 LOG_ERROR("libtcd error: bad max_time_add in tide record\n");
5989 ret = NVFalse;
5990 }
5991
5992 if (rec->max_level_add < -65.536 || rec->max_level_add > 65.535) {
5993 LOG_ERROR("libtcd error: max_level_add out of range in tide record\n");
5994 ret = NVFalse;
5995 }
5996
5997 if (rec->max_level_multiply < 0.0 || rec->max_level_multiply > 65.535) {
5998 LOG_ERROR(
5999 "libtcd error: max_level_multiply out of range in tide record\n");
6000 ret = NVFalse;
6001 }
6002
6003 if (rec->flood_begins != NULLSLACKOFFSET &&
6004 (rec->flood_begins < -4096 || rec->flood_begins > 4095 ||
6005 rec->flood_begins % 100 >= 60)) {
6006 LOG_ERROR("libtcd error: bad flood_begins in tide record\n");
6007 ret = NVFalse;
6008 }
6009
6010 if (rec->ebb_begins != NULLSLACKOFFSET &&
6011 (rec->ebb_begins < -4096 || rec->ebb_begins > 4095 ||
6012 rec->ebb_begins % 100 >= 60)) {
6013 LOG_ERROR("libtcd error: bad ebb_begins in tide record\n");
6014 ret = NVFalse;
6015 }
6016
6017 break;
6018
6019 default:
6020 LOG_ERROR("libtcd error: invalid record_type in tide record\n");
6021 ret = NVFalse;
6022 }
6023
6024 if (ret == NVFalse) dump_tide_record(rec);
6025 return ret;
6026}
6027
6028/*****************************************************************************\
6029 DWF 2004-10-13
6030 Calculate size of a tide record as it would be encoded in the TCD file.
6031 Size is stored in record_size field. Return is number of constituents
6032 that will be encoded.
6033\*****************************************************************************/
6034static NV_U_INT32 figure_size(TIDE_RECORD *rec) {
6035 NV_U_INT32 i, count = 0, name_size, source_size, comments_size, notes_size,
6036 station_id_context_size, station_id_size, xfields_size;
6037
6038 assert(rec);
6039
6040 /* Figure out how many bits we'll need for this record. */
6041
6042 name_size = strlen(clip_string(rec->header.name)) + 1;
6043 source_size = strlen(clip_string(rec->source)) + 1;
6044 comments_size = strlen(clip_string(rec->comments)) + 1;
6045 notes_size = strlen(clip_string(rec->notes)) + 1;
6046 station_id_context_size = strlen(clip_string(rec->station_id_context)) + 1;
6047 station_id_size = strlen(clip_string(rec->station_id)) + 1;
6048 /* No clipping on xfields -- trailing \n required by syntax */
6049 xfields_size = strlen(rec->xfields) + 1;
6050
6051 rec->header.record_size =
6052 hd.record_size_bits + hd.record_type_bits + hd.latitude_bits +
6053 hd.longitude_bits + hd.station_bits + hd.tzfile_bits + (name_size * 8) +
6054
6055 hd.country_bits + (source_size * 8) + hd.restriction_bits +
6056 (comments_size * 8) + (notes_size * 8) + hd.legalese_bits +
6057 (station_id_context_size * 8) + (station_id_size * 8) + hd.date_bits +
6058 (xfields_size * 8) + hd.dir_unit_bits + hd.direction_bits +
6059 hd.direction_bits + hd.level_unit_bits;
6060
6061 switch (rec->header.record_type) {
6062 case REFERENCE_STATION:
6063 rec->header.record_size += hd.datum_offset_bits + hd.datum_bits +
6064 hd.time_bits + hd.date_bits +
6065 hd.months_on_station_bits + hd.date_bits +
6066 hd.confidence_value_bits + hd.constituent_bits;
6067
6068 for (i = 0; i < hd.pub.constituents; ++i) {
6069 assert(rec->amplitude[i] >= 0.0);
6070 if (rec->amplitude[i] >= AMPLITUDE_EPSILON) ++count;
6071 }
6072
6073 rec->header.record_size +=
6074 (count * hd.constituent_bits + count * hd.amplitude_bits +
6075 count * hd.epoch_bits);
6076
6077 break;
6078
6079 case SUBORDINATE_STATION:
6080 rec->header.record_size += hd.time_bits + hd.level_add_bits +
6081 hd.level_multiply_bits + hd.time_bits +
6082 hd.level_add_bits + hd.level_multiply_bits +
6083 hd.time_bits + hd.time_bits;
6084 break;
6085
6086 default:
6087 assert(0);
6088 }
6089
6090 rec->header.record_size = bits2bytes(rec->header.record_size);
6091 return count;
6092}
6093
6094/*****************************************************************************\
6095DWF 2004-10-14
6096\*****************************************************************************/
6097static void pack_string(NV_U_BYTE *buf, NV_U_INT32 *pos, NV_CHAR *s) {
6098 NV_U_INT32 i, temp_size;
6099 assert(buf);
6100 assert(pos);
6101 assert(s);
6102 temp_size = strlen(s) + 1;
6103 for (i = 0; i < temp_size; ++i) {
6104 bit_pack(buf, *pos, 8, s[i]);
6105 *pos += 8;
6106 }
6107}
6108
6109/*****************************************************************************\
6110
6111 Function pack_tide_record - convert TIDE_RECORD to packed form
6112
6113 Synopsis pack_tide_record (rec, bufptr, bufsize);
6114
6115 TIDE_RECORD *rec tide record (in)
6116 NV_U_BYTE **bufptr packed record (out)
6117 NV_U_INT32 *bufsize size of buf in bytes (out)
6118
6119 buf is allocated by pack_tide_record and should be
6120 freed by the caller.
6121
6122 Returns void
6123
6124 Author Extracted from write_tide_record by David Flater
6125 Date 2006-05-26
6126
6127\*****************************************************************************/
6128
6129static void pack_tide_record(TIDE_RECORD *rec, NV_U_BYTE **bufptr,
6130 NV_U_INT32 *bufsize) {
6131 NV_U_INT32 i, pos, constituent_count;
6132 NV_INT32 temp_int;
6133 NV_U_BYTE *buf;
6134
6135 /* Validate input */
6136 assert(rec);
6137 /* Cursory check for buffer overflows. Should not happen here --
6138 check_tide_record does a more thorough job when called by add_tide_record
6139 and update_tide_record. */
6140 boundscheck_oneliner(rec->header.name);
6141 boundscheck_oneliner(rec->source);
6142 boundscheck_monologue(rec->comments);
6143 boundscheck_monologue(rec->notes);
6144 boundscheck_oneliner(rec->station_id_context);
6145 boundscheck_oneliner(rec->station_id);
6146 boundscheck_monologue(rec->xfields);
6147
6148 constituent_count = figure_size(rec);
6149
6150 if (!(*bufptr =
6151 (NV_U_BYTE *)calloc(rec->header.record_size, sizeof(NV_U_BYTE)))) {
6152 perror("libtcd can't allocate memory in pack_tide_record");
6153 exit(-1);
6154 }
6155 buf = *bufptr; /* To conserve asterisks */
6156
6157 /* Bit pack the common section. "pos" is the bit position within the
6158 buffer "buf". */
6159
6160 pos = 0;
6161
6162 bit_pack(buf, pos, hd.record_size_bits, rec->header.record_size);
6163 pos += hd.record_size_bits;
6164
6165 bit_pack(buf, pos, hd.record_type_bits, rec->header.record_type);
6166 pos += hd.record_type_bits;
6167
6168 temp_int = NINT(rec->header.latitude * hd.latitude_scale);
6169 bit_pack(buf, pos, hd.latitude_bits, temp_int);
6170 pos += hd.latitude_bits;
6171
6172 temp_int = NINT(rec->header.longitude * hd.longitude_scale);
6173 bit_pack(buf, pos, hd.longitude_bits, temp_int);
6174 pos += hd.longitude_bits;
6175
6176 /* This ordering doesn't match everywhere else but there's no technical
6177 reason to change it from its V1 ordering. To do so would force
6178 another conditional in unpack_partial_tide_record. */
6179
6180 bit_pack(buf, pos, hd.tzfile_bits, rec->header.tzfile);
6181 pos += hd.tzfile_bits;
6182
6183 pack_string(buf, &pos, clip_string(rec->header.name));
6184
6185 bit_pack(buf, pos, hd.station_bits, rec->header.reference_station);
6186 pos += hd.station_bits;
6187
6188 bit_pack(buf, pos, hd.country_bits, rec->country);
6189 pos += hd.country_bits;
6190
6191 pack_string(buf, &pos, clip_string(rec->source));
6192
6193 bit_pack(buf, pos, hd.restriction_bits, rec->restriction);
6194 pos += hd.restriction_bits;
6195
6196 pack_string(buf, &pos, clip_string(rec->comments));
6197 pack_string(buf, &pos, clip_string(rec->notes));
6198
6199 bit_pack(buf, pos, hd.legalese_bits, rec->legalese);
6200 pos += hd.legalese_bits;
6201
6202 pack_string(buf, &pos, clip_string(rec->station_id_context));
6203 pack_string(buf, &pos, clip_string(rec->station_id));
6204
6205 bit_pack(buf, pos, hd.date_bits, rec->date_imported);
6206 pos += hd.date_bits;
6207
6208 /* No clipping on xfields -- trailing \n required by syntax */
6209 pack_string(buf, &pos, rec->xfields);
6210
6211 bit_pack(buf, pos, hd.dir_unit_bits, rec->direction_units);
6212 pos += hd.dir_unit_bits;
6213
6214 bit_pack(buf, pos, hd.direction_bits, rec->min_direction);
6215 pos += hd.direction_bits;
6216
6217 bit_pack(buf, pos, hd.direction_bits, rec->max_direction);
6218 pos += hd.direction_bits;
6219
6220 /* The units-to-level-units compatibility hack is in check_tide_record */
6221 bit_pack(buf, pos, hd.level_unit_bits, rec->level_units);
6222 pos += hd.level_unit_bits;
6223
6224 /* Bit pack record type 1 records. */
6225
6226 if (rec->header.record_type == REFERENCE_STATION) {
6227 temp_int = NINT(rec->datum_offset * hd.datum_offset_scale);
6228 bit_pack(buf, pos, hd.datum_offset_bits, temp_int);
6229 pos += hd.datum_offset_bits;
6230
6231 bit_pack(buf, pos, hd.datum_bits, rec->datum);
6232 pos += hd.datum_bits;
6233
6234 bit_pack(buf, pos, hd.time_bits, rec->zone_offset);
6235 pos += hd.time_bits;
6236
6237 bit_pack(buf, pos, hd.date_bits, rec->expiration_date);
6238 pos += hd.date_bits;
6239
6240 bit_pack(buf, pos, hd.months_on_station_bits, rec->months_on_station);
6241 pos += hd.months_on_station_bits;
6242
6243 bit_pack(buf, pos, hd.date_bits, rec->last_date_on_station);
6244 pos += hd.date_bits;
6245
6246 bit_pack(buf, pos, hd.confidence_value_bits, rec->confidence);
6247 pos += hd.confidence_value_bits;
6248
6249 bit_pack(buf, pos, hd.constituent_bits, constituent_count);
6250 pos += hd.constituent_bits;
6251
6252 for (i = 0; i < hd.pub.constituents; ++i) {
6253 if (rec->amplitude[i] >= AMPLITUDE_EPSILON) {
6254 bit_pack(buf, pos, hd.constituent_bits, i);
6255 pos += hd.constituent_bits;
6256
6257 temp_int = NINT(rec->amplitude[i] * hd.amplitude_scale);
6258 assert(temp_int);
6259 bit_pack(buf, pos, hd.amplitude_bits, temp_int);
6260 pos += hd.amplitude_bits;
6261
6262 temp_int = NINT(rec->epoch[i] * hd.epoch_scale);
6263 bit_pack(buf, pos, hd.epoch_bits, temp_int);
6264 pos += hd.epoch_bits;
6265 }
6266 }
6267 }
6268
6269 /* Bit pack record type 2 records. */
6270 else if (rec->header.record_type == SUBORDINATE_STATION) {
6271 bit_pack(buf, pos, hd.time_bits, rec->min_time_add);
6272 pos += hd.time_bits;
6273
6274 temp_int = NINT(rec->min_level_add * hd.level_add_scale);
6275 bit_pack(buf, pos, hd.level_add_bits, temp_int);
6276 pos += hd.level_add_bits;
6277
6278 temp_int = NINT(rec->min_level_multiply * hd.level_multiply_scale);
6279 bit_pack(buf, pos, hd.level_multiply_bits, temp_int);
6280 pos += hd.level_multiply_bits;
6281
6282 bit_pack(buf, pos, hd.time_bits, rec->max_time_add);
6283 pos += hd.time_bits;
6284
6285 temp_int = NINT(rec->max_level_add * hd.level_add_scale);
6286 bit_pack(buf, pos, hd.level_add_bits, temp_int);
6287 pos += hd.level_add_bits;
6288
6289 temp_int = NINT(rec->max_level_multiply * hd.level_multiply_scale);
6290 bit_pack(buf, pos, hd.level_multiply_bits, temp_int);
6291 pos += hd.level_multiply_bits;
6292
6293 bit_pack(buf, pos, hd.time_bits, rec->flood_begins);
6294 pos += hd.time_bits;
6295
6296 bit_pack(buf, pos, hd.time_bits, rec->ebb_begins);
6297 pos += hd.time_bits;
6298 }
6299
6300 else {
6301 LOG_ERROR("libtcd error: Record type %d is undefined\n",
6302 rec->header.record_type);
6303 exit(-1);
6304 }
6305
6306 *bufsize = rec->header.record_size;
6307 assert(*bufsize == bits2bytes(pos));
6308}
6309
6310/*****************************************************************************\
6311
6312 Function write_tide_record - writes a tide record to the database
6313
6314 Synopsis write_tide_record (num, rec);
6315
6316 NV_INT32 num record number:
6317 >= 0 overwrite record num
6318 -1 write at current file position
6319 TIDE_RECORD *rec tide record
6320
6321 Returns NV_BOOL NVTrue if successful
6322
6323 Author Jan C. Depner
6324 Date 08/01/02
6325
6326 See libtcd.html for changelog.
6327
6328 hd.end_of_file is not updated by this function in any event.
6329
6330\*****************************************************************************/
6331
6332static NV_BOOL write_tide_record(NV_INT32 num, TIDE_RECORD *rec) {
6333 NV_U_BYTE *buf = NULL;
6334 NV_U_INT32 bufsize = 0;
6335
6336 if (!fp) {
6337 LOG_ERROR(
6338 "libtcd error: attempt to access database when database not open\n");
6339 return NVFalse;
6340 }
6341 write_protect();
6342
6343 pack_tide_record(rec, &buf, &bufsize);
6344
6345 if (num == -1)
6346 ;
6347 else if (num >= 0)
6348 fseek(fp, tindex[num].address, SEEK_SET);
6349 else
6350 assert(0);
6351
6352 chk_fwrite(buf, bufsize, 1, fp);
6353 free(buf);
6354 modified = NVTrue;
6355 return NVTrue;
6356}
6357
6358/*****************************************************************************\
6359
6360 Function read_next_tide_record - reads the next tide record from
6361 the database
6362
6363 Synopsis read_next_tide_record (rec);
6364
6365 TIDE_RECORD *rec tide record
6366
6367 Returns NV_INT32 record number of the tide record
6368
6369 Author Jan C. Depner
6370 Date 08/01/02
6371
6372 See libtcd.html for changelog.
6373
6374\*****************************************************************************/
6375
6376NV_INT32 read_next_tide_record(TIDE_RECORD *rec) {
6377 return (read_tide_record(current_record + 1, rec));
6378}
6379
6380/*****************************************************************************\
6381
6382 Function unpack_tide_record - convert TIDE_RECORD from packed form
6383
6384 Synopsis unpack_tide_record (buf, bufsize, rec);
6385
6386 NV_U_BYTE *buf packed record (in)
6387 NV_U_INT32 bufsize size of buf in bytes (in)
6388 TIDE_RECORD *rec tide record (in-out)
6389
6390 rec must be allocated by the caller.
6391
6392 Returns void
6393
6394 Author Extracted from read_tide_record by David Flater
6395 Date 2006-05-26
6396
6397 rec->header.record_number is initialized from the global current_record.
6398
6399\*****************************************************************************/
6400
6401static void unpack_tide_record(NV_U_BYTE *buf, NV_U_INT32 bufsize,
6402 TIDE_RECORD *rec) {
6403 NV_INT32 temp_int;
6404 NV_U_INT32 i, j, pos, count;
6405
6406 assert(rec);
6407
6408 /* Initialize record */
6409 memset(rec, 0, sizeof(TIDE_RECORD));
6410 {
6411 int r = find_dir_units("degrees true");
6412 assert(r > 0);
6413 rec->direction_units = (NV_U_BYTE)r;
6414 }
6415 rec->min_direction = rec->max_direction = 361;
6416 rec->flood_begins = rec->ebb_begins = NULLSLACKOFFSET;
6417 rec->header.record_number = current_record;
6418
6419 unpack_partial_tide_record(buf, bufsize, rec, &pos);
6420
6421 switch (rec->header.record_type) {
6422 case REFERENCE_STATION:
6423 case SUBORDINATE_STATION:
6424 break;
6425 default:
6426 LOG_ERROR("libtcd fatal error: tried to read type %d tide record.\n",
6427 rec->header.record_type);
6428 LOG_ERROR(
6429 "This version of libtcd only supports types 1 and 2. Perhaps you "
6430 "should\nupgrade.\n");
6431 exit(-1);
6432 }
6433
6434 switch (hd.pub.major_rev) {
6435 /************************* TCD V1 *****************************/
6436 case 0:
6437 case 1:
6438
6439 /* "pos" is the bit position within the buffer "buf". */
6440
6441 rec->country = bit_unpack(buf, pos, hd.country_bits);
6442 pos += hd.country_bits;
6443
6444 /* pedigree */
6445 pos += hd.pedigree_bits;
6446
6447 unpack_string(buf, bufsize, &pos, rec->source, ONELINER_LENGTH,
6448 "source field");
6449
6450 rec->restriction = bit_unpack(buf, pos, hd.restriction_bits);
6451 pos += hd.restriction_bits;
6452
6453 unpack_string(buf, bufsize, &pos, rec->comments, MONOLOGUE_LENGTH,
6454 "comments field");
6455
6456 if (rec->header.record_type == REFERENCE_STATION) {
6457 rec->level_units = bit_unpack(buf, pos, hd.level_unit_bits);
6458#ifdef COMPAT114
6459 rec->units = rec->level_units;
6460#endif
6461 pos += hd.level_unit_bits;
6462
6463 temp_int = signed_bit_unpack(buf, pos, hd.datum_offset_bits);
6464 rec->datum_offset = (NV_FLOAT32)temp_int / hd.datum_offset_scale;
6465 pos += hd.datum_offset_bits;
6466
6467 rec->datum = bit_unpack(buf, pos, hd.datum_bits);
6468 pos += hd.datum_bits;
6469
6470 rec->zone_offset = signed_bit_unpack(buf, pos, hd.time_bits);
6471 pos += hd.time_bits;
6472
6473 rec->expiration_date = bit_unpack(buf, pos, hd.date_bits);
6474 pos += hd.date_bits;
6475
6476 rec->months_on_station =
6477 bit_unpack(buf, pos, hd.months_on_station_bits);
6478 pos += hd.months_on_station_bits;
6479
6480 rec->last_date_on_station = bit_unpack(buf, pos, hd.date_bits);
6481 pos += hd.date_bits;
6482
6483 rec->confidence = bit_unpack(buf, pos, hd.confidence_value_bits);
6484 pos += hd.confidence_value_bits;
6485
6486 for (i = 0; i < hd.pub.constituents; ++i) {
6487 rec->amplitude[i] = 0.0;
6488 rec->epoch[i] = 0.0;
6489 }
6490
6491 count = bit_unpack(buf, pos, hd.constituent_bits);
6492 pos += hd.constituent_bits;
6493
6494 for (i = 0; i < count; ++i) {
6495 j = bit_unpack(buf, pos, hd.constituent_bits);
6496 pos += hd.constituent_bits;
6497
6498 rec->amplitude[j] =
6499 (NV_FLOAT32)bit_unpack(buf, pos, hd.amplitude_bits) /
6500 hd.amplitude_scale;
6501 pos += hd.amplitude_bits;
6502
6503 rec->epoch[j] =
6504 (NV_FLOAT32)bit_unpack(buf, pos, hd.epoch_bits) / hd.epoch_scale;
6505 pos += hd.epoch_bits;
6506 }
6507 } else if (rec->header.record_type == SUBORDINATE_STATION) {
6508 rec->level_units = bit_unpack(buf, pos, hd.level_unit_bits);
6509 pos += hd.level_unit_bits;
6510
6511 rec->direction_units = bit_unpack(buf, pos, hd.dir_unit_bits);
6512 pos += hd.dir_unit_bits;
6513
6514 /* avg_level_units */
6515 pos += hd.level_unit_bits;
6516
6517 rec->min_time_add = signed_bit_unpack(buf, pos, hd.time_bits);
6518 pos += hd.time_bits;
6519
6520 temp_int = signed_bit_unpack(buf, pos, hd.level_add_bits);
6521 rec->min_level_add = (NV_FLOAT32)temp_int / hd.level_add_scale;
6522 pos += hd.level_add_bits;
6523
6524 /* Signed in V1 */
6525 temp_int = signed_bit_unpack(buf, pos, hd.level_multiply_bits);
6526 rec->min_level_multiply =
6527 (NV_FLOAT32)temp_int / hd.level_multiply_scale;
6528 pos += hd.level_multiply_bits;
6529
6530 /* min_avg_level */
6531 pos += hd.level_add_bits;
6532
6533 rec->min_direction = bit_unpack(buf, pos, hd.direction_bits);
6534 pos += hd.direction_bits;
6535
6536 rec->max_time_add = signed_bit_unpack(buf, pos, hd.time_bits);
6537 pos += hd.time_bits;
6538
6539 temp_int = signed_bit_unpack(buf, pos, hd.level_add_bits);
6540 rec->max_level_add = (NV_FLOAT32)temp_int / hd.level_add_scale;
6541 pos += hd.level_add_bits;
6542
6543 /* Signed in V1 */
6544 temp_int = signed_bit_unpack(buf, pos, hd.level_multiply_bits);
6545 rec->max_level_multiply =
6546 (NV_FLOAT32)temp_int / hd.level_multiply_scale;
6547 pos += hd.level_multiply_bits;
6548
6549 /* max_avg_level */
6550 pos += hd.level_add_bits;
6551
6552 rec->max_direction = bit_unpack(buf, pos, hd.direction_bits);
6553 pos += hd.direction_bits;
6554
6555 rec->flood_begins = signed_bit_unpack(buf, pos, hd.time_bits);
6556 pos += hd.time_bits;
6557
6558 rec->ebb_begins = signed_bit_unpack(buf, pos, hd.time_bits);
6559 pos += hd.time_bits;
6560 } else {
6561 assert(0);
6562 }
6563 break;
6564
6565 /************************* TCD V2 *****************************/
6566 case 2:
6567 rec->country = bit_unpack(buf, pos, hd.country_bits);
6568 pos += hd.country_bits;
6569
6570 unpack_string(buf, bufsize, &pos, rec->source, ONELINER_LENGTH,
6571 "source field");
6572
6573 rec->restriction = bit_unpack(buf, pos, hd.restriction_bits);
6574 pos += hd.restriction_bits;
6575
6576 unpack_string(buf, bufsize, &pos, rec->comments, MONOLOGUE_LENGTH,
6577 "comments field");
6578 unpack_string(buf, bufsize, &pos, rec->notes, MONOLOGUE_LENGTH,
6579 "notes field");
6580
6581 rec->legalese = bit_unpack(buf, pos, hd.legalese_bits);
6582 pos += hd.legalese_bits;
6583
6584 unpack_string(buf, bufsize, &pos, rec->station_id_context,
6585 ONELINER_LENGTH, "station_id_context field");
6586 unpack_string(buf, bufsize, &pos, rec->station_id, ONELINER_LENGTH,
6587 "station_id field");
6588
6589 rec->date_imported = bit_unpack(buf, pos, hd.date_bits);
6590 pos += hd.date_bits;
6591
6592 unpack_string(buf, bufsize, &pos, rec->xfields, MONOLOGUE_LENGTH,
6593 "xfields field");
6594
6595 rec->direction_units = bit_unpack(buf, pos, hd.dir_unit_bits);
6596 pos += hd.dir_unit_bits;
6597
6598 rec->min_direction = bit_unpack(buf, pos, hd.direction_bits);
6599 pos += hd.direction_bits;
6600
6601 rec->max_direction = bit_unpack(buf, pos, hd.direction_bits);
6602 pos += hd.direction_bits;
6603
6604 rec->level_units = bit_unpack(buf, pos, hd.level_unit_bits);
6605#ifdef COMPAT114
6606 rec->units = rec->level_units;
6607#endif
6608 pos += hd.level_unit_bits;
6609
6610 if (rec->header.record_type == REFERENCE_STATION) {
6611 temp_int = signed_bit_unpack(buf, pos, hd.datum_offset_bits);
6612 rec->datum_offset = (NV_FLOAT32)temp_int / hd.datum_offset_scale;
6613 pos += hd.datum_offset_bits;
6614
6615 rec->datum = bit_unpack(buf, pos, hd.datum_bits);
6616 pos += hd.datum_bits;
6617
6618 rec->zone_offset = signed_bit_unpack(buf, pos, hd.time_bits);
6619 pos += hd.time_bits;
6620
6621 rec->expiration_date = bit_unpack(buf, pos, hd.date_bits);
6622 pos += hd.date_bits;
6623
6624 rec->months_on_station =
6625 bit_unpack(buf, pos, hd.months_on_station_bits);
6626 pos += hd.months_on_station_bits;
6627
6628 rec->last_date_on_station = bit_unpack(buf, pos, hd.date_bits);
6629 pos += hd.date_bits;
6630
6631 rec->confidence = bit_unpack(buf, pos, hd.confidence_value_bits);
6632 pos += hd.confidence_value_bits;
6633
6634 for (i = 0; i < hd.pub.constituents; ++i) {
6635 rec->amplitude[i] = 0.0;
6636 rec->epoch[i] = 0.0;
6637 }
6638
6639 count = bit_unpack(buf, pos, hd.constituent_bits);
6640 pos += hd.constituent_bits;
6641
6642 for (i = 0; i < count; ++i) {
6643 j = bit_unpack(buf, pos, hd.constituent_bits);
6644 pos += hd.constituent_bits;
6645
6646 rec->amplitude[j] =
6647 (NV_FLOAT32)bit_unpack(buf, pos, hd.amplitude_bits) /
6648 hd.amplitude_scale;
6649 pos += hd.amplitude_bits;
6650
6651 rec->epoch[j] =
6652 (NV_FLOAT32)bit_unpack(buf, pos, hd.epoch_bits) / hd.epoch_scale;
6653 pos += hd.epoch_bits;
6654 }
6655 } else if (rec->header.record_type == SUBORDINATE_STATION) {
6656 rec->min_time_add = signed_bit_unpack(buf, pos, hd.time_bits);
6657 pos += hd.time_bits;
6658
6659 temp_int = signed_bit_unpack(buf, pos, hd.level_add_bits);
6660 rec->min_level_add = (NV_FLOAT32)temp_int / hd.level_add_scale;
6661 pos += hd.level_add_bits;
6662
6663 /* Made unsigned in V2 */
6664 temp_int = bit_unpack(buf, pos, hd.level_multiply_bits);
6665 rec->min_level_multiply =
6666 (NV_FLOAT32)temp_int / hd.level_multiply_scale;
6667 pos += hd.level_multiply_bits;
6668
6669 rec->max_time_add = signed_bit_unpack(buf, pos, hd.time_bits);
6670 pos += hd.time_bits;
6671
6672 temp_int = signed_bit_unpack(buf, pos, hd.level_add_bits);
6673 rec->max_level_add = (NV_FLOAT32)temp_int / hd.level_add_scale;
6674 pos += hd.level_add_bits;
6675
6676 /* Made unsigned in V2 */
6677 temp_int = bit_unpack(buf, pos, hd.level_multiply_bits);
6678 rec->max_level_multiply =
6679 (NV_FLOAT32)temp_int / hd.level_multiply_scale;
6680 pos += hd.level_multiply_bits;
6681
6682 rec->flood_begins = signed_bit_unpack(buf, pos, hd.time_bits);
6683 pos += hd.time_bits;
6684
6685 rec->ebb_begins = signed_bit_unpack(buf, pos, hd.time_bits);
6686 pos += hd.time_bits;
6687 } else {
6688 assert(0);
6689 }
6690 break;
6691
6692 default:
6693 assert(0);
6694 }
6695
6696 assert(pos <= bufsize * 8);
6697}
6698
6699/*****************************************************************************\
6700
6701 Function read_tide_record - reads tide record "num" from the
6702 database
6703
6704 Synopsis read_tide_record (num, rec);
6705
6706 NV_INT32 num record number (in)
6707 TIDE_RECORD *rec tide record (in-out)
6708
6709 rec must be allocated by the caller.
6710
6711 Returns NV_INT32 num if success, -1 if failure
6712
6713 Author Jan C. Depner
6714 Date 08/01/02
6715
6716 See libtcd.html for changelog.
6717
6718\*****************************************************************************/
6719
6720NV_INT32 read_tide_record(NV_INT32 num, TIDE_RECORD *rec) {
6721 NV_U_BYTE *buf;
6722 NV_U_INT32 bufsize;
6723
6724 if (!fp) {
6725 LOG_ERROR(
6726 "libtcd error: attempt to access database when database not open\n");
6727 return -1;
6728 }
6729
6730 if (num < 0 || num >= (NV_INT32)hd.pub.number_of_records) return -1;
6731 assert(rec);
6732
6733 bufsize = tindex[num].record_size;
6734 if ((buf = (NV_U_BYTE *)calloc(bufsize, sizeof(NV_U_BYTE))) == NULL) {
6735 perror("Allocating read_tide_record buffer");
6736 exit(-1);
6737 }
6738
6739 current_record = num;
6740 require(fseek(fp, tindex[num].address, SEEK_SET) == 0);
6741 chk_fread(buf, tindex[num].record_size, 1, fp);
6742 unpack_tide_record(buf, bufsize, rec);
6743 free(buf);
6744 return num;
6745}
6746
6747/*****************************************************************************\
6748
6749 Function add_tide_record - adds a tide record to the database
6750
6751 Synopsis add_tide_record (rec);
6752
6753 TIDE_RECORD *rec tide record
6754
6755 Returns NV_BOOL NVTrue if successful
6756
6757 Author Jan C. Depner
6758 Date 08/01/02
6759
6760 See libtcd.html for changelog.
6761
6762\*****************************************************************************/
6763
6764NV_BOOL add_tide_record(TIDE_RECORD *rec, DB_HEADER_PUBLIC *db) {
6765 NV_INT32 pos;
6766
6767 if (!fp) {
6768 LOG_ERROR(
6769 "libtcd error: attempt to access database when database not open\n");
6770 return NVFalse;
6771 }
6772 write_protect();
6773
6774 if (!check_tide_record(rec)) return NVFalse;
6775
6776 fseek(fp, hd.end_of_file, SEEK_SET);
6777 pos = ftell(fp);
6778 assert(pos > 0);
6779
6780 rec->header.record_number = hd.pub.number_of_records++;
6781
6782 if (write_tide_record(-1, rec)) {
6783 if ((tindex = (TIDE_INDEX *)realloc(
6784 tindex, hd.pub.number_of_records * sizeof(TIDE_INDEX))) == NULL) {
6785 perror("Allocating more index records");
6786 exit(-1);
6787 }
6788
6789 tindex[rec->header.record_number].address = pos;
6790 tindex[rec->header.record_number].record_size = rec->header.record_size;
6791 tindex[rec->header.record_number].record_type = rec->header.record_type;
6792 tindex[rec->header.record_number].reference_station =
6793 rec->header.reference_station;
6794 assert(rec->header.tzfile >= 0);
6795 tindex[rec->header.record_number].tzfile = rec->header.tzfile;
6796 tindex[rec->header.record_number].lat =
6797 NINT(rec->header.latitude * hd.latitude_scale);
6798 tindex[rec->header.record_number].lon =
6799 NINT(rec->header.longitude * hd.longitude_scale);
6800
6801 if ((tindex[rec->header.record_number].name = (NV_CHAR *)calloc(
6802 strlen(rec->header.name) + 1, sizeof(NV_CHAR))) == NULL) {
6803 perror("Allocating index name memory");
6804 exit(-1);
6805 }
6806
6807 strcpy(tindex[rec->header.record_number].name, rec->header.name);
6808 pos = ftell(fp);
6809 assert(pos > 0);
6810 hd.end_of_file = pos;
6811 modified = NVTrue;
6812
6813 /* Get the new number of records. */
6814 if (db) *db = hd.pub;
6815
6816 return NVTrue;
6817 }
6818
6819 return NVFalse;
6820}
6821
6822#if 0
6823/*****************************************************************************\
6824
6825 Function delete_tide_record - deletes a record and all subordinate
6826 records from the database
6827
6828 Synopsis delete_tide_record (num);
6829
6830 NV_INT32 num record number
6831
6832 Returns NV_BOOL NVTrue if successful
6833
6834 Author Jan C. Depner (redone by David Flater)
6835 Date 08/01/02 (2006-05-26)
6836
6837 See libtcd.html for changelog.
6838
6839\*****************************************************************************/
6840
6841NV_BOOL delete_tide_record (NV_INT32 num, DB_HEADER_PUBLIC *db)
6842{
6843 NV_INT32 i, newrecnum, *map;
6844 NV_U_BYTE **allrecs_packed;
6845
6846 if (!fp) {
6847 LOG_ERROR ("libtcd error: attempt to access database when database not open\n");
6848 return NVFalse;
6849 }
6850 write_protect();
6851
6852 if (num < 0 || num >= (NV_INT32)hd.pub.number_of_records) return NVFalse;
6853
6854 /* Allocate workspace */
6855
6856 if (!(map = (NV_INT32 *) malloc (hd.pub.number_of_records * sizeof(NV_INT32)))) {
6857 perror ("libtcd: delete_tide_record: can't malloc");
6858 return NVFalse;
6859 }
6860 if (!(allrecs_packed = (NV_U_BYTE **) malloc (hd.pub.number_of_records * sizeof(NV_U_BYTE*)))) {
6861 perror ("libtcd: delete_tide_record: can't malloc");
6862 free (map);
6863 return NVFalse;
6864 }
6865
6866 /* First pass: read in database, build record number map and mark records
6867 for deletion */
6868
6869 require (fseek (fp, tindex[0].address, SEEK_SET) == 0);
6870 for (newrecnum=0,i=0; i<(NV_INT32)hd.pub.number_of_records; ++i) {
6871 assert (ftell(fp) == tindex[i].address);
6872 if (i == num || (tindex[i].record_type == SUBORDINATE_STATION && tindex[i].reference_station == num)) {
6873 map[i] = -1;
6874 allrecs_packed[i] = NULL;
6875 require (fseek (fp, tindex[i].record_size, SEEK_CUR) == 0);
6876 } else {
6877 map[i] = newrecnum++;
6878 if (!(allrecs_packed[i] = (NV_U_BYTE *) malloc (tindex[i].record_size))) {
6879 perror ("libtcd: delete_tide_record: can't malloc");
6880 for (--i; i>=0; --i)
6881 free (allrecs_packed[i]);
6882 free (allrecs_packed);
6883 free (map);
6884 return NVFalse;
6885 }
6886 chk_fread (allrecs_packed[i], tindex[i].record_size, 1, fp);
6887 }
6888 }
6889
6890 /* Second pass: rewrite database and fix substation linkage */
6891
6892 require (fseek (fp, tindex[0].address, SEEK_SET) == 0);
6893 require (ftruncate (fileno(fp), tindex[0].address) == 0);
6894
6895 for (i=0; i<(NV_INT32)hd.pub.number_of_records; ++i)
6896 if (map[i] >= 0) {
6897 if (tindex[i].record_type == SUBORDINATE_STATION) {
6898 assert (tindex[i].reference_station >= 0);
6899 assert (tindex[i].reference_station <= (NV_INT32)hd.pub.number_of_records);
6900 if (map[tindex[i].reference_station] != tindex[i].reference_station) {
6901 /* Fix broken reference station linkage */
6902 TIDE_RECORD rec;
6903 unpack_tide_record (allrecs_packed[i], tindex[i].record_size, &rec);
6904 free (allrecs_packed[i]);
6905 rec.header.reference_station = map[tindex[i].reference_station];
6906 pack_tide_record (&rec, &(allrecs_packed[i]), &(tindex[i].record_size));
6907 }
6908 }
6909 chk_fwrite (allrecs_packed[i], tindex[i].record_size, 1, fp);
6910 free (allrecs_packed[i]);
6911 }
6912
6913 /* Free workspace (packed records were freed above) */
6914
6915 free (allrecs_packed);
6916 free (map);
6917
6918 /* Flush, reopen, renew. The index is now garbage; close and reopen
6919 to reindex. */
6920
6921 hd.end_of_file = ftell(fp);
6922 hd.pub.number_of_records = newrecnum;
6923 modified = NVTrue;
6924 close_tide_db ();
6925 open_tide_db (filename);
6926
6927 if (db)
6928 *db = hd.pub;
6929
6930 return NVTrue;
6931}
6932
6933#endif
6934
6935/*****************************************************************************\
6936
6937 Function update_tide_record - updates a tide record in the database
6938
6939 Synopsis update_tide_record (num, rec);
6940
6941 NV_INT32 num record number
6942 TIDE_RECORD *rec tide record
6943
6944 Returns NV_BOOL NVTrue if successful
6945
6946 Author Jan C. Depner
6947 Date 08/01/02
6948
6949 See libtcd.html for changelog.
6950
6951\*****************************************************************************/
6952
6953#ifdef COMPAT114
6954NV_BOOL update_tide_record(NV_INT32 num, TIDE_RECORD *rec)
6955#else
6956NV_BOOL update_tide_record(NV_INT32 num, TIDE_RECORD *rec, DB_HEADER_PUBLIC *db)
6957#endif
6958{
6959 NV_INT32 pos, size;
6960 TIDE_RECORD tmp_rec;
6961 NV_U_BYTE *block = NULL;
6962
6963 if (!fp) {
6964 LOG_ERROR(
6965 "libtcd error: attempt to access database when database not open\n");
6966 return NVFalse;
6967 }
6968 write_protect();
6969
6970 if (num < 0 || num >= (NV_INT32)hd.pub.number_of_records) return NVFalse;
6971
6972 if (!check_tide_record(rec)) return NVFalse;
6973
6974 figure_size(rec);
6975 read_tide_record(num, &tmp_rec);
6976 if (rec->header.record_size != tmp_rec.header.record_size) {
6977 /* Aaaaaaarrrrrgggggghhhh!!!! We have to move stuff! */
6978
6979 /* Save where we are - end of record being modified. */
6980 pos = ftell(fp);
6981 assert(pos > 0);
6982
6983 /* Figure out how big a block we need to move. */
6984 size = hd.end_of_file - pos;
6985 assert(size >= 0);
6986
6987 /* Allocate memory and read the block. */
6988 if (size) {
6989 if ((block = (NV_U_BYTE *)calloc(size, sizeof(NV_U_BYTE))) == NULL) {
6990 perror("Allocating block");
6991 return NVFalse;
6992 }
6993 chk_fread(block, size, 1, fp);
6994 }
6995
6996 /* Write out the modified record. */
6997 write_tide_record(num, rec);
6998
6999 /* If we weren't at the end of file, move the block. */
7000 if (size) {
7001 chk_fwrite(block, size, 1, fp);
7002 free(block);
7003 }
7004
7005 hd.end_of_file = ftell(fp);
7006
7007 /* Close the file and reopen it to index the records again. */
7008 close_tide_db();
7009 open_tide_db(filename);
7010 }
7011
7012 /* The easy way. No change to the record size. */
7013 else {
7014 write_tide_record(num, rec);
7015
7016 /* Save the header info in the index. */
7017 tindex[num].record_size = rec->header.record_size;
7018 tindex[num].record_type = rec->header.record_type;
7019 tindex[num].reference_station = rec->header.reference_station;
7020 tindex[num].tzfile = rec->header.tzfile;
7021 tindex[num].lat = NINT(rec->header.latitude * hd.latitude_scale);
7022 tindex[num].lon = NINT(rec->header.longitude * hd.longitude_scale);
7023
7024 /* AH maybe? */
7025 /* DWF: agree, same size record does not imply that name length
7026 is identical. */
7027 if (strcmp(tindex[num].name, rec->header.name) != 0) {
7028 free(tindex[num].name);
7029 tindex[num].name =
7030 (NV_CHAR *)calloc(strlen(rec->header.name) + 1, sizeof(NV_CHAR));
7031 strcpy(tindex[num].name, rec->header.name);
7032 }
7033 }
7034
7035#ifndef COMPAT114
7036 if (db) *db = hd.pub;
7037#endif
7038
7039 return (NVTrue);
7040}
7041
7042/*****************************************************************************\
7043
7044 Function infer_constituents - computes inferred constituents when
7045 M2, S2, K1, and O1 are given. This function fills the
7046 remaining unfilled constituents. The inferred constituents
7047 are developed or decided based on article 230 of
7048 "Manual of Harmonic Analysis and Prediction of Tides",
7049 Paul Schureman, C & GS special publication no. 98,
7050 October 1971. This function is really just for NAVO
7051 since we go to weird places and put in tide gages for
7052 ridiculously short periods of time so we only get a
7053 few major constituents developed. This function was
7054 modified from the NAVO FORTRAN program pred_tide_corr,
7055 subroutine infer.ftn, 08-oct-86.
7056
7057 Synopsis infer_constituents (rec);
7058
7059 TIDE_RECORD rec tide record
7060
7061 Returns NV_BOOL NVFalse if not enough constituents
7062 available to infer others
7063
7064 Author Jan C. Depner
7065 Date 08/01/02
7066
7067 See libtcd.html for changelog.
7068
7069\*****************************************************************************/
7070
7071NV_BOOL infer_constituents(TIDE_RECORD *rec) {
7072 NV_U_INT32 i, j;
7073 NV_INT32 m2, s2, k1, o1;
7074 NV_FLOAT32 epoch_m2, epoch_s2, epoch_k1, epoch_o1;
7075
7076 assert(rec);
7077 require((m2 = find_constituent("M2")) >= 0);
7078 require((s2 = find_constituent("S2")) >= 0);
7079 require((k1 = find_constituent("K1")) >= 0);
7080 require((o1 = find_constituent("O1")) >= 0);
7081
7082 if (rec->amplitude[m2] == 0.0 || rec->amplitude[s2] == 0.0 ||
7083 rec->amplitude[k1] == 0.0 || rec->amplitude[o1] == 0.0)
7084 return (NVFalse);
7085
7086 epoch_m2 = rec->epoch[m2];
7087 epoch_s2 = rec->epoch[s2];
7088 epoch_k1 = rec->epoch[k1];
7089 epoch_o1 = rec->epoch[o1];
7090
7091 for (i = 0; i < hd.pub.constituents; ++i) {
7092 if (rec->amplitude[i] == 0.0 && rec->epoch[i] == 0.0) {
7093 for (j = 0; j < INFERRED_SEMI_DIURNAL_COUNT; ++j) {
7094 if (!strcmp(inferred_semi_diurnal[j], get_constituent(i))) {
7095 /* Compute the inferred semi-diurnal constituent. */
7096
7097 rec->amplitude[i] =
7098 (semi_diurnal_coeff[j] / coeff[0]) * rec->amplitude[m2];
7099
7100 if (fabs((NV_FLOAT64)(epoch_s2 - epoch_m2)) > 180.0) {
7101 if (epoch_s2 < epoch_m2) {
7102 epoch_s2 += 360.0;
7103 } else {
7104 epoch_m2 += 360.0;
7105 }
7106 }
7107 rec->epoch[i] = epoch_m2 + ((hd.speed[i] - hd.speed[m2]) /
7108 (hd.speed[s2] - hd.speed[m2])) *
7109 (epoch_s2 - epoch_m2);
7110 }
7111 }
7112
7113 for (j = 0; j < INFERRED_DIURNAL_COUNT; ++j) {
7114 if (!strcmp(inferred_diurnal[j], get_constituent(i))) {
7115 /* Compute the inferred diurnal constituent. */
7116
7117 rec->amplitude[i] =
7118 (diurnal_coeff[j] / coeff[1]) * rec->amplitude[o1];
7119
7120 if (fabs((NV_FLOAT64)(epoch_k1 - epoch_o1)) > 180.0) {
7121 if (epoch_k1 < epoch_o1) {
7122 epoch_k1 += 360.0;
7123 } else {
7124 epoch_o1 += 360.0;
7125 }
7126 }
7127 rec->epoch[i] = epoch_o1 + ((hd.speed[i] - hd.speed[o1]) /
7128 (hd.speed[k1] - hd.speed[o1])) *
7129 (epoch_k1 - epoch_o1);
7130 }
7131 }
7132 }
7133 }
7134
7135 return (NVTrue);
7136}
7137
7138/* $Id: bit_pack.c 1805 2007-01-22 15:36:20Z flaterco $ */
7139
7140#include <math.h>
7141#include <stdio.h>
7142#include <assert.h>
7143
7144static NV_U_BYTE mask[8] = {0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe},
7145 notmask[8] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01};
7146
7147/*****************************************************************************\
7148
7149 DISTRIBUTION STATEMENT
7150
7151 This source file is unclassified, distribution unlimited, public
7152 domain. It is distributed in the hope that it will be useful, but
7153 WITHOUT ANY WARRANTY; without even the implied warranty of
7154 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7155
7156\*****************************************************************************/
7157
7158/***************************************************************************\
7159* *
7160* Function calculate_bits - Computes the number of bits needed *
7161* to store a specified value. *
7162* *
7163* Synopsis calculate_bits (value); *
7164* *
7165* NV_U_INT32 value the value to store *
7166* *
7167* Returns NV_U_INT32 number of bits needed *
7168* *
7169* If value = 0, return is 0. *
7170* No bits are needed to store a field whose only possible value is 0. *
7171* *
7172* Author Jan C. Depner *
7173* *
7174* Rewritten by DWF 2007-01-21 *
7175* - "Range" was ambiguous and off-by-one errors existed in tide_db.c *
7176* - Use of log10(x)/log10(2) was vulnerable to roundoff error *
7177* - Conversion to floating point was unnecessary *
7178* - Was giving the answer 0 for the input value 1 *
7179* - God only knows what it did for the input value 0 (the logarithm *
7180* is undefined) *
7181* *
7182\***************************************************************************/
7183
7184NV_U_INT32 calculate_bits(NV_U_INT32 value) {
7185 NV_U_INT32 bits = 32;
7186 NV_U_INT32 theBit = 0x80000000;
7187
7188 while (value < theBit) {
7189 theBit >>= 1;
7190 --bits;
7191 }
7192 assert(bits <= 32);
7193 return bits;
7194}
7195
7196/***************************************************************************\
7197* *
7198* Function bit_pack - Packs a long value into consecutive bits in *
7199* buffer. *
7200* *
7201* Synopsis bit_pack (buffer, start, numbits, value); *
7202* *
7203* NV_U_BYTE buffer[] address of buffer to use *
7204* NV_U_INT32 start start bit position in buffer *
7205* NV_U_INT32 numbits number of bits to store *
7206* NV_INT32 value value to store *
7207* *
7208* Description Packs the value 'value' into 'numbits' bits in 'buffer' *
7209* starting at bit position 'start'. The majority of *
7210* this code is based on Appendix C of Naval Ocean *
7211* Research and Development Activity Report #236, 'Data *
7212* Base Structure to Support the Production of the Digital *
7213* Bathymetric Data Base', Nov. 1989, James E. Braud, *
7214* John L. Breckenridge, James E. Current, Jerry L. *
7215* Landrum. *
7216* *
7217* Returns void *
7218* *
7219* Author Jan C. Depner *
7220* *
7221\***************************************************************************/
7222
7223void bit_pack(NV_U_BYTE buffer[], NV_U_INT32 start, NV_U_INT32 numbits,
7224 NV_INT32 value) {
7225 NV_INT32 start_byte, end_byte, start_bit, end_bit, i;
7226
7227 i = start + numbits;
7228
7229 /* Right shift the start and end by 3 bits, this is the same as */
7230 /* dividing by 8 but is faster. This is computing the start and end */
7231 /* bytes for the field. */
7232
7233 start_byte = start >> 3;
7234 end_byte = i >> 3;
7235
7236 /* AND the start and end bit positions with 7, this is the same as */
7237 /* doing a mod with 8 but is faster. Here we are computing the start */
7238 /* and end bits within the start and end bytes for the field. */
7239
7240 start_bit = start & 7;
7241 end_bit = i & 7;
7242
7243 /* Compute the number of bytes covered. */
7244
7245 i = end_byte - start_byte - 1;
7246
7247 /* If the value is to be stored in one byte, store it. */
7248
7249 if (start_byte == end_byte) {
7250 /* Rather tricky. We are masking out anything prior to the start */
7251 /* bit and after the end bit in order to not corrupt data that has */
7252 /* already been stored there. */
7253
7254 buffer[start_byte] &= mask[start_bit] | notmask[end_bit];
7255
7256 /* Now we mask out anything in the value that is prior to the */
7257 /* start bit and after the end bit. This is, of course, after we */
7258 /* have shifted the value left past the end bit. */
7259
7260 buffer[start_byte] |=
7261 (value << (8 - end_bit)) & (notmask[start_bit] & mask[end_bit]);
7262 }
7263
7264 /* If the value covers more than 1 byte, store it. */
7265
7266 else {
7267#pragma GCC diagnostic push
7268#pragma GCC diagnostic ignored "-Warray-bounds"
7269 // Compiler is confused about bit manipulated index, but it looks ok.
7270
7271 /* Here we mask out data prior to the start bit of the first byte. */
7272
7273 buffer[start_byte] &= mask[start_bit];
7274
7275 /* Get the upper bits of the value and mask out anything prior to */
7276 /* the start bit. As an example of what's happening here, if we */
7277 /* wanted to store a 14 bit field and the start bit for the first */
7278 /* byte is 3, we would be storing the upper 5 bits of the value in */
7279 /* the first byte. */
7280
7281 buffer[start_byte++] |=
7282 (value >> (numbits - (8 - start_bit))) & notmask[start_bit];
7283
7284 /* Loop while decrementing the byte counter. */
7285
7286 while (i--) {
7287 /* Clear the entire byte. */
7288
7289 buffer[start_byte] &= 0;
7290
7291 /* Get the next 8 bits from the value. */
7292
7293 buffer[start_byte++] |= (value >> ((i << 3) + end_bit)) & 255;
7294 }
7295
7296 /* For the last byte we mask out anything after the end bit. */
7297
7298 buffer[start_byte] &= notmask[end_bit];
7299
7300 /* Get the last part of the value and stuff it in the end byte. */
7301 /* The left shift effectively erases anything above 8 - end_bit */
7302 /* bits in the value so that it will fit in the last byte. */
7303
7304 buffer[start_byte] |= (value << (8 - end_bit));
7305#pragma GCC diagnostic pop
7306 }
7307}
7308
7309/***************************************************************************\
7310* *
7311* Function bit_unpack - Unpacks a long value from consecutive bits *
7312* in buffer. *
7313* *
7314* Synopsis bit_unpack (buffer, start, numbits); *
7315* *
7316* NV_U_BYTE buffer[] address of buffer to use *
7317* NV_U_INT32 start start bit position in buffer *
7318* NV_U_INT32 numbits number of bits to retrieve *
7319* *
7320* Description Unpacks the value from 'numbits' bits in 'buffer' *
7321* starting at bit position 'start'. The value is assumed *
7322* to be unsigned. The majority of this code is based on *
7323* Appendix C of Naval Ocean Research and Development *
7324* Activity Report #236, 'Data Base Structure to Support *
7325* the Production of the Digital Bathymetric Data Base', *
7326* Nov. 1989, James E. Braud, John L. Breckenridge, James *
7327* E. Current, Jerry L. Landrum. *
7328* *
7329* Returns NV_U_INT32 value retrieved from buffer *
7330* *
7331* Author Jan C. Depner *
7332* *
7333\***************************************************************************/
7334
7335NV_U_INT32 bit_unpack(NV_U_BYTE buffer[], NV_U_INT32 start,
7336 NV_U_INT32 numbits) {
7337 NV_INT32 start_byte, end_byte, start_bit, end_bit, i;
7338 NV_U_INT32 value;
7339
7340 i = start + numbits;
7341
7342 /* Right shift the start and end by 3 bits, this is the same as */
7343 /* dividing by 8 but is faster. This is computing the start and end */
7344 /* bytes for the field. */
7345
7346 start_byte = start >> 3;
7347 end_byte = i >> 3;
7348
7349 /* AND the start and end bit positions with 7, this is the same as */
7350 /* doing a mod with 8 but is faster. Here we are computing the start */
7351 /* and end bits within the start and end bytes for the field. */
7352
7353 start_bit = start & 7;
7354 end_bit = i & 7;
7355
7356 /* Compute the number of bytes covered. */
7357
7358 i = end_byte - start_byte - 1;
7359
7360 /* If the value is stored in one byte, retrieve it. */
7361
7362 if (start_byte == end_byte) {
7363 /* Mask out anything prior to the start bit and after the end bit. */
7364
7365 value =
7366 (NV_U_INT32)buffer[start_byte] & (notmask[start_bit] & mask[end_bit]);
7367
7368 /* Now we shift the value to the right. */
7369
7370 value >>= (8 - end_bit);
7371 }
7372
7373 /* If the value covers more than 1 byte, retrieve it. */
7374
7375 else {
7376 /* Here we mask out data prior to the start bit of the first byte */
7377 /* and shift to the left the necessary amount. */
7378
7379 value = (NV_U_INT32)(buffer[start_byte++] & notmask[start_bit])
7380 << (numbits - (8 - start_bit));
7381
7382 /* Loop while decrementing the byte counter. */
7383
7384 while (i--) {
7385 /* Get the next 8 bits from the buffer. */
7386
7387 value += (NV_U_INT32)buffer[start_byte++] << ((i << 3) + end_bit);
7388 }
7389
7390 /* For the last byte we mask out anything after the end bit and */
7391 /* then shift to the right (8 - end_bit) bits. */
7392 if (mask[end_bit]) {
7393 value +=
7394 (NV_U_INT32)(buffer[start_byte] & mask[end_bit]) >> (8 - end_bit);
7395 }
7396 }
7397
7398 return (value);
7399}
7400
7401/***************************************************************************\
7402* *
7403* Function signed_bit_unpack - Unpacks a signed long value from *
7404* consecutive bits in buffer. *
7405* *
7406* Synopsis signed_bit_unpack (buffer, start, numbits); *
7407* *
7408* NV_U_BYTE buffer[] address of buffer to use *
7409* NV_U_INT32 start start bit position in buffer *
7410* NV_U_INT32 numbits number of bits to retrieve *
7411* *
7412* Description Unpacks the value from 'numbits' bits in 'buffer' *
7413* starting at bit position 'start'. The value is assumed *
7414* to be signed. The majority of this code is based on *
7415* Appendix C of Naval Ocean Research and Development *
7416* Activity Report #236, 'Data Base Structure to Support *
7417* the Production of the Digital Bathymetric Data Base', *
7418* Nov. 1989, James E. Braud, John L. Breckenridge, James *
7419* E. Current, Jerry L. Landrum. *
7420* *
7421* Returns NV_INT32 value retrieved from buffer *
7422* *
7423* Author Jan C. Depner *
7424* *
7425\***************************************************************************/
7426
7427NV_INT32 signed_bit_unpack(NV_U_BYTE buffer[], NV_U_INT32 start,
7428 NV_U_INT32 numbits) {
7429 static NV_INT32 extend_mask = 0x7fffffff;
7430 NV_INT32 value;
7431
7432 /* This function is not used anywhere that this case could arise. */
7433 assert(numbits > 0);
7434
7435 value = bit_unpack(buffer, start, numbits);
7436
7437 if (value & (1 << (numbits - 1))) value |= (extend_mask << numbits);
7438
7439 return (value);
7440}
Represents an index entry for tidal and current data.
Definition idx_entry.h:48
int have_offsets
Flag indicating presence of time/height offsets.
Definition idx_entry.h:84
time_t epoch
Epoch time for the station.
Definition idx_entry.h:106
int IDX_time_zone
Station timezone offset from UTC (in minutes)
Definition idx_entry.h:94
char IDX_type
Entry type identifier "TCtcIUu".
Definition idx_entry.h:60
int num_nodes
Number of nodes in harmonic analysis.
Definition idx_entry.h:98
float IDX_lt_off
Low tide height offset.
Definition idx_entry.h:70
TCDataSource * pDataSource
Pointer to the associated data source.
Definition idx_entry.h:55
float IDX_lt_mpy
Low tide height multiplier.
Definition idx_entry.h:69
int Valid15
Validity flag for 15-minute interval data.
Definition idx_entry.h:75
time_t recent_high_time
Time of the most recent high tide.
Definition idx_entry.h:115
int epoch_year
Year of the epoch.
Definition idx_entry.h:107
int IDX_flood_dir
Flood current direction (in degrees)
Definition idx_entry.h:72
int IDX_Useable
Flag indicating if the entry is usable.
Definition idx_entry.h:74
char IDX_station_name[MAXNAMELEN]
Name of the tidal or current station.
Definition idx_entry.h:62
float recent_low_level
Most recently calculated low tide level.
Definition idx_entry.h:116
int station_tz_offset
Offset in seconds to convert from harmonic data (epochs) to the station time zone.
Definition idx_entry.h:93
double max_amplitude
Maximum tidal amplitude.
Definition idx_entry.h:83
int first_year
First year of valid data.
Definition idx_entry.h:105
double * m_work_buffer
Work buffer for calculations.
Definition idx_entry.h:104
int IDX_ht_time_off
High tide time offset (in minutes)
Definition idx_entry.h:65
float Dir15
Direction for 15-minute interval data.
Definition idx_entry.h:77
float recent_high_level
Most recently calculated high tide level.
Definition idx_entry.h:114
double ** m_cst_nodes
2D array of constituent nodes
Definition idx_entry.h:102
int IDX_ebb_dir
Ebb current direction (in degrees)
Definition idx_entry.h:73
double ** m_cst_epochs
2D array of constituent epochs
Definition idx_entry.h:103
float IDX_ht_mpy
High tide height multiplier.
Definition idx_entry.h:66
int current_depth
Depth for current stations.
Definition idx_entry.h:108
double IDX_lat
Latitude of the station (in degrees, +North)
Definition idx_entry.h:64
double IDX_lon
Longitude of the station (in degrees, +East)
Definition idx_entry.h:63
bool Ret15
Return flag for 15-minute interval data.
Definition idx_entry.h:78
bool b_skipTooDeep
Flag to skip processing if depth exceeds limit.
Definition idx_entry.h:109
int num_epochs
Number of epochs in harmonic data.
Definition idx_entry.h:100
double * m_cst_speeds
Array of constituent speeds.
Definition idx_entry.h:101
Station_Data * pref_sta_data
Pointer to the reference station data.
Definition idx_entry.h:96
int IDX_lt_time_off
Low tide time offset (in minutes)
Definition idx_entry.h:68
time_t recent_highlow_calc_time
Timestamp of the most recent high/low calculation.
Definition idx_entry.h:112
int num_csts
Number of harmonic constituents.
Definition idx_entry.h:99
time_t recent_low_time
Time of the most recent low tide.
Definition idx_entry.h:117
float IDX_ht_off
High tide height offset.
Definition idx_entry.h:67
int IDX_rec_num
Record number for multiple entries with same name.
Definition idx_entry.h:59
float Value15
Value for 15-minute interval data.
Definition idx_entry.h:76
Definition tcmgr.h:89
OpenCPN Georef utility.
General purpose GUI support.
Enhanced logging interface on top of wx/log.h.
std::string tolower(const std::string &input)
Return copy of s with all characters converted to lower case.
wxDateTime toUsrDateTime(const wxDateTime ts, const int format, const double lon)
Converts a timestamp from UTC to the user's preferred time format.
Definition navutil.cpp:2924
Utility functions.
Definition tcmgr.h:609
Runtime representation of a plugin block.
TCMgr * ptcmgr
Global instance.
Definition tcmgr.cpp:42
double BOGUS_amplitude(double mpy, IDX_entry *pIDX)
BOGUS amplitude stuff - Added mgh For knots^2 current stations, returns square root of (value * ampli...
Definition tcmgr.cpp:67
Tide and Current Manager @TODO Add original author copyright.