Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: S-57 Translator
4 : * Purpose: Implements S57FileCollector() function. This function collects
5 : * a list of S-57 data files based on the contents of a directory,
6 : * catalog file, or direct reference to an S-57 file.
7 : * Author: Frank Warmerdam, warmerdam@pobox.com
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 1999, Frank Warmerdam
11 : *
12 : * SPDX-License-Identifier: MIT
13 : ****************************************************************************/
14 :
15 : #include "cpl_conv.h"
16 : #include "cpl_string.h"
17 : #include "s57.h"
18 :
19 : /************************************************************************/
20 : /* S57FileCollector() */
21 : /************************************************************************/
22 :
23 0 : char **S57FileCollector(const char *pszDataset)
24 :
25 : {
26 : /* -------------------------------------------------------------------- */
27 : /* Stat the dataset, and fail if it isn't a file or directory. */
28 : /* -------------------------------------------------------------------- */
29 : VSIStatBuf sStatBuf;
30 0 : if (CPLStat(pszDataset, &sStatBuf))
31 : {
32 0 : CPLError(CE_Failure, CPLE_AppDefined,
33 : "No S-57 files found, %s\nisn't a directory or a file.\n",
34 : pszDataset);
35 :
36 0 : return nullptr;
37 : }
38 :
39 : /* -------------------------------------------------------------------- */
40 : /* We handle directories by scanning for all S-57 data files in */
41 : /* them, but not for catalogs. */
42 : /* -------------------------------------------------------------------- */
43 0 : char **papszRetList = nullptr;
44 :
45 0 : if (VSI_ISDIR(sStatBuf.st_mode))
46 : {
47 0 : char **papszDirFiles = VSIReadDir(pszDataset);
48 0 : DDFModule oModule;
49 :
50 0 : for (int iFile = 0;
51 0 : papszDirFiles != nullptr && papszDirFiles[iFile] != nullptr;
52 : iFile++)
53 : {
54 0 : char *pszFullFile = CPLStrdup(
55 0 : CPLFormFilename(pszDataset, papszDirFiles[iFile], nullptr));
56 :
57 : // Add to list if it is an S-57 _data_ file.
58 0 : if (VSIStat(pszFullFile, &sStatBuf) == 0 &&
59 0 : VSI_ISREG(sStatBuf.st_mode) && oModule.Open(pszFullFile, TRUE))
60 : {
61 0 : if (oModule.FindFieldDefn("DSID") != nullptr)
62 0 : papszRetList = CSLAddString(papszRetList, pszFullFile);
63 : }
64 :
65 0 : CPLFree(pszFullFile);
66 : }
67 :
68 0 : return papszRetList;
69 : }
70 :
71 : /* -------------------------------------------------------------------- */
72 : /* If this is a regular file, but not a catalog just return it. */
73 : /* Note that the caller may still open it and fail. */
74 : /* -------------------------------------------------------------------- */
75 0 : DDFModule oModule;
76 :
77 0 : if (!oModule.Open(pszDataset))
78 : {
79 0 : CPLError(CE_Failure, CPLE_AppDefined,
80 : "The file %s isn't an S-57 data file, or catalog.\n",
81 : pszDataset);
82 :
83 0 : return nullptr;
84 : }
85 :
86 0 : DDFRecord *poRecord = oModule.ReadRecord();
87 0 : if (poRecord == nullptr)
88 0 : return nullptr;
89 :
90 0 : if (poRecord->FindField("CATD") == nullptr ||
91 0 : oModule.FindFieldDefn("CATD")->FindSubfieldDefn("IMPL") == nullptr)
92 : {
93 0 : papszRetList = CSLAddString(papszRetList, pszDataset);
94 0 : return papszRetList;
95 : }
96 :
97 : /* -------------------------------------------------------------------- */
98 : /* We presumably have a catalog. It contains paths to files */
99 : /* that generally lack the ENC_ROOT component. Try to find the */
100 : /* correct name for the ENC_ROOT directory if available and */
101 : /* build a base path for our purposes. */
102 : /* -------------------------------------------------------------------- */
103 0 : char *pszCatDir = CPLStrdup(CPLGetPath(pszDataset));
104 0 : char *pszRootDir = nullptr;
105 :
106 0 : if (CPLStat(CPLFormFilename(pszCatDir, "ENC_ROOT", nullptr), &sStatBuf) ==
107 0 : 0 &&
108 0 : VSI_ISDIR(sStatBuf.st_mode))
109 : {
110 0 : pszRootDir = CPLStrdup(CPLFormFilename(pszCatDir, "ENC_ROOT", nullptr));
111 : }
112 0 : else if (CPLStat(CPLFormFilename(pszCatDir, "enc_root", nullptr),
113 0 : &sStatBuf) == 0 &&
114 0 : VSI_ISDIR(sStatBuf.st_mode))
115 : {
116 0 : pszRootDir = CPLStrdup(CPLFormFilename(pszCatDir, "enc_root", nullptr));
117 : }
118 :
119 0 : if (pszRootDir)
120 0 : CPLDebug("S57", "Found root directory to be %s.", pszRootDir);
121 :
122 : /* -------------------------------------------------------------------- */
123 : /* We have a catalog. Scan it for data files, those with an */
124 : /* IMPL of BIN. Is there be a better way of testing */
125 : /* whether a file is a data file or another catalog file? */
126 : /* -------------------------------------------------------------------- */
127 0 : for (; poRecord != nullptr; poRecord = oModule.ReadRecord())
128 : {
129 0 : if (poRecord->FindField("CATD") != nullptr &&
130 0 : EQUAL(poRecord->GetStringSubfield("CATD", 0, "IMPL", 0), "BIN"))
131 : {
132 : const char *pszFile =
133 0 : poRecord->GetStringSubfield("CATD", 0, "FILE", 0);
134 :
135 : // Often there is an extra ENC_ROOT in the path, try finding
136 : // this file.
137 :
138 : const char *pszWholePath =
139 0 : CPLFormFilename(pszCatDir, pszFile, nullptr);
140 0 : if (CPLStat(pszWholePath, &sStatBuf) != 0 && pszRootDir != nullptr)
141 : {
142 0 : pszWholePath = CPLFormFilename(pszRootDir, pszFile, nullptr);
143 : }
144 :
145 0 : if (CPLStat(pszWholePath, &sStatBuf) != 0)
146 : {
147 0 : CPLError(CE_Warning, CPLE_OpenFailed,
148 : "Can't find file %s from catalog %s.", pszFile,
149 : pszDataset);
150 0 : continue;
151 : }
152 :
153 0 : papszRetList = CSLAddString(papszRetList, pszWholePath);
154 0 : CPLDebug("S57", "Got path %s from CATALOG.", pszWholePath);
155 : }
156 : }
157 :
158 0 : CPLFree(pszCatDir);
159 0 : CPLFree(pszRootDir);
160 :
161 0 : return papszRetList;
162 : }
|