/src/gdal/ogr/ogrsf_frmts/openfilegdb/ogropenfilegdbdriver.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: OpenGIS Simple Features Reference Implementation |
4 | | * Purpose: Implements Open FileGDB OGR driver. |
5 | | * Author: Even Rouault, <even dot rouault at spatialys.com> |
6 | | * |
7 | | ****************************************************************************** |
8 | | * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys.com> |
9 | | * |
10 | | * SPDX-License-Identifier: MIT |
11 | | ****************************************************************************/ |
12 | | |
13 | | #include "cpl_port.h" |
14 | | #include "ogr_openfilegdb.h" |
15 | | #include "ogropenfilegdbdrivercore.h" |
16 | | |
17 | | #include <cstddef> |
18 | | #include <cstring> |
19 | | |
20 | | #include "cpl_conv.h" |
21 | | #include "cpl_vsi.h" |
22 | | #include "gdal.h" |
23 | | #include "gdal_priv.h" |
24 | | #include "gdalalgorithm.h" |
25 | | #include "ogr_core.h" |
26 | | |
27 | | // g++ -O2 -Wall -Wextra -g -shared -fPIC ogr/ogrsf_frmts/openfilegdb/*.cpp |
28 | | // -o ogr_OpenFileGDB.so -Iport -Igcore -Iogr -Iogr/ogrsf_frmts |
29 | | // -Iogr/ogrsf_frmts/mem -Iogr/ogrsf_frmts/openfilegdb -L. -lgdal |
30 | | |
31 | | extern "C" void RegisterOGROpenFileGDB(); |
32 | | |
33 | | /************************************************************************/ |
34 | | /* Open() */ |
35 | | /************************************************************************/ |
36 | | |
37 | | static GDALDataset *OGROpenFileGDBDriverOpen(GDALOpenInfo *poOpenInfo) |
38 | | |
39 | 12.6k | { |
40 | 12.6k | const char *pszFilename = poOpenInfo->pszFilename; |
41 | 12.6k | if (OGROpenFileGDBDriverIdentify(poOpenInfo, pszFilename) == |
42 | 12.6k | GDAL_IDENTIFY_FALSE) |
43 | 0 | return nullptr; |
44 | | |
45 | | #ifdef DEBUG |
46 | | /* For AFL, so that .cur_input is detected as the archive filename */ |
47 | | if (poOpenInfo->fpL != nullptr && |
48 | | !STARTS_WITH(poOpenInfo->pszFilename, "/vsitar/") && |
49 | | EQUAL(CPLGetFilename(poOpenInfo->pszFilename), ".cur_input")) |
50 | | { |
51 | | GDALOpenInfo oOpenInfo( |
52 | | (CPLString("/vsitar/") + poOpenInfo->pszFilename).c_str(), |
53 | | poOpenInfo->nOpenFlags); |
54 | | oOpenInfo.papszOpenOptions = poOpenInfo->papszOpenOptions; |
55 | | return OGROpenFileGDBDriverOpen(&oOpenInfo); |
56 | | } |
57 | | #endif |
58 | | |
59 | 12.6k | auto poDS = std::make_unique<OGROpenFileGDBDataSource>(); |
60 | 12.6k | bool bRetryFileGDB = false; |
61 | 12.6k | if (poDS->Open(poOpenInfo, bRetryFileGDB)) |
62 | 5.93k | { |
63 | 5.93k | if (poDS->GetSubdatasets().size() == 2) |
64 | 0 | { |
65 | | // If there is a single raster dataset, open it right away. |
66 | 0 | GDALOpenInfo oOpenInfo( |
67 | 0 | poDS->GetSubdatasets().FetchNameValue("SUBDATASET_1_NAME"), |
68 | 0 | poOpenInfo->nOpenFlags); |
69 | 0 | poDS = std::make_unique<OGROpenFileGDBDataSource>(); |
70 | 0 | if (poDS->Open(&oOpenInfo, bRetryFileGDB)) |
71 | 0 | { |
72 | 0 | poDS->SetDescription(poOpenInfo->pszFilename); |
73 | 0 | } |
74 | 0 | else |
75 | 0 | { |
76 | 0 | poDS.reset(); |
77 | 0 | } |
78 | 0 | } |
79 | 5.93k | return poDS.release(); |
80 | 5.93k | } |
81 | 6.74k | else if (bRetryFileGDB) |
82 | 0 | { |
83 | 0 | auto poDriver = GetGDALDriverManager()->GetDriverByName("FileGDB"); |
84 | 0 | if (poDriver) |
85 | 0 | { |
86 | 0 | GDALOpenInfo oOpenInfo(pszFilename, poOpenInfo->nOpenFlags); |
87 | 0 | CPLStringList aosOpenOptions; |
88 | 0 | aosOpenOptions.SetNameValue("@MAY_USE_OPENFILEGDB", "NO"); |
89 | 0 | oOpenInfo.papszOpenOptions = aosOpenOptions.List(); |
90 | 0 | return poDriver->Open(&oOpenInfo, false); |
91 | 0 | } |
92 | 0 | } |
93 | | |
94 | 6.74k | return nullptr; |
95 | 12.6k | } |
96 | | |
97 | | /************************************************************************/ |
98 | | /* Create() */ |
99 | | /************************************************************************/ |
100 | | |
101 | | static GDALDataset *OGROpenFileGDBDriverCreate(const char *pszName, int nXSize, |
102 | | int nYSize, int nBands, |
103 | | GDALDataType eType, |
104 | | char ** /* papszOptions*/) |
105 | | |
106 | 42 | { |
107 | 42 | if (!(nXSize == 0 && nYSize == 0 && nBands == 0 && eType == GDT_Unknown)) |
108 | 0 | { |
109 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
110 | 0 | "OpenFileGDB::Create(): only vector datasets supported"); |
111 | 0 | return nullptr; |
112 | 0 | } |
113 | | |
114 | 42 | auto poDS = std::make_unique<OGROpenFileGDBDataSource>(); |
115 | 42 | if (!poDS->Create(pszName)) |
116 | 0 | return nullptr; |
117 | 42 | return poDS.release(); |
118 | 42 | } |
119 | | |
120 | | /************************************************************************/ |
121 | | /* OGROpenFileGDBDriverDelete() */ |
122 | | /************************************************************************/ |
123 | | |
124 | | static CPLErr OGROpenFileGDBDriverDelete(const char *pszFilename) |
125 | 32 | { |
126 | 32 | CPLStringList aosFiles(VSIReadDir(pszFilename)); |
127 | 32 | if (aosFiles.empty()) |
128 | 0 | return CE_Failure; |
129 | | |
130 | 4.26k | for (int i = 0; i < aosFiles.size(); ++i) |
131 | 4.23k | { |
132 | 4.23k | if (strcmp(aosFiles[i], ".") != 0 && strcmp(aosFiles[i], "..") != 0) |
133 | 4.23k | { |
134 | 4.23k | const std::string osFilename( |
135 | 4.23k | CPLFormFilenameSafe(pszFilename, aosFiles[i], nullptr)); |
136 | 4.23k | if (VSIUnlink(osFilename.c_str()) != 0) |
137 | 0 | { |
138 | 0 | CPLError(CE_Failure, CPLE_FileIO, "Cannot delete %s", |
139 | 0 | osFilename.c_str()); |
140 | 0 | return CE_Failure; |
141 | 0 | } |
142 | 4.23k | } |
143 | 4.23k | } |
144 | 32 | if (VSIRmdir(pszFilename) != 0) |
145 | 0 | { |
146 | 0 | CPLError(CE_Failure, CPLE_FileIO, "Cannot delete %s", pszFilename); |
147 | 0 | return CE_Failure; |
148 | 0 | } |
149 | | |
150 | 32 | return CE_None; |
151 | 32 | } |
152 | | |
153 | | /************************************************************************/ |
154 | | /* OpenFileGDBRepackAlgorithm */ |
155 | | /************************************************************************/ |
156 | | |
157 | | #ifndef _ |
158 | 0 | #define _(x) x |
159 | | #endif |
160 | | |
161 | | class OpenFileGDBRepackAlgorithm final : public GDALAlgorithm |
162 | | { |
163 | | public: |
164 | | OpenFileGDBRepackAlgorithm() |
165 | 0 | : GDALAlgorithm("repack", "Repack a FileGeoDatabase dataset", |
166 | 0 | "/drivers/vector/openfilegdb.html") |
167 | 0 | { |
168 | 0 | AddProgressArg(); |
169 | |
|
170 | 0 | constexpr int type = GDAL_OF_RASTER | GDAL_OF_VECTOR | GDAL_OF_UPDATE; |
171 | 0 | auto &arg = |
172 | 0 | AddArg("dataset", 0, _("FileGeoDatabase dataset"), &m_dataset, type) |
173 | 0 | .SetPositional() |
174 | 0 | .SetRequired(); |
175 | 0 | SetAutoCompleteFunctionForFilename(arg, type); |
176 | 0 | } |
177 | | |
178 | | protected: |
179 | | bool RunImpl(GDALProgressFunc pfnProgress, void *pProgressData) override; |
180 | | |
181 | | private: |
182 | | GDALArgDatasetValue m_dataset{}; |
183 | | }; |
184 | | |
185 | | bool OpenFileGDBRepackAlgorithm::RunImpl(GDALProgressFunc pfnProgress, |
186 | | void *pProgressData) |
187 | 0 | { |
188 | 0 | auto poDS = |
189 | 0 | dynamic_cast<OGROpenFileGDBDataSource *>(m_dataset.GetDatasetRef()); |
190 | 0 | if (!poDS) |
191 | 0 | { |
192 | 0 | ReportError(CE_Failure, CPLE_AppDefined, "%s is not a FileGeoDatabase", |
193 | 0 | m_dataset.GetName().c_str()); |
194 | 0 | return false; |
195 | 0 | } |
196 | 0 | bool bSuccess = true; |
197 | 0 | int iLayer = 0; |
198 | 0 | for (auto &poLayer : poDS->GetLayers()) |
199 | 0 | { |
200 | 0 | void *pScaledData = GDALCreateScaledProgress( |
201 | 0 | static_cast<double>(iLayer) / poDS->GetLayerCount(), |
202 | 0 | static_cast<double>(iLayer + 1) / poDS->GetLayerCount(), |
203 | 0 | pfnProgress, pProgressData); |
204 | 0 | const bool bRet = poLayer->Repack( |
205 | 0 | pScaledData ? GDALScaledProgress : nullptr, pScaledData); |
206 | 0 | GDALDestroyScaledProgress(pScaledData); |
207 | 0 | if (!bRet) |
208 | 0 | { |
209 | 0 | ReportError(CE_Failure, CPLE_AppDefined, |
210 | 0 | "Repack of layer %s failed", poLayer->GetName()); |
211 | 0 | bSuccess = false; |
212 | 0 | } |
213 | 0 | ++iLayer; |
214 | 0 | } |
215 | 0 | return bSuccess; |
216 | 0 | } |
217 | | |
218 | | /************************************************************************/ |
219 | | /* OGROpenFileGDBInstantiateAlgorithm() */ |
220 | | /************************************************************************/ |
221 | | |
222 | | static GDALAlgorithm * |
223 | | OGROpenFileGDBInstantiateAlgorithm(const std::vector<std::string> &aosPath) |
224 | 0 | { |
225 | 0 | if (aosPath.size() == 1 && aosPath[0] == "repack") |
226 | 0 | { |
227 | 0 | return std::make_unique<OpenFileGDBRepackAlgorithm>().release(); |
228 | 0 | } |
229 | 0 | else |
230 | 0 | { |
231 | 0 | return nullptr; |
232 | 0 | } |
233 | 0 | } |
234 | | |
235 | | /***********************************************************************/ |
236 | | /* RegisterOGROpenFileGDB() */ |
237 | | /***********************************************************************/ |
238 | | |
239 | | void RegisterOGROpenFileGDB() |
240 | | |
241 | 26 | { |
242 | 26 | if (!GDAL_CHECK_VERSION("OGR OpenFileGDB")) |
243 | 0 | return; |
244 | | |
245 | 26 | if (GDALGetDriverByName(DRIVER_NAME) != nullptr) |
246 | 0 | return; |
247 | | |
248 | 26 | GDALDriver *poDriver = new GDALDriver(); |
249 | 26 | OGROpenFileGDBDriverSetCommonMetadata(poDriver); |
250 | | |
251 | 26 | poDriver->pfnOpen = OGROpenFileGDBDriverOpen; |
252 | 26 | poDriver->pfnCreate = OGROpenFileGDBDriverCreate; |
253 | 26 | poDriver->pfnDelete = OGROpenFileGDBDriverDelete; |
254 | 26 | poDriver->pfnInstantiateAlgorithm = OGROpenFileGDBInstantiateAlgorithm; |
255 | | |
256 | 26 | GetGDALDriverManager()->RegisterDriver(poDriver); |
257 | 26 | } |