OpenCPN Partial API docs
Loading...
Searching...
No Matches
s57classregistrar.cpp
1/******************************************************************************
2 *
3 * Project: S-57 Translator
4 * Purpose: Implements S57ClassRegistrar class for keeping track of
5 * information on S57 object classes.
6 * Author: Frank Warmerdam, warmerda@home.com
7 *
8 ******************************************************************************
9 * Copyright (c) 1999, Frank Warmerdam
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included
19 * in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 * DEALINGS IN THE SOFTWARE.
28 ******************************************************************************
29 *
30 */
31
32#include "gdal/cpl_conv.h"
33#include "gdal/cpl_string.h"
34#include "s57.h"
35#include "S57ClassRegistrar.h"
36
37#ifdef S57_BUILTIN_CLASSES
38#include "s57tables.h"
39#endif
40
41/************************************************************************/
42/* S57ClassRegistrar() */
43/************************************************************************/
44
45S57ClassRegistrar::S57ClassRegistrar()
46
47{
48 nClasses = 0;
49
50 iCurrentClass = -1;
51
52 papszCurrentFields = NULL;
53 papszTempResult = NULL;
54 papszNextLine = NULL;
55 pnClassesOBJL = NULL;
56 papapszClassesTokenized = NULL;
57 papszAttrAcronym = NULL;
58 papszAttrNames = NULL;
59 pachAttrType = NULL;
60 pachAttrClass = NULL;
61 panAttrIndex = NULL;
62 pnClassesOBJL = NULL;
63}
64
65/************************************************************************/
66/* ~S57ClassRegistrar() */
67/************************************************************************/
68
69S57ClassRegistrar::~S57ClassRegistrar()
70
71{
72 CSLDestroy(papszTempResult);
73
74 DestroySparseStringlist(papszAttrAcronym);
75 DestroySparseStringlist(papszAttrNames);
76
77 CPLFree(pachAttrType);
78 CPLFree(pachAttrClass);
79 CPLFree(panAttrIndex);
80 CPLFree(pnClassesOBJL);
81
82 for (int i = 0; i < nClasses; i++) {
83 if (papapszClassesTokenized[i]) CSLDestroy(papapszClassesTokenized[i]);
84 }
85 CPLFree(papapszClassesTokenized);
86}
87
88/************************************************************************/
89/* FindFile() */
90/************************************************************************/
91
92int S57ClassRegistrar::FindFile(const char *pszTarget, const char *pszDirectory,
93 int bReportErr, FILE **pfp)
94
95{
96 const char *pszFilename;
97
98 if (pszDirectory == NULL) {
99 pszFilename = CPLFindFile("s57", pszTarget);
100 if (pszFilename == NULL) pszFilename = pszTarget;
101 } else {
102 pszFilename = CPLFormFilename(pszDirectory, pszTarget, NULL);
103 }
104
105 *pfp = VSIFOpen(pszFilename, "rb");
106
107#ifdef S57_BUILTIN_CLASSES
108 if (*pfp == NULL) {
109 if (EQUAL(pszTarget, "s57objectclasses.csv"))
110 papszNextLine = gpapszS57Classes;
111 else
112 papszNextLine = gpapszS57attributes;
113 }
114#else
115 if (*pfp == NULL) {
116 if (bReportErr)
117 CPLError(CE_Failure, CPLE_OpenFailed, "Failed to open %s.\n",
118 pszFilename);
119 return FALSE;
120 }
121#endif
122
123 return TRUE;
124}
125
126const char *S57ClassRegistrar::OCPLReadLine(FILE *fp)
127
128{
129 int nReadSoFar = 0;
130
131 /* -------------------------------------------------------------------- */
132 /* Cleanup case. */
133 /* -------------------------------------------------------------------- */
134 if (fp == NULL) {
135 CPLFree(pszRLBuffer);
136 pszRLBuffer = NULL;
137 nRLBufferSize = 0;
138 return NULL;
139 }
140
141 /* -------------------------------------------------------------------- */
142 /* Loop reading chunks of the line till we get to the end of */
143 /* the line. */
144 /* -------------------------------------------------------------------- */
145 do {
146 /* -------------------------------------------------------------------- */
147 /* Grow the working buffer if we have it nearly full. Fail out */
148 /* of read line if we can't reallocate it big enough (for */
149 /* instance for a _very large_ file with no newlines). */
150 /* -------------------------------------------------------------------- */
151 if (nRLBufferSize - nReadSoFar < 256) {
152 nRLBufferSize = nRLBufferSize * 2 + 256;
153 pszRLBuffer = (char *)VSIRealloc(pszRLBuffer, nRLBufferSize);
154 if (pszRLBuffer == NULL) {
155 nRLBufferSize = 0;
156 return NULL;
157 }
158 }
159
160 /* -------------------------------------------------------------------- */
161 /* Do the actual read. */
162 /* -------------------------------------------------------------------- */
163 if (CPLFGets(pszRLBuffer + nReadSoFar, nRLBufferSize - nReadSoFar, fp) ==
164 NULL) {
165 CPLFree(pszRLBuffer);
166 pszRLBuffer = NULL;
167 nRLBufferSize = 0;
168
169 return NULL;
170 }
171
172 nReadSoFar = strlen(pszRLBuffer);
173
174 } while (nReadSoFar == nRLBufferSize - 1 &&
175 pszRLBuffer[nRLBufferSize - 2] != 13 &&
176 pszRLBuffer[nRLBufferSize - 2] != 10);
177
178 return (pszRLBuffer);
179}
180
181/************************************************************************/
182/* ReadLine() */
183/* */
184/* Read a line from the provided file, or from the "built-in" */
185/* configuration file line list if the file is NULL. */
186/************************************************************************/
187
188const char *S57ClassRegistrar::ReadLine(FILE *fp)
189
190{
191 if (fp != NULL)
192 return OCPLReadLine(fp);
193 else
194 return NULL;
195
196 /*
197 if( papszNextLine == NULL )
198 return NULL;
199
200 if( *papszNextLine == NULL )
201 {
202 papszNextLine = NULL;
203 return NULL;
204 }
205 else
206 return *(papszNextLine++);
207 */
208}
209
210/************************************************************************/
211/* LoadInfo() */
212/************************************************************************/
213
214int S57ClassRegistrar::LoadInfo(const char *pszDirectory, int bReportErr) {
215 FILE *fp;
216
217 if (NULL == pszDirectory) return FALSE;
218
219 /* ==================================================================== */
220 /* Read the s57objectclasses file. */
221 /* ==================================================================== */
222 if (!FindFile("s57objectclasses.csv", pszDirectory, bReportErr, &fp))
223 return FALSE;
224
225 pszRLBuffer = (char *)VSIRealloc(pszRLBuffer, 512);
226 nRLBufferSize = 512;
227
228 /* -------------------------------------------------------------------- */
229 /* Skip the line defining the column titles. */
230 /* -------------------------------------------------------------------- */
231 const char *pszLine = ReadLine(fp);
232
233 if (!EQUAL(pszLine,
234 "\"Code\",\"ObjectClass\",\"Acronym\",\"Attribute_A\","
235 "\"Attribute_B\",\"Attribute_C\",\"Class\",\"Primitives\"")) {
236 CPLError(CE_Failure, CPLE_AppDefined,
237 "s57objectclasses columns don't match expected format!\n");
238 return FALSE;
239 }
240
241 /* -------------------------------------------------------------------- */
242 /* Read and form string lists. */
243 /* -------------------------------------------------------------------- */
244
245 pnClassesOBJL = (int *)CPLCalloc(sizeof(int *), MAX_CLASSES);
246
247 papapszClassesTokenized = (char ***)CPLCalloc(sizeof(char *), MAX_CLASSES);
248
249 nClasses = 0;
250 char **papszTempFields = NULL;
251
252 while (nClasses < MAX_CLASSES && (pszLine = ReadLine(fp)) != NULL) {
253 papszTempFields = CSLTokenizeStringComplex(pszLine, ",", TRUE, TRUE);
254
255 pnClassesOBJL[nClasses] = atoi(papszTempFields[0]);
256
257 papapszClassesTokenized[nClasses] = papszTempFields;
258
259 if (pszLine == NULL) break;
260
261 nClasses++;
262 }
263
264 if (nClasses == MAX_CLASSES)
265 CPLError(CE_Warning, CPLE_AppDefined,
266 "MAX_CLASSES exceeded in S57ClassRegistrar::LoadInfo().\n");
267
268 /* -------------------------------------------------------------------- */
269 /* Cleanup, and establish state. */
270 /* -------------------------------------------------------------------- */
271 if (fp != NULL) VSIFClose(fp);
272 iCurrentClass = -1;
273
274 if (nClasses == 0) return FALSE;
275
276 /* ==================================================================== */
277 /* Read the attributes list. */
278 /* ==================================================================== */
279 if (!FindFile("s57attributes.csv", pszDirectory, bReportErr, &fp))
280 return FALSE;
281
282 /* -------------------------------------------------------------------- */
283 /* Skip the line defining the column titles. */
284 /* -------------------------------------------------------------------- */
285 pszLine = ReadLine(fp);
286
287 if (!EQUAL(
288 pszLine,
289 "\"Code\",\"Attribute\",\"Acronym\",\"Attributetype\",\"Class\"")) {
290 CPLError(CE_Failure, CPLE_AppDefined,
291 "s57attributes columns don't match expected format!\n");
292 return FALSE;
293 }
294
295 /* -------------------------------------------------------------------- */
296 /* Prepare arrays for the per-attribute information. */
297 /* -------------------------------------------------------------------- */
298 nAttrMax = MAX_ATTRIBUTES - 1;
299 papszAttrNames = (char **)CPLCalloc(sizeof(char *), nAttrMax);
300 papszAttrAcronym = (char **)CPLCalloc(sizeof(char *), nAttrMax);
301 // papapszAttrValues = (char ***) CPLCalloc(sizeof(char **),nAttrMax);
302 pachAttrType = (char *)CPLCalloc(sizeof(char), nAttrMax);
303 pachAttrClass = (char *)CPLCalloc(sizeof(char), nAttrMax);
304 panAttrIndex = (int *)CPLCalloc(sizeof(int), nAttrMax);
305
306 /* -------------------------------------------------------------------- */
307 /* Read and form string list. */
308 /* -------------------------------------------------------------------- */
309 int iAttr;
310
311 while ((pszLine = ReadLine(fp)) != NULL) {
312 char **papszTokens = CSLTokenizeStringComplex(pszLine, ",", TRUE, TRUE);
313
314 if (CSLCount(papszTokens) < 5) {
315 CSLDestroy(papszTokens);
316 CPLAssert(FALSE);
317 continue;
318 }
319
320 iAttr = atoi(papszTokens[0]);
321 if (iAttr < 0 || iAttr >= nAttrMax || papszAttrNames[iAttr] != NULL) {
322 CSLDestroy(papszTokens);
323 CPLAssert(FALSE);
324 continue;
325 }
326
327 papszAttrNames[iAttr] = CPLStrdup(papszTokens[1]);
328 papszAttrAcronym[iAttr] = CPLStrdup(papszTokens[2]);
329 pachAttrType[iAttr] = papszTokens[3][0];
330 pachAttrClass[iAttr] = papszTokens[4][0];
331
332 CSLDestroy(papszTokens);
333 }
334
335 if (fp != NULL) VSIFClose(fp);
336
337 /* -------------------------------------------------------------------- */
338 /* Build unsorted index of attributes. */
339 /* -------------------------------------------------------------------- */
340 nAttrCount = 0;
341 for (iAttr = 0; iAttr < nAttrMax; iAttr++) {
342 if (papszAttrAcronym[iAttr] != NULL) panAttrIndex[nAttrCount++] = iAttr;
343 }
344
345 /* -------------------------------------------------------------------- */
346 /* Sort index by acronym. */
347 /* -------------------------------------------------------------------- */
348 int bModified;
349
350 do {
351 bModified = FALSE;
352 for (iAttr = 0; iAttr < nAttrCount - 1; iAttr++) {
353 if (strcmp(papszAttrAcronym[panAttrIndex[iAttr]],
354 papszAttrAcronym[panAttrIndex[iAttr + 1]]) > 0) {
355 int nTemp;
356
357 nTemp = panAttrIndex[iAttr];
358 panAttrIndex[iAttr] = panAttrIndex[iAttr + 1];
359 panAttrIndex[iAttr + 1] = nTemp;
360
361 bModified = TRUE;
362 }
363 }
364 } while (bModified);
365
366 return TRUE;
367}
368
369/************************************************************************/
370/* SelectClassByIndex() */
371/************************************************************************/
372
373int S57ClassRegistrar::SelectClassByIndex(int nNewIndex)
374
375{
376 if (nNewIndex < 0 || nNewIndex >= nClasses) return FALSE;
377
378 papszCurrentFields = papapszClassesTokenized[nNewIndex];
379
380 iCurrentClass = nNewIndex;
381
382 return TRUE;
383}
384
385/************************************************************************/
386/* SelectClass() */
387/************************************************************************/
388
389int S57ClassRegistrar::SelectClass(int nOBJL)
390
391{
392 for (int i = 0; i < nClasses; i++) {
393 if (pnClassesOBJL[i] == nOBJL) return SelectClassByIndex(i);
394 }
395
396 return FALSE;
397}
398
399/************************************************************************/
400/* SelectClass() */
401/************************************************************************/
402
403int S57ClassRegistrar::SelectClass(const char *pszAcronym)
404
405{
406 for (int i = 0; i < nClasses; i++) {
407 if (!SelectClassByIndex(i)) continue;
408
409 if (EQUAL(GetAcronym(), pszAcronym)) return TRUE;
410 }
411
412 return FALSE;
413}
414
415/************************************************************************/
416/* GetOBJL() */
417/************************************************************************/
418
419int S57ClassRegistrar::GetOBJL()
420
421{
422 if (iCurrentClass >= 0)
423 return pnClassesOBJL[iCurrentClass];
424 else
425 return -1;
426}
427
428/************************************************************************/
429/* GetDescription() */
430/************************************************************************/
431
432const char *S57ClassRegistrar::GetDescription()
433
434{
435 if (iCurrentClass >= 0 && CSLCount(papszCurrentFields) > 1)
436 return papszCurrentFields[1];
437 else
438 return NULL;
439}
440
441/************************************************************************/
442/* GetAcronym() */
443/************************************************************************/
444
445const char *S57ClassRegistrar::GetAcronym()
446
447{
448 if (iCurrentClass >= 0 && CSLCount(papszCurrentFields) > 2)
449 return papszCurrentFields[2];
450 else
451 return NULL;
452}
453
454/************************************************************************/
455/* GetAttributeList() */
456/* */
457/* The passed string can be "a", "b", "c" or NULL for all. The */
458/* returned list remained owned by this object, not the caller. */
459/************************************************************************/
460
461char **S57ClassRegistrar::GetAttributeList(const char *pszType)
462
463{
464 if (iCurrentClass < 0) return NULL;
465
466 CSLDestroy(papszTempResult);
467 papszTempResult = NULL;
468
469 for (int iColumn = 3; iColumn < 6; iColumn++) {
470 if (pszType != NULL && iColumn == 3 && !EQUAL(pszType, "a")) continue;
471
472 if (pszType != NULL && iColumn == 4 && !EQUAL(pszType, "b")) continue;
473
474 if (pszType != NULL && iColumn == 5 && !EQUAL(pszType, "c")) continue;
475
476 char **papszTokens;
477
478 papszTokens =
479 CSLTokenizeStringComplex(papszCurrentFields[iColumn], ";", TRUE, FALSE);
480
481 papszTempResult = CSLInsertStrings(papszTempResult, -1, papszTokens);
482
483 CSLDestroy(papszTokens);
484 }
485
486 return papszTempResult;
487}
488
489/************************************************************************/
490/* GetClassCode() */
491/************************************************************************/
492
493char S57ClassRegistrar::GetClassCode()
494
495{
496 if (iCurrentClass >= 0 && CSLCount(papszCurrentFields) > 6)
497 return papszCurrentFields[6][0];
498 else
499 return '\0';
500}
501
502/************************************************************************/
503/* GetPrimitives() */
504/************************************************************************/
505
506char **S57ClassRegistrar::GetPrimitives()
507
508{
509 if (iCurrentClass >= 0 && CSLCount(papszCurrentFields) > 7) {
510 CSLDestroy(papszTempResult);
511 papszTempResult =
512 CSLTokenizeStringComplex(papszCurrentFields[7], ";", TRUE, FALSE);
513 return papszTempResult;
514 } else
515 return NULL;
516}
517
518/************************************************************************/
519/* FindAttrByAcronym() */
520/************************************************************************/
521
522int S57ClassRegistrar::FindAttrByAcronym(const char *pszName)
523
524{
525 int iStart, iEnd, iCandidate;
526
527 iStart = 0;
528 iEnd = nAttrCount - 1;
529
530 while (iStart <= iEnd) {
531 int nCompareValue;
532
533 iCandidate = (iStart + iEnd) / 2;
534 nCompareValue = strcmp(pszName, papszAttrAcronym[panAttrIndex[iCandidate]]);
535
536 if (nCompareValue < 0) {
537 iEnd = iCandidate - 1;
538 } else if (nCompareValue > 0) {
539 iStart = iCandidate + 1;
540 } else
541 return panAttrIndex[iCandidate];
542 }
543
544 return -1;
545}
546
547/************************************************************************/
548/* DestroySparseStringlist */
549/************************************************************************/
550void S57ClassRegistrar::DestroySparseStringlist(char **papszStrList) {
551 if (papszStrList) {
552 for (int iAttr = 0; iAttr < nAttrMax; iAttr++) {
553 if (papszStrList[iAttr] != NULL) CPLFree(papszStrList[iAttr]);
554 }
555
556 CPLFree(papszStrList);
557 }
558}