Line data Source code
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 551 : static GDALDataset *OGROpenFileGDBDriverOpen(GDALOpenInfo *poOpenInfo)
38 :
39 : {
40 551 : const char *pszFilename = poOpenInfo->pszFilename;
41 551 : if (OGROpenFileGDBDriverIdentify(poOpenInfo, pszFilename) ==
42 : 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 1181 : if (poOpenInfo->fpL != nullptr &&
48 630 : !STARTS_WITH(poOpenInfo->pszFilename, "/vsitar/") &&
49 79 : EQUAL(CPLGetFilename(poOpenInfo->pszFilename), ".cur_input"))
50 : {
51 : GDALOpenInfo oOpenInfo(
52 2 : (CPLString("/vsitar/") + poOpenInfo->pszFilename).c_str(),
53 3 : poOpenInfo->nOpenFlags);
54 1 : oOpenInfo.papszOpenOptions = poOpenInfo->papszOpenOptions;
55 1 : return OGROpenFileGDBDriverOpen(&oOpenInfo);
56 : }
57 : #endif
58 :
59 1100 : auto poDS = std::make_unique<OGROpenFileGDBDataSource>();
60 550 : bool bRetryFileGDB = false;
61 550 : if (poDS->Open(poOpenInfo, bRetryFileGDB))
62 : {
63 491 : if (poDS->GetSubdatasets().size() == 2)
64 : {
65 : // If there is a single raster dataset, open it right away.
66 : GDALOpenInfo oOpenInfo(
67 7 : poDS->GetSubdatasets().FetchNameValue("SUBDATASET_1_NAME"),
68 21 : poOpenInfo->nOpenFlags);
69 7 : poDS = std::make_unique<OGROpenFileGDBDataSource>();
70 7 : if (poDS->Open(&oOpenInfo, bRetryFileGDB))
71 : {
72 7 : poDS->SetDescription(poOpenInfo->pszFilename);
73 : }
74 : else
75 : {
76 0 : poDS.reset();
77 : }
78 : }
79 491 : return poDS.release();
80 : }
81 59 : else if (bRetryFileGDB)
82 : {
83 2 : auto poDriver = GetGDALDriverManager()->GetDriverByName("FileGDB");
84 2 : if (poDriver)
85 : {
86 4 : GDALOpenInfo oOpenInfo(pszFilename, poOpenInfo->nOpenFlags);
87 4 : CPLStringList aosOpenOptions;
88 2 : aosOpenOptions.SetNameValue("@MAY_USE_OPENFILEGDB", "NO");
89 2 : oOpenInfo.papszOpenOptions = aosOpenOptions.List();
90 2 : return poDriver->Open(&oOpenInfo, false);
91 : }
92 : }
93 :
94 57 : return nullptr;
95 : }
96 :
97 : /************************************************************************/
98 : /* Create() */
99 : /************************************************************************/
100 :
101 295 : static GDALDataset *OGROpenFileGDBDriverCreate(const char *pszName, int nXSize,
102 : int nYSize, int nBands,
103 : GDALDataType eType,
104 : char ** /* papszOptions*/)
105 :
106 : {
107 295 : if (!(nXSize == 0 && nYSize == 0 && nBands == 0 && eType == GDT_Unknown))
108 : {
109 50 : CPLError(CE_Failure, CPLE_NotSupported,
110 : "OpenFileGDB::Create(): only vector datasets supported");
111 50 : return nullptr;
112 : }
113 :
114 490 : auto poDS = std::make_unique<OGROpenFileGDBDataSource>();
115 245 : if (!poDS->Create(pszName))
116 3 : return nullptr;
117 242 : return poDS.release();
118 : }
119 :
120 : /************************************************************************/
121 : /* OGROpenFileGDBDriverDelete() */
122 : /************************************************************************/
123 :
124 32 : static CPLErr OGROpenFileGDBDriverDelete(const char *pszFilename)
125 : {
126 64 : CPLStringList aosFiles(VSIReadDir(pszFilename));
127 32 : if (aosFiles.empty())
128 0 : return CE_Failure;
129 :
130 657 : for (int i = 0; i < aosFiles.size(); ++i)
131 : {
132 625 : if (strcmp(aosFiles[i], ".") != 0 && strcmp(aosFiles[i], "..") != 0)
133 : {
134 : const std::string osFilename(
135 623 : CPLFormFilenameSafe(pszFilename, aosFiles[i], nullptr));
136 623 : if (VSIUnlink(osFilename.c_str()) != 0)
137 : {
138 0 : CPLError(CE_Failure, CPLE_FileIO, "Cannot delete %s",
139 : osFilename.c_str());
140 0 : return CE_Failure;
141 : }
142 : }
143 : }
144 32 : if (VSIRmdir(pszFilename) != 0)
145 : {
146 0 : CPLError(CE_Failure, CPLE_FileIO, "Cannot delete %s", pszFilename);
147 0 : return CE_Failure;
148 : }
149 :
150 32 : return CE_None;
151 : }
152 :
153 : /************************************************************************/
154 : /* OpenFileGDBRepackAlgorithm */
155 : /************************************************************************/
156 :
157 : #ifndef _
158 : #define _(x) x
159 : #endif
160 :
161 : class OpenFileGDBRepackAlgorithm final : public GDALAlgorithm
162 : {
163 : public:
164 13 : OpenFileGDBRepackAlgorithm()
165 13 : : GDALAlgorithm("repack", "Repack a FileGeoDatabase dataset",
166 13 : "/drivers/vector/openfilegdb.html")
167 : {
168 13 : AddProgressArg();
169 :
170 13 : constexpr int type = GDAL_OF_RASTER | GDAL_OF_VECTOR | GDAL_OF_UPDATE;
171 : auto &arg =
172 26 : AddArg("dataset", 0, _("FileGeoDatabase dataset"), &m_dataset, type)
173 13 : .SetPositional()
174 13 : .SetRequired();
175 13 : SetAutoCompleteFunctionForFilename(arg, type);
176 13 : }
177 :
178 : protected:
179 3 : bool RunImpl(GDALProgressFunc pfnProgress, void *pProgressData) override
180 : {
181 : auto poDS =
182 3 : dynamic_cast<OGROpenFileGDBDataSource *>(m_dataset.GetDatasetRef());
183 3 : if (!poDS)
184 : {
185 1 : ReportError(CE_Failure, CPLE_AppDefined,
186 : "%s is not a FileGeoDatabase",
187 1 : m_dataset.GetName().c_str());
188 1 : return false;
189 : }
190 2 : bool bSuccess = true;
191 2 : int iLayer = 0;
192 4 : for (auto &poLayer : poDS->GetLayers())
193 : {
194 2 : void *pScaledData = GDALCreateScaledProgress(
195 2 : static_cast<double>(iLayer) / poDS->GetLayerCount(),
196 2 : static_cast<double>(iLayer + 1) / poDS->GetLayerCount(),
197 : pfnProgress, pProgressData);
198 2 : const bool bRet = poLayer->Repack(
199 : pScaledData ? GDALScaledProgress : nullptr, pScaledData);
200 2 : GDALDestroyScaledProgress(pScaledData);
201 2 : if (!bRet)
202 : {
203 0 : ReportError(CE_Failure, CPLE_AppDefined,
204 : "Repack of layer %s failed", poLayer->GetName());
205 0 : bSuccess = false;
206 : }
207 2 : ++iLayer;
208 : }
209 2 : return bSuccess;
210 : }
211 :
212 : private:
213 : GDALArgDatasetValue m_dataset{};
214 : };
215 :
216 : /************************************************************************/
217 : /* OGROpenFileGDBInstantiateAlgorithm() */
218 : /************************************************************************/
219 :
220 : static GDALAlgorithm *
221 13 : OGROpenFileGDBInstantiateAlgorithm(const std::vector<std::string> &aosPath)
222 : {
223 13 : if (aosPath.size() == 1 && aosPath[0] == "repack")
224 : {
225 13 : return std::make_unique<OpenFileGDBRepackAlgorithm>().release();
226 : }
227 : else
228 : {
229 0 : return nullptr;
230 : }
231 : }
232 :
233 : /***********************************************************************/
234 : /* RegisterOGROpenFileGDB() */
235 : /***********************************************************************/
236 :
237 1889 : void RegisterOGROpenFileGDB()
238 :
239 : {
240 1889 : if (!GDAL_CHECK_VERSION("OGR OpenFileGDB"))
241 0 : return;
242 :
243 1889 : if (GDALGetDriverByName(DRIVER_NAME) != nullptr)
244 282 : return;
245 :
246 1607 : GDALDriver *poDriver = new GDALDriver();
247 1607 : OGROpenFileGDBDriverSetCommonMetadata(poDriver);
248 :
249 1607 : poDriver->pfnOpen = OGROpenFileGDBDriverOpen;
250 1607 : poDriver->pfnCreate = OGROpenFileGDBDriverCreate;
251 1607 : poDriver->pfnDelete = OGROpenFileGDBDriverDelete;
252 1607 : poDriver->pfnInstantiateAlgorithm = OGROpenFileGDBInstantiateAlgorithm;
253 :
254 1607 : GetGDALDriverManager()->RegisterDriver(poDriver);
255 : }
|