1 /******************************************************************************
2 *
3 * Project: Azavea Raster Grid format driver.
4 * Purpose: Implements support for reading and writing Azavea Raster Grid
5 * format.
6 * Author: David Zwarg <dzwarg@azavea.com>
7 *
8 ******************************************************************************
9 * Copyright (c) 2012, David Zwarg <dzwarg@azavea.com>
10 * Copyright (c) 2012-2013, Even Rouault <even dot rouault at spatialys.com>
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a
13 * copy of this software and associated documentation files (the "Software"),
14 * to deal in the Software without restriction, including without limitation
15 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 * and/or sell copies of the Software, and to permit persons to whom the
17 * Software is furnished to do so, subject to the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included
20 * in all copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 * DEALINGS IN THE SOFTWARE.
29 ****************************************************************************/
30
31 #include "cpl_string.h"
32 #include "gdal_frmts.h"
33 #include "ogr_spatialref.h"
34 #include "rawdataset.h"
35
36 #include "ogrgeojsonreader.h"
37 #include <limits>
38
39 CPL_CVSID("$Id: argdataset.cpp f6099e5ed704166bf5cc113a053dd1b2725cb391 2020-03-22 11:20:10 +0100 Kai Pastor $")
40
41 /************************************************************************/
42 /* ==================================================================== */
43 /* ARGDataset */
44 /* ==================================================================== */
45 /************************************************************************/
46
47 class ARGDataset final: public RawDataset
48 {
49 VSILFILE *fpImage; // image data file.
50 double adfGeoTransform[6];
51 char *pszFilename;
52
53 public:
54 ARGDataset();
55 ~ARGDataset() override;
56
57 CPLErr GetGeoTransform( double * padfTransform ) override;
58
59 static int Identify( GDALOpenInfo * );
60 static GDALDataset *Open( GDALOpenInfo * );
61 static GDALDataset *CreateCopy( const char *, GDALDataset *, int,
62 char **, GDALProgressFunc, void *);
63 char **GetFileList(void) override;
64 };
65
66 /************************************************************************/
67 /* ARGDataset() */
68 /************************************************************************/
69
ARGDataset()70 ARGDataset::ARGDataset() :
71 fpImage(nullptr),
72 pszFilename(nullptr)
73 {
74 adfGeoTransform[0] = 0.0;
75 adfGeoTransform[1] = 1.0;
76 adfGeoTransform[2] = 0.0;
77 adfGeoTransform[3] = 0.0;
78 adfGeoTransform[4] = 0.0;
79 adfGeoTransform[5] = 1.0;
80 }
81
82 /************************************************************************/
83 /* ~ARGDataset() */
84 /************************************************************************/
85
~ARGDataset()86 ARGDataset::~ARGDataset()
87
88 {
89 CPLFree(pszFilename);
90
91 FlushCache();
92 if( fpImage != nullptr )
93 VSIFCloseL( fpImage );
94 }
95
96 /************************************************************************/
97 /* GetGeoTransform() */
98 /************************************************************************/
99
GetGeoTransform(double * padfTransform)100 CPLErr ARGDataset::GetGeoTransform( double * padfTransform )
101
102 {
103 memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
104
105 return CE_None;
106 }
107
108 /************************************************************************/
109 /* GetJsonFilename() */
110 /************************************************************************/
GetJsonFilename(CPLString pszFilename)111 static CPLString GetJsonFilename(CPLString pszFilename)
112 {
113 return CPLSPrintf( "%s/%s.json", CPLGetDirname(pszFilename),
114 CPLGetBasename(pszFilename) );
115 }
116
117 /************************************************************************/
118 /* GetJsonObject() */
119 /************************************************************************/
GetJsonObject(CPLString pszFilename)120 static json_object * GetJsonObject(CPLString pszFilename)
121 {
122 CPLString osJSONFilename = GetJsonFilename(pszFilename);
123
124 json_object *pJSONObject =
125 json_object_from_file(const_cast<char *>(osJSONFilename.c_str()));
126 if (pJSONObject == nullptr) {
127 CPLDebug("ARGDataset", "GetJsonObject(): Could not parse JSON file.");
128 return nullptr;
129 }
130
131 return pJSONObject;
132 }
133
134 /************************************************************************/
135 /* GetJsonValueStr() */
136 /************************************************************************/
GetJsonValueStr(json_object * pJSONObject,CPLString pszKey)137 static const char *GetJsonValueStr( json_object * pJSONObject,
138 CPLString pszKey )
139 {
140 json_object *pJSONItem =
141 CPL_json_object_object_get(pJSONObject, pszKey.c_str());
142 if( pJSONItem == nullptr )
143 {
144 CPLDebug("ARGDataset", "GetJsonValueStr(): "
145 "Could not find '%s' in JSON.", pszKey.c_str());
146 return nullptr;
147 }
148
149 return json_object_get_string(pJSONItem);
150 }
151
152 /************************************************************************/
153 /* GetJsonValueDbl() */
154 /************************************************************************/
GetJsonValueDbl(json_object * pJSONObject,CPLString pszKey)155 static double GetJsonValueDbl( json_object * pJSONObject, CPLString pszKey )
156 {
157 const char *pszJSONStr = GetJsonValueStr(pJSONObject, pszKey.c_str());
158 if (pszJSONStr == nullptr) {
159 return std::numeric_limits<double>::quiet_NaN();
160 }
161 char *pszTmp = const_cast<char *>(pszJSONStr);
162 double dfTmp = CPLStrtod(pszJSONStr, &pszTmp);
163 if (pszTmp == pszJSONStr) {
164 CPLDebug("ARGDataset", "GetJsonValueDbl(): "
165 "Key value is not a numeric value: %s:%s",
166 pszKey.c_str(), pszTmp);
167 return std::numeric_limits<double>::quiet_NaN();
168 }
169
170 return dfTmp;
171 }
172
173 /************************************************************************/
174 /* GetJsonValueInt() */
175 /************************************************************************/
GetJsonValueInt(json_object * pJSONObject,CPLString pszKey)176 static int GetJsonValueInt( json_object *pJSONObject, CPLString pszKey )
177 {
178 const double dfTmp = GetJsonValueDbl(pJSONObject, pszKey.c_str());
179 if (CPLIsNan(dfTmp)) {
180 return -1;
181 }
182
183 return static_cast<int>(dfTmp);
184 }
185
186 /************************************************************************/
187 /* GetFileList() */
188 /************************************************************************/
GetFileList()189 char **ARGDataset::GetFileList()
190 {
191 char **papszFileList = GDALPamDataset::GetFileList();
192 CPLString osJSONFilename = GetJsonFilename(pszFilename);
193
194 papszFileList = CSLAddString( papszFileList, osJSONFilename );
195
196 return papszFileList;
197 }
198
199 /************************************************************************/
200 /* Identify() */
201 /************************************************************************/
202
Identify(GDALOpenInfo * poOpenInfo)203 int ARGDataset::Identify( GDALOpenInfo *poOpenInfo )
204 {
205 #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
206 if (!EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "arg")) {
207 return FALSE;
208 }
209 #endif
210
211 json_object *pJSONObject = GetJsonObject(poOpenInfo->pszFilename);
212 if (pJSONObject == nullptr) {
213 return FALSE;
214 }
215
216 json_object_put(pJSONObject);
217 pJSONObject = nullptr;
218
219 return TRUE;
220 }
221
222 /************************************************************************/
223 /* Open() */
224 /************************************************************************/
Open(GDALOpenInfo * poOpenInfo)225 GDALDataset *ARGDataset::Open( GDALOpenInfo *poOpenInfo )
226 {
227 if ( !Identify( poOpenInfo ) || poOpenInfo->fpL == nullptr )
228 return nullptr;
229
230 /* -------------------------------------------------------------------- */
231 /* Confirm the requested access is supported. */
232 /* -------------------------------------------------------------------- */
233 if( poOpenInfo->eAccess == GA_Update )
234 {
235 CPLError( CE_Failure, CPLE_NotSupported,
236 "The ARG driver does not support update access to existing"
237 " datasets." );
238 return nullptr;
239 }
240 /* -------------------------------------------------------------------- */
241 /* Check metadata settings in JSON. */
242 /* -------------------------------------------------------------------- */
243
244 json_object *pJSONObject = GetJsonObject(poOpenInfo->pszFilename);
245
246 if (pJSONObject == nullptr) {
247 CPLError(CE_Failure, CPLE_AppDefined, "Error parsing JSON.");
248 return nullptr;
249 }
250
251 // get the type (always 'arg')
252 const char *pszJSONStr = GetJsonValueStr(pJSONObject, "type");
253 if (pszJSONStr == nullptr ) {
254 CPLError(CE_Failure, CPLE_AppDefined,
255 "The ARG 'type' is missing from the JSON file.");
256 json_object_put(pJSONObject);
257 pJSONObject = nullptr;
258 return nullptr;
259 }
260 else if (!EQUAL(pszJSONStr, "arg")) {
261 CPLError(CE_Failure, CPLE_AppDefined,
262 "The ARG 'type' is not recognized: '%s'.", pszJSONStr);
263 json_object_put(pJSONObject);
264 pJSONObject = nullptr;
265 return nullptr;
266 }
267
268 double dfNoDataValue;
269 GDALDataType eType;
270 int nPixelOffset;
271
272 // get the datatype
273 pszJSONStr = GetJsonValueStr(pJSONObject, "datatype");
274 if (pszJSONStr == nullptr) {
275 CPLError(CE_Failure, CPLE_AppDefined,
276 "The ARG 'datatype' is missing from the JSON file.");
277 json_object_put(pJSONObject);
278 pJSONObject = nullptr;
279 return nullptr;
280 }
281 else if (EQUAL(pszJSONStr, "int8")) {
282 CPLDebug("ARGDataset", "Open(): "
283 "int8 data is not supported in GDAL -- mapped to uint8");
284 eType = GDT_Byte;
285 nPixelOffset = 1;
286 dfNoDataValue = 128;
287 }
288 else if (EQUAL(pszJSONStr, "int16")) {
289 eType = GDT_Int16;
290 nPixelOffset = 2;
291 dfNoDataValue = -32767;
292 }
293 else if (EQUAL(pszJSONStr, "int32")) {
294 eType = GDT_Int32;
295 nPixelOffset = 4;
296 dfNoDataValue = -2e31;
297 }
298 else if (EQUAL(pszJSONStr, "uint8")) {
299 eType = GDT_Byte;
300 nPixelOffset = 1;
301 dfNoDataValue = 255;
302 }
303 else if (EQUAL(pszJSONStr, "uint16")) {
304 eType = GDT_UInt16;
305 nPixelOffset = 2;
306 dfNoDataValue = 65535;
307 }
308 else if (EQUAL(pszJSONStr, "uint32")) {
309 eType = GDT_UInt32;
310 nPixelOffset = 4;
311 dfNoDataValue = -2e31;
312 }
313 else if (EQUAL(pszJSONStr, "float32")) {
314 eType = GDT_Float32;
315 nPixelOffset = 4;
316 dfNoDataValue = std::numeric_limits<double>::quiet_NaN();
317 }
318 else if (EQUAL(pszJSONStr, "float64")) {
319 eType = GDT_Float64;
320 nPixelOffset = 8;
321 dfNoDataValue = std::numeric_limits<double>::quiet_NaN();
322 }
323 else {
324 if (EQUAL(pszJSONStr, "int64") ||
325 EQUAL(pszJSONStr, "uint64")) {
326 CPLError(CE_Failure, CPLE_AppDefined,
327 "The ARG 'datatype' is unsupported in GDAL: '%s'.", pszJSONStr);
328 }
329 else {
330 CPLError(CE_Failure, CPLE_AppDefined,
331 "The ARG 'datatype' is unknown: '%s'.", pszJSONStr);
332 }
333 json_object_put(pJSONObject);
334 pJSONObject = nullptr;
335 return nullptr;
336 }
337
338 // get the xmin of the bounding box
339 const double dfXmin = GetJsonValueDbl(pJSONObject, "xmin");
340 if (CPLIsNan(dfXmin)) {
341 CPLError(CE_Failure, CPLE_AppDefined,
342 "The ARG 'xmin' is missing or invalid.");
343 json_object_put(pJSONObject);
344 pJSONObject = nullptr;
345 return nullptr;
346 }
347
348 // get the ymin of the bounding box
349 const double dfYmin = GetJsonValueDbl(pJSONObject, "ymin");
350 if (CPLIsNan(dfYmin)) {
351 CPLError(CE_Failure, CPLE_AppDefined,
352 "The ARG 'ymin' is missing or invalid.");
353 json_object_put(pJSONObject);
354 pJSONObject = nullptr;
355 return nullptr;
356 }
357
358 // get the xmax of the bounding boxfpL
359 const double dfXmax = GetJsonValueDbl(pJSONObject, "xmax");
360 if (CPLIsNan(dfXmax)) {
361 CPLError(CE_Failure, CPLE_AppDefined,
362 "The ARG 'xmax' is missing or invalid.");
363 json_object_put(pJSONObject);
364 pJSONObject = nullptr;
365 return nullptr;
366 }
367
368 // get the ymax of the bounding box
369 const double dfYmax = GetJsonValueDbl(pJSONObject, "ymax");
370 if (CPLIsNan(dfYmax)) {
371 CPLError(CE_Failure, CPLE_AppDefined,
372 "The ARG 'ymax' is missing or invalid.");
373 json_object_put(pJSONObject);
374 pJSONObject = nullptr;
375 return nullptr;
376 }
377
378 // get the cell width
379 const double dfCellwidth = GetJsonValueDbl(pJSONObject, "cellwidth");
380 if (CPLIsNan(dfCellwidth)) {
381 CPLError(CE_Failure, CPLE_AppDefined,
382 "The ARG 'cellwidth' is missing or invalid.");
383 json_object_put(pJSONObject);
384 pJSONObject = nullptr;
385 return nullptr;
386 }
387
388 // get the cell height
389 const double dfCellheight = GetJsonValueDbl(pJSONObject, "cellheight");
390 if (CPLIsNan(dfCellheight)) {
391 CPLError(CE_Failure, CPLE_AppDefined,
392 "The ARG 'cellheight' is missing or invalid.");
393 json_object_put(pJSONObject);
394 pJSONObject = nullptr;
395 return nullptr;
396 }
397
398 double dfXSkew = GetJsonValueDbl(pJSONObject, "xskew");
399 if (CPLIsNan(dfXSkew)) {
400 // not an error -- default to 0.0
401 dfXSkew = 0.0f;
402 }
403
404 double dfYSkew = GetJsonValueDbl(pJSONObject, "yskew");
405 if (CPLIsNan(dfYSkew)) {
406 // not an error -- default to 0.0
407 dfYSkew = 0.0f;
408 }
409
410 // get the rows
411 const int nRows = GetJsonValueInt(pJSONObject, "rows");
412 if (nRows < 0) {
413 CPLError(CE_Failure, CPLE_AppDefined,
414 "The ARG 'rows' is missing or invalid.");
415 json_object_put(pJSONObject);
416 pJSONObject = nullptr;
417 return nullptr;
418 }
419
420 // get the columns
421 const int nCols = GetJsonValueInt(pJSONObject, "cols");
422 if (nCols < 0) {
423 CPLError(CE_Failure, CPLE_AppDefined,
424 "The ARG 'cols' is missing or invalid.");
425 json_object_put(pJSONObject);
426 pJSONObject = nullptr;
427 return nullptr;
428 }
429
430 int nSrs = GetJsonValueInt(pJSONObject, "epsg");
431 if (nSrs < 0) {
432 // not an error -- default to web mercator
433 nSrs = 3857;
434 }
435
436 OGRSpatialReference oSRS;
437 OGRErr nErr = oSRS.importFromEPSG(nSrs);
438 if (nErr != OGRERR_NONE) {
439 nErr = oSRS.importFromEPSG(3857);
440
441 if (nErr == OGRERR_NONE) {
442 CPLDebug("ARGDataset", "Open(): "
443 "The EPSG provided did not import cleanly. "
444 "Defaulting to EPSG:3857");
445 }
446 else {
447 CPLError( CE_Failure, CPLE_AppDefined,
448 "The 'epsg' value did not translate to a known "
449 "spatial reference. "
450 "Please check the 'epsg' value and try again.");
451
452 json_object_put(pJSONObject);
453 pJSONObject = nullptr;
454
455 return nullptr;
456 }
457 }
458
459 char *pszWKT = nullptr;
460 nErr = oSRS.exportToWkt(&pszWKT);
461 if (nErr != OGRERR_NONE) {
462 CPLError(CE_Failure, CPLE_AppDefined,
463 "The spatial reference is known, but could not be set on the "
464 "dataset. Please check the 'epsg' value and try again.");
465
466 json_object_put(pJSONObject);
467 pJSONObject = nullptr;
468 CPLFree(pszWKT);
469 return nullptr;
470 }
471
472 // get the layer (always the file basename)
473 pszJSONStr = GetJsonValueStr(pJSONObject, "layer");
474 if (pszJSONStr == nullptr) {
475 CPLError(CE_Failure, CPLE_AppDefined,
476 "The ARG 'layer' is missing from the JSON file.");
477 json_object_put(pJSONObject);
478 pJSONObject = nullptr;
479 CPLFree(pszWKT);
480 return nullptr;
481 }
482
483 char *pszLayer = CPLStrdup(pszJSONStr);
484
485 // done with the json object now
486 json_object_put(pJSONObject);
487 pJSONObject = nullptr;
488
489 /* -------------------------------------------------------------------- */
490 /* Create a corresponding GDALDataset. */
491 /* -------------------------------------------------------------------- */
492 ARGDataset *poDS = new ARGDataset();
493
494 poDS->pszFilename = CPLStrdup(poOpenInfo->pszFilename);
495 poDS->SetMetadataItem("LAYER",pszLayer,nullptr);
496 poDS->nRasterXSize = nCols;
497 poDS->nRasterYSize = nRows;
498 poDS->SetProjection( pszWKT );
499
500 // done with the projection string
501 CPLFree(pszWKT);
502 CPLFree(pszLayer);
503
504 /* -------------------------------------------------------------------- */
505 /* Assume ownership of the file handled from the GDALOpenInfo. */
506 /* -------------------------------------------------------------------- */
507 poDS->fpImage = poOpenInfo->fpL;
508 poOpenInfo->fpL = nullptr;
509
510 poDS->adfGeoTransform[0] = dfXmin;
511 poDS->adfGeoTransform[1] = dfCellwidth;
512 poDS->adfGeoTransform[2] = dfXSkew;
513 poDS->adfGeoTransform[3] = dfYmax;
514 poDS->adfGeoTransform[4] = dfYSkew;
515 poDS->adfGeoTransform[5] = -dfCellheight;
516
517 /* -------------------------------------------------------------------- */
518 /* Create band information objects. */
519 /* -------------------------------------------------------------------- */
520 #ifdef CPL_LSB
521 bool bNative = false;
522 #else
523 bool bNative = true;
524 #endif
525
526 RawRasterBand *poBand
527 = new RawRasterBand( poDS, 1, poDS->fpImage,
528 0, nPixelOffset, nPixelOffset * nCols,
529 eType, bNative, RawRasterBand::OwnFP::NO );
530 poDS->SetBand( 1, poBand );
531
532 poBand->SetNoDataValue( dfNoDataValue );
533
534 /* -------------------------------------------------------------------- */
535 /* Initialize any PAM information. */
536 /* -------------------------------------------------------------------- */
537 poDS->SetDescription( poOpenInfo->pszFilename );
538 poDS->TryLoadXML();
539
540 /* -------------------------------------------------------------------- */
541 /* Check for overviews. */
542 /* -------------------------------------------------------------------- */
543 poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
544
545 return poDS;
546 }
547
548 /************************************************************************/
549 /* CreateCopy() */
550 /************************************************************************/
CreateCopy(const char * pszFilename,GDALDataset * poSrcDS,int,char **,GDALProgressFunc,void *)551 GDALDataset *ARGDataset::CreateCopy( const char *pszFilename,
552 GDALDataset *poSrcDS,
553 int /* bStrict */ ,
554 char ** /* papszOptions */ ,
555 GDALProgressFunc /* pfnProgress */ ,
556 void * /*pProgressData */ )
557 {
558 const int nBands = poSrcDS->GetRasterCount();
559 if( nBands != 1 )
560 {
561 CPLError( CE_Failure, CPLE_NotSupported,
562 "ARG driver doesn't support %d bands. Must be 1 band.", nBands );
563 return nullptr;
564 }
565
566 CPLString pszDataType;
567 int nPixelOffset = 0;
568
569 GDALDataType eType = poSrcDS->GetRasterBand(1)->GetRasterDataType();
570 if( eType == GDT_Unknown ||
571 eType == GDT_CInt16 ||
572 eType == GDT_CInt32 ||
573 eType == GDT_CFloat32 ||
574 eType == GDT_CFloat64 )
575 {
576 CPLError( CE_Failure, CPLE_NotSupported,
577 "ARG driver doesn't support data type %s.",
578 GDALGetDataTypeName(eType) );
579 return nullptr;
580 }
581 else if (eType == GDT_Int16) {
582 pszDataType = "int16";
583 nPixelOffset = 2;
584 }
585 else if (eType == GDT_Int32) {
586 pszDataType = "int32";
587 nPixelOffset = 4;
588 }
589 else if (eType == GDT_Byte) {
590 pszDataType = "uint8";
591 nPixelOffset = 1;
592 }
593 else if (eType == GDT_UInt16) {
594 pszDataType = "uint16";
595 nPixelOffset = 2;
596 }
597 else if (eType == GDT_UInt32) {
598 pszDataType = "uint32";
599 nPixelOffset = 4;
600 }
601 else if (eType == GDT_Float32) {
602 pszDataType = "float32";
603 nPixelOffset = 4;
604 }
605 else if (eType == GDT_Float64) {
606 pszDataType = "float64";
607 nPixelOffset = 8;
608 }
609
610 double adfTransform[6];
611 poSrcDS->GetGeoTransform( adfTransform );
612
613 const char *pszWKT = poSrcDS->GetProjectionRef();
614 OGRSpatialReference oSRS;
615 OGRErr nErr = oSRS.importFromWkt(pszWKT);
616 if (nErr != OGRERR_NONE) {
617 CPLError( CE_Failure, CPLE_NotSupported,
618 "Cannot import spatial reference WKT from source dataset.");
619 return nullptr;
620 }
621
622 int nSrs = 0;
623 if (oSRS.GetAuthorityCode("PROJCS") != nullptr) {
624 nSrs = atoi(oSRS.GetAuthorityCode("PROJCS"));
625 }
626 else if (oSRS.GetAuthorityCode("GEOGCS") != nullptr) {
627 nSrs = atoi(oSRS.GetAuthorityCode("GEOGCS"));
628 }
629 else {
630 // could not determine projected or geographic code
631 // default to EPSG:3857 if no code could be found
632 nSrs = 3857;
633 }
634
635 /********************************************************************/
636 /* Create JSON companion file. */
637 /********************************************************************/
638 const CPLString osJSONFilename = GetJsonFilename(pszFilename);
639
640 json_object *poJSONObject = json_object_new_object();
641
642 char **pszTokens = poSrcDS->GetMetadata();
643 const char *pszLayer = CSLFetchNameValue(pszTokens, "LAYER");
644
645 if ( pszLayer == nullptr) {
646 // Set the layer
647 json_object_object_add(poJSONObject, "layer", json_object_new_string(
648 CPLGetBasename(osJSONFilename)
649 ));
650 }
651 else {
652 // Set the layer
653 json_object_object_add(poJSONObject, "layer", json_object_new_string(
654 pszLayer
655 ));
656 }
657
658 // Set the type
659 json_object_object_add(poJSONObject, "type", json_object_new_string("arg"));
660 // Set the datatype
661 json_object_object_add(poJSONObject, "datatype", json_object_new_string(pszDataType));
662
663 const int nXSize = poSrcDS->GetRasterXSize();
664 const int nYSize = poSrcDS->GetRasterYSize();
665
666 // Set the number of rows
667 json_object_object_add(poJSONObject, "rows", json_object_new_int(nYSize));
668 // Set the number of columns
669 json_object_object_add(poJSONObject, "cols", json_object_new_int(nXSize));
670 // Set the xmin
671 json_object_object_add(poJSONObject, "xmin", json_object_new_double(adfTransform[0]));
672 // Set the ymax
673 json_object_object_add(poJSONObject, "ymax", json_object_new_double(adfTransform[3]));
674 // Set the cellwidth
675 json_object_object_add(poJSONObject, "cellwidth", json_object_new_double(adfTransform[1]));
676 // Set the cellheight
677 json_object_object_add(poJSONObject, "cellheight", json_object_new_double(-adfTransform[5]));
678 // Set the xmax
679 json_object_object_add(poJSONObject, "xmax", json_object_new_double(adfTransform[0] + nXSize * adfTransform[1]));
680 // Set the ymin
681 json_object_object_add(poJSONObject, "ymin", json_object_new_double(adfTransform[3] + nYSize * adfTransform[5]));
682 // Set the xskew
683 json_object_object_add(poJSONObject, "xskew", json_object_new_double(adfTransform[2]));
684 // Set the yskew
685 json_object_object_add(poJSONObject, "yskew", json_object_new_double(adfTransform[4]));
686 if (nSrs > 0) {
687 // Set the epsg
688 json_object_object_add(poJSONObject, "epsg", json_object_new_int(nSrs));
689 }
690
691 if (json_object_to_file(const_cast<char *>(osJSONFilename.c_str()), poJSONObject) < 0) {
692 CPLError( CE_Failure, CPLE_NotSupported,
693 "ARG driver can't write companion file.");
694
695 json_object_put(poJSONObject);
696 poJSONObject = nullptr;
697
698 return nullptr;
699 }
700
701 json_object_put(poJSONObject);
702 poJSONObject = nullptr;
703
704 VSILFILE *fpImage = VSIFOpenL(pszFilename, "wb");
705 if (fpImage == nullptr)
706 {
707 CPLError( CE_Failure, CPLE_NotSupported,
708 "ARG driver can't create data file %s.", pszFilename);
709
710 // remove JSON file
711 VSIUnlink( osJSONFilename.c_str() );
712
713 return nullptr;
714 }
715
716 // only 1 raster band
717 GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand( 1 );
718
719 #ifdef CPL_LSB
720 bool bNative = false;
721 #else
722 bool bNative = true;
723 #endif
724
725 RawRasterBand *poDstBand = new RawRasterBand( fpImage, 0, nPixelOffset,
726 nPixelOffset * nXSize, eType,
727 bNative,
728 nXSize, nYSize,
729 RawRasterBand::OwnFP::NO);
730 poDstBand->SetAccess(GA_Update);
731
732 int nXBlockSize, nYBlockSize;
733 poSrcBand->GetBlockSize(&nXBlockSize, &nYBlockSize);
734
735 void *pabyData = CPLMalloc(nXBlockSize * nPixelOffset);
736
737 // convert any blocks into scanlines
738 for (int nYBlock = 0; nYBlock * nYBlockSize < nYSize; nYBlock++) {
739 for (int nYScanline = 0; nYScanline < nYBlockSize; nYScanline++) {
740 if ((nYScanline+1) + nYBlock * nYBlockSize > poSrcBand->GetYSize() )
741 {
742 continue;
743 }
744
745 for (int nXBlock = 0; nXBlock * nXBlockSize < nXSize; nXBlock++) {
746 int nXValid;
747
748 if( (nXBlock+1) * nXBlockSize > poSrcBand->GetXSize() )
749 nXValid = poSrcBand->GetXSize() - nXBlock * nXBlockSize;
750 else
751 nXValid = nXBlockSize;
752
753 CPLErr eErr = poSrcBand->RasterIO(GF_Read, nXBlock * nXBlockSize,
754 nYBlock * nYBlockSize + nYScanline, nXValid, 1, pabyData, nXBlockSize,
755 1, eType, 0, 0, nullptr);
756
757 if (eErr != CE_None) {
758 CPLError(CE_Failure, CPLE_AppDefined, "Error reading.");
759
760 CPLFree( pabyData );
761 delete poDstBand;
762 VSIFCloseL( fpImage );
763
764 return nullptr;
765 }
766
767 eErr = poDstBand->RasterIO(GF_Write, nXBlock * nXBlockSize,
768 nYBlock * nYBlockSize + nYScanline, nXValid, 1, pabyData, nXBlockSize,
769 1, eType, 0, 0, nullptr);
770
771 if (eErr != CE_None) {
772 CPLError(CE_Failure, CPLE_AppDefined, "Error writing.");
773
774 CPLFree( pabyData );
775 delete poDstBand;
776 VSIFCloseL( fpImage );
777
778 return nullptr;
779 }
780 }
781 }
782 }
783
784 CPLFree( pabyData );
785 delete poDstBand;
786 VSIFCloseL( fpImage );
787
788 return reinterpret_cast<GDALDataset *>( GDALOpen( pszFilename, GA_ReadOnly ) );
789 }
790
791 /************************************************************************/
792 /* GDALRegister_ARG() */
793 /************************************************************************/
794
GDALRegister_ARG()795 void GDALRegister_ARG()
796 {
797 if( GDALGetDriverByName( "ARG" ) != nullptr )
798 return;
799
800 GDALDriver *poDriver = new GDALDriver();
801
802 poDriver->SetDescription( "ARG" );
803 poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
804 poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
805 "Azavea Raster Grid format" );
806 poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
807 "drivers/raster/arg.html" );
808 poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
809
810 poDriver->pfnIdentify = ARGDataset::Identify;
811 poDriver->pfnOpen = ARGDataset::Open;
812 poDriver->pfnCreateCopy = ARGDataset::CreateCopy;
813
814 GetGDALDriverManager()->RegisterDriver( poDriver );
815 }
816