32#include "gdal/cpl_conv.h"
33#include "gdal/cpl_string.h"
35#include "S57ClassRegistrar.h"
37#ifdef S57_BUILTIN_CLASSES
45S57ClassRegistrar::S57ClassRegistrar()
52 papszCurrentFields = NULL;
53 papszTempResult = NULL;
56 papapszClassesTokenized = NULL;
57 papszAttrAcronym = NULL;
58 papszAttrNames = NULL;
69S57ClassRegistrar::~S57ClassRegistrar()
72 CSLDestroy(papszTempResult);
74 DestroySparseStringlist(papszAttrAcronym);
75 DestroySparseStringlist(papszAttrNames);
77 CPLFree(pachAttrType);
78 CPLFree(pachAttrClass);
79 CPLFree(panAttrIndex);
80 CPLFree(pnClassesOBJL);
82 for (
int i = 0; i < nClasses; i++) {
83 if (papapszClassesTokenized[i]) CSLDestroy(papapszClassesTokenized[i]);
85 CPLFree(papapszClassesTokenized);
92int S57ClassRegistrar::FindFile(
const char *pszTarget,
const char *pszDirectory,
93 int bReportErr, FILE **pfp)
96 const char *pszFilename;
98 if (pszDirectory == NULL) {
99 pszFilename = CPLFindFile(
"s57", pszTarget);
100 if (pszFilename == NULL) pszFilename = pszTarget;
102 pszFilename = CPLFormFilename(pszDirectory, pszTarget, NULL);
105 *pfp = VSIFOpen(pszFilename,
"rb");
107#ifdef S57_BUILTIN_CLASSES
109 if (EQUAL(pszTarget,
"s57objectclasses.csv"))
110 papszNextLine = gpapszS57Classes;
112 papszNextLine = gpapszS57attributes;
117 CPLError(CE_Failure, CPLE_OpenFailed,
"Failed to open %s.\n",
126const char *S57ClassRegistrar::OCPLReadLine(FILE *fp)
135 CPLFree(pszRLBuffer);
151 if (nRLBufferSize - nReadSoFar < 256) {
152 nRLBufferSize = nRLBufferSize * 2 + 256;
153 pszRLBuffer = (
char *)VSIRealloc(pszRLBuffer, nRLBufferSize);
154 if (pszRLBuffer == NULL) {
163 if (CPLFGets(pszRLBuffer + nReadSoFar, nRLBufferSize - nReadSoFar, fp) ==
165 CPLFree(pszRLBuffer);
172 nReadSoFar = strlen(pszRLBuffer);
174 }
while (nReadSoFar == nRLBufferSize - 1 &&
175 pszRLBuffer[nRLBufferSize - 2] != 13 &&
176 pszRLBuffer[nRLBufferSize - 2] != 10);
178 return (pszRLBuffer);
188const char *S57ClassRegistrar::ReadLine(FILE *fp)
192 return OCPLReadLine(fp);
214int S57ClassRegistrar::LoadInfo(
const char *pszDirectory,
int bReportErr) {
217 if (NULL == pszDirectory)
return FALSE;
222 if (!FindFile(
"s57objectclasses.csv", pszDirectory, bReportErr, &fp))
225 pszRLBuffer = (
char *)VSIRealloc(pszRLBuffer, 512);
231 const char *pszLine = ReadLine(fp);
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");
245 pnClassesOBJL = (
int *)CPLCalloc(
sizeof(
int *), MAX_CLASSES);
247 papapszClassesTokenized = (
char ***)CPLCalloc(
sizeof(
char *), MAX_CLASSES);
250 char **papszTempFields = NULL;
252 while (nClasses < MAX_CLASSES && (pszLine = ReadLine(fp)) != NULL) {
253 papszTempFields = CSLTokenizeStringComplex(pszLine,
",", TRUE, TRUE);
255 pnClassesOBJL[nClasses] = atoi(papszTempFields[0]);
257 papapszClassesTokenized[nClasses] = papszTempFields;
259 if (pszLine == NULL)
break;
264 if (nClasses == MAX_CLASSES)
265 CPLError(CE_Warning, CPLE_AppDefined,
266 "MAX_CLASSES exceeded in S57ClassRegistrar::LoadInfo().\n");
271 if (fp != NULL) VSIFClose(fp);
274 if (nClasses == 0)
return FALSE;
279 if (!FindFile(
"s57attributes.csv", pszDirectory, bReportErr, &fp))
285 pszLine = ReadLine(fp);
289 "\"Code\",\"Attribute\",\"Acronym\",\"Attributetype\",\"Class\"")) {
290 CPLError(CE_Failure, CPLE_AppDefined,
291 "s57attributes columns don't match expected format!\n");
298 nAttrMax = MAX_ATTRIBUTES - 1;
299 papszAttrNames = (
char **)CPLCalloc(
sizeof(
char *), nAttrMax);
300 papszAttrAcronym = (
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);
311 while ((pszLine = ReadLine(fp)) != NULL) {
312 char **papszTokens = CSLTokenizeStringComplex(pszLine,
",", TRUE, TRUE);
314 if (CSLCount(papszTokens) < 5) {
315 CSLDestroy(papszTokens);
320 iAttr = atoi(papszTokens[0]);
321 if (iAttr < 0 || iAttr >= nAttrMax || papszAttrNames[iAttr] != NULL) {
322 CSLDestroy(papszTokens);
327 papszAttrNames[iAttr] = CPLStrdup(papszTokens[1]);
328 papszAttrAcronym[iAttr] = CPLStrdup(papszTokens[2]);
329 pachAttrType[iAttr] = papszTokens[3][0];
330 pachAttrClass[iAttr] = papszTokens[4][0];
332 CSLDestroy(papszTokens);
335 if (fp != NULL) VSIFClose(fp);
341 for (iAttr = 0; iAttr < nAttrMax; iAttr++) {
342 if (papszAttrAcronym[iAttr] != NULL) panAttrIndex[nAttrCount++] = iAttr;
352 for (iAttr = 0; iAttr < nAttrCount - 1; iAttr++) {
353 if (strcmp(papszAttrAcronym[panAttrIndex[iAttr]],
354 papszAttrAcronym[panAttrIndex[iAttr + 1]]) > 0) {
357 nTemp = panAttrIndex[iAttr];
358 panAttrIndex[iAttr] = panAttrIndex[iAttr + 1];
359 panAttrIndex[iAttr + 1] = nTemp;
373int S57ClassRegistrar::SelectClassByIndex(
int nNewIndex)
376 if (nNewIndex < 0 || nNewIndex >= nClasses)
return FALSE;
378 papszCurrentFields = papapszClassesTokenized[nNewIndex];
380 iCurrentClass = nNewIndex;
389int S57ClassRegistrar::SelectClass(
int nOBJL)
392 for (
int i = 0; i < nClasses; i++) {
393 if (pnClassesOBJL[i] == nOBJL)
return SelectClassByIndex(i);
403int S57ClassRegistrar::SelectClass(
const char *pszAcronym)
406 for (
int i = 0; i < nClasses; i++) {
407 if (!SelectClassByIndex(i))
continue;
409 if (EQUAL(GetAcronym(), pszAcronym))
return TRUE;
419int S57ClassRegistrar::GetOBJL()
422 if (iCurrentClass >= 0)
423 return pnClassesOBJL[iCurrentClass];
432const char *S57ClassRegistrar::GetDescription()
435 if (iCurrentClass >= 0 && CSLCount(papszCurrentFields) > 1)
436 return papszCurrentFields[1];
445const char *S57ClassRegistrar::GetAcronym()
448 if (iCurrentClass >= 0 && CSLCount(papszCurrentFields) > 2)
449 return papszCurrentFields[2];
461char **S57ClassRegistrar::GetAttributeList(
const char *pszType)
464 if (iCurrentClass < 0)
return NULL;
466 CSLDestroy(papszTempResult);
467 papszTempResult = NULL;
469 for (
int iColumn = 3; iColumn < 6; iColumn++) {
470 if (pszType != NULL && iColumn == 3 && !EQUAL(pszType,
"a"))
continue;
472 if (pszType != NULL && iColumn == 4 && !EQUAL(pszType,
"b"))
continue;
474 if (pszType != NULL && iColumn == 5 && !EQUAL(pszType,
"c"))
continue;
479 CSLTokenizeStringComplex(papszCurrentFields[iColumn],
";", TRUE, FALSE);
481 papszTempResult = CSLInsertStrings(papszTempResult, -1, papszTokens);
483 CSLDestroy(papszTokens);
486 return papszTempResult;
493char S57ClassRegistrar::GetClassCode()
496 if (iCurrentClass >= 0 && CSLCount(papszCurrentFields) > 6)
497 return papszCurrentFields[6][0];
506char **S57ClassRegistrar::GetPrimitives()
509 if (iCurrentClass >= 0 && CSLCount(papszCurrentFields) > 7) {
510 CSLDestroy(papszTempResult);
512 CSLTokenizeStringComplex(papszCurrentFields[7],
";", TRUE, FALSE);
513 return papszTempResult;
522int S57ClassRegistrar::FindAttrByAcronym(
const char *pszName)
525 int iStart, iEnd, iCandidate;
528 iEnd = nAttrCount - 1;
530 while (iStart <= iEnd) {
533 iCandidate = (iStart + iEnd) / 2;
534 nCompareValue = strcmp(pszName, papszAttrAcronym[panAttrIndex[iCandidate]]);
536 if (nCompareValue < 0) {
537 iEnd = iCandidate - 1;
538 }
else if (nCompareValue > 0) {
539 iStart = iCandidate + 1;
541 return panAttrIndex[iCandidate];
550void S57ClassRegistrar::DestroySparseStringlist(
char **papszStrList) {
552 for (
int iAttr = 0; iAttr < nAttrMax; iAttr++) {
553 if (papszStrList[iAttr] != NULL) CPLFree(papszStrList[iAttr]);
556 CPLFree(papszStrList);