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 : CPLFormFilenameSafe(pszDataset, papszDirFiles[iFile], nullptr)
56 : .c_str());
57 :
58 : // Add to list if it is an S-57 _data_ file.
59 0 : if (VSIStat(pszFullFile, &sStatBuf) == 0 &&
60 0 : VSI_ISREG(sStatBuf.st_mode) && oModule.Open(pszFullFile, TRUE))
61 : {
62 0 : if (oModule.FindFieldDefn("DSID") != nullptr)
63 0 : papszRetList = CSLAddString(papszRetList, pszFullFile);
64 : }
65 :
66 0 : CPLFree(pszFullFile);
67 : }
68 :
69 0 : return papszRetList;
70 : }
71 :
72 : /* -------------------------------------------------------------------- */
73 : /* If this is a regular file, but not a catalog just return it. */
74 : /* Note that the caller may still open it and fail. */
75 : /* -------------------------------------------------------------------- */
76 0 : DDFModule oModule;
77 :
78 0 : if (!oModule.Open(pszDataset))
79 : {
80 0 : CPLError(CE_Failure, CPLE_AppDefined,
81 : "The file %s isn't an S-57 data file, or catalog.\n",
82 : pszDataset);
83 :
84 0 : return nullptr;
85 : }
86 :
87 0 : DDFRecord *poRecord = oModule.ReadRecord();
88 0 : if (poRecord == nullptr)
89 0 : return nullptr;
90 :
91 0 : if (poRecord->FindField("CATD") == nullptr ||
92 0 : oModule.FindFieldDefn("CATD")->FindSubfieldDefn("IMPL") == nullptr)
93 : {
94 0 : papszRetList = CSLAddString(papszRetList, pszDataset);
95 0 : return papszRetList;
96 : }
97 :
98 : /* -------------------------------------------------------------------- */
99 : /* We presumably have a catalog. It contains paths to files */
100 : /* that generally lack the ENC_ROOT component. Try to find the */
101 : /* correct name for the ENC_ROOT directory if available and */
102 : /* build a base path for our purposes. */
103 : /* -------------------------------------------------------------------- */
104 0 : char *pszCatDir = CPLStrdup(CPLGetPathSafe(pszDataset).c_str());
105 0 : char *pszRootDir = nullptr;
106 :
107 0 : if (CPLStat(CPLFormFilenameSafe(pszCatDir, "ENC_ROOT", nullptr).c_str(),
108 0 : &sStatBuf) == 0 &&
109 0 : VSI_ISDIR(sStatBuf.st_mode))
110 : {
111 0 : pszRootDir = CPLStrdup(
112 0 : CPLFormFilenameSafe(pszCatDir, "ENC_ROOT", nullptr).c_str());
113 : }
114 0 : else if (CPLStat(
115 0 : CPLFormFilenameSafe(pszCatDir, "enc_root", nullptr).c_str(),
116 0 : &sStatBuf) == 0 &&
117 0 : VSI_ISDIR(sStatBuf.st_mode))
118 : {
119 0 : pszRootDir = CPLStrdup(
120 0 : CPLFormFilenameSafe(pszCatDir, "enc_root", nullptr).c_str());
121 : }
122 :
123 0 : if (pszRootDir)
124 0 : CPLDebug("S57", "Found root directory to be %s.", pszRootDir);
125 :
126 : /* -------------------------------------------------------------------- */
127 : /* We have a catalog. Scan it for data files, those with an */
128 : /* IMPL of BIN. Is there be a better way of testing */
129 : /* whether a file is a data file or another catalog file? */
130 : /* -------------------------------------------------------------------- */
131 0 : for (; poRecord != nullptr; poRecord = oModule.ReadRecord())
132 : {
133 0 : if (poRecord->FindField("CATD") != nullptr &&
134 0 : EQUAL(poRecord->GetStringSubfield("CATD", 0, "IMPL", 0), "BIN"))
135 : {
136 : const char *pszFile =
137 0 : poRecord->GetStringSubfield("CATD", 0, "FILE", 0);
138 :
139 : // Often there is an extra ENC_ROOT in the path, try finding
140 : // this file.
141 :
142 : std::string osWholePath =
143 0 : CPLFormFilenameSafe(pszCatDir, pszFile, nullptr);
144 0 : if (CPLStat(osWholePath.c_str(), &sStatBuf) != 0 &&
145 : pszRootDir != nullptr)
146 : {
147 0 : osWholePath = CPLFormFilenameSafe(pszRootDir, pszFile, nullptr);
148 : }
149 :
150 0 : if (CPLStat(osWholePath.c_str(), &sStatBuf) != 0)
151 : {
152 0 : CPLError(CE_Warning, CPLE_OpenFailed,
153 : "Can't find file %s from catalog %s.", pszFile,
154 : pszDataset);
155 0 : continue;
156 : }
157 :
158 0 : papszRetList = CSLAddString(papszRetList, osWholePath.c_str());
159 0 : CPLDebug("S57", "Got path %s from CATALOG.", osWholePath.c_str());
160 : }
161 : }
162 :
163 0 : CPLFree(pszCatDir);
164 0 : CPLFree(pszRootDir);
165 :
166 0 : return papszRetList;
167 : }
|