/src/gdal/gcore/gdalopeninfo.cpp
Line | Count | Source |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: GDAL Core |
4 | | * Purpose: Implementation of GDALOpenInfo class. |
5 | | * Author: Frank Warmerdam, warmerdam@pobox.com |
6 | | * |
7 | | ********************************************************************** |
8 | | * Copyright (c) 2002, Frank Warmerdam |
9 | | * Copyright (c) 2008-2012, Even Rouault <even dot rouault at spatialys.com> |
10 | | * |
11 | | * SPDX-License-Identifier: MIT |
12 | | ****************************************************************************/ |
13 | | |
14 | | #include "gdal_priv.h" // Must be included first for mingw VSIStatBufL. |
15 | | #include "cpl_port.h" |
16 | | #include "cpl_vsi_virtual.h" |
17 | | |
18 | | #include <cstdlib> |
19 | | #include <cstring> |
20 | | #ifdef HAVE_UNISTD_H |
21 | | #include <unistd.h> |
22 | | #endif |
23 | | |
24 | | #include <algorithm> |
25 | | #include <map> |
26 | | #include <mutex> |
27 | | #include <vector> |
28 | | |
29 | | #include "cpl_config.h" |
30 | | #include "cpl_conv.h" |
31 | | #include "cpl_error.h" |
32 | | #include "cpl_string.h" |
33 | | #include "cpl_vsi.h" |
34 | | #include "gdal.h" |
35 | | |
36 | | // Keep in sync prototype of those 2 functions between gdalopeninfo.cpp, |
37 | | // ogrsqlitedatasource.cpp and ogrgeopackagedatasource.cpp |
38 | | void GDALOpenInfoDeclareFileNotToOpen(const char *pszFilename, |
39 | | const GByte *pabyHeader, |
40 | | int nHeaderBytes); |
41 | | void GDALOpenInfoUnDeclareFileNotToOpen(const char *pszFilename); |
42 | | |
43 | | /************************************************************************/ |
44 | | |
45 | | /* This whole section helps for SQLite/GPKG, especially with write-ahead |
46 | | * log enabled. The issue is that sqlite3 relies on POSIX advisory locks to |
47 | | * properly work and decide when to create/delete the wal related files. |
48 | | * One issue with POSIX advisory locks is that if within the same process |
49 | | * you do |
50 | | * f1 = open('somefile') |
51 | | * set locks on f1 |
52 | | * f2 = open('somefile') |
53 | | * close(f2) |
54 | | * The close(f2) will cancel the locks set on f1. The work on f1 is done by |
55 | | * libsqlite3 whereas the work on f2 is done by GDALOpenInfo. |
56 | | * So as soon as sqlite3 has opened a file we should make sure not to re-open |
57 | | * it (actually close it) ourselves. |
58 | | */ |
59 | | |
60 | | namespace |
61 | | { |
62 | | struct FileNotToOpen |
63 | | { |
64 | | CPLString osFilename{}; |
65 | | int nRefCount{}; |
66 | | GByte *pabyHeader{nullptr}; |
67 | | int nHeaderBytes{0}; |
68 | | }; |
69 | | } // namespace |
70 | | |
71 | | static std::mutex sFNTOMutex; |
72 | | static std::map<CPLString, FileNotToOpen> *pMapFNTO = nullptr; |
73 | | |
74 | | void GDALOpenInfoDeclareFileNotToOpen(const char *pszFilename, |
75 | | const GByte *pabyHeader, int nHeaderBytes) |
76 | 0 | { |
77 | 0 | std::lock_guard<std::mutex> oLock(sFNTOMutex); |
78 | 0 | if (pMapFNTO == nullptr) |
79 | 0 | pMapFNTO = new std::map<CPLString, FileNotToOpen>(); |
80 | 0 | auto oIter = pMapFNTO->find(pszFilename); |
81 | 0 | if (oIter != pMapFNTO->end()) |
82 | 0 | { |
83 | 0 | oIter->second.nRefCount++; |
84 | 0 | } |
85 | 0 | else |
86 | 0 | { |
87 | 0 | FileNotToOpen fnto; |
88 | 0 | fnto.osFilename = pszFilename; |
89 | 0 | fnto.nRefCount = 1; |
90 | 0 | fnto.pabyHeader = static_cast<GByte *>(CPLMalloc(nHeaderBytes + 1)); |
91 | 0 | memcpy(fnto.pabyHeader, pabyHeader, nHeaderBytes); |
92 | 0 | fnto.pabyHeader[nHeaderBytes] = 0; |
93 | 0 | fnto.nHeaderBytes = nHeaderBytes; |
94 | 0 | (*pMapFNTO)[pszFilename] = std::move(fnto); |
95 | 0 | } |
96 | 0 | } |
97 | | |
98 | | void GDALOpenInfoUnDeclareFileNotToOpen(const char *pszFilename) |
99 | 0 | { |
100 | 0 | std::lock_guard<std::mutex> oLock(sFNTOMutex); |
101 | 0 | CPLAssert(pMapFNTO); |
102 | 0 | auto oIter = pMapFNTO->find(pszFilename); |
103 | 0 | CPLAssert(oIter != pMapFNTO->end()); |
104 | 0 | oIter->second.nRefCount--; |
105 | 0 | if (oIter->second.nRefCount == 0) |
106 | 0 | { |
107 | 0 | CPLFree(oIter->second.pabyHeader); |
108 | 0 | pMapFNTO->erase(oIter); |
109 | 0 | } |
110 | 0 | if (pMapFNTO->empty()) |
111 | 0 | { |
112 | 0 | delete pMapFNTO; |
113 | 0 | pMapFNTO = nullptr; |
114 | 0 | } |
115 | 0 | } |
116 | | |
117 | | static GByte *GDALOpenInfoGetFileNotToOpen(const char *pszFilename, |
118 | | int *pnHeaderBytes) |
119 | 0 | { |
120 | 0 | std::lock_guard<std::mutex> oLock(sFNTOMutex); |
121 | 0 | *pnHeaderBytes = 0; |
122 | 0 | if (pMapFNTO == nullptr) |
123 | 0 | { |
124 | 0 | return nullptr; |
125 | 0 | } |
126 | 0 | auto oIter = pMapFNTO->find(pszFilename); |
127 | 0 | if (oIter == pMapFNTO->end()) |
128 | 0 | { |
129 | 0 | return nullptr; |
130 | 0 | } |
131 | 0 | *pnHeaderBytes = oIter->second.nHeaderBytes; |
132 | 0 | GByte *pabyHeader = static_cast<GByte *>(CPLMalloc(*pnHeaderBytes + 1)); |
133 | 0 | memcpy(pabyHeader, oIter->second.pabyHeader, *pnHeaderBytes); |
134 | 0 | pabyHeader[*pnHeaderBytes] = 0; |
135 | 0 | return pabyHeader; |
136 | 0 | } |
137 | | |
138 | | /************************************************************************/ |
139 | | /* ==================================================================== */ |
140 | | /* GDALOpenInfo */ |
141 | | /* ==================================================================== */ |
142 | | /************************************************************************/ |
143 | | |
144 | | /************************************************************************/ |
145 | | /* GDALOpenInfo() */ |
146 | | /************************************************************************/ |
147 | | |
148 | | /** Constructor/ |
149 | | * @param pszFilenameIn filename |
150 | | * @param nOpenFlagsIn open flags |
151 | | * @param papszSiblingFilesIn list of sibling files, or NULL. |
152 | | */ |
153 | | GDALOpenInfo::GDALOpenInfo(const char *pszFilenameIn, int nOpenFlagsIn, |
154 | | const char *const *papszSiblingFilesIn) |
155 | 0 | : pszFilename(CPLStrdup(pszFilenameIn)), |
156 | 0 | osExtension(CPLGetExtensionSafe(pszFilenameIn)), |
157 | 0 | eAccess(nOpenFlagsIn & GDAL_OF_UPDATE ? GA_Update : GA_ReadOnly), |
158 | 0 | nOpenFlags(nOpenFlagsIn) |
159 | 0 | { |
160 | | /* -------------------------------------------------------------------- */ |
161 | | /* Ensure that C: is treated as C:\ so we can stat it on */ |
162 | | /* Windows. Similar to what is done in CPLStat(). */ |
163 | | /* -------------------------------------------------------------------- */ |
164 | | #ifdef _WIN32 |
165 | | if (strlen(pszFilename) == 2 && pszFilename[1] == ':') |
166 | | { |
167 | | char szAltPath[10]; |
168 | | |
169 | | strcpy(szAltPath, pszFilename); |
170 | | strcat(szAltPath, "\\"); |
171 | | CPLFree(pszFilename); |
172 | | pszFilename = CPLStrdup(szAltPath); |
173 | | } |
174 | | #endif // WIN32 |
175 | |
|
176 | 0 | Init(papszSiblingFilesIn, nullptr); |
177 | 0 | } |
178 | | |
179 | | /************************************************************************/ |
180 | | /* GDALOpenInfo() */ |
181 | | /************************************************************************/ |
182 | | |
183 | | /** Constructor/ |
184 | | * @param pszFilenameIn filename |
185 | | * @param nOpenFlagsIn open flags |
186 | | * @param poFile already opened file |
187 | | * @since 3.13 |
188 | | */ |
189 | | GDALOpenInfo::GDALOpenInfo(const char *pszFilenameIn, int nOpenFlagsIn, |
190 | | std::unique_ptr<VSIVirtualHandle> poFile) |
191 | 0 | : pszFilename(CPLStrdup(pszFilenameIn)), |
192 | 0 | osExtension(CPLGetExtensionSafe(pszFilenameIn)), |
193 | 0 | eAccess(nOpenFlagsIn & GDAL_OF_UPDATE ? GA_Update : GA_ReadOnly), |
194 | 0 | nOpenFlags(nOpenFlagsIn) |
195 | 0 | { |
196 | 0 | Init(nullptr, std::move(poFile)); |
197 | 0 | } |
198 | | |
199 | | /************************************************************************/ |
200 | | /* Init() */ |
201 | | /************************************************************************/ |
202 | | |
203 | | void GDALOpenInfo::Init(const char *const *papszSiblingFilesIn, |
204 | | std::unique_ptr<VSIVirtualHandle> poFile) |
205 | 0 | { |
206 | 0 | if (STARTS_WITH(pszFilename, "MVT:/vsi")) |
207 | 0 | return; |
208 | | |
209 | | /* -------------------------------------------------------------------- */ |
210 | | /* Collect information about the file. */ |
211 | | /* -------------------------------------------------------------------- */ |
212 | | |
213 | 0 | #if !defined(_WIN32) |
214 | 0 | bool bHasRetried = false; |
215 | |
|
216 | 0 | retry: // TODO(schwehr): Stop using goto. |
217 | |
|
218 | 0 | #endif // !defined(_WIN32) |
219 | |
|
220 | | #if !(defined(_WIN32) || defined(__linux__) || defined(__ANDROID__) || \ |
221 | | (defined(__MACH__) && defined(__APPLE__))) |
222 | | /* On BSDs, fread() on a directory returns non zero, so we have to */ |
223 | | /* do a stat() before to check the nature of pszFilename. */ |
224 | | bool bPotentialDirectory = (eAccess == GA_ReadOnly); |
225 | | #else |
226 | 0 | bool bPotentialDirectory = false; |
227 | 0 | #endif |
228 | | |
229 | | /* Check if the filename might be a directory of a special virtual file |
230 | | * system */ |
231 | 0 | if (STARTS_WITH(pszFilename, "/vsizip/") || |
232 | 0 | STARTS_WITH(pszFilename, "/vsitar/") || |
233 | 0 | STARTS_WITH(pszFilename, "/vsi7z/") || |
234 | 0 | STARTS_WITH(pszFilename, "/vsirar/")) |
235 | 0 | { |
236 | 0 | const char *pszExt = osExtension.c_str(); |
237 | 0 | if (EQUAL(pszExt, "zip") || EQUAL(pszExt, "tar") || |
238 | 0 | EQUAL(pszExt, "gz") || EQUAL(pszExt, "7z") || |
239 | 0 | EQUAL(pszExt, "rar") || |
240 | 0 | pszFilename[strlen(pszFilename) - 1] == '}' |
241 | 0 | #ifdef DEBUG |
242 | | // For AFL, so that .cur_input is detected as the archive filename. |
243 | 0 | || EQUAL(CPLGetFilename(pszFilename), ".cur_input") |
244 | 0 | #endif // DEBUG |
245 | 0 | ) |
246 | 0 | { |
247 | 0 | bPotentialDirectory = true; |
248 | 0 | } |
249 | 0 | } |
250 | 0 | else if (STARTS_WITH(pszFilename, "/vsicurl/")) |
251 | 0 | { |
252 | 0 | bPotentialDirectory = true; |
253 | 0 | } |
254 | |
|
255 | 0 | if (bPotentialDirectory && !poFile) |
256 | 0 | { |
257 | 0 | int nStatFlags = VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG; |
258 | 0 | if (nOpenFlags & GDAL_OF_VERBOSE_ERROR) |
259 | 0 | nStatFlags |= VSI_STAT_SET_ERROR_FLAG; |
260 | | |
261 | | // For those special files, opening them with VSIFOpenL() might result |
262 | | // in content, even if they should be considered as directories, so |
263 | | // use stat. |
264 | 0 | VSIStatBufL sStat; |
265 | |
|
266 | 0 | if (VSIStatExL(pszFilename, &sStat, nStatFlags) == 0) |
267 | 0 | { |
268 | 0 | bStatOK = TRUE; |
269 | 0 | if (VSI_ISDIR(sStat.st_mode)) |
270 | 0 | bIsDirectory = TRUE; |
271 | 0 | } |
272 | 0 | } |
273 | |
|
274 | 0 | if (poFile) |
275 | 0 | { |
276 | 0 | fpL = poFile.release(); |
277 | 0 | } |
278 | 0 | else |
279 | 0 | { |
280 | 0 | pabyHeader = GDALOpenInfoGetFileNotToOpen(pszFilename, &nHeaderBytes); |
281 | |
|
282 | 0 | if (!bIsDirectory && pabyHeader == nullptr) |
283 | 0 | { |
284 | 0 | fpL = |
285 | 0 | VSIFOpenExL(pszFilename, (eAccess == GA_Update) ? "r+b" : "rb", |
286 | 0 | (nOpenFlags & GDAL_OF_VERBOSE_ERROR) > 0); |
287 | 0 | } |
288 | 0 | } |
289 | |
|
290 | 0 | if (pabyHeader) |
291 | 0 | { |
292 | 0 | bStatOK = TRUE; |
293 | 0 | nHeaderBytesTried = nHeaderBytes; |
294 | 0 | } |
295 | 0 | else if (fpL != nullptr) |
296 | 0 | { |
297 | 0 | bStatOK = TRUE; |
298 | 0 | int nBufSize = |
299 | 0 | atoi(CPLGetConfigOption("GDAL_INGESTED_BYTES_AT_OPEN", "1024")); |
300 | 0 | if (nBufSize < 1024) |
301 | 0 | nBufSize = 1024; |
302 | 0 | else if (nBufSize > 10 * 1024 * 1024) |
303 | 0 | nBufSize = 10 * 1024 * 1024; |
304 | 0 | pabyHeader = static_cast<GByte *>(CPLCalloc(nBufSize + 1, 1)); |
305 | 0 | nHeaderBytesTried = nBufSize; |
306 | 0 | nHeaderBytes = |
307 | 0 | static_cast<int>(VSIFReadL(pabyHeader, 1, nHeaderBytesTried, fpL)); |
308 | 0 | VSIRewindL(fpL); |
309 | | |
310 | | /* If we cannot read anything, check if it is not a directory instead */ |
311 | 0 | VSIStatBufL sStat; |
312 | 0 | if (nHeaderBytes == 0 && |
313 | 0 | VSIStatExL(pszFilename, &sStat, |
314 | 0 | VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG) == 0 && |
315 | 0 | VSI_ISDIR(sStat.st_mode)) |
316 | 0 | { |
317 | 0 | CPL_IGNORE_RET_VAL(VSIFCloseL(fpL)); |
318 | 0 | fpL = nullptr; |
319 | 0 | CPLFree(pabyHeader); |
320 | 0 | pabyHeader = nullptr; |
321 | 0 | bIsDirectory = TRUE; |
322 | 0 | } |
323 | 0 | } |
324 | 0 | else if (!bStatOK) |
325 | 0 | { |
326 | 0 | VSIStatBufL sStat; |
327 | 0 | if (!bPotentialDirectory && |
328 | 0 | VSIStatExL(pszFilename, &sStat, |
329 | 0 | VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG) == 0) |
330 | 0 | { |
331 | 0 | bStatOK = TRUE; |
332 | 0 | if (VSI_ISDIR(sStat.st_mode)) |
333 | 0 | bIsDirectory = TRUE; |
334 | 0 | } |
335 | 0 | #if !defined(_WIN32) |
336 | 0 | else if (!bHasRetried && !STARTS_WITH(pszFilename, "/vsi")) |
337 | 0 | { |
338 | | // If someone creates a file with "ln -sf |
339 | | // /vsicurl/http://download.osgeo.org/gdal/data/gtiff/utm.tif |
340 | | // my_remote_utm.tif" we will be able to open it by passing |
341 | | // my_remote_utm.tif. This helps a lot for GDAL based readers that |
342 | | // only provide file explorers to open datasets. |
343 | 0 | const int nBufSize = 2048; |
344 | 0 | std::vector<char> oFilename(nBufSize); |
345 | 0 | char *szPointerFilename = &oFilename[0]; |
346 | 0 | int nBytes = static_cast<int>( |
347 | 0 | readlink(pszFilename, szPointerFilename, nBufSize)); |
348 | 0 | if (nBytes != -1) |
349 | 0 | { |
350 | 0 | szPointerFilename[std::min(nBytes, nBufSize - 1)] = 0; |
351 | 0 | CPLFree(pszFilename); |
352 | 0 | pszFilename = CPLStrdup(szPointerFilename); |
353 | 0 | osExtension = CPLGetExtensionSafe(pszFilename); |
354 | 0 | papszSiblingFilesIn = nullptr; |
355 | 0 | bHasRetried = true; |
356 | 0 | goto retry; |
357 | 0 | } |
358 | 0 | } |
359 | 0 | #endif // !defined(_WIN32) |
360 | 0 | } |
361 | | |
362 | | /* -------------------------------------------------------------------- */ |
363 | | /* Capture sibling list either from passed in values, or by */ |
364 | | /* scanning for them only if requested through GetSiblingFiles(). */ |
365 | | /* -------------------------------------------------------------------- */ |
366 | 0 | if (papszSiblingFilesIn != nullptr) |
367 | 0 | { |
368 | 0 | papszSiblingFiles = CSLDuplicate(papszSiblingFilesIn); |
369 | 0 | bHasGotSiblingFiles = true; |
370 | 0 | } |
371 | 0 | else if (bStatOK && !bIsDirectory) |
372 | 0 | { |
373 | 0 | papszSiblingFiles = VSISiblingFiles(pszFilename); |
374 | 0 | if (papszSiblingFiles != nullptr) |
375 | 0 | { |
376 | 0 | bHasGotSiblingFiles = true; |
377 | 0 | } |
378 | 0 | else |
379 | 0 | { |
380 | 0 | const char *pszOptionVal = VSIGetPathSpecificOption( |
381 | 0 | pszFilename, "GDAL_DISABLE_READDIR_ON_OPEN", "NO"); |
382 | 0 | if (EQUAL(pszOptionVal, "EMPTY_DIR")) |
383 | 0 | { |
384 | 0 | papszSiblingFiles = |
385 | 0 | CSLAddString(nullptr, CPLGetFilename(pszFilename)); |
386 | 0 | bHasGotSiblingFiles = true; |
387 | 0 | } |
388 | 0 | else if (CPLTestBool(pszOptionVal)) |
389 | 0 | { |
390 | | /* skip reading the directory */ |
391 | 0 | papszSiblingFiles = nullptr; |
392 | 0 | bHasGotSiblingFiles = true; |
393 | 0 | } |
394 | 0 | else |
395 | 0 | { |
396 | | /* will be lazy loaded */ |
397 | 0 | papszSiblingFiles = nullptr; |
398 | 0 | bHasGotSiblingFiles = false; |
399 | 0 | } |
400 | 0 | } |
401 | 0 | } |
402 | 0 | else |
403 | 0 | { |
404 | 0 | papszSiblingFiles = nullptr; |
405 | 0 | bHasGotSiblingFiles = true; |
406 | 0 | } |
407 | 0 | } |
408 | | |
409 | | /************************************************************************/ |
410 | | /* ~GDALOpenInfo() */ |
411 | | /************************************************************************/ |
412 | | |
413 | | GDALOpenInfo::~GDALOpenInfo() |
414 | | |
415 | 0 | { |
416 | 0 | VSIFree(pabyHeader); |
417 | 0 | CPLFree(pszFilename); |
418 | |
|
419 | 0 | if (fpL != nullptr) |
420 | 0 | CPL_IGNORE_RET_VAL(VSIFCloseL(fpL)); |
421 | 0 | CSLDestroy(papszSiblingFiles); |
422 | 0 | } |
423 | | |
424 | | /************************************************************************/ |
425 | | /* GetSiblingFiles() */ |
426 | | /************************************************************************/ |
427 | | |
428 | | /** Return sibling files. |
429 | | * |
430 | | * If the list of sibling files has not already been established, it will be, |
431 | | * unless the GDAL_DISABLE_READDIR_ON_OPEN configuration option has been set to |
432 | | * YES or EMPTY_DIR when this instance was constructed. |
433 | | * |
434 | | * @return sibling files. Ownership belongs to "this". |
435 | | */ |
436 | | char **GDALOpenInfo::GetSiblingFiles() |
437 | 0 | { |
438 | 0 | if (bHasGotSiblingFiles) |
439 | 0 | return papszSiblingFiles; |
440 | 0 | bHasGotSiblingFiles = true; |
441 | |
|
442 | 0 | papszSiblingFiles = VSISiblingFiles(pszFilename); |
443 | 0 | if (papszSiblingFiles != nullptr) |
444 | 0 | { |
445 | 0 | return papszSiblingFiles; |
446 | 0 | } |
447 | | |
448 | 0 | const CPLString osDir = CPLGetDirnameSafe(pszFilename); |
449 | 0 | const int nMaxFiles = atoi(VSIGetPathSpecificOption( |
450 | 0 | pszFilename, "GDAL_READDIR_LIMIT_ON_OPEN", "1000")); |
451 | 0 | papszSiblingFiles = VSIReadDirEx(osDir, nMaxFiles); |
452 | 0 | if (nMaxFiles > 0 && CSLCount(papszSiblingFiles) > nMaxFiles) |
453 | 0 | { |
454 | 0 | CPLDebug("GDAL", "GDAL_READDIR_LIMIT_ON_OPEN reached on %s", |
455 | 0 | osDir.c_str()); |
456 | 0 | CSLDestroy(papszSiblingFiles); |
457 | 0 | papszSiblingFiles = nullptr; |
458 | 0 | } |
459 | |
|
460 | 0 | return papszSiblingFiles; |
461 | 0 | } |
462 | | |
463 | | /************************************************************************/ |
464 | | /* StealSiblingFiles() */ |
465 | | /* */ |
466 | | /* Same as GetSiblingFiles() except that the list is stealed */ |
467 | | /* (ie ownership transferred to the caller) and the associated */ |
468 | | /* member variable is set to NULL. */ |
469 | | /************************************************************************/ |
470 | | |
471 | | /** Return sibling files and steal reference |
472 | | * @return sibling files. Ownership below to the caller (must be freed with |
473 | | * CSLDestroy) |
474 | | */ |
475 | | char **GDALOpenInfo::StealSiblingFiles() |
476 | 0 | { |
477 | 0 | char **papszRet = GetSiblingFiles(); |
478 | 0 | papszSiblingFiles = nullptr; |
479 | 0 | return papszRet; |
480 | 0 | } |
481 | | |
482 | | /************************************************************************/ |
483 | | /* AreSiblingFilesLoaded() */ |
484 | | /************************************************************************/ |
485 | | |
486 | | /** Return whether sibling files have been loaded. |
487 | | * @return true or false. |
488 | | */ |
489 | | bool GDALOpenInfo::AreSiblingFilesLoaded() const |
490 | 0 | { |
491 | 0 | return bHasGotSiblingFiles; |
492 | 0 | } |
493 | | |
494 | | /************************************************************************/ |
495 | | /* TryToIngest() */ |
496 | | /************************************************************************/ |
497 | | |
498 | | /** Ingest bytes from the file. |
499 | | * @param nBytes number of bytes to ingest. |
500 | | * @return TRUE if successful |
501 | | */ |
502 | | int GDALOpenInfo::TryToIngest(int nBytes) |
503 | 0 | { |
504 | 0 | if (fpL == nullptr) |
505 | 0 | return FALSE; |
506 | 0 | if (nHeaderBytes < nHeaderBytesTried) |
507 | 0 | return TRUE; |
508 | 0 | pabyHeader = static_cast<GByte *>(CPLRealloc(pabyHeader, nBytes + 1)); |
509 | 0 | memset(pabyHeader, 0, nBytes + 1); |
510 | 0 | VSIRewindL(fpL); |
511 | 0 | nHeaderBytesTried = nBytes; |
512 | 0 | nHeaderBytes = static_cast<int>(VSIFReadL(pabyHeader, 1, nBytes, fpL)); |
513 | 0 | VSIRewindL(fpL); |
514 | |
|
515 | 0 | return TRUE; |
516 | 0 | } |
517 | | |
518 | | /************************************************************************/ |
519 | | /* IsSingleAllowedDriver() */ |
520 | | /************************************************************************/ |
521 | | |
522 | | /** Returns true if the driver name is the single in the list of allowed |
523 | | * drivers. |
524 | | * |
525 | | * @param pszDriverName Driver name to test. |
526 | | * @return true if the driver name is the single in the list of allowed |
527 | | * drivers. |
528 | | * @since GDAL 3.10 |
529 | | */ |
530 | | bool GDALOpenInfo::IsSingleAllowedDriver(const char *pszDriverName) const |
531 | 0 | { |
532 | 0 | return papszAllowedDrivers && papszAllowedDrivers[0] && |
533 | 0 | !papszAllowedDrivers[1] && |
534 | 0 | EQUAL(papszAllowedDrivers[0], pszDriverName); |
535 | 0 | } |