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