Line data Source code
1 : /******************************************************************************
2 : * Purpose: Racurs PHOTOMOD tiled format reader (http://www.racurs.ru)
3 : * Author: Andrew Sudorgin (drons [a] list dot ru)
4 : ******************************************************************************
5 : * Copyright (c) 2016, Andrew Sudorgin
6 : *
7 : * Permission is hereby granted, free of charge, to any person obtaining a
8 : * copy of this software and associated documentation files (the "Software"),
9 : * to deal in the Software without restriction, including without limitation
10 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 : * and/or sell copies of the Software, and to permit persons to whom the
12 : * Software is furnished to do so, subject to the following conditions:
13 : *
14 : * The above copyright notice and this permission notice shall be included
15 : * in all copies or substantial portions of the Software.
16 : *
17 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 : * DEALINGS IN THE SOFTWARE.
24 : ****************************************************************************/
25 :
26 : #include "cpl_minixml.h"
27 : #include "gdal.h"
28 : #include "gdal_priv.h"
29 : #include "gdal_proxy.h"
30 : #include "../vrt/vrtdataset.h"
31 :
32 : enum ph_format
33 : {
34 : ph_megatiff,
35 : ph_xdem
36 : };
37 :
38 : #define PH_PRF_DRIVER "PRF"
39 : #define PH_PRF_EXT "prf"
40 : #define PH_DEM_EXT "x-dem"
41 : #define PH_GEOREF_SHIFT_Y (1.0)
42 :
43 : class PhPrfBand final : public VRTSourcedRasterBand
44 : {
45 : std::vector<GDALRasterBand *> osOverview;
46 :
47 : public:
48 7 : PhPrfBand(GDALDataset *poDataset, int nBandCount, GDALDataType eType,
49 : int nXSize, int nYSize)
50 7 : : VRTSourcedRasterBand(poDataset, nBandCount, eType, nXSize, nYSize)
51 : {
52 7 : }
53 :
54 3 : void AddOverview(GDALRasterBand *ov)
55 : {
56 3 : osOverview.push_back(ov);
57 3 : }
58 :
59 2 : int GetOverviewCount() override
60 : {
61 2 : if (!osOverview.empty())
62 : {
63 1 : return static_cast<int>(osOverview.size());
64 : }
65 : else
66 : {
67 1 : return VRTSourcedRasterBand::GetOverviewCount();
68 : }
69 : }
70 :
71 1 : GDALRasterBand *GetOverview(int i) override
72 : {
73 1 : size_t n = static_cast<size_t>(i);
74 1 : if (n < osOverview.size())
75 : {
76 1 : return osOverview[n];
77 : }
78 : else
79 : {
80 0 : return VRTSourcedRasterBand::GetOverview(i);
81 : }
82 : }
83 : };
84 :
85 : class PhPrfDataset final : public VRTDataset
86 : {
87 : std::vector<GDALDataset *> osSubTiles;
88 :
89 : public:
90 : PhPrfDataset(GDALAccess eAccess, int nSizeX, int nSizeY, int nBandCount,
91 : GDALDataType eType, const char *pszName);
92 : ~PhPrfDataset();
93 : bool AddTile(const char *pszPartName, GDALAccess eAccess, int nWidth,
94 : int nHeight, int nOffsetX, int nOffsetY, int nScale);
95 : int CloseDependentDatasets() override;
96 : static int Identify(GDALOpenInfo *poOpenInfo);
97 : static GDALDataset *Open(GDALOpenInfo *poOpenInfo);
98 : };
99 :
100 7 : PhPrfDataset::PhPrfDataset(GDALAccess _eAccess, int nSizeX, int nSizeY,
101 : int nBandCount, GDALDataType eType,
102 7 : const char *pszName)
103 7 : : VRTDataset(nSizeX, nSizeY)
104 : {
105 7 : poDriver = (GDALDriver *)GDALGetDriverByName(PH_PRF_DRIVER);
106 7 : eAccess = _eAccess;
107 7 : SetWritable(FALSE); // Avoid rewrite of *.prf file with 'vrt' file
108 7 : SetDescription(pszName);
109 :
110 14 : for (int i = 0; i != nBandCount; ++i)
111 : {
112 7 : PhPrfBand *poBand = new PhPrfBand(this, i + 1, eType, nSizeX, nSizeY);
113 7 : SetBand(i + 1, poBand);
114 : }
115 7 : }
116 :
117 14 : PhPrfDataset::~PhPrfDataset()
118 : {
119 7 : PhPrfDataset::CloseDependentDatasets();
120 14 : }
121 :
122 39 : bool PhPrfDataset::AddTile(const char *pszPartName, GDALAccess eAccessType,
123 : int nWidth, int nHeight, int nOffsetX, int nOffsetY,
124 : int nScale)
125 : {
126 : GDALProxyPoolDataset *poTileDataset;
127 39 : poTileDataset = new GDALProxyPoolDataset(pszPartName, nWidth, nHeight,
128 39 : eAccessType, FALSE);
129 :
130 78 : for (int nBand = 1; nBand != GetRasterCount() + 1; ++nBand)
131 : {
132 39 : PhPrfBand *poBand = dynamic_cast<PhPrfBand *>(GetRasterBand(nBand));
133 :
134 39 : if (poBand == nullptr)
135 : {
136 0 : delete poTileDataset;
137 0 : return false;
138 : }
139 :
140 : // Block sizes (nBlockXSize&nBlockYSize) passed as zeros.
141 : // They will be loaded when RefUnderlyingRasterBand
142 : // function is called on first open of tile's dataset 'poTileDataset'.
143 39 : poTileDataset->AddSrcBandDescription(poBand->GetRasterDataType(), 0, 0);
144 39 : GDALRasterBand *poTileBand = poTileDataset->GetRasterBand(nBand);
145 :
146 39 : if (0 == nScale)
147 : {
148 36 : poBand->AddSimpleSource(poTileBand, 0, 0, nWidth, nHeight, nOffsetX,
149 : nOffsetY, nWidth, nHeight);
150 : }
151 : else
152 : {
153 3 : poBand->AddOverview(poTileBand);
154 : }
155 : }
156 :
157 39 : osSubTiles.push_back(poTileDataset);
158 :
159 39 : return true;
160 : }
161 :
162 7 : int PhPrfDataset::CloseDependentDatasets()
163 : {
164 7 : int bDroppedRef = VRTDataset::CloseDependentDatasets();
165 46 : for (std::vector<GDALDataset *>::iterator ii(osSubTiles.begin());
166 46 : ii != osSubTiles.end(); ++ii)
167 : {
168 39 : delete (*ii);
169 39 : bDroppedRef = TRUE;
170 : }
171 7 : osSubTiles.clear();
172 7 : return bDroppedRef;
173 : }
174 :
175 47956 : int PhPrfDataset::Identify(GDALOpenInfo *poOpenInfo)
176 : {
177 47956 : if (poOpenInfo->pabyHeader == nullptr || poOpenInfo->nHeaderBytes < 20)
178 : {
179 45312 : return FALSE;
180 : }
181 :
182 2644 : if (strstr(reinterpret_cast<char *>(poOpenInfo->pabyHeader), "phini") ==
183 : nullptr)
184 : {
185 2637 : return FALSE;
186 : }
187 :
188 7 : if (EQUAL(CPLGetExtension(poOpenInfo->pszFilename), PH_PRF_EXT))
189 : {
190 4 : return TRUE;
191 : }
192 3 : else if (EQUAL(CPLGetExtension(poOpenInfo->pszFilename), PH_DEM_EXT))
193 : {
194 3 : return TRUE;
195 : }
196 :
197 0 : return FALSE;
198 : }
199 :
200 745 : static void GetXmlNameValuePair(const CPLXMLNode *psElt, CPLString &osName,
201 : CPLString &osValue)
202 : {
203 2079 : for (const CPLXMLNode *psAttr = psElt->psChild; psAttr != nullptr;
204 1334 : psAttr = psAttr->psNext)
205 : {
206 1334 : if (psAttr->eType != CXT_Attribute || psAttr->pszValue == nullptr ||
207 819 : psAttr->psChild == nullptr || psAttr->psChild->pszValue == nullptr)
208 : {
209 515 : continue;
210 : }
211 819 : if (EQUAL(psAttr->pszValue, "n"))
212 : {
213 438 : osName = psAttr->psChild->pszValue;
214 : }
215 381 : else if (EQUAL(psAttr->pszValue, "v"))
216 : {
217 381 : osValue = psAttr->psChild->pszValue;
218 : }
219 : }
220 745 : }
221 :
222 39 : static CPLString GetXmlAttribute(const CPLXMLNode *psElt,
223 : const CPLString &osAttrName,
224 : const CPLString &osDef = CPLString())
225 : {
226 39 : for (const CPLXMLNode *psAttr = psElt->psChild; psAttr != nullptr;
227 0 : psAttr = psAttr->psNext)
228 : {
229 39 : if (psAttr->eType != CXT_Attribute || psAttr->pszValue == nullptr ||
230 39 : psAttr->psChild == nullptr || psAttr->psChild->pszValue == nullptr)
231 : {
232 0 : continue;
233 : }
234 39 : if (EQUAL(psAttr->pszValue, osAttrName))
235 : {
236 39 : return psAttr->psChild->pszValue;
237 : }
238 : }
239 0 : return osDef;
240 : }
241 :
242 4 : static bool ParseGeoref(const CPLXMLNode *psGeorefElt, double *padfGeoTrans)
243 : {
244 4 : bool abOk[6] = {false, false, false, false, false, false};
245 : static const char *const apszGeoKeys[6] = {"A_0", "A_1", "A_2",
246 : "B_0", "B_1", "B_2"};
247 32 : for (const CPLXMLNode *elt = psGeorefElt->psChild; elt != nullptr;
248 28 : elt = elt->psNext)
249 : {
250 56 : CPLString osName;
251 56 : CPLString osValue;
252 28 : GetXmlNameValuePair(elt, osName, osValue);
253 196 : for (int k = 0; k != 6; ++k)
254 : {
255 168 : if (EQUAL(osName, apszGeoKeys[k]))
256 : {
257 24 : padfGeoTrans[k] = CPLAtof(osValue);
258 24 : abOk[k] = true;
259 : }
260 : }
261 : }
262 :
263 24 : for (int k = 0; k != 6; ++k)
264 : {
265 24 : if (!abOk[k])
266 : {
267 0 : break;
268 : }
269 24 : if (k == 5)
270 : {
271 4 : padfGeoTrans[3] -= PH_GEOREF_SHIFT_Y * padfGeoTrans[4];
272 4 : padfGeoTrans[3] -= PH_GEOREF_SHIFT_Y * padfGeoTrans[5];
273 4 : return true;
274 : }
275 : }
276 0 : return false;
277 : }
278 :
279 3 : static bool ParseDemShift(const CPLXMLNode *psDemShiftElt, double *padfDemShift)
280 : {
281 3 : bool abOk[6] = {false, false, false, false, false, false};
282 : static const char *const apszDemShiftKeys[6] = {"x", "y", "z", "", "", ""};
283 :
284 15 : for (const CPLXMLNode *elt = psDemShiftElt->psChild; elt != nullptr;
285 12 : elt = elt->psNext)
286 : {
287 24 : CPLString osName;
288 24 : CPLString osValue;
289 12 : GetXmlNameValuePair(elt, osName, osValue);
290 48 : for (int k = 0; k != 3; ++k)
291 : {
292 36 : if (EQUAL(osName, apszDemShiftKeys[k]))
293 : {
294 9 : padfDemShift[k] = CPLAtof(osValue);
295 9 : abOk[k] = true;
296 : }
297 : }
298 : }
299 3 : return abOk[0] && abOk[1] && abOk[2];
300 : }
301 :
302 7 : static GDALDataType ParseChannelsInfo(const CPLXMLNode *psElt)
303 : {
304 14 : CPLString osType;
305 14 : CPLString osBytesPS;
306 14 : CPLString osChannels;
307 :
308 35 : for (const CPLXMLNode *psChild = psElt->psChild; psChild != nullptr;
309 28 : psChild = psChild->psNext)
310 : {
311 28 : if (psChild->eType != CXT_Element)
312 : {
313 7 : continue;
314 : }
315 :
316 42 : CPLString osName;
317 42 : CPLString osValue;
318 :
319 21 : GetXmlNameValuePair(psChild, osName, osValue);
320 :
321 21 : if (EQUAL(osName, "type"))
322 : {
323 7 : osType = std::move(osValue);
324 : }
325 14 : else if (EQUAL(osName, "bytes_ps"))
326 : {
327 7 : osBytesPS = std::move(osValue);
328 : }
329 7 : else if (EQUAL(osName, "channels"))
330 : {
331 7 : osChannels = std::move(osValue);
332 : }
333 : }
334 :
335 7 : const int nDataTypeSize = atoi(osBytesPS);
336 7 : if (osType == "U")
337 : {
338 4 : switch (nDataTypeSize)
339 : {
340 0 : case 1:
341 0 : return GDT_Byte;
342 4 : case 2:
343 4 : return GDT_UInt16;
344 0 : case 4:
345 0 : return GDT_UInt32;
346 0 : default:
347 0 : CPLError(CE_Failure, CPLE_OpenFailed,
348 : "Unsupported datatype size %d", nDataTypeSize);
349 0 : return GDT_Unknown;
350 : }
351 : }
352 3 : else if (osType == "F")
353 : {
354 3 : switch (nDataTypeSize)
355 : {
356 3 : case 4:
357 3 : return GDT_Float32;
358 0 : case 8:
359 0 : return GDT_Float64;
360 0 : default:
361 0 : CPLError(CE_Failure, CPLE_OpenFailed,
362 : "Unsupported datatype size %d", nDataTypeSize);
363 0 : return GDT_Unknown;
364 : }
365 : }
366 :
367 0 : return GDT_Unknown;
368 : }
369 :
370 7 : GDALDataset *PhPrfDataset::Open(GDALOpenInfo *poOpenInfo)
371 : {
372 : ph_format eFormat;
373 :
374 7 : if (EQUAL(CPLGetExtension(poOpenInfo->pszFilename), PH_PRF_EXT))
375 : {
376 4 : eFormat = ph_megatiff;
377 : }
378 3 : else if (EQUAL(CPLGetExtension(poOpenInfo->pszFilename), PH_DEM_EXT))
379 : {
380 3 : eFormat = ph_xdem;
381 : }
382 : else
383 : {
384 0 : return nullptr;
385 : }
386 :
387 14 : CPLXMLTreeCloser oDoc(CPLParseXMLFile(poOpenInfo->pszFilename));
388 :
389 7 : if (oDoc.get() == nullptr)
390 : {
391 0 : return nullptr;
392 : }
393 :
394 7 : const CPLXMLNode *psPhIni(CPLSearchXMLNode(oDoc.get(), "=phini"));
395 7 : if (psPhIni == nullptr)
396 : {
397 0 : return nullptr;
398 : }
399 :
400 7 : int nSizeX = 0;
401 7 : int nSizeY = 0;
402 7 : int nBandCount = 0;
403 7 : GDALDataType eResultDatatype = GDT_Unknown;
404 14 : CPLString osPartsBasePath(CPLGetPath(poOpenInfo->pszFilename));
405 14 : CPLString osPartsPath(osPartsBasePath + "/" +
406 21 : CPLGetBasename(poOpenInfo->pszFilename));
407 14 : CPLString osPartsExt;
408 7 : double adfGeoTrans[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
409 7 : bool bGeoTransOk = false;
410 :
411 7 : double adfDemShift[3] = {0.0, 0.0, 0.0};
412 7 : bool bDemShiftOk = false;
413 7 : const int nDemMDCount = 7;
414 7 : bool abDemMetadataOk[nDemMDCount] = {false, false, false, false,
415 : false, false, false};
416 7 : double adfDemMetadata[nDemMDCount] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
417 : static const char *const apszDemKeys[nDemMDCount] = {
418 : "XR_0", "XR_1", "YR_0", "YR_1", "ZR_0", "ZR_1", "BadZ"};
419 7 : if (eFormat == ph_megatiff)
420 : {
421 4 : osPartsExt = ".tif";
422 : }
423 3 : else if (eFormat == ph_xdem)
424 : {
425 3 : osPartsExt = ".demtif";
426 : }
427 :
428 187 : for (const CPLXMLNode *psElt = psPhIni->psChild; psElt != nullptr;
429 180 : psElt = psElt->psNext)
430 : {
431 180 : if (!EQUAL(psElt->pszValue, "s") || psElt->eType != CXT_Element)
432 : {
433 176 : continue;
434 : }
435 :
436 8 : CPLString osName;
437 8 : CPLString osValue;
438 :
439 4 : GetXmlNameValuePair(psElt, osName, osValue);
440 :
441 4 : if (EQUAL(osName, "parts_ext"))
442 : {
443 4 : osPartsExt = "." + osValue;
444 : }
445 : }
446 :
447 187 : for (const CPLXMLNode *psElt = psPhIni->psChild; psElt != nullptr;
448 180 : psElt = psElt->psNext)
449 : {
450 360 : CPLString osName;
451 360 : CPLString osValue;
452 :
453 180 : GetXmlNameValuePair(psElt, osName, osValue);
454 :
455 180 : if (EQUAL(osName, "ChannelsInfo"))
456 : {
457 7 : eResultDatatype = ParseChannelsInfo(psElt);
458 : }
459 173 : else if (EQUAL(osName, "Width"))
460 : {
461 7 : nSizeX = atoi(osValue);
462 : }
463 166 : else if (EQUAL(osName, "Height"))
464 : {
465 7 : nSizeY = atoi(osValue);
466 : }
467 159 : else if (EQUAL(osName, "QChans"))
468 : {
469 7 : nBandCount = atoi(osValue);
470 : }
471 152 : else if (EQUAL(osName, "GeoRef"))
472 : {
473 4 : bGeoTransOk = ParseGeoref(psElt, adfGeoTrans);
474 : }
475 148 : else if (EQUAL(osName, "DemShift"))
476 : {
477 3 : bDemShiftOk = ParseDemShift(psElt, adfDemShift);
478 : }
479 : else
480 : {
481 1160 : for (int n = 0; n != nDemMDCount; ++n)
482 : {
483 1015 : if (EQUAL(osName, apszDemKeys[n]))
484 : {
485 21 : adfDemMetadata[n] = CPLAtof(osValue);
486 21 : abDemMetadataOk[n] = true;
487 : }
488 : }
489 : }
490 : }
491 :
492 7 : if (eResultDatatype == GDT_Unknown)
493 : {
494 0 : CPLError(CE_Failure, CPLE_OpenFailed,
495 : "GDAL Dataset datatype not found");
496 0 : return nullptr;
497 : }
498 :
499 7 : if (nSizeX <= 0 || nSizeY <= 0 || nBandCount <= 0)
500 : {
501 0 : return nullptr;
502 : }
503 :
504 : PhPrfDataset *poDataset =
505 : new PhPrfDataset(GA_ReadOnly, nSizeX, nSizeY, nBandCount,
506 7 : eResultDatatype, poOpenInfo->pszFilename);
507 :
508 7 : if (!GDALCheckDatasetDimensions(poDataset->GetRasterXSize(),
509 : poDataset->GetRasterYSize()))
510 : {
511 0 : delete poDataset;
512 0 : return nullptr;
513 : }
514 :
515 187 : for (const CPLXMLNode *psElt = psPhIni->psChild; psElt != nullptr;
516 180 : psElt = psElt->psNext)
517 : {
518 180 : int nWidth = 0;
519 180 : int nHeight = 0;
520 180 : int nOffsetX = 0;
521 180 : int nOffsetY = 0;
522 180 : int nScale = 0;
523 :
524 680 : for (const CPLXMLNode *psItem = psElt->psChild; psItem != nullptr;
525 500 : psItem = psItem->psNext)
526 : {
527 1000 : CPLString osName;
528 1000 : CPLString osValue;
529 :
530 500 : GetXmlNameValuePair(psItem, osName, osValue);
531 :
532 500 : if (EQUAL(osName, "Width"))
533 : {
534 39 : nWidth = atoi(osValue);
535 : }
536 461 : else if (EQUAL(osName, "Height"))
537 : {
538 39 : nHeight = atoi(osValue);
539 : }
540 422 : else if (EQUAL(osName, "DispX"))
541 : {
542 36 : nOffsetX = atoi(osValue);
543 : }
544 386 : else if (EQUAL(osName, "DispY"))
545 : {
546 36 : nOffsetY = atoi(osValue);
547 : }
548 350 : else if (EQUAL(osName, "Scale"))
549 : {
550 3 : nScale = atoi(osValue);
551 : }
552 : }
553 :
554 180 : if (nWidth == 0 || nHeight == 0)
555 : {
556 141 : continue;
557 : }
558 :
559 78 : CPLString osPartName(osPartsPath + "/" + GetXmlAttribute(psElt, "n") +
560 39 : osPartsExt);
561 :
562 39 : if (!poDataset->AddTile(osPartName, GA_ReadOnly, nWidth, nHeight,
563 : nOffsetX, nOffsetY, nScale))
564 : {
565 0 : delete poDataset;
566 0 : return nullptr;
567 : }
568 : }
569 :
570 7 : if (eFormat == ph_megatiff && bGeoTransOk)
571 : {
572 4 : poDataset->SetGeoTransform(adfGeoTrans);
573 : }
574 :
575 7 : if (eFormat == ph_xdem)
576 : {
577 3 : GDALRasterBand *poFirstBand = poDataset->GetRasterBand(1);
578 :
579 3 : if (poFirstBand != nullptr)
580 : {
581 3 : poFirstBand->SetUnitType("m"); // Always meters.
582 : }
583 :
584 3 : if (abDemMetadataOk[0] && abDemMetadataOk[1] && abDemMetadataOk[2] &&
585 3 : abDemMetadataOk[3] && nSizeX > 1 && nSizeY > 1)
586 : {
587 3 : adfGeoTrans[0] = adfDemMetadata[0];
588 3 : adfGeoTrans[1] =
589 3 : (adfDemMetadata[1] - adfDemMetadata[0]) / (nSizeX - 1);
590 3 : adfGeoTrans[2] = 0;
591 3 : adfGeoTrans[3] = adfDemMetadata[3];
592 3 : adfGeoTrans[4] = 0;
593 3 : adfGeoTrans[5] =
594 3 : (adfDemMetadata[2] - adfDemMetadata[3]) / (nSizeY - 1);
595 :
596 3 : adfGeoTrans[0] -= 0.5 * adfGeoTrans[1];
597 3 : adfGeoTrans[3] -= 0.5 * adfGeoTrans[5];
598 :
599 3 : if (bDemShiftOk)
600 : {
601 3 : adfGeoTrans[0] += adfDemShift[0];
602 3 : adfGeoTrans[3] += adfDemShift[1];
603 : }
604 :
605 3 : poDataset->SetGeoTransform(adfGeoTrans);
606 : }
607 :
608 3 : if (abDemMetadataOk[4] && abDemMetadataOk[5])
609 : {
610 3 : poFirstBand->SetMetadataItem("STATISTICS_MINIMUM",
611 3 : CPLSPrintf("%f", adfDemMetadata[4]));
612 3 : poFirstBand->SetMetadataItem("STATISTICS_MAXIMUM",
613 3 : CPLSPrintf("%f", adfDemMetadata[5]));
614 : }
615 :
616 3 : if (abDemMetadataOk[6])
617 : {
618 3 : poFirstBand->SetNoDataValue(adfDemMetadata[6]);
619 : }
620 :
621 3 : if (bDemShiftOk)
622 : {
623 3 : poFirstBand->SetOffset(adfDemShift[2]);
624 : }
625 : }
626 :
627 7 : const char *pszPrj = CPLResetExtension(poOpenInfo->pszFilename, "prj");
628 7 : VSILFILE *const fp = VSIFOpenL(pszPrj, "rt");
629 7 : if (fp != nullptr)
630 : {
631 3 : const size_t nBufMax = 100000;
632 3 : char *const pszWKT = static_cast<char *>(CPLMalloc(nBufMax));
633 3 : const size_t nBytes = VSIFReadL(pszWKT, 1, nBufMax - 1, fp);
634 3 : VSIFCloseL(fp);
635 3 : if (nBytes > 0 && nBytes < nBufMax - 1)
636 : {
637 3 : auto poSRS = new OGRSpatialReference();
638 3 : poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
639 3 : pszWKT[nBytes] = '\0';
640 3 : if (poSRS->importFromWkt(pszWKT) == OGRERR_NONE)
641 : {
642 3 : poDataset->SetSpatialRef(poSRS);
643 : }
644 3 : delete poSRS;
645 : }
646 3 : CPLFree(pszWKT);
647 : }
648 :
649 7 : return poDataset;
650 : }
651 :
652 1512 : void GDALRegister_PRF()
653 : {
654 1512 : if (GDALGetDriverByName(PH_PRF_DRIVER) != nullptr)
655 295 : return;
656 :
657 1217 : GDALDriver *poDriver = new GDALDriver;
658 :
659 1217 : poDriver->SetDescription(PH_PRF_DRIVER);
660 1217 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Racurs PHOTOMOD PRF");
661 1217 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
662 1217 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
663 1217 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "prf");
664 1217 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/prf.html");
665 1217 : poDriver->pfnIdentify = PhPrfDataset::Identify;
666 1217 : poDriver->pfnOpen = PhPrfDataset::Open;
667 1217 : GDALRegisterDriver((GDALDriverH)poDriver);
668 : }
|