Line data Source code
1 : /*****************************************************************************
2 : *
3 : * Project: Idrisi Raster Image File Driver
4 : * Purpose: Read/write Idrisi Raster Image Format RST
5 : * Author: Ivan Lucena, [lucena_ivan at hotmail.com]
6 : *
7 : * Revised by Hongmei Zhu, February, 2013
8 : * honzhu@clarku.edu
9 : * Clark Labs/Clark University
10 : *
11 : ******************************************************************************
12 : * Copyright( c ) 2006, Ivan Lucena
13 : * Copyright (c) 2007-2012, Even Rouault <even dot rouault at spatialys.com>
14 : *
15 : * SPDX-License-Identifier: MIT
16 : ****************************************************************************/
17 :
18 : #include "cpl_conv.h"
19 : #include "cpl_string.h"
20 : #include "cpl_csv.h"
21 : #include "gdal_frmts.h"
22 : #include "gdal_pam.h"
23 : #include "gdal_alg.h"
24 : #include "gdal_priv.h"
25 : #include "gdal_rat.h"
26 : #include "ogr_spatialref.h"
27 : #include "idrisi.h"
28 :
29 : #include "proj_experimental.h"
30 : #include "ogr_proj_p.h"
31 :
32 : #include <cmath>
33 :
34 : #ifdef _WIN32
35 : #define PATHDELIM '\\'
36 : #else
37 : #define PATHDELIM '/'
38 : #endif
39 :
40 : //----- Safe numeric conversion, NULL as zero
41 : #define atoi_nz(s) (s == nullptr ? (int)0 : atoi(s))
42 : #define CPLAtof_nz(s) (s == nullptr ? (double)0.0 : CPLAtof(s))
43 :
44 : //----- file extensions:
45 : static const char *const extRST = "rst";
46 : static const char *const extRDC = "rdc";
47 : static const char *const extSMP = "smp";
48 : static const char *const extREF = "ref";
49 : // static const char * const extRSTu = "RST";
50 : static const char *const extRDCu = "RDC";
51 : static const char *const extSMPu = "SMP";
52 : static const char *const extREFu = "REF";
53 :
54 : //----- field names on rdc file:
55 : static const char *const rdcFILE_FORMAT = "file format ";
56 : static const char *const rdcFILE_TITLE = "file title ";
57 : static const char *const rdcDATA_TYPE = "data type ";
58 : static const char *const rdcFILE_TYPE = "file type ";
59 : static const char *const rdcCOLUMNS = "columns ";
60 : static const char *const rdcROWS = "rows ";
61 : static const char *const rdcREF_SYSTEM = "ref. system ";
62 : static const char *const rdcREF_UNITS = "ref. units ";
63 : static const char *const rdcUNIT_DIST = "unit dist. ";
64 : static const char *const rdcMIN_X = "min. X ";
65 : static const char *const rdcMAX_X = "max. X ";
66 : static const char *const rdcMIN_Y = "min. Y ";
67 : static const char *const rdcMAX_Y = "max. Y ";
68 : static const char *const rdcPOSN_ERROR = "pos'n error ";
69 : static const char *const rdcRESOLUTION = "resolution ";
70 : static const char *const rdcMIN_VALUE = "min. value ";
71 : static const char *const rdcMAX_VALUE = "max. value ";
72 : static const char *const rdcDISPLAY_MIN = "display min ";
73 : static const char *const rdcDISPLAY_MAX = "display max ";
74 : static const char *const rdcVALUE_UNITS = "value units ";
75 : static const char *const rdcVALUE_ERROR = "value error ";
76 : static const char *const rdcFLAG_VALUE = "flag value ";
77 : static const char *const rdcFLAG_DEFN = "flag def'n ";
78 : static const char *const rdcFLAG_DEFN2 = "flag def`n ";
79 : static const char *const rdcLEGEND_CATS = "legend cats ";
80 : static const char *const rdcLINEAGES = "lineage ";
81 : static const char *const rdcCOMMENTS = "comment ";
82 : static const char *const rdcCODE_N = "code %6d ";
83 :
84 : //----- ".ref" file field names:
85 : static const char *const refREF_SYSTEM = "ref. system ";
86 : static const char *const refREF_SYSTEM2 = "ref.system ";
87 : static const char *const refPROJECTION = "projection ";
88 : static const char *const refDATUM = "datum ";
89 : static const char *const refDELTA_WGS84 = "delta WGS84 ";
90 : static const char *const refELLIPSOID = "ellipsoid ";
91 : static const char *const refMAJOR_SAX = "major s-ax ";
92 : static const char *const refMINOR_SAX = "minor s-ax ";
93 : static const char *const refORIGIN_LONG = "origin long ";
94 : static const char *const refORIGIN_LAT = "origin lat ";
95 : static const char *const refORIGIN_X = "origin X ";
96 : static const char *const refORIGIN_Y = "origin Y ";
97 : static const char *const refSCALE_FAC = "scale fac ";
98 : static const char *const refUNITS = "units ";
99 : static const char *const refPARAMETERS = "parameters ";
100 : static const char *const refSTANDL_1 = "stand ln 1 ";
101 : static const char *const refSTANDL_2 = "stand ln 2 ";
102 :
103 : //----- standard values:
104 : static const char *const rstVERSION = "Idrisi Raster A.1";
105 : static const char *const rstBYTE = "byte";
106 : static const char *const rstINTEGER = "integer";
107 : static const char *const rstREAL = "real";
108 : static const char *const rstRGB24 = "rgb24";
109 : static const char *const rstDEGREE = "deg";
110 : static const char *const rstMETER = "m";
111 : static const char *const rstLATLONG = "latlong";
112 : static const char *const rstLATLONG2 = "lat/long";
113 : static const char *const rstPLANE = "plane";
114 : static const char *const rstUTM = "utm-%d%c";
115 : static const char *const rstSPC = "spc%2d%2s%d";
116 :
117 : //----- palette file( .smp ) header size:
118 : constexpr int smpHEADERSIZE = 18;
119 :
120 : //----- check if file exists:
121 : bool FileExists(const char *pszPath);
122 :
123 : //----- Reference Table
124 : struct ReferenceTab
125 : {
126 : int nCode;
127 : const char *pszName;
128 : };
129 :
130 : //----- USA State's reference table to USGS PCS Code
131 : constexpr ReferenceTab aoUSStateTable[] = {
132 : {101, "al"}, {201, "az"}, {301, "ar"}, {401, "ca"}, {501, "co"},
133 : {600, "ct"}, {700, "de"}, {901, "fl"}, {1001, "ga"}, {1101, "id"},
134 : {1201, "il"}, {1301, "in"}, {1401, "ia"}, {1501, "ks"}, {1601, "ky"},
135 : {1701, "la"}, {1801, "me"}, {1900, "md"}, {2001, "ma"}, {2111, "mi"},
136 : {2201, "mn"}, {2301, "ms"}, {2401, "mo"}, {2500, "mt"}, {2600, "ne"},
137 : {2701, "nv"}, {2800, "nh"}, {2900, "nj"}, {3001, "nm"}, {3101, "ny"},
138 : {3200, "nc"}, {3301, "nd"}, {3401, "oh"}, {3501, "ok"}, {3601, "or"},
139 : {3701, "pa"}, {3800, "ri"}, {3900, "sc"}, {4001, "sd"}, {4100, "tn"},
140 : {4201, "tx"}, {4301, "ut"}, {4400, "vt"}, {4501, "va"}, {4601, "wa"},
141 : {4701, "wv"}, {4801, "wv"}, {4901, "wy"}, {5001, "ak"}, {5101, "hi"},
142 : {5200, "pr"}};
143 :
144 : //---- The origin table for USA State Plane Systems
145 : struct OriginTab83
146 : {
147 : double longitude;
148 : double latitude;
149 : const char *spcs;
150 : };
151 :
152 : constexpr int ORIGIN_COUNT = 148;
153 :
154 : //---- USA State plane coordinate system in IDRISI
155 : static const OriginTab83 SPCS83Origin[] = {
156 : {85.83, 30.50, "SPC83AL1"}, {87.50, 30.00, "SPC83AL2"},
157 : {176.00, 51.00, "SPC83AK0"}, {142.00, 54.00, "SPC83AK2"},
158 : {146.00, 54.00, "SPC83AK3"}, {150.00, 54.00, "SPC83AK4"},
159 : {154.00, 54.00, "SPC83AK5"}, {158.00, 54.00, "SPC83AK6"},
160 : {162.00, 54.00, "SPC83AK7"}, {166.00, 54.00, "SPC83AK8"},
161 : {170.00, 54.00, "SPC83AK9"}, {110.17, 31.00, "SPC83AZ1"},
162 : {111.92, 31.00, "SPC83AZ2"}, {113.75, 31.00, "SPC83AZ3"},
163 : {92.00, 34.33, "SPC83AR1"}, {92.00, 32.67, "SPC83AR2"},
164 : {122.00, 39.33, "SPC83CA1"}, {122.00, 37.67, "SPC83CA2"},
165 : {120.50, 36.50, "SPC83CA3"}, {119.00, 35.33, "SPC83CA4"},
166 : {118.00, 33.50, "SPC83CA5"}, {116.25, 32.17, "SPC83CA6"},
167 : {105.50, 39.33, "SPC83CO1"}, {105.50, 37.83, "SPC83CO2"},
168 : {105.50, 36.67, "SPC83CO3"}, {72.75, 40.83, "SPC83CT1"},
169 : {75.42, 38.00, "SPC83DE1"}, {81.00, 24.33, "SPC83FL1"},
170 : {82.00, 24.33, "SPC83FL2"}, {84.50, 29.00, "SPC83FL3"},
171 : {82.17, 30.00, "SPC83GA1"}, {84.17, 30.00, "SPC83GA2"},
172 : {155.50, 18.83, "SPC83HI1"}, {156.67, 20.33, "SPC83HI2"},
173 : {158.00, 21.17, "SPC83HI3"}, {159.50, 21.83, "SPC83HI4"},
174 : {160.17, 21.67, "SPC83HI5"}, {112.17, 41.67, "SPC83ID1"},
175 : {114.00, 41.67, "SPC83ID2"}, {115.75, 41.67, "SPC83ID3"},
176 : {88.33, 36.67, "SPC83IL1"}, {90.17, 36.67, "SPC83IL1"},
177 : {85.67, 37.50, "SPC83IN1"}, {87.08, 37.50, "SPC83IN2"},
178 : {93.50, 41.50, "SPC83IA1"}, {93.50, 40.00, "SPC83IA1"},
179 : {98.00, 38.33, "SPC83KS1"}, {98.50, 36.67, "SPC83KS2"},
180 : {84.25, 37.50, "SPC83KY1"}, {85.75, 36.33, "SPC83KY2"},
181 : {92.50, 30.50, "SPC83LA1"}, {91.33, 28.50, "SPC83LA2"},
182 : {91.33, 25.50, "SPC83LA3"}, {92.50, 30.67, "SPC27LA1"}, // NAD27 system
183 : {91.33, 28.67, "SPC27LA2"}, {91.33, 25.67, "SPC27LA3"}, //
184 : {68.50, 43.67, "SPC83ME1"}, {68.50, 43.83, "SPC27ME1"}, // NAD27
185 : {70.17, 42.83, "SPC83ME2"}, {77.00, 37.67, "SPC83MD1"}, //
186 : {77.00, 37.83, "SPC27MD1"}, // NAD27
187 : {71.50, 41.00, "SPC83MA1"}, {70.50, 41.00, "SPC83MA2"},
188 : {87.00, 44.78, "SPC83MI1"}, {84.37, 43.32, "SPC83MI2"},
189 : {84.37, 41.50, "SPC83MI3"}, {84.33, 43.32, "SPC27MI2"}, // NAD27 L
190 : {84.33, 41.50, "SPC27MI3"}, // NAD27 L
191 : {83.67, 41.50, "SPC27MI4"}, // NAD27 TM
192 : {85.75, 41.50, "SPC27MI5"}, // NAD27 TM
193 : {88.75, 41.50, "SPC27MI6"}, // NAD27 TM
194 : {93.10, 46.50, "SPC83MN1"}, {94.25, 45.00, "SPC83MN2"},
195 : {94.00, 43.00, "SPC83MN3"}, {88.83, 29.50, "SPC83MS1"},
196 : {90.33, 29.50, "SPC83MS2"}, {88.83, 29.67, "SPC83MS1"}, // NAD27
197 : {90.33, 30.50, "SPC83MS2"}, //
198 : {90.50, 35.83, "SPC83MO1"}, {92.50, 35.83, "SPC83MO2"},
199 : {94.50, 36.17, "SPC83MO3"}, {109.50, 44.25, "SPC83MT1"},
200 : {109.50, 47.00, "SPC27MT1"}, // NAD27
201 : {109.50, 45.83, "SPC27MT2"}, {109.50, 44.00, "SPC27MT3"}, //
202 : {100.00, 39.83, "SPC83NE1"}, {115.58, 34.75, "SPC83NV1"},
203 : {116.67, 34.75, "SPC83NV2"}, {118.58, 34.75, "SPC83NV3"},
204 : {71.67, 42.50, "SPC83NH1"}, {74.50, 38.83, "SPC83NJ1"},
205 : {74.67, 38.83, "SPC27NJ1"}, // NAD27
206 : {104.33, 31.00, "SPC83NM1"}, {106.25, 31.00, "SPC83NM2"},
207 : {107.83, 31.00, "SPC83NM3"}, {74.50, 38.83, "SPC83NY1"},
208 : {76.58, 40.00, "SPC83NY2"}, {78.58, 40.00, "SPC83NY3"},
209 : {74.00, 40.17, "SPC83NY4"}, {74.33, 40.00, "SPC27NY1"}, // NAD27
210 : {74.00, 40.50, "SPC27NY4"}, //
211 : {79.00, 33.75, "SPC83NC1"}, {100.50, 47.00, "SPC83ND1"},
212 : {100.50, 45.67, "SPC83ND2"}, {82.50, 39.67, "SPC83OH1"},
213 : {82.50, 38.00, "SPC83OH2"}, {98.00, 35.00, "SPC83OK1"},
214 : {98.00, 33.33, "SPC83OK2"}, {120.50, 43.67, "SPC83OR1"},
215 : {120.50, 41.67, "SPC83OR2"}, {77.75, 40.17, "SPC83PA1"},
216 : {77.75, 39.33, "SPC83PA2"}, {71.50, 41.08, "SPC83RI1"},
217 : {81.00, 31.83, "SPC83SC1"}, {81.00, 33.00, "SPC27SC1"}, // NAD27
218 : {81.00, 31.83, "SPC27SC2"}, // NAD27
219 : {100.00, 43.83, "SPC83SD1"}, {100.33, 42.33, "SPC83SD2"},
220 : {86.00, 34.33, "SPC83TN1"}, {86.00, 34.67, "SPC27TN1"}, // NAD27
221 : {101.50, 34.00, "SPC83TX1"}, //
222 : {98.50, 31.67, "SPC83TX2"}, {100.33, 29.67, "SPC83TX3"},
223 : {99.00, 27.83, "SPC83TX4"}, {98.50, 25.67, "SPC83TX5"},
224 : {97.50, 31.67, "SPC27TX2"}, // NAD27
225 : {111.50, 40.33, "SPC83UT1"}, {111.50, 38.33, "SPC83UT2"},
226 : {111.50, 36.67, "SPC83UT3"}, {72.50, 42.50, "SPC83VT1"},
227 : {78.50, 37.67, "SPC83VA1"}, {78.50, 36.33, "SPC83VA2"},
228 : {120.83, 47.00, "SPC83WA1"}, {120.50, 45.33, "SPC83WA2"},
229 : {79.50, 38.50, "SPC83WV1"}, {81.00, 37.00, "SPC83WV2"},
230 : {90.00, 45.17, "SPC83WI1"}, {90.00, 43.83, "SPC83WI2"},
231 : {90.00, 42.00, "SPC83WI3"}, {105.17, 40.50, "SPC83WY1"},
232 : {107.33, 40.50, "SPC83WY2"}, {108.75, 40.50, "SPC83WY3"},
233 : {110.08, 40.50, "SPC83WY4"}, {105.17, 40.67, "SPC27WY1"}, // NAD27
234 : {105.33, 40.67, "SPC27WY2"}, {108.75, 40.67, "SPC27WY3"},
235 : {110.08, 40.67, "SPC27WY4"}, //
236 : {66.43, 17.83, "SPC83PR1"}};
237 :
238 : // Get IDRISI State Plane name by origin
239 : char *GetSpcs(double dfLon, double dfLat);
240 :
241 : // change NAD from 83 to 27
242 : void NAD83to27(char *pszOutRef, char *pszInRef);
243 :
244 : #define US_STATE_COUNT (sizeof(aoUSStateTable) / sizeof(ReferenceTab))
245 :
246 : //----- Get the Code of a US State
247 : int GetStateCode(const char *pszState);
248 :
249 : //----- Get the state name of a Code
250 : const char *GetStateName(int nCode);
251 :
252 : //----- Conversion Table definition
253 : struct ConversionTab
254 : {
255 : const char *pszName;
256 : int nDefaultI;
257 : int nDefaultG;
258 : double dfConv;
259 : };
260 :
261 : //----- Linear Unit Conversion Table
262 : static const ConversionTab aoLinearUnitsConv[] = {
263 : {"m", /* 0 */ 0, 1, 1.0},
264 : {SRS_UL_METER, /* 1 */ 0, 1, 1.0},
265 : {"meters", /* 2 */ 0, 1, 1.0},
266 : {"metre", /* 3 */ 0, 1, 1.0},
267 :
268 : {"ft", /* 4 */ 4, 5, 0.3048},
269 : {SRS_UL_FOOT, /* 5 */ 4, 5, 0.3048},
270 : {"feet", /* 6 */ 4, 5, 0.3048},
271 : {"foot_us", /* 7 */ 4, 5, 0.3048006},
272 : {"u.s. foot", /* 8 */ 4, 5, 0.3048006},
273 :
274 : {"mi", /* 9 */ 9, 10, 1612.9},
275 : {"mile", /* 10 */ 9, 10, 1612.9},
276 : {"miles", /* 11 */ 9, 10, 1612.9},
277 :
278 : {"km", /* 12 */ 12, 13, 1000.0},
279 : {"kilometers", /* 13 */ 12, 13, 1000.0},
280 : {"kilometer", /* 14 */ 12, 13, 1000.0},
281 : {"kilometre", /* 15 */ 12, 13, 1000.0},
282 :
283 : {"deg", /* 16 */ 16, 17, 0.0},
284 : {SRS_UA_DEGREE, /* 17 */ 16, 17, 0.0},
285 : {"degrees", /* 18 */ 16, 17, 0.0},
286 :
287 : {"rad", /* 19 */ 19, 20, 0.0},
288 : {SRS_UA_RADIAN, /* 20 */ 19, 20, 0.0},
289 : {"radians", /* 21 */ 19, 20, 0.0}};
290 : #define LINEAR_UNITS_COUNT (sizeof(aoLinearUnitsConv) / sizeof(ConversionTab))
291 :
292 : //----- Get the index of a given linear unit
293 : static int GetUnitIndex(const char *pszUnitName);
294 :
295 : //----- Get the default name
296 : static char *GetUnitDefault(const char *pszUnitName,
297 : const char *pszToMeter = nullptr);
298 :
299 : //----- Get the "to meter"
300 : static int GetToMeterIndex(const char *pszToMeter);
301 :
302 : //----- CSLSaveCRLF
303 : static int SaveAsCRLF(char **papszStrList, const char *pszFname);
304 :
305 : /************************************************************************/
306 : /* myCSLFetchNameValue() */
307 : /************************************************************************/
308 :
309 1192 : static const char *myCSLFetchNameValue(char **papszStrList, const char *pszName)
310 : {
311 1192 : if (papszStrList == nullptr || pszName == nullptr)
312 4 : return nullptr;
313 :
314 1188 : size_t nLen = strlen(pszName);
315 4541 : while (nLen > 0 && pszName[nLen - 1] == ' ')
316 3353 : nLen--;
317 20461 : while (*papszStrList != nullptr)
318 : {
319 20449 : if (EQUALN(*papszStrList, pszName, nLen))
320 : {
321 : size_t i;
322 4451 : for (i = nLen; (*papszStrList)[i] == ' '; ++i)
323 : {
324 : }
325 1176 : if ((*papszStrList)[i] == '=' || (*papszStrList)[i] == ':')
326 : {
327 1176 : return (*papszStrList) + i + 1;
328 : }
329 : }
330 19273 : ++papszStrList;
331 : }
332 12 : return nullptr;
333 : }
334 :
335 : /************************************************************************/
336 : /* myCSLSetNameValueSeparator() */
337 : /************************************************************************/
338 :
339 86 : static void myCSLSetNameValueSeparator(char **papszList,
340 : const char *pszSeparator)
341 : {
342 86 : const int nLines = CSLCount(papszList);
343 :
344 1926 : for (int iLine = 0; iLine < nLines; ++iLine)
345 : {
346 1840 : char *pszSep = strchr(papszList[iLine], '=');
347 1840 : if (pszSep == nullptr)
348 1164 : pszSep = strchr(papszList[iLine], ':');
349 1840 : if (pszSep == nullptr)
350 0 : continue;
351 1840 : *pszSep = '\0';
352 1840 : const char *pszKey = papszList[iLine];
353 1840 : const char *pszValue = pszSep + 1;
354 2626 : while (*pszValue == ' ')
355 786 : pszValue++;
356 :
357 3680 : char *pszNewLine = static_cast<char *>(CPLMalloc(
358 1840 : strlen(pszValue) + strlen(pszKey) + strlen(pszSeparator) + 1));
359 1840 : strcpy(pszNewLine, pszKey);
360 1840 : strcat(pszNewLine, pszSeparator);
361 1840 : strcat(pszNewLine, pszValue);
362 1840 : CPLFree(papszList[iLine]);
363 1840 : papszList[iLine] = pszNewLine;
364 : }
365 86 : }
366 :
367 : //----- Classes pre-definition:
368 : class IdrisiRasterBand;
369 :
370 : // ----------------------------------------------------------------------------
371 : // Idrisi GDALDataset
372 : // ----------------------------------------------------------------------------
373 :
374 : class IdrisiDataset final : public GDALPamDataset
375 : {
376 : friend class IdrisiRasterBand;
377 :
378 : private:
379 : VSILFILE *fp;
380 :
381 : char *pszFilename;
382 : char *pszDocFilename;
383 : char **papszRDC;
384 : double adfGeoTransform[6];
385 :
386 : mutable OGRSpatialReference m_oSRS{};
387 : char **papszCategories;
388 : char *pszUnitType;
389 : // Move GeoReference2Wkt() into header file.
390 : CPLErr Wkt2GeoReference(const OGRSpatialReference &oSRS,
391 : char **pszRefSystem, char **pszRefUnit);
392 :
393 : protected:
394 : GDALColorTable *poColorTable;
395 :
396 : public:
397 : IdrisiDataset();
398 : virtual ~IdrisiDataset();
399 :
400 : static GDALDataset *Open(GDALOpenInfo *poOpenInfo);
401 : static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize,
402 : int nBands, GDALDataType eType,
403 : char **papszOptions);
404 : static GDALDataset *CreateCopy(const char *pszFilename,
405 : GDALDataset *poSrcDS, int bStrict,
406 : char **papszOptions,
407 : GDALProgressFunc pfnProgress,
408 : void *pProgressData);
409 : virtual char **GetFileList(void) override;
410 : virtual CPLErr GetGeoTransform(double *padfTransform) override;
411 : virtual CPLErr SetGeoTransform(double *padfTransform) override;
412 :
413 : const OGRSpatialReference *GetSpatialRef() const override;
414 : CPLErr SetSpatialRef(const OGRSpatialReference *poSRS) override;
415 : };
416 :
417 : // ----------------------------------------------------------------------------
418 : // Idrisi GDALPamRasterBand
419 : // ----------------------------------------------------------------------------
420 :
421 : class IdrisiRasterBand final : public GDALPamRasterBand
422 : {
423 : friend class IdrisiDataset;
424 :
425 : GDALRasterAttributeTable *poDefaultRAT;
426 :
427 : private:
428 : int nRecordSize;
429 : GByte *pabyScanLine;
430 :
431 : public:
432 : IdrisiRasterBand(IdrisiDataset *poDS, int nBand, GDALDataType eDataType);
433 : virtual ~IdrisiRasterBand();
434 :
435 : virtual double GetNoDataValue(int *pbSuccess = nullptr) override;
436 : virtual double GetMinimum(int *pbSuccess = nullptr) override;
437 : virtual double GetMaximum(int *pbSuccess = nullptr) override;
438 : virtual CPLErr IReadBlock(int nBlockXOff, int nBlockYOff,
439 : void *pImage) override;
440 : virtual CPLErr IWriteBlock(int nBlockXOff, int nBlockYOff,
441 : void *pImage) override;
442 : virtual GDALColorTable *GetColorTable() override;
443 : virtual GDALColorInterp GetColorInterpretation() override;
444 : virtual char **GetCategoryNames() override;
445 : virtual const char *GetUnitType() override;
446 :
447 : virtual CPLErr SetCategoryNames(char **papszCategoryNames) override;
448 : virtual CPLErr SetNoDataValue(double dfNoDataValue) override;
449 : virtual CPLErr SetColorTable(GDALColorTable *poColorTable) override;
450 : virtual CPLErr SetUnitType(const char *pszUnitType) override;
451 : virtual CPLErr SetStatistics(double dfMin, double dfMax, double dfMean,
452 : double dfStdDev) override;
453 : CPLErr SetMinMax(double dfMin, double dfMax);
454 : virtual GDALRasterAttributeTable *GetDefaultRAT() override;
455 : virtual CPLErr SetDefaultRAT(const GDALRasterAttributeTable *) override;
456 :
457 : float fMaximum;
458 : float fMinimum;
459 : bool bFirstVal;
460 : };
461 :
462 : // ------------------------------------------------------------------------ //
463 : // Implementation of IdrisiDataset //
464 : // ------------------------------------------------------------------------ //
465 :
466 : /************************************************************************/
467 : /* IdrisiDataset() */
468 : /************************************************************************/
469 :
470 36 : IdrisiDataset::IdrisiDataset()
471 : : fp(nullptr), pszFilename(nullptr), pszDocFilename(nullptr),
472 : papszRDC(nullptr), papszCategories(nullptr), pszUnitType(nullptr),
473 36 : poColorTable(new GDALColorTable())
474 : {
475 36 : m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
476 36 : adfGeoTransform[0] = 0.0;
477 36 : adfGeoTransform[1] = 1.0;
478 36 : adfGeoTransform[2] = 0.0;
479 36 : adfGeoTransform[3] = 0.0;
480 36 : adfGeoTransform[4] = 0.0;
481 36 : adfGeoTransform[5] = 1.0;
482 36 : }
483 :
484 : /************************************************************************/
485 : /* ~IdrisiDataset() */
486 : /************************************************************************/
487 :
488 72 : IdrisiDataset::~IdrisiDataset()
489 : {
490 36 : FlushCache(true);
491 :
492 36 : if (papszRDC != nullptr && eAccess == GA_Update)
493 : {
494 : // int bSuccessMin = FALSE;
495 : // int bSuccessMax = FALSE;
496 :
497 20 : double dfMin = 0.0;
498 20 : double dfMax = 0.0;
499 20 : double dfMean = 0.0;
500 20 : double dfStdDev = 0.0;
501 :
502 40 : for (int i = 0; i < nBands; i++)
503 : {
504 20 : IdrisiRasterBand *poBand = (IdrisiRasterBand *)GetRasterBand(i + 1);
505 20 : poBand->ComputeStatistics(false, &dfMin, &dfMax, &dfMean, &dfStdDev,
506 20 : nullptr, nullptr);
507 : /*
508 : dfMin = poBand->GetMinimum( &bSuccessMin );
509 : dfMax = poBand->GetMaximum( &bSuccessMax );
510 :
511 : if( ! ( bSuccessMin && bSuccessMax ) )
512 : {
513 : poBand->GetStatistics( false, true, &dfMin, &dfMax, NULL, NULL );
514 : }
515 : */
516 20 : poBand->SetMinMax(dfMin, dfMax);
517 : }
518 :
519 20 : myCSLSetNameValueSeparator(papszRDC, ": ");
520 20 : SaveAsCRLF(papszRDC, pszDocFilename);
521 : }
522 36 : CSLDestroy(papszRDC);
523 :
524 36 : if (poColorTable)
525 : {
526 36 : delete poColorTable;
527 : }
528 36 : CPLFree(pszFilename);
529 36 : CPLFree(pszDocFilename);
530 36 : CSLDestroy(papszCategories);
531 36 : CPLFree(pszUnitType);
532 :
533 36 : if (fp != nullptr)
534 36 : VSIFCloseL(fp);
535 72 : }
536 :
537 : /************************************************************************/
538 : /* Open() */
539 : /************************************************************************/
540 :
541 31902 : GDALDataset *IdrisiDataset::Open(GDALOpenInfo *poOpenInfo)
542 : {
543 36227 : if ((poOpenInfo->fpL == nullptr) ||
544 4325 : (EQUAL(CPLGetExtension(poOpenInfo->pszFilename), extRST) ==
545 : FALSE)) // modified
546 31858 : return nullptr;
547 :
548 : // --------------------------------------------------------------------
549 : // Check the documentation file .rdc
550 : // --------------------------------------------------------------------
551 :
552 : const char *pszLDocFilename =
553 44 : CPLResetExtension(poOpenInfo->pszFilename, extRDC);
554 :
555 40 : if (!FileExists(pszLDocFilename))
556 : {
557 0 : pszLDocFilename = CPLResetExtension(poOpenInfo->pszFilename, extRDCu);
558 :
559 0 : if (!FileExists(pszLDocFilename))
560 : {
561 0 : return nullptr;
562 : }
563 : }
564 :
565 40 : char **papszLRDC = CSLLoad(pszLDocFilename);
566 :
567 40 : myCSLSetNameValueSeparator(papszLRDC, ":");
568 :
569 40 : const char *pszVersion = myCSLFetchNameValue(papszLRDC, rdcFILE_FORMAT);
570 :
571 40 : if (pszVersion == nullptr || !EQUAL(pszVersion, rstVERSION))
572 : {
573 4 : CSLDestroy(papszLRDC);
574 4 : return nullptr;
575 : }
576 :
577 : // --------------------------------------------------------------------
578 : // Create a corresponding GDALDataset
579 : // --------------------------------------------------------------------
580 :
581 36 : IdrisiDataset *poDS = new IdrisiDataset();
582 36 : poDS->eAccess = poOpenInfo->eAccess;
583 36 : poDS->pszFilename = CPLStrdup(poOpenInfo->pszFilename);
584 :
585 36 : if (poOpenInfo->eAccess == GA_ReadOnly)
586 : {
587 16 : poDS->fp = VSIFOpenL(poDS->pszFilename, "rb");
588 : }
589 : else
590 : {
591 20 : poDS->fp = VSIFOpenL(poDS->pszFilename, "r+b");
592 : }
593 :
594 36 : if (poDS->fp == nullptr)
595 : {
596 0 : CSLDestroy(papszLRDC);
597 0 : delete poDS;
598 0 : return nullptr;
599 : }
600 :
601 36 : poDS->pszDocFilename = CPLStrdup(pszLDocFilename);
602 36 : poDS->papszRDC = CSLDuplicate(papszLRDC);
603 36 : CSLDestroy(papszLRDC);
604 :
605 : // --------------------------------------------------------------------
606 : // Load information from rdc
607 : // --------------------------------------------------------------------
608 :
609 36 : poDS->nRasterXSize =
610 36 : atoi_nz(myCSLFetchNameValue(poDS->papszRDC, rdcCOLUMNS));
611 36 : poDS->nRasterYSize = atoi_nz(myCSLFetchNameValue(poDS->papszRDC, rdcROWS));
612 36 : if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
613 : {
614 6 : delete poDS;
615 6 : return nullptr;
616 : }
617 :
618 : // --------------------------------------------------------------------
619 : // Create band information
620 : // --------------------------------------------------------------------
621 :
622 30 : const char *pszDataType = myCSLFetchNameValue(poDS->papszRDC, rdcDATA_TYPE);
623 30 : if (pszDataType == nullptr)
624 : {
625 0 : delete poDS;
626 0 : return nullptr;
627 : }
628 :
629 30 : if (EQUAL(pszDataType, rstBYTE))
630 : {
631 5 : poDS->nBands = 1;
632 5 : poDS->SetBand(1, new IdrisiRasterBand(poDS, 1, GDT_Byte));
633 : }
634 25 : else if (EQUAL(pszDataType, rstINTEGER))
635 : {
636 9 : poDS->nBands = 1;
637 9 : poDS->SetBand(1, new IdrisiRasterBand(poDS, 1, GDT_Int16));
638 : }
639 16 : else if (EQUAL(pszDataType, rstREAL))
640 : {
641 10 : poDS->nBands = 1;
642 10 : poDS->SetBand(1, new IdrisiRasterBand(poDS, 1, GDT_Float32));
643 : }
644 6 : else if (EQUAL(pszDataType, rstRGB24))
645 : {
646 6 : poDS->nBands = 3;
647 6 : poDS->SetBand(1, new IdrisiRasterBand(poDS, 1, GDT_Byte));
648 6 : poDS->SetBand(2, new IdrisiRasterBand(poDS, 2, GDT_Byte));
649 6 : poDS->SetBand(3, new IdrisiRasterBand(poDS, 3, GDT_Byte));
650 : }
651 : else
652 : {
653 0 : CPLError(CE_Failure, CPLE_AppDefined, "Unknown data type : %s",
654 : pszDataType);
655 0 : delete poDS;
656 0 : return nullptr;
657 : }
658 :
659 72 : for (int i = 0; i < poDS->nBands; i++)
660 : {
661 42 : IdrisiRasterBand *band = (IdrisiRasterBand *)poDS->GetRasterBand(i + 1);
662 42 : if (band->pabyScanLine == nullptr)
663 : {
664 0 : delete poDS;
665 0 : return nullptr;
666 : }
667 : }
668 :
669 : // --------------------------------------------------------------------
670 : // Load the transformation matrix
671 : // --------------------------------------------------------------------
672 :
673 30 : const char *pszMinX = myCSLFetchNameValue(poDS->papszRDC, rdcMIN_X);
674 30 : const char *pszMaxX = myCSLFetchNameValue(poDS->papszRDC, rdcMAX_X);
675 30 : const char *pszMinY = myCSLFetchNameValue(poDS->papszRDC, rdcMIN_Y);
676 30 : const char *pszMaxY = myCSLFetchNameValue(poDS->papszRDC, rdcMAX_Y);
677 30 : const char *pszUnit = myCSLFetchNameValue(poDS->papszRDC, rdcUNIT_DIST);
678 :
679 30 : if (pszMinX != nullptr && strlen(pszMinX) > 0 && pszMaxX != nullptr &&
680 30 : strlen(pszMaxX) > 0 && pszMinY != nullptr && strlen(pszMinY) > 0 &&
681 30 : pszMaxY != nullptr && strlen(pszMaxY) > 0 && pszUnit != nullptr &&
682 30 : strlen(pszUnit) > 0)
683 : {
684 : double dfMinX, dfMaxX, dfMinY, dfMaxY, dfUnit, dfXPixSz, dfYPixSz;
685 :
686 30 : dfMinX = CPLAtof_nz(pszMinX);
687 30 : dfMaxX = CPLAtof_nz(pszMaxX);
688 30 : dfMinY = CPLAtof_nz(pszMinY);
689 30 : dfMaxY = CPLAtof_nz(pszMaxY);
690 30 : dfUnit = CPLAtof_nz(pszUnit);
691 :
692 30 : dfMinX = dfMinX * dfUnit;
693 30 : dfMaxX = dfMaxX * dfUnit;
694 30 : dfMinY = dfMinY * dfUnit;
695 30 : dfMaxY = dfMaxY * dfUnit;
696 :
697 30 : dfYPixSz = (dfMinY - dfMaxY) / poDS->nRasterYSize;
698 30 : dfXPixSz = (dfMaxX - dfMinX) / poDS->nRasterXSize;
699 :
700 30 : poDS->adfGeoTransform[0] = dfMinX;
701 30 : poDS->adfGeoTransform[1] = dfXPixSz;
702 30 : poDS->adfGeoTransform[2] = 0.0;
703 30 : poDS->adfGeoTransform[3] = dfMaxY;
704 30 : poDS->adfGeoTransform[4] = 0.0;
705 30 : poDS->adfGeoTransform[5] = dfYPixSz;
706 : }
707 :
708 : // --------------------------------------------------------------------
709 : // Set Color Table in the presence of a smp file
710 : // --------------------------------------------------------------------
711 :
712 30 : if (poDS->nBands != 3)
713 : {
714 : const char *pszSMPFilename =
715 24 : CPLResetExtension(poDS->pszFilename, extSMP);
716 24 : VSILFILE *fpSMP = VSIFOpenL(pszSMPFilename, "rb");
717 24 : if (fpSMP != nullptr)
718 : {
719 : int dfMaxValue =
720 0 : atoi_nz(myCSLFetchNameValue(poDS->papszRDC, rdcMAX_VALUE));
721 : int nCatCount =
722 0 : atoi_nz(myCSLFetchNameValue(poDS->papszRDC, rdcLEGEND_CATS));
723 0 : if (nCatCount == 0)
724 0 : dfMaxValue = 255;
725 0 : VSIFSeekL(fpSMP, smpHEADERSIZE, SEEK_SET);
726 : GDALColorEntry oEntry;
727 : unsigned char aucRGB[3];
728 0 : int i = 0;
729 0 : while ((VSIFReadL(&aucRGB, sizeof(aucRGB), 1, fpSMP)) &&
730 : (i <= dfMaxValue))
731 : {
732 0 : oEntry.c1 = (short)aucRGB[0];
733 0 : oEntry.c2 = (short)aucRGB[1];
734 0 : oEntry.c3 = (short)aucRGB[2];
735 0 : oEntry.c4 = (short)255;
736 0 : poDS->poColorTable->SetColorEntry(i, &oEntry);
737 0 : i++;
738 : }
739 0 : VSIFCloseL(fpSMP);
740 : }
741 : }
742 :
743 : // --------------------------------------------------------------------
744 : // Check for Unit Type
745 : // --------------------------------------------------------------------
746 :
747 : const char *pszValueUnit =
748 30 : myCSLFetchNameValue(poDS->papszRDC, rdcVALUE_UNITS);
749 :
750 30 : if (pszValueUnit == nullptr)
751 0 : poDS->pszUnitType = CPLStrdup("unspecified");
752 : else
753 : {
754 30 : if (STARTS_WITH_CI(pszValueUnit, "meter"))
755 : {
756 0 : poDS->pszUnitType = CPLStrdup("m");
757 : }
758 30 : else if (STARTS_WITH_CI(pszValueUnit, "feet"))
759 : {
760 0 : poDS->pszUnitType = CPLStrdup("ft");
761 : }
762 : else
763 30 : poDS->pszUnitType = CPLStrdup(pszValueUnit);
764 : }
765 :
766 : // --------------------------------------------------------------------
767 : // Check for category names.
768 : // --------------------------------------------------------------------
769 :
770 : int nCatCount =
771 30 : atoi_nz(myCSLFetchNameValue(poDS->papszRDC, rdcLEGEND_CATS));
772 :
773 30 : if (nCatCount > 0)
774 : {
775 : // ----------------------------------------------------------------
776 : // Sequentialize categories names, from 0 to the last "code n"
777 : // ----------------------------------------------------------------
778 :
779 0 : int nLine = -1;
780 0 : for (int i = 0; (i < CSLCount(poDS->papszRDC)) && (nLine == -1); i++)
781 0 : if (EQUALN(poDS->papszRDC[i], rdcLEGEND_CATS, 11))
782 0 : nLine = i; // get the line where legend cats is
783 :
784 0 : if (nLine > 0)
785 : {
786 0 : int nCode = 0;
787 0 : int nCount = 0;
788 0 : sscanf(poDS->papszRDC[++nLine], rdcCODE_N,
789 : &nCode); // assign legend cats to nCode
790 0 : for (int i = 0; (i < 255) && (nCount < nCatCount); i++)
791 : {
792 0 : if (i == nCode)
793 : {
794 0 : poDS->papszCategories = CSLAddString(
795 : poDS->papszCategories,
796 0 : CPLParseNameValue(poDS->papszRDC[nLine], nullptr));
797 0 : nCount++;
798 0 : if (nCount < nCatCount)
799 0 : sscanf(poDS->papszRDC[++nLine], rdcCODE_N, &nCode);
800 : }
801 : else
802 0 : poDS->papszCategories =
803 0 : CSLAddString(poDS->papszCategories, "");
804 : }
805 : }
806 : }
807 :
808 : /* -------------------------------------------------------------------- */
809 : /* Automatic Generated Color Table */
810 : /* -------------------------------------------------------------------- */
811 :
812 30 : if (poDS->papszCategories != nullptr &&
813 0 : (poDS->poColorTable->GetColorEntryCount() == 0))
814 : {
815 0 : int nEntryCount = CSLCount(poDS->papszCategories);
816 :
817 : GDALColorEntry sFromColor;
818 0 : sFromColor.c1 = (short)(255);
819 0 : sFromColor.c2 = (short)(0);
820 0 : sFromColor.c3 = (short)(0);
821 0 : sFromColor.c4 = (short)(255);
822 :
823 : GDALColorEntry sToColor;
824 0 : sToColor.c1 = (short)(0);
825 0 : sToColor.c2 = (short)(0);
826 0 : sToColor.c3 = (short)(255);
827 0 : sToColor.c4 = (short)(255);
828 :
829 0 : poDS->poColorTable->CreateColorRamp(0, &sFromColor, (nEntryCount - 1),
830 : &sToColor);
831 : }
832 :
833 : /* -------------------------------------------------------------------- */
834 : /* Initialize any PAM information. */
835 : /* -------------------------------------------------------------------- */
836 :
837 30 : poDS->SetDescription(poOpenInfo->pszFilename);
838 30 : poDS->TryLoadXML();
839 :
840 : /* -------------------------------------------------------------------- */
841 : /* Check for external overviews. */
842 : /* -------------------------------------------------------------------- */
843 :
844 30 : poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename);
845 :
846 30 : return poDS;
847 : }
848 :
849 : /************************************************************************/
850 : /* Create() */
851 : /************************************************************************/
852 :
853 50 : GDALDataset *IdrisiDataset::Create(const char *pszFilename, int nXSize,
854 : int nYSize, int nBandsIn, GDALDataType eType,
855 : char ** /* papszOptions */)
856 : {
857 : // --------------------------------------------------------------------
858 : // Check input options
859 : // --------------------------------------------------------------------
860 :
861 50 : if (nBandsIn != 1 && nBandsIn != 3)
862 : {
863 4 : CPLError(CE_Failure, CPLE_AppDefined,
864 : "Attempt to create IDRISI dataset with an illegal number of "
865 : "bands(%d)."
866 : " Try again by selecting a specific band if possible. \n",
867 : nBandsIn);
868 4 : return nullptr;
869 : }
870 :
871 46 : if (nBandsIn == 3 && eType != GDT_Byte)
872 : {
873 13 : CPLError(
874 : CE_Failure, CPLE_AppDefined,
875 : "Attempt to create IDRISI dataset with an unsupported combination "
876 : "of the number of bands(%d) and data type(%s). \n",
877 : nBandsIn, GDALGetDataTypeName(eType));
878 13 : return nullptr;
879 : }
880 :
881 : // ----------------------------------------------------------------
882 : // Create the header file with minimum information
883 : // ----------------------------------------------------------------
884 :
885 33 : const char *pszLDataType = nullptr;
886 :
887 33 : switch (eType)
888 : {
889 17 : case GDT_Byte:
890 17 : if (nBandsIn == 1)
891 14 : pszLDataType = rstBYTE;
892 : else
893 3 : pszLDataType = rstRGB24;
894 17 : break;
895 2 : case GDT_Int16:
896 2 : pszLDataType = rstINTEGER;
897 2 : break;
898 3 : case GDT_Float32:
899 3 : pszLDataType = rstREAL;
900 3 : break;
901 : //--- process compatible data types
902 1 : case (GDT_UInt16):
903 1 : pszLDataType = rstINTEGER;
904 1 : CPLError(CE_Warning, CPLE_AppDefined,
905 : "This process requires a conversion from %s to signed "
906 : "16-bit %s, "
907 : "which may cause data loss.\n",
908 : GDALGetDataTypeName(eType), rstINTEGER);
909 1 : break;
910 1 : case GDT_UInt32:
911 1 : pszLDataType = rstINTEGER;
912 1 : CPLError(CE_Warning, CPLE_AppDefined,
913 : "This process requires a conversion from %s to signed "
914 : "16-bit %s, "
915 : "which may cause data loss.\n",
916 : GDALGetDataTypeName(eType), rstINTEGER);
917 1 : break;
918 1 : case GDT_Int32:
919 1 : pszLDataType = rstINTEGER;
920 1 : CPLError(CE_Warning, CPLE_AppDefined,
921 : "This process requires a conversion from %s to signed "
922 : "16-bit %s, "
923 : "which may cause data loss.\n",
924 : GDALGetDataTypeName(eType), rstINTEGER);
925 1 : break;
926 1 : case GDT_Float64:
927 1 : pszLDataType = rstREAL;
928 1 : CPLError(CE_Warning, CPLE_AppDefined,
929 : "This process requires a conversion from %s to float "
930 : "32-bit %s, "
931 : "which may cause data loss.\n",
932 : GDALGetDataTypeName(eType), rstREAL);
933 1 : break;
934 7 : default:
935 7 : CPLError(CE_Failure, CPLE_AppDefined,
936 : "Attempt to create IDRISI dataset with an illegal "
937 : "data type(%s).\n",
938 : GDALGetDataTypeName(eType));
939 7 : return nullptr;
940 : };
941 :
942 26 : char **papszLRDC = nullptr;
943 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcFILE_FORMAT, rstVERSION);
944 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcFILE_TITLE, "");
945 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcDATA_TYPE, pszLDataType);
946 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcFILE_TYPE, "binary");
947 : papszLRDC =
948 26 : CSLAddNameValue(papszLRDC, rdcCOLUMNS, CPLSPrintf("%d", nXSize));
949 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcROWS, CPLSPrintf("%d", nYSize));
950 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcREF_SYSTEM, "plane");
951 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcREF_UNITS, "m");
952 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcUNIT_DIST, "1");
953 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcMIN_X, "0");
954 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcMAX_X, CPLSPrintf("%d", nXSize));
955 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcMIN_Y, "0");
956 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcMAX_Y, CPLSPrintf("%d", nYSize));
957 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcPOSN_ERROR, "unspecified");
958 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcRESOLUTION, "1.0");
959 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcMIN_VALUE, "0");
960 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcMAX_VALUE, "0");
961 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcDISPLAY_MIN, "0");
962 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcDISPLAY_MAX, "0");
963 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcVALUE_UNITS, "unspecified");
964 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcVALUE_ERROR, "unspecified");
965 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcFLAG_VALUE, "none");
966 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcFLAG_DEFN, "none");
967 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcLEGEND_CATS, "0");
968 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcLINEAGES, "");
969 26 : papszLRDC = CSLAddNameValue(papszLRDC, rdcCOMMENTS, "");
970 :
971 26 : const char *pszLDocFilename = CPLResetExtension(pszFilename, extRDC);
972 :
973 26 : myCSLSetNameValueSeparator(papszLRDC, ": ");
974 26 : SaveAsCRLF(papszLRDC, pszLDocFilename);
975 26 : CSLDestroy(papszLRDC);
976 :
977 : // ----------------------------------------------------------------
978 : // Create an empty data file
979 : // ----------------------------------------------------------------
980 :
981 26 : VSILFILE *fp = VSIFOpenL(pszFilename, "wb+");
982 :
983 26 : if (fp == nullptr)
984 : {
985 2 : CPLError(CE_Failure, CPLE_OpenFailed,
986 : "Attempt to create file %s' failed.\n", pszFilename);
987 2 : return nullptr;
988 : }
989 :
990 36 : const int nTargetDTSize = EQUAL(pszLDataType, rstBYTE) ? 1
991 19 : : EQUAL(pszLDataType, rstINTEGER) ? 2
992 7 : : EQUAL(pszLDataType, rstRGB24) ? 3
993 : : 4;
994 24 : VSIFTruncateL(fp,
995 24 : static_cast<vsi_l_offset>(nXSize) * nYSize * nTargetDTSize);
996 24 : VSIFCloseL(fp);
997 :
998 24 : return (IdrisiDataset *)GDALOpen(pszFilename, GA_Update);
999 : }
1000 :
1001 : /************************************************************************/
1002 : /* CreateCopy() */
1003 : /************************************************************************/
1004 :
1005 29 : GDALDataset *IdrisiDataset::CreateCopy(const char *pszFilename,
1006 : GDALDataset *poSrcDS, int bStrict,
1007 : char **papszOptions,
1008 : GDALProgressFunc pfnProgress,
1009 : void *pProgressData)
1010 : {
1011 29 : if (!pfnProgress(0.0, nullptr, pProgressData))
1012 0 : return nullptr;
1013 :
1014 : // ------------------------------------------------------------------------
1015 : // Check number of bands
1016 : // ------------------------------------------------------------------------
1017 29 : if (!(poSrcDS->GetRasterCount() == 1) && !(poSrcDS->GetRasterCount() == 3))
1018 : {
1019 4 : CPLError(CE_Failure, CPLE_AppDefined,
1020 : "Attempt to create IDRISI dataset with an illegal number of "
1021 : "bands(%d)."
1022 : " Try again by selecting a specific band if possible.\n",
1023 : poSrcDS->GetRasterCount());
1024 4 : return nullptr;
1025 : }
1026 27 : if ((poSrcDS->GetRasterCount() == 3) &&
1027 2 : ((poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_Byte) ||
1028 2 : (poSrcDS->GetRasterBand(2)->GetRasterDataType() != GDT_Byte) ||
1029 2 : (poSrcDS->GetRasterBand(3)->GetRasterDataType() != GDT_Byte)))
1030 : {
1031 0 : CPLError(
1032 : CE_Failure, CPLE_AppDefined,
1033 : "Attempt to create IDRISI dataset with an unsupported "
1034 : "data type when there are three bands. Only BYTE allowed.\n"
1035 : "Try again by selecting a specific band to convert if possible.\n");
1036 0 : return nullptr;
1037 : }
1038 :
1039 : // ------------------------------------------------------------------------
1040 : // Check Data types
1041 : // ------------------------------------------------------------------------
1042 :
1043 46 : for (int i = 1; i <= poSrcDS->GetRasterCount(); i++)
1044 : {
1045 29 : GDALDataType eType = poSrcDS->GetRasterBand(i)->GetRasterDataType();
1046 :
1047 29 : if (bStrict)
1048 : {
1049 25 : if (eType != GDT_Byte && eType != GDT_Int16 && eType != GDT_Float32)
1050 : {
1051 8 : CPLError(CE_Failure, CPLE_AppDefined,
1052 : "Attempt to create IDRISI dataset in strict mode "
1053 : "with an illegal data type(%s).\n",
1054 : GDALGetDataTypeName(eType));
1055 8 : return nullptr;
1056 : }
1057 : }
1058 : else
1059 : {
1060 4 : if (eType != GDT_Byte && eType != GDT_Int16 &&
1061 0 : eType != GDT_UInt16 && eType != GDT_UInt32 &&
1062 0 : eType != GDT_Int32 && eType != GDT_Float32 &&
1063 : eType != GDT_Float64)
1064 : {
1065 0 : CPLError(CE_Failure, CPLE_AppDefined,
1066 : "Attempt to create IDRISI dataset with an illegal "
1067 : "data type(%s).\n",
1068 : GDALGetDataTypeName(eType));
1069 0 : return nullptr;
1070 : }
1071 : }
1072 : }
1073 :
1074 : // --------------------------------------------------------------------
1075 : // Define data type
1076 : // --------------------------------------------------------------------
1077 :
1078 17 : GDALRasterBand *poBand = poSrcDS->GetRasterBand(1);
1079 17 : GDALDataType eType = poBand->GetRasterDataType();
1080 :
1081 17 : int bSuccessMin = FALSE;
1082 17 : int bSuccessMax = FALSE;
1083 :
1084 17 : double dfMin = poBand->GetMinimum(&bSuccessMin);
1085 17 : double dfMax = poBand->GetMaximum(&bSuccessMax);
1086 :
1087 17 : if (!(bSuccessMin && bSuccessMax))
1088 : {
1089 6 : poBand->GetStatistics(false, true, &dfMin, &dfMax, nullptr, nullptr);
1090 : }
1091 :
1092 17 : if (!((eType == GDT_Byte) || (eType == GDT_Int16) ||
1093 : (eType == GDT_Float32)))
1094 : {
1095 0 : if (eType == GDT_Float64)
1096 : {
1097 0 : eType = GDT_Float32;
1098 : }
1099 : else
1100 : {
1101 0 : if ((dfMin < (double)SHRT_MIN) || (dfMax > (double)SHRT_MAX))
1102 : {
1103 0 : eType = GDT_Float32;
1104 : }
1105 : else
1106 : {
1107 0 : eType = GDT_Int16;
1108 : }
1109 : }
1110 : }
1111 :
1112 : // --------------------------------------------------------------------
1113 : // Create the dataset
1114 : // --------------------------------------------------------------------
1115 :
1116 17 : IdrisiDataset *poDS = (IdrisiDataset *)IdrisiDataset::Create(
1117 : pszFilename, poSrcDS->GetRasterXSize(), poSrcDS->GetRasterYSize(),
1118 : poSrcDS->GetRasterCount(), eType, papszOptions);
1119 :
1120 17 : if (poDS == nullptr)
1121 12 : return nullptr;
1122 :
1123 : // --------------------------------------------------------------------
1124 : // Copy information to the dataset
1125 : // --------------------------------------------------------------------
1126 :
1127 : double adfGeoTransform[6];
1128 5 : if (poSrcDS->GetGeoTransform(adfGeoTransform) == CE_None)
1129 : {
1130 5 : poDS->SetGeoTransform(adfGeoTransform);
1131 : }
1132 :
1133 5 : if (!EQUAL(poSrcDS->GetProjectionRef(), ""))
1134 : {
1135 5 : poDS->SetProjection(poSrcDS->GetProjectionRef());
1136 : }
1137 :
1138 : // --------------------------------------------------------------------
1139 : // Copy information to the raster band(s)
1140 : // --------------------------------------------------------------------
1141 :
1142 14 : for (int i = 1; i <= poDS->nBands; i++)
1143 : {
1144 9 : GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(i);
1145 : IdrisiRasterBand *poDstBand =
1146 9 : (IdrisiRasterBand *)poDS->GetRasterBand(i);
1147 :
1148 9 : if (poDS->nBands == 1)
1149 : {
1150 3 : poDstBand->SetUnitType(poSrcBand->GetUnitType());
1151 3 : poDstBand->SetColorTable(poSrcBand->GetColorTable());
1152 3 : poDstBand->SetCategoryNames(poSrcBand->GetCategoryNames());
1153 :
1154 3 : const GDALRasterAttributeTable *poRAT = poSrcBand->GetDefaultRAT();
1155 :
1156 3 : if (poRAT != nullptr)
1157 : {
1158 0 : poDstBand->SetDefaultRAT(poRAT);
1159 : }
1160 : }
1161 :
1162 9 : dfMin = poSrcBand->GetMinimum(nullptr);
1163 9 : dfMax = poSrcBand->GetMaximum(nullptr);
1164 9 : poDstBand->SetMinMax(dfMin, dfMax);
1165 : int bHasNoDataValue;
1166 9 : double dfNoDataValue = poSrcBand->GetNoDataValue(&bHasNoDataValue);
1167 9 : if (bHasNoDataValue)
1168 0 : poDstBand->SetNoDataValue(dfNoDataValue);
1169 : }
1170 :
1171 : // --------------------------------------------------------------------
1172 : // Copy image data
1173 : // --------------------------------------------------------------------
1174 :
1175 5 : if (GDALDatasetCopyWholeRaster((GDALDatasetH)poSrcDS, (GDALDatasetH)poDS,
1176 : nullptr, pfnProgress,
1177 5 : pProgressData) != CE_None)
1178 : {
1179 0 : delete poDS;
1180 0 : return nullptr;
1181 : }
1182 :
1183 : // --------------------------------------------------------------------
1184 : // Finalize
1185 : // --------------------------------------------------------------------
1186 :
1187 5 : poDS->FlushCache(false);
1188 :
1189 5 : return poDS;
1190 : }
1191 :
1192 : /************************************************************************/
1193 : /* GetFileList() */
1194 : /************************************************************************/
1195 :
1196 4 : char **IdrisiDataset::GetFileList()
1197 : {
1198 4 : char **papszFileList = GDALPamDataset::GetFileList();
1199 :
1200 : // --------------------------------------------------------------------
1201 : // Symbol table file
1202 : // --------------------------------------------------------------------
1203 :
1204 4 : const char *pszAssociated = CPLResetExtension(pszFilename, extSMP);
1205 :
1206 4 : if (FileExists(pszAssociated))
1207 : {
1208 0 : papszFileList = CSLAddString(papszFileList, pszAssociated);
1209 : }
1210 : else
1211 : {
1212 4 : pszAssociated = CPLResetExtension(pszFilename, extSMPu);
1213 :
1214 4 : if (FileExists(pszAssociated))
1215 : {
1216 0 : papszFileList = CSLAddString(papszFileList, pszAssociated);
1217 : }
1218 : }
1219 :
1220 : // --------------------------------------------------------------------
1221 : // Documentation file
1222 : // --------------------------------------------------------------------
1223 :
1224 4 : pszAssociated = CPLResetExtension(pszFilename, extRDC);
1225 :
1226 4 : if (FileExists(pszAssociated))
1227 : {
1228 4 : papszFileList = CSLAddString(papszFileList, pszAssociated);
1229 : }
1230 : else
1231 : {
1232 0 : pszAssociated = CPLResetExtension(pszFilename, extRDCu);
1233 :
1234 0 : if (FileExists(pszAssociated))
1235 : {
1236 0 : papszFileList = CSLAddString(papszFileList, pszAssociated);
1237 : }
1238 : }
1239 :
1240 : // --------------------------------------------------------------------
1241 : // Reference file
1242 : // --------------------------------------------------------------------
1243 :
1244 4 : pszAssociated = CPLResetExtension(pszFilename, extREF);
1245 :
1246 4 : if (FileExists(pszAssociated))
1247 : {
1248 0 : papszFileList = CSLAddString(papszFileList, pszAssociated);
1249 : }
1250 : else
1251 : {
1252 4 : pszAssociated = CPLResetExtension(pszFilename, extREFu);
1253 :
1254 4 : if (FileExists(pszAssociated))
1255 : {
1256 0 : papszFileList = CSLAddString(papszFileList, pszAssociated);
1257 : }
1258 : }
1259 :
1260 4 : return papszFileList;
1261 : }
1262 :
1263 : /************************************************************************/
1264 : /* GetGeoTransform() */
1265 : /************************************************************************/
1266 :
1267 9 : CPLErr IdrisiDataset::GetGeoTransform(double *padfTransform)
1268 : {
1269 9 : if (GDALPamDataset::GetGeoTransform(padfTransform) != CE_None)
1270 : {
1271 9 : memcpy(padfTransform, adfGeoTransform, sizeof(double) * 6);
1272 : /*
1273 : if( adfGeoTransform[0] == 0.0
1274 : && adfGeoTransform[1] == 1.0
1275 : && adfGeoTransform[2] == 0.0
1276 : && adfGeoTransform[3] == 0.0
1277 : && adfGeoTransform[4] == 0.0
1278 : && adfGeoTransform[5] == 1.0 )
1279 : return CE_Failure;
1280 : */
1281 : }
1282 :
1283 9 : return CE_None;
1284 : }
1285 :
1286 : /************************************************************************/
1287 : /* SetGeoTransform() */
1288 : /************************************************************************/
1289 :
1290 13 : CPLErr IdrisiDataset::SetGeoTransform(double *padfTransform)
1291 : {
1292 13 : if (padfTransform[2] != 0.0 || padfTransform[4] != 0.0)
1293 : {
1294 0 : CPLError(CE_Failure, CPLE_AppDefined,
1295 : "Attempt to set rotated geotransform on Idrisi Raster file.\n"
1296 : "Idrisi Raster does not support rotation.\n");
1297 0 : return CE_Failure;
1298 : }
1299 :
1300 : // --------------------------------------------------------------------
1301 : // Update the .rdc file
1302 : // --------------------------------------------------------------------
1303 :
1304 13 : double dfXPixSz = padfTransform[1];
1305 13 : double dfYPixSz = padfTransform[5];
1306 13 : double dfMinX = padfTransform[0];
1307 13 : double dfMaxX = (dfXPixSz * nRasterXSize) + dfMinX;
1308 :
1309 : double dfMinY, dfMaxY;
1310 13 : if (dfYPixSz < 0)
1311 : {
1312 13 : dfMaxY = padfTransform[3];
1313 13 : dfMinY = (dfYPixSz * nRasterYSize) + padfTransform[3];
1314 : }
1315 : else
1316 : {
1317 0 : dfMaxY = (dfYPixSz * nRasterYSize) + padfTransform[3];
1318 0 : dfMinY = padfTransform[3];
1319 : }
1320 :
1321 13 : papszRDC = CSLSetNameValue(papszRDC, rdcMIN_X, CPLSPrintf("%.7f", dfMinX));
1322 13 : papszRDC = CSLSetNameValue(papszRDC, rdcMAX_X, CPLSPrintf("%.7f", dfMaxX));
1323 13 : papszRDC = CSLSetNameValue(papszRDC, rdcMIN_Y, CPLSPrintf("%.7f", dfMinY));
1324 13 : papszRDC = CSLSetNameValue(papszRDC, rdcMAX_Y, CPLSPrintf("%.7f", dfMaxY));
1325 13 : papszRDC = CSLSetNameValue(papszRDC, rdcRESOLUTION,
1326 : CPLSPrintf("%.7f", fabs(dfYPixSz)));
1327 :
1328 : // --------------------------------------------------------------------
1329 : // Update the Dataset attribute
1330 : // --------------------------------------------------------------------
1331 :
1332 13 : memcpy(adfGeoTransform, padfTransform, sizeof(double) * 6);
1333 :
1334 13 : return CE_None;
1335 : }
1336 :
1337 : /************************************************************************/
1338 : /* GetSpatialRef() */
1339 : /************************************************************************/
1340 :
1341 1 : const OGRSpatialReference *IdrisiDataset::GetSpatialRef() const
1342 : {
1343 1 : const auto poSRS = GDALPamDataset::GetSpatialRef();
1344 1 : if (poSRS)
1345 0 : return poSRS;
1346 :
1347 1 : if (m_oSRS.IsEmpty())
1348 : {
1349 1 : const char *pszRefSystem = myCSLFetchNameValue(papszRDC, rdcREF_SYSTEM);
1350 1 : const char *pszRefUnit = myCSLFetchNameValue(papszRDC, rdcREF_UNITS);
1351 1 : if (pszRefSystem != nullptr && pszRefUnit != nullptr)
1352 1 : IdrisiGeoReference2Wkt(pszFilename, pszRefSystem, pszRefUnit,
1353 1 : m_oSRS);
1354 : }
1355 1 : return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
1356 : }
1357 :
1358 : /************************************************************************/
1359 : /* SetProjection() */
1360 : /************************************************************************/
1361 :
1362 13 : CPLErr IdrisiDataset::SetSpatialRef(const OGRSpatialReference *poSRS)
1363 : {
1364 13 : m_oSRS.Clear();
1365 13 : if (poSRS)
1366 13 : m_oSRS = *poSRS;
1367 :
1368 13 : char *pszRefSystem = nullptr;
1369 13 : char *pszRefUnit = nullptr;
1370 :
1371 13 : CPLErr eResult = Wkt2GeoReference(m_oSRS, &pszRefSystem, &pszRefUnit);
1372 :
1373 13 : papszRDC = CSLSetNameValue(papszRDC, rdcREF_SYSTEM, pszRefSystem);
1374 13 : papszRDC = CSLSetNameValue(papszRDC, rdcREF_UNITS, pszRefUnit);
1375 :
1376 13 : CPLFree(pszRefSystem);
1377 13 : CPLFree(pszRefUnit);
1378 :
1379 13 : return eResult;
1380 : }
1381 :
1382 : /************************************************************************/
1383 : /* IdrisiRasterBand() */
1384 : /************************************************************************/
1385 :
1386 42 : IdrisiRasterBand::IdrisiRasterBand(IdrisiDataset *poDSIn, int nBandIn,
1387 42 : GDALDataType eDataTypeIn)
1388 : : poDefaultRAT(nullptr),
1389 126 : nRecordSize(poDSIn->GetRasterXSize() * poDSIn->nBands *
1390 42 : GDALGetDataTypeSizeBytes(eDataTypeIn)),
1391 42 : pabyScanLine(static_cast<GByte *>(VSI_MALLOC3_VERBOSE(
1392 : poDSIn->GetRasterXSize(), GDALGetDataTypeSizeBytes(eDataTypeIn),
1393 : poDSIn->nBands))),
1394 84 : fMaximum(0.0), fMinimum(0.0), bFirstVal(true)
1395 : {
1396 42 : poDS = poDSIn;
1397 42 : nBand = nBandIn;
1398 42 : eDataType = eDataTypeIn;
1399 42 : nBlockYSize = 1;
1400 42 : nBlockXSize = poDS->GetRasterXSize();
1401 42 : }
1402 :
1403 : /************************************************************************/
1404 : /* ~IdrisiRasterBand() */
1405 : /************************************************************************/
1406 :
1407 84 : IdrisiRasterBand::~IdrisiRasterBand()
1408 : {
1409 42 : CPLFree(pabyScanLine);
1410 :
1411 42 : if (poDefaultRAT)
1412 : {
1413 0 : delete poDefaultRAT;
1414 : }
1415 84 : }
1416 :
1417 : /************************************************************************/
1418 : /* IReadBlock() */
1419 : /************************************************************************/
1420 :
1421 1392 : CPLErr IdrisiRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff,
1422 : void *pImage)
1423 : {
1424 1392 : IdrisiDataset *poGDS = (IdrisiDataset *)poDS;
1425 :
1426 1392 : if (VSIFSeekL(poGDS->fp, vsi_l_offset(nRecordSize) * nBlockYOff, SEEK_SET) <
1427 : 0)
1428 : {
1429 0 : CPLError(CE_Failure, CPLE_FileIO,
1430 : "Can't seek(%s) block with X offset %d and Y offset %d.\n%s",
1431 : poGDS->pszFilename, nBlockXOff, nBlockYOff,
1432 0 : VSIStrerror(errno));
1433 0 : return CE_Failure;
1434 : }
1435 :
1436 1392 : if ((int)VSIFReadL(pabyScanLine, 1, nRecordSize, poGDS->fp) < nRecordSize)
1437 : {
1438 0 : CPLError(CE_Failure, CPLE_FileIO,
1439 : "Can't read(%s) block with X offset %d and Y offset %d.\n%s",
1440 : poGDS->pszFilename, nBlockXOff, nBlockYOff,
1441 0 : VSIStrerror(errno));
1442 0 : return CE_Failure;
1443 : }
1444 :
1445 1392 : if (poGDS->nBands == 3)
1446 : {
1447 43380 : for (int i = 0, j = (3 - nBand); i < nBlockXSize; i++, j += 3)
1448 : {
1449 42800 : ((GByte *)pImage)[i] = pabyScanLine[j];
1450 : }
1451 : }
1452 : else
1453 : {
1454 812 : memcpy(pImage, pabyScanLine, nRecordSize);
1455 : }
1456 :
1457 : #ifdef CPL_MSB
1458 : if (eDataType == GDT_Float32)
1459 : GDALSwapWords(pImage, 4, nBlockXSize * nBlockYSize, 4);
1460 : #endif
1461 :
1462 1392 : return CE_None;
1463 : }
1464 :
1465 : /************************************************************************/
1466 : /* IWriteBlock() */
1467 : /************************************************************************/
1468 :
1469 230 : CPLErr IdrisiRasterBand::IWriteBlock(int nBlockXOff, int nBlockYOff,
1470 : void *pImage)
1471 : {
1472 230 : IdrisiDataset *poGDS = (IdrisiDataset *)poDS;
1473 :
1474 : #ifdef CPL_MSB
1475 : // Swap in input buffer if needed.
1476 : if (eDataType == GDT_Float32)
1477 : GDALSwapWords(pImage, 4, nBlockXSize * nBlockYSize, 4);
1478 : #endif
1479 :
1480 230 : if (poGDS->nBands == 1)
1481 : {
1482 50 : memcpy(pabyScanLine, pImage, nRecordSize);
1483 : }
1484 : else
1485 : {
1486 180 : if (nBand > 1)
1487 : {
1488 120 : VSIFSeekL(poGDS->fp, vsi_l_offset(nRecordSize) * nBlockYOff,
1489 : SEEK_SET);
1490 120 : VSIFReadL(pabyScanLine, 1, nRecordSize, poGDS->fp);
1491 : }
1492 : int i, j;
1493 7980 : for (i = 0, j = (3 - nBand); i < nBlockXSize; i++, j += 3)
1494 : {
1495 7800 : pabyScanLine[j] = ((GByte *)pImage)[i];
1496 : }
1497 : }
1498 :
1499 : #ifdef CPL_MSB
1500 : // Swap input buffer back to original form.
1501 : if (eDataType == GDT_Float32)
1502 : GDALSwapWords(pImage, 4, nBlockXSize * nBlockYSize, 4);
1503 : #endif
1504 :
1505 230 : VSIFSeekL(poGDS->fp, vsi_l_offset(nRecordSize) * nBlockYOff, SEEK_SET);
1506 :
1507 230 : if ((int)VSIFWriteL(pabyScanLine, 1, nRecordSize, poGDS->fp) < nRecordSize)
1508 : {
1509 0 : CPLError(CE_Failure, CPLE_FileIO,
1510 : "Can't write(%s) block with X offset %d and Y offset %d.\n%s",
1511 : poGDS->pszFilename, nBlockXOff, nBlockYOff,
1512 0 : VSIStrerror(errno));
1513 0 : return CE_Failure;
1514 : }
1515 :
1516 230 : int bHasNoDataValue = FALSE;
1517 230 : float fNoDataValue = (float)GetNoDataValue(&bHasNoDataValue);
1518 :
1519 : // --------------------------------------------------------------------
1520 : // Search for the minimum and maximum values
1521 : // --------------------------------------------------------------------
1522 :
1523 230 : if (eDataType == GDT_Float32)
1524 : {
1525 530 : for (int i = 0; i < nBlockXSize; i++)
1526 : {
1527 500 : float fVal = ((float *)pabyScanLine)[i]; // this is fine
1528 500 : if (!bHasNoDataValue || fVal != fNoDataValue)
1529 : {
1530 500 : if (bFirstVal)
1531 : {
1532 2 : fMinimum = fVal;
1533 2 : fMaximum = fVal;
1534 2 : bFirstVal = false;
1535 : }
1536 : else
1537 : {
1538 498 : if (fVal < fMinimum)
1539 3 : fMinimum = fVal;
1540 498 : if (fVal > fMaximum)
1541 9 : fMaximum = fVal;
1542 : }
1543 : }
1544 : }
1545 : }
1546 200 : else if (eDataType == GDT_Int16)
1547 : {
1548 110 : for (int i = 0; i < nBlockXSize; i++)
1549 : {
1550 100 : float fVal = (float)((GInt16 *)pabyScanLine)[i];
1551 100 : if (!bHasNoDataValue || fVal != fNoDataValue)
1552 : {
1553 100 : if (bFirstVal)
1554 : {
1555 1 : fMinimum = fVal;
1556 1 : fMaximum = fVal;
1557 1 : bFirstVal = false;
1558 : }
1559 : else
1560 : {
1561 99 : if (fVal < fMinimum)
1562 0 : fMinimum = fVal;
1563 99 : if (fVal > fMaximum)
1564 0 : fMaximum = fVal;
1565 : }
1566 : }
1567 : }
1568 : }
1569 190 : else if (poGDS->nBands == 1)
1570 : {
1571 110 : for (int i = 0; i < nBlockXSize; i++)
1572 : {
1573 100 : float fVal = (float)((GByte *)pabyScanLine)[i];
1574 100 : if (!bHasNoDataValue || fVal != fNoDataValue)
1575 : {
1576 100 : if (bFirstVal)
1577 : {
1578 1 : fMinimum = fVal;
1579 1 : fMaximum = fVal;
1580 1 : bFirstVal = false;
1581 : }
1582 : else
1583 : {
1584 99 : if (fVal < fMinimum)
1585 0 : fMinimum =
1586 : fVal; // I don't change this part, keep it as it is
1587 99 : if (fVal > fMaximum)
1588 0 : fMaximum = fVal;
1589 : }
1590 : }
1591 : }
1592 : }
1593 : else
1594 : {
1595 7980 : for (int i = 0, j = (3 - nBand); i < nBlockXSize; i++, j += 3)
1596 : {
1597 7800 : float fVal = (float)((GByte *)pabyScanLine)[j];
1598 7800 : if (!bHasNoDataValue || fVal != fNoDataValue)
1599 : {
1600 7800 : if (bFirstVal)
1601 : {
1602 6 : fMinimum = fVal;
1603 6 : fMaximum = fVal;
1604 6 : bFirstVal = false;
1605 : }
1606 : else
1607 : {
1608 7794 : if (fVal < fMinimum)
1609 0 : fMinimum = fVal;
1610 7794 : if (fVal > fMaximum)
1611 28 : fMaximum = fVal;
1612 : }
1613 : }
1614 : }
1615 : }
1616 :
1617 230 : return CE_None;
1618 : }
1619 :
1620 : /************************************************************************/
1621 : /* GetMinimum() */
1622 : /************************************************************************/
1623 :
1624 0 : double IdrisiRasterBand::GetMinimum(int *pbSuccess)
1625 : {
1626 0 : IdrisiDataset *poGDS = (IdrisiDataset *)poDS;
1627 :
1628 0 : if (myCSLFetchNameValue(poGDS->papszRDC, rdcMIN_VALUE) == nullptr)
1629 0 : return GDALPamRasterBand::GetMinimum(pbSuccess);
1630 :
1631 : double adfMinValue[3];
1632 0 : CPLsscanf(myCSLFetchNameValue(poGDS->papszRDC, rdcMIN_VALUE), "%lf %lf %lf",
1633 : &adfMinValue[0], &adfMinValue[1], &adfMinValue[2]);
1634 :
1635 0 : if (pbSuccess)
1636 : {
1637 0 : *pbSuccess = true;
1638 : }
1639 :
1640 0 : return adfMinValue[this->nBand - 1];
1641 : }
1642 :
1643 : /************************************************************************/
1644 : /* GetMaximum() */
1645 : /************************************************************************/
1646 :
1647 0 : double IdrisiRasterBand::GetMaximum(int *pbSuccess)
1648 : {
1649 0 : IdrisiDataset *poGDS = (IdrisiDataset *)poDS;
1650 :
1651 0 : if (myCSLFetchNameValue(poGDS->papszRDC, rdcMAX_VALUE) == nullptr)
1652 0 : return GDALPamRasterBand::GetMaximum(pbSuccess);
1653 :
1654 : double adfMaxValue[3];
1655 0 : CPLsscanf(myCSLFetchNameValue(poGDS->papszRDC, rdcMAX_VALUE), "%lf %lf %lf",
1656 : &adfMaxValue[0], &adfMaxValue[1], &adfMaxValue[2]);
1657 :
1658 0 : if (pbSuccess)
1659 : {
1660 0 : *pbSuccess = true;
1661 : }
1662 :
1663 0 : return adfMaxValue[this->nBand - 1];
1664 : }
1665 :
1666 : /************************************************************************/
1667 : /* GetNoDataValue() */
1668 : /************************************************************************/
1669 :
1670 276 : double IdrisiRasterBand::GetNoDataValue(int *pbSuccess)
1671 : {
1672 276 : IdrisiDataset *poGDS = (IdrisiDataset *)poDS;
1673 :
1674 276 : const char *pszFlagDefn = nullptr;
1675 :
1676 276 : if (myCSLFetchNameValue(poGDS->papszRDC, rdcFLAG_DEFN) != nullptr)
1677 276 : pszFlagDefn = myCSLFetchNameValue(poGDS->papszRDC, rdcFLAG_DEFN);
1678 0 : else if (myCSLFetchNameValue(poGDS->papszRDC, rdcFLAG_DEFN2) != nullptr)
1679 0 : pszFlagDefn = myCSLFetchNameValue(poGDS->papszRDC, rdcFLAG_DEFN2);
1680 :
1681 : // ------------------------------------------------------------------------
1682 : // If Flag_Def is not "none", Flag_Value means "background"
1683 : // or "missing data"
1684 : // ------------------------------------------------------------------------
1685 :
1686 : double dfNoData;
1687 276 : if (pszFlagDefn != nullptr && !EQUAL(pszFlagDefn, "none"))
1688 : {
1689 0 : dfNoData =
1690 0 : CPLAtof_nz(myCSLFetchNameValue(poGDS->papszRDC, rdcFLAG_VALUE));
1691 0 : if (pbSuccess)
1692 0 : *pbSuccess = TRUE;
1693 : }
1694 : else
1695 : {
1696 276 : dfNoData = -9999.0; /* this value should be ignored */
1697 276 : if (pbSuccess)
1698 276 : *pbSuccess = FALSE;
1699 : }
1700 :
1701 276 : return dfNoData;
1702 : }
1703 :
1704 : /************************************************************************/
1705 : /* SetNoDataValue() */
1706 : /************************************************************************/
1707 :
1708 0 : CPLErr IdrisiRasterBand::SetNoDataValue(double dfNoDataValue)
1709 : {
1710 0 : IdrisiDataset *poGDS = (IdrisiDataset *)poDS;
1711 :
1712 0 : poGDS->papszRDC = CSLSetNameValue(poGDS->papszRDC, rdcFLAG_VALUE,
1713 : CPLSPrintf("%.7g", dfNoDataValue));
1714 0 : poGDS->papszRDC =
1715 0 : CSLSetNameValue(poGDS->papszRDC, rdcFLAG_DEFN, "missing data");
1716 :
1717 0 : return CE_None;
1718 : }
1719 :
1720 : /************************************************************************/
1721 : /* GetColorInterpretation() */
1722 : /************************************************************************/
1723 :
1724 0 : GDALColorInterp IdrisiRasterBand::GetColorInterpretation()
1725 : {
1726 0 : IdrisiDataset *poGDS = (IdrisiDataset *)poDS;
1727 :
1728 0 : if (poGDS->nBands == 3)
1729 : {
1730 0 : switch (nBand)
1731 : {
1732 0 : case 1:
1733 0 : return GCI_BlueBand;
1734 0 : case 2:
1735 0 : return GCI_GreenBand;
1736 0 : case 3:
1737 0 : return GCI_RedBand;
1738 : }
1739 : }
1740 0 : else if (poGDS->poColorTable->GetColorEntryCount() > 0)
1741 : {
1742 0 : return GCI_PaletteIndex;
1743 : }
1744 0 : return GCI_GrayIndex;
1745 : }
1746 :
1747 : /************************************************************************/
1748 : /* GetCategoryNames() */
1749 : /************************************************************************/
1750 :
1751 0 : char **IdrisiRasterBand::GetCategoryNames()
1752 : {
1753 0 : IdrisiDataset *poGDS = (IdrisiDataset *)poDS;
1754 :
1755 0 : return poGDS->papszCategories;
1756 : }
1757 :
1758 : /************************************************************************/
1759 : /* SetCategoryNames() */
1760 : /************************************************************************/
1761 :
1762 3 : CPLErr IdrisiRasterBand::SetCategoryNames(char **papszCategoryNames)
1763 : {
1764 3 : const int nCatCount = CSLCount(papszCategoryNames);
1765 :
1766 3 : if (nCatCount == 0)
1767 3 : return CE_None;
1768 :
1769 0 : IdrisiDataset *poGDS = (IdrisiDataset *)poDS;
1770 :
1771 0 : CSLDestroy(poGDS->papszCategories);
1772 0 : poGDS->papszCategories = CSLDuplicate(papszCategoryNames);
1773 :
1774 : // ------------------------------------------------------
1775 : // Search for the "Legend cats : N" line
1776 : // ------------------------------------------------------
1777 :
1778 0 : int nLine = -1;
1779 0 : for (int i = 0; (i < CSLCount(poGDS->papszRDC)) && (nLine == -1); i++)
1780 0 : if (EQUALN(poGDS->papszRDC[i], rdcLEGEND_CATS, 12))
1781 0 : nLine = i;
1782 :
1783 0 : if (nLine < 0)
1784 0 : return CE_None;
1785 :
1786 0 : int nCount = atoi_nz(myCSLFetchNameValue(poGDS->papszRDC, rdcLEGEND_CATS));
1787 :
1788 : // ------------------------------------------------------
1789 : // Delete old instance of the category names
1790 : // ------------------------------------------------------
1791 :
1792 0 : if (nCount > 0)
1793 0 : poGDS->papszRDC =
1794 0 : CSLRemoveStrings(poGDS->papszRDC, nLine + 1, nCount, nullptr);
1795 :
1796 0 : nCount = 0;
1797 :
1798 0 : for (int i = 0; i < nCatCount; i++)
1799 : {
1800 0 : if ((strlen(papszCategoryNames[i]) > 0))
1801 : {
1802 0 : poGDS->papszRDC =
1803 0 : CSLInsertString(poGDS->papszRDC, (nLine + nCount + 1),
1804 : CPLSPrintf("%s:%s", CPLSPrintf(rdcCODE_N, i),
1805 0 : papszCategoryNames[i]));
1806 0 : nCount++;
1807 : }
1808 : }
1809 :
1810 0 : poGDS->papszRDC =
1811 0 : CSLSetNameValue(poGDS->papszRDC, rdcLEGEND_CATS,
1812 : CPLSPrintf("%d", nCount)); // this is fine
1813 :
1814 0 : return CE_None;
1815 : }
1816 :
1817 : /************************************************************************/
1818 : /* GetColorTable() */
1819 : /************************************************************************/
1820 :
1821 0 : GDALColorTable *IdrisiRasterBand::GetColorTable()
1822 : {
1823 0 : IdrisiDataset *poGDS = (IdrisiDataset *)poDS;
1824 :
1825 0 : if (poGDS->poColorTable->GetColorEntryCount() == 0)
1826 : {
1827 0 : return nullptr;
1828 : }
1829 :
1830 0 : return poGDS->poColorTable;
1831 : }
1832 :
1833 : /************************************************************************/
1834 : /* SetColorTable() */
1835 : /************************************************************************/
1836 :
1837 3 : CPLErr IdrisiRasterBand::SetColorTable(GDALColorTable *poColorTable)
1838 : {
1839 3 : if (poColorTable == nullptr)
1840 : {
1841 3 : return CE_None;
1842 : }
1843 :
1844 0 : if (poColorTable->GetColorEntryCount() == 0)
1845 : {
1846 0 : return CE_None;
1847 : }
1848 :
1849 0 : IdrisiDataset *poGDS = (IdrisiDataset *)poDS;
1850 :
1851 0 : delete poGDS->poColorTable;
1852 :
1853 0 : poGDS->poColorTable = poColorTable->Clone();
1854 :
1855 0 : const char *pszSMPFilename = CPLResetExtension(poGDS->pszFilename, extSMP);
1856 0 : VSILFILE *fpSMP = VSIFOpenL(pszSMPFilename, "w");
1857 :
1858 0 : if (fpSMP != nullptr)
1859 : {
1860 0 : VSIFWriteL("[Idrisi]", 8, 1, fpSMP);
1861 0 : GByte nPlatform = 1;
1862 0 : VSIFWriteL(&nPlatform, 1, 1, fpSMP);
1863 0 : GByte nVersion = 11;
1864 0 : VSIFWriteL(&nVersion, 1, 1, fpSMP);
1865 0 : GByte nDepth = 8;
1866 0 : VSIFWriteL(&nDepth, 1, 1, fpSMP);
1867 0 : GByte nHeadSz = 18;
1868 0 : VSIFWriteL(&nHeadSz, 1, 1, fpSMP);
1869 0 : GUInt16 nCount = 255;
1870 0 : VSIFWriteL(&nCount, 2, 1, fpSMP);
1871 0 : GUInt16 nMix = 0;
1872 0 : VSIFWriteL(&nMix, 2, 1, fpSMP);
1873 0 : GUInt16 nMax = 255;
1874 0 : VSIFWriteL(&nMax, 2, 1, fpSMP);
1875 :
1876 : GDALColorEntry oEntry;
1877 : GByte aucRGB[3];
1878 :
1879 0 : for (int i = 0; i < poColorTable->GetColorEntryCount(); i++)
1880 : {
1881 0 : poColorTable->GetColorEntryAsRGB(i, &oEntry);
1882 0 : aucRGB[0] = (GByte)oEntry.c1;
1883 0 : aucRGB[1] = (GByte)oEntry.c2;
1884 0 : aucRGB[2] = (GByte)oEntry.c3;
1885 0 : VSIFWriteL(&aucRGB, 3, 1, fpSMP);
1886 : }
1887 : /* smp files always have 256 occurrences. */
1888 0 : for (int i = poColorTable->GetColorEntryCount(); i <= 255; i++)
1889 : {
1890 0 : poColorTable->GetColorEntryAsRGB(i, &oEntry);
1891 0 : aucRGB[0] = (GByte)0;
1892 0 : aucRGB[1] = (GByte)0;
1893 0 : aucRGB[2] = (GByte)0;
1894 0 : VSIFWriteL(&aucRGB, 3, 1, fpSMP);
1895 : }
1896 0 : VSIFCloseL(fpSMP);
1897 : }
1898 :
1899 0 : return CE_None;
1900 : }
1901 :
1902 : /************************************************************************/
1903 : /* GetUnitType() */
1904 : /************************************************************************/
1905 :
1906 0 : const char *IdrisiRasterBand::GetUnitType()
1907 : {
1908 0 : IdrisiDataset *poGDS = (IdrisiDataset *)poDS;
1909 :
1910 0 : return poGDS->pszUnitType;
1911 : }
1912 :
1913 : /************************************************************************/
1914 : /* SetUnitType() */
1915 : /************************************************************************/
1916 :
1917 3 : CPLErr IdrisiRasterBand::SetUnitType(const char *pszUnitType)
1918 : {
1919 3 : IdrisiDataset *poGDS = (IdrisiDataset *)poDS;
1920 :
1921 3 : if (strlen(pszUnitType) == 0)
1922 : {
1923 3 : poGDS->papszRDC =
1924 3 : CSLSetNameValue(poGDS->papszRDC, rdcVALUE_UNITS, "unspecified");
1925 : }
1926 : else
1927 : {
1928 0 : poGDS->papszRDC =
1929 0 : CSLSetNameValue(poGDS->papszRDC, rdcVALUE_UNITS, pszUnitType);
1930 : }
1931 :
1932 3 : return CE_None;
1933 : }
1934 :
1935 : /************************************************************************/
1936 : /* SetMinMax() */
1937 : /************************************************************************/
1938 :
1939 49 : CPLErr IdrisiRasterBand::SetMinMax(double dfMin, double dfMax)
1940 : {
1941 49 : IdrisiDataset *poGDS = (IdrisiDataset *)poDS;
1942 :
1943 49 : fMinimum = (float)dfMin;
1944 49 : fMaximum = (float)dfMax;
1945 :
1946 49 : double adfMin[3] = {0.0, 0.0, 0.0};
1947 49 : double adfMax[3] = {0.0, 0.0, 0.0};
1948 :
1949 49 : if (myCSLFetchNameValue(poGDS->papszRDC, rdcMIN_VALUE) != nullptr)
1950 49 : CPLsscanf(myCSLFetchNameValue(poGDS->papszRDC, rdcMIN_VALUE),
1951 : "%lf %lf %lf", &adfMin[0], &adfMin[1], &adfMin[2]);
1952 49 : if (myCSLFetchNameValue(poGDS->papszRDC, rdcMAX_VALUE) != nullptr)
1953 49 : CPLsscanf(myCSLFetchNameValue(poGDS->papszRDC, rdcMAX_VALUE),
1954 : "%lf %lf %lf", &adfMax[0], &adfMax[1], &adfMax[2]);
1955 :
1956 49 : adfMin[nBand - 1] = dfMin;
1957 49 : adfMax[nBand - 1] = dfMax;
1958 :
1959 49 : if (poGDS->nBands == 3)
1960 : {
1961 24 : poGDS->papszRDC = CSLSetNameValue(
1962 : poGDS->papszRDC, rdcMIN_VALUE,
1963 : CPLSPrintf("%.8g %.8g %.8g", adfMin[0], adfMin[1], adfMin[2]));
1964 24 : poGDS->papszRDC = CSLSetNameValue(
1965 : poGDS->papszRDC, rdcMAX_VALUE,
1966 : CPLSPrintf("%.8g %.8g %.8g", adfMax[0], adfMax[1], adfMax[2]));
1967 24 : poGDS->papszRDC = CSLSetNameValue(
1968 : poGDS->papszRDC, rdcDISPLAY_MIN,
1969 : CPLSPrintf("%.8g %.8g %.8g", adfMin[0], adfMin[1], adfMin[2]));
1970 24 : poGDS->papszRDC = CSLSetNameValue(
1971 : poGDS->papszRDC, rdcDISPLAY_MAX,
1972 : CPLSPrintf("%.8g %.8g %.8g", adfMax[0], adfMax[1], adfMax[2]));
1973 : }
1974 : else
1975 : {
1976 25 : poGDS->papszRDC = CSLSetNameValue(poGDS->papszRDC, rdcMIN_VALUE,
1977 : CPLSPrintf("%.8g", adfMin[0]));
1978 25 : poGDS->papszRDC = CSLSetNameValue(poGDS->papszRDC, rdcMAX_VALUE,
1979 : CPLSPrintf("%.8g", adfMax[0]));
1980 25 : poGDS->papszRDC = CSLSetNameValue(poGDS->papszRDC, rdcDISPLAY_MIN,
1981 : CPLSPrintf("%.8g", adfMin[0]));
1982 25 : poGDS->papszRDC = CSLSetNameValue(poGDS->papszRDC, rdcDISPLAY_MAX,
1983 : CPLSPrintf("%.8g", adfMax[0]));
1984 : }
1985 :
1986 49 : return CE_None;
1987 : }
1988 :
1989 : /************************************************************************/
1990 : /* SetStatistics() */
1991 : /************************************************************************/
1992 :
1993 20 : CPLErr IdrisiRasterBand::SetStatistics(double dfMin, double dfMax,
1994 : double dfMean, double dfStdDev)
1995 : {
1996 20 : SetMinMax(dfMin, dfMax);
1997 :
1998 20 : return GDALPamRasterBand::SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
1999 : }
2000 :
2001 : /************************************************************************/
2002 : /* SetDefaultRAT() */
2003 : /************************************************************************/
2004 :
2005 0 : CPLErr IdrisiRasterBand::SetDefaultRAT(const GDALRasterAttributeTable *poRAT)
2006 : {
2007 0 : if (!poRAT)
2008 : {
2009 0 : return CE_Failure;
2010 : }
2011 :
2012 : // ----------------------------------------------------------
2013 : // Get field indices
2014 : // ----------------------------------------------------------
2015 :
2016 0 : int iValue = -1;
2017 0 : int iRed = poRAT->GetColOfUsage(GFU_Red);
2018 0 : int iGreen = poRAT->GetColOfUsage(GFU_Green);
2019 0 : int iBlue = poRAT->GetColOfUsage(GFU_Blue);
2020 :
2021 0 : GDALColorTable *poCT = nullptr;
2022 0 : char **papszNames = nullptr;
2023 :
2024 0 : int nFact = 1;
2025 :
2026 : // ----------------------------------------------------------
2027 : // Seek for "Value" field index (AGIS standards field name)
2028 : // ----------------------------------------------------------
2029 :
2030 0 : if (GetColorTable() == nullptr ||
2031 0 : GetColorTable()->GetColorEntryCount() == 0)
2032 : {
2033 0 : for (int i = 0; i < poRAT->GetColumnCount(); i++)
2034 : {
2035 0 : if (STARTS_WITH_CI(poRAT->GetNameOfCol(i), "Value"))
2036 : {
2037 0 : iValue = i;
2038 0 : break;
2039 : }
2040 : }
2041 :
2042 0 : if (iRed != -1 && iGreen != -1 && iBlue != -1)
2043 : {
2044 0 : poCT = new GDALColorTable();
2045 0 : nFact = poRAT->GetTypeOfCol(iRed) == GFT_Real ? 255 : 1;
2046 : }
2047 : }
2048 :
2049 : // ----------------------------------------------------------
2050 : // Seek for Name field index
2051 : // ----------------------------------------------------------
2052 :
2053 0 : int iName = -1;
2054 0 : if (CSLCount(GetCategoryNames()) == 0)
2055 : {
2056 0 : iName = poRAT->GetColOfUsage(GFU_Name);
2057 0 : if (iName == -1)
2058 : {
2059 0 : for (int i = 0; i < poRAT->GetColumnCount(); i++)
2060 : {
2061 0 : if (STARTS_WITH_CI(poRAT->GetNameOfCol(i), "Class_Name"))
2062 : {
2063 0 : iName = i;
2064 0 : break;
2065 : }
2066 0 : else if (STARTS_WITH_CI(poRAT->GetNameOfCol(i), "Categor"))
2067 : {
2068 0 : iName = i;
2069 0 : break;
2070 : }
2071 0 : else if (STARTS_WITH_CI(poRAT->GetNameOfCol(i), "Name"))
2072 : {
2073 0 : iName = i;
2074 0 : break;
2075 : }
2076 : }
2077 : }
2078 :
2079 : /* if still can't find it use the first String column */
2080 :
2081 0 : if (iName == -1)
2082 : {
2083 0 : for (int i = 0; i < poRAT->GetColumnCount(); i++)
2084 : {
2085 0 : if (poRAT->GetTypeOfCol(i) == GFT_String)
2086 : {
2087 0 : iName = i;
2088 0 : break;
2089 : }
2090 : }
2091 : }
2092 :
2093 : // ----------------------------------------------------------
2094 : // Incomplete Attribute Table;
2095 : // ----------------------------------------------------------
2096 :
2097 0 : if (iName == -1)
2098 : {
2099 0 : iName = iValue;
2100 : }
2101 : }
2102 :
2103 : // ----------------------------------------------------------
2104 : // Load values
2105 : // ----------------------------------------------------------
2106 :
2107 : GDALColorEntry sColor;
2108 0 : int iEntry = 0;
2109 0 : int iOut = 0;
2110 0 : int nEntryCount = poRAT->GetRowCount();
2111 0 : int nValue = 0;
2112 :
2113 0 : if (iValue != -1)
2114 : {
2115 0 : nValue = poRAT->GetValueAsInt(iEntry, iValue);
2116 : }
2117 :
2118 0 : for (iOut = 0; iOut < 65535 && (iEntry < nEntryCount); iOut++)
2119 : {
2120 0 : if (iOut == nValue)
2121 : {
2122 0 : if (poCT)
2123 : {
2124 0 : const double dRed = poRAT->GetValueAsDouble(iEntry, iRed);
2125 0 : const double dGreen = poRAT->GetValueAsDouble(iEntry, iGreen);
2126 0 : const double dBlue = poRAT->GetValueAsDouble(iEntry, iBlue);
2127 0 : sColor.c1 = (short)(dRed * nFact);
2128 0 : sColor.c2 = (short)(dGreen * nFact);
2129 0 : sColor.c3 = (short)(dBlue * nFact);
2130 0 : sColor.c4 = (short)(255 / nFact);
2131 0 : poCT->SetColorEntry(iEntry, &sColor);
2132 : }
2133 :
2134 0 : if (iName != -1)
2135 : {
2136 0 : papszNames = CSLAddString(
2137 0 : papszNames, poRAT->GetValueAsString(iEntry, iName));
2138 : }
2139 :
2140 : /* Advance on the table */
2141 :
2142 0 : if ((++iEntry) < nEntryCount)
2143 : {
2144 0 : if (iValue != -1)
2145 0 : nValue = poRAT->GetValueAsInt(iEntry, iValue);
2146 : else
2147 0 : nValue = iEntry;
2148 : }
2149 : }
2150 0 : else if (iOut < nValue)
2151 : {
2152 0 : if (poCT)
2153 : {
2154 0 : sColor.c1 = (short)0;
2155 0 : sColor.c2 = (short)0;
2156 0 : sColor.c3 = (short)0;
2157 0 : sColor.c4 = (short)255;
2158 0 : poCT->SetColorEntry(iEntry, &sColor);
2159 : }
2160 :
2161 0 : if (iName != -1)
2162 0 : papszNames = CSLAddString(papszNames, "");
2163 : }
2164 : }
2165 :
2166 : // ----------------------------------------------------------
2167 : // Set Color Table
2168 : // ----------------------------------------------------------
2169 :
2170 0 : if (poCT)
2171 : {
2172 0 : SetColorTable(poCT);
2173 0 : delete poCT;
2174 : }
2175 :
2176 : // ----------------------------------------------------------
2177 : // Update Category Names
2178 : // ----------------------------------------------------------
2179 :
2180 0 : if (papszNames)
2181 : {
2182 0 : SetCategoryNames(papszNames);
2183 0 : CSLDestroy(papszNames);
2184 : }
2185 :
2186 : // ----------------------------------------------------------
2187 : // Update Attribute Table
2188 : // ----------------------------------------------------------
2189 :
2190 0 : if (poDefaultRAT)
2191 : {
2192 0 : delete poDefaultRAT;
2193 : }
2194 :
2195 0 : poDefaultRAT = poRAT->Clone();
2196 :
2197 0 : return CE_None;
2198 : }
2199 :
2200 : /************************************************************************/
2201 : /* GetDefaultRAT() */
2202 : /************************************************************************/
2203 :
2204 0 : GDALRasterAttributeTable *IdrisiRasterBand::GetDefaultRAT()
2205 : {
2206 0 : IdrisiDataset *poGDS = (IdrisiDataset *)poDS;
2207 :
2208 0 : if (poGDS->papszCategories == nullptr)
2209 : {
2210 0 : return nullptr;
2211 : }
2212 :
2213 0 : bool bHasColorTable = poGDS->poColorTable->GetColorEntryCount() > 0;
2214 :
2215 : // ----------------------------------------------------------
2216 : // Create the bands Attribute Table
2217 : // ----------------------------------------------------------
2218 :
2219 0 : if (poDefaultRAT)
2220 : {
2221 0 : delete poDefaultRAT;
2222 : }
2223 :
2224 0 : poDefaultRAT = new GDALDefaultRasterAttributeTable();
2225 :
2226 : // ----------------------------------------------------------
2227 : // Create (Value, Red, Green, Blue, Alpha, Class_Name) fields
2228 : // ----------------------------------------------------------
2229 :
2230 0 : poDefaultRAT->CreateColumn("Value", GFT_Integer, GFU_Generic);
2231 0 : poDefaultRAT->CreateColumn("Value_1", GFT_Integer, GFU_MinMax);
2232 :
2233 0 : if (bHasColorTable)
2234 : {
2235 0 : poDefaultRAT->CreateColumn("Red", GFT_Integer, GFU_Red);
2236 0 : poDefaultRAT->CreateColumn("Green", GFT_Integer, GFU_Green);
2237 0 : poDefaultRAT->CreateColumn("Blue", GFT_Integer, GFU_Blue);
2238 0 : poDefaultRAT->CreateColumn("Alpha", GFT_Integer, GFU_Alpha);
2239 : }
2240 0 : poDefaultRAT->CreateColumn("Class_name", GFT_String, GFU_Name);
2241 :
2242 : // ----------------------------------------------------------
2243 : // Loop through the Category Names.
2244 : // ----------------------------------------------------------
2245 :
2246 : GDALColorEntry sEntry;
2247 0 : int iName = poDefaultRAT->GetColOfUsage(GFU_Name);
2248 0 : int nEntryCount = CSLCount(poGDS->papszCategories);
2249 0 : int iRows = 0;
2250 :
2251 0 : for (int iEntry = 0; iEntry < nEntryCount; iEntry++)
2252 : {
2253 0 : if (EQUAL(poGDS->papszCategories[iEntry], ""))
2254 : {
2255 0 : continue; // Eliminate the empty ones
2256 : }
2257 0 : poDefaultRAT->SetRowCount(poDefaultRAT->GetRowCount() + 1);
2258 0 : poDefaultRAT->SetValue(iRows, 0, iEntry);
2259 0 : poDefaultRAT->SetValue(iRows, 1, iEntry);
2260 0 : if (bHasColorTable)
2261 : {
2262 0 : poGDS->poColorTable->GetColorEntryAsRGB(iEntry, &sEntry);
2263 0 : poDefaultRAT->SetValue(iRows, 2, sEntry.c1);
2264 0 : poDefaultRAT->SetValue(iRows, 3, sEntry.c2);
2265 0 : poDefaultRAT->SetValue(iRows, 4, sEntry.c3);
2266 0 : poDefaultRAT->SetValue(iRows, 5, sEntry.c4);
2267 : }
2268 0 : poDefaultRAT->SetValue(iRows, iName, poGDS->papszCategories[iEntry]);
2269 0 : iRows++;
2270 : }
2271 :
2272 0 : return poDefaultRAT;
2273 : }
2274 :
2275 : /************************************************************************/
2276 : /* IdrisiGeoReference2Wkt() */
2277 : /************************************************************************/
2278 :
2279 : /***
2280 : * Converts Idrisi geographic reference information to OpenGIS WKT.
2281 : *
2282 : * The Idrisi metadata file contain two fields that describe the
2283 : * geographic reference, RefSystem and RefUnit.
2284 : *
2285 : * RefSystem can contains the world "plane" or the name of a georeference
2286 : * file <refsystem>.ref that details the geographic reference
2287 : * system( coordinate system and projection parameters ). RefUnits
2288 : * indicates the unit of the image bounds.
2289 : *
2290 : * The georeference files are generally located in the product installation
2291 : * folder $IDRISIDIR\Georef, but they are first looked for in the same
2292 : * folder as the data file.
2293 : *
2294 : * If a Reference system names can be recognized by a name convention
2295 : * it will be interpreted without the need to read the georeference file.
2296 : * That includes "latlong" and all the UTM and State Plane zones.
2297 : *
2298 : * RefSystem "latlong" means that the data is not project and the coordinate
2299 : * system is WGS84. RefSystem "plane" means that the there is no coordinate
2300 : * system but the it is possible to calculate areas and distance by looking
2301 : * at the RefUnits.
2302 : *
2303 : * If the environment variable IDRISIDIR is not set and the georeference file
2304 : * need to be read then the projection string will result as unknown.
2305 : ***/
2306 :
2307 4 : CPLErr IdrisiGeoReference2Wkt(const char *pszFilename, const char *pszRefSystem,
2308 : const char *pszRefUnits,
2309 : OGRSpatialReference &oSRS)
2310 : {
2311 : // ---------------------------------------------------------
2312 : // Plane
2313 : // ---------------------------------------------------------
2314 :
2315 4 : if (EQUAL(pszRefSystem, rstPLANE))
2316 : {
2317 0 : oSRS.SetLocalCS("Plane");
2318 0 : int nUnit = GetUnitIndex(pszRefUnits);
2319 0 : if (nUnit > -1)
2320 : {
2321 0 : int nDeft = aoLinearUnitsConv[nUnit].nDefaultG;
2322 0 : oSRS.SetLinearUnits(aoLinearUnitsConv[nDeft].pszName,
2323 0 : aoLinearUnitsConv[nDeft].dfConv);
2324 : }
2325 0 : return CE_None;
2326 : }
2327 :
2328 : // ---------------------------------------------------------
2329 : // Latlong
2330 : // ---------------------------------------------------------
2331 :
2332 4 : if (EQUAL(pszRefSystem, rstLATLONG) || EQUAL(pszRefSystem, rstLATLONG2))
2333 : {
2334 1 : oSRS.SetWellKnownGeogCS("WGS84");
2335 1 : return CE_None;
2336 : }
2337 :
2338 : // ---------------------------------------------------------
2339 : // Prepare for scanning in lower case
2340 : // ---------------------------------------------------------
2341 :
2342 3 : char *pszRefSystemLower = CPLStrdup(pszRefSystem);
2343 3 : CPLStrlwr(pszRefSystemLower);
2344 :
2345 : // ---------------------------------------------------------
2346 : // UTM naming convention( ex.: utm-30n )
2347 : // ---------------------------------------------------------
2348 :
2349 3 : if (EQUALN(pszRefSystem, rstUTM, 3))
2350 : {
2351 : int nZone;
2352 : char cNorth;
2353 3 : sscanf(pszRefSystemLower, rstUTM, &nZone, &cNorth);
2354 3 : oSRS.SetWellKnownGeogCS("WGS84");
2355 3 : oSRS.SetUTM(nZone, (cNorth == 'n'));
2356 3 : CPLFree(pszRefSystemLower);
2357 3 : return CE_None;
2358 : }
2359 :
2360 : // ---------------------------------------------------------
2361 : // State Plane naming convention( ex.: spc83ma1 )
2362 : // ---------------------------------------------------------
2363 :
2364 0 : if (EQUALN(pszRefSystem, rstSPC, 3))
2365 : {
2366 : int nNAD;
2367 : int nZone;
2368 : char szState[3];
2369 0 : sscanf(pszRefSystemLower, rstSPC, &nNAD, szState, &nZone);
2370 0 : int nSPCode = GetStateCode(szState);
2371 0 : if (nSPCode != -1)
2372 : {
2373 0 : nZone = (nZone == 1 ? nSPCode : nSPCode + nZone - 1);
2374 :
2375 0 : if (oSRS.SetStatePlane(nZone, (nNAD == 83)) != OGRERR_FAILURE)
2376 : {
2377 0 : CPLFree(pszRefSystemLower);
2378 0 : return CE_None;
2379 : }
2380 :
2381 : // ----------------------------------------------------------
2382 : // If SetStatePlane fails, set GeoCS as NAD Datum and let it
2383 : // try to read the projection info from georeference file( * )
2384 : // ----------------------------------------------------------
2385 :
2386 0 : oSRS.SetWellKnownGeogCS(CPLSPrintf("NAD%d", nNAD));
2387 : }
2388 : }
2389 :
2390 0 : CPLFree(pszRefSystemLower);
2391 0 : pszRefSystemLower = nullptr;
2392 :
2393 : // ------------------------------------------------------------------
2394 : // Search for georeference file <RefSystem>.ref
2395 : // ------------------------------------------------------------------
2396 :
2397 0 : const char *pszFName = CPLSPrintf("%s%c%s.ref", CPLGetDirname(pszFilename),
2398 : PATHDELIM, pszRefSystem);
2399 :
2400 0 : if (!FileExists(pszFName))
2401 : {
2402 : // ------------------------------------------------------------------
2403 : // Look at $IDRISIDIR\Georef\<RefSystem>.ref
2404 : // ------------------------------------------------------------------
2405 :
2406 0 : const char *pszIdrisiDir = CPLGetConfigOption("IDRISIDIR", nullptr);
2407 :
2408 0 : if ((pszIdrisiDir) != nullptr)
2409 : {
2410 0 : pszFName = CPLSPrintf("%s%cgeoref%c%s.ref", pszIdrisiDir, PATHDELIM,
2411 : PATHDELIM, pszRefSystem);
2412 : }
2413 : }
2414 :
2415 : // ------------------------------------------------------------------
2416 : // Cannot find georeference file
2417 : // ------------------------------------------------------------------
2418 :
2419 0 : if (!FileExists(pszFName))
2420 : {
2421 0 : CPLDebug("RST", "Cannot find Idrisi georeference file %s",
2422 : pszRefSystem);
2423 :
2424 0 : if (oSRS.IsGeographic() == FALSE) /* see State Plane remarks( * ) */
2425 : {
2426 0 : oSRS.SetLocalCS("Unknown");
2427 0 : int nUnit = GetUnitIndex(pszRefUnits);
2428 0 : if (nUnit > -1)
2429 : {
2430 0 : int nDeft = aoLinearUnitsConv[nUnit].nDefaultG;
2431 0 : oSRS.SetLinearUnits(aoLinearUnitsConv[nDeft].pszName,
2432 0 : aoLinearUnitsConv[nDeft].dfConv);
2433 : }
2434 : }
2435 0 : return CE_Failure;
2436 : }
2437 :
2438 : // ------------------------------------------------------------------
2439 : // Read values from georeference file
2440 : // ------------------------------------------------------------------
2441 :
2442 0 : char **papszRef = CSLLoad(pszFName);
2443 0 : myCSLSetNameValueSeparator(papszRef, ":");
2444 :
2445 0 : char *pszGeorefName = nullptr;
2446 :
2447 0 : const char *pszREF_SYSTEM = myCSLFetchNameValue(papszRef, refREF_SYSTEM);
2448 0 : if (pszREF_SYSTEM != nullptr && EQUAL(pszREF_SYSTEM, "") == FALSE)
2449 : {
2450 0 : pszGeorefName = CPLStrdup(pszREF_SYSTEM);
2451 : }
2452 : else
2453 : {
2454 : pszGeorefName =
2455 0 : CPLStrdup(myCSLFetchNameValue(papszRef, refREF_SYSTEM2));
2456 : }
2457 0 : char *pszProjName = CPLStrdup(myCSLFetchNameValue(papszRef, refPROJECTION));
2458 0 : char *pszDatum = CPLStrdup(myCSLFetchNameValue(papszRef, refDATUM));
2459 0 : char *pszEllipsoid = CPLStrdup(myCSLFetchNameValue(papszRef, refELLIPSOID));
2460 : const double dfCenterLat =
2461 0 : CPLAtof_nz(myCSLFetchNameValue(papszRef, refORIGIN_LAT));
2462 : const double dfCenterLong =
2463 0 : CPLAtof_nz(myCSLFetchNameValue(papszRef, refORIGIN_LONG));
2464 : const double dfSemiMajor =
2465 0 : CPLAtof_nz(myCSLFetchNameValue(papszRef, refMAJOR_SAX));
2466 : const double dfSemiMinor =
2467 0 : CPLAtof_nz(myCSLFetchNameValue(papszRef, refMINOR_SAX));
2468 : const double dfFalseEasting =
2469 0 : CPLAtof_nz(myCSLFetchNameValue(papszRef, refORIGIN_X));
2470 : const double dfFalseNorthing =
2471 0 : CPLAtof_nz(myCSLFetchNameValue(papszRef, refORIGIN_Y));
2472 : const double dfStdP1 =
2473 0 : CPLAtof_nz(myCSLFetchNameValue(papszRef, refSTANDL_1));
2474 : const double dfStdP2 =
2475 0 : CPLAtof_nz(myCSLFetchNameValue(papszRef, refSTANDL_2));
2476 : double dfScale;
2477 0 : double adfToWGS84[3] = {0.0, 0.0, 0.0};
2478 :
2479 0 : const char *pszToWGS84 = myCSLFetchNameValue(papszRef, refDELTA_WGS84);
2480 0 : if (pszToWGS84)
2481 0 : CPLsscanf(pszToWGS84, "%lf %lf %lf", &adfToWGS84[0], &adfToWGS84[1],
2482 : &adfToWGS84[2]);
2483 :
2484 0 : const char *pszSCALE_FAC = myCSLFetchNameValue(papszRef, refSCALE_FAC);
2485 0 : if (pszSCALE_FAC == nullptr || EQUAL(pszSCALE_FAC, "na"))
2486 0 : dfScale = 1.0;
2487 : else
2488 0 : dfScale = CPLAtof_nz(pszSCALE_FAC);
2489 :
2490 0 : CSLDestroy(papszRef);
2491 :
2492 : // ----------------------------------------------------------------------
2493 : // Set the Geographic Coordinate System
2494 : // ----------------------------------------------------------------------
2495 :
2496 0 : if (oSRS.IsGeographic() == FALSE) /* see State Plane remarks(*) */
2497 : {
2498 0 : int nEPSG = 0;
2499 :
2500 : // ----------------------------------------------------------------------
2501 : // Is it a WGS84 equivalent?
2502 : // ----------------------------------------------------------------------
2503 :
2504 0 : if ((STARTS_WITH_CI(pszEllipsoid, "WGS")) &&
2505 0 : (strstr(pszEllipsoid, "84")) && (STARTS_WITH_CI(pszDatum, "WGS")) &&
2506 0 : (strstr(pszDatum, "84")) && (adfToWGS84[0] == 0.0) &&
2507 0 : (adfToWGS84[1] == 0.0) && (adfToWGS84[2] == 0.0))
2508 : {
2509 0 : nEPSG = 4326;
2510 : }
2511 :
2512 : // ----------------------------------------------------------------------
2513 : // Match GCS's DATUM_NAME by using 'ApproxString' over Datum
2514 : // ----------------------------------------------------------------------
2515 :
2516 0 : if (nEPSG == 0)
2517 : {
2518 0 : const PJ_TYPE nObjType = PJ_TYPE_GEODETIC_REFERENCE_FRAME;
2519 : auto datumList =
2520 0 : proj_create_from_name(OSRGetProjTLSContext(), "EPSG", pszDatum,
2521 : &nObjType, 1, true, 1, nullptr);
2522 0 : if (datumList && proj_list_get_count(datumList) == 1)
2523 : {
2524 : auto datum =
2525 0 : proj_list_get(OSRGetProjTLSContext(), datumList, 0);
2526 0 : if (datum)
2527 : {
2528 0 : const char *datumCode = proj_get_id_code(datum, 0);
2529 0 : if (datumCode)
2530 : {
2531 0 : auto crsList = proj_query_geodetic_crs_from_datum(
2532 : OSRGetProjTLSContext(), "EPSG", "EPSG", datumCode,
2533 : "geographic 2D");
2534 0 : if (crsList && proj_list_get_count(crsList) != 0)
2535 : {
2536 0 : auto crs = proj_list_get(OSRGetProjTLSContext(),
2537 : crsList, 0);
2538 0 : if (crs)
2539 : {
2540 0 : const char *crsCode = proj_get_id_code(crs, 0);
2541 0 : if (crsCode)
2542 : {
2543 0 : nEPSG = atoi(crsCode);
2544 : }
2545 0 : proj_destroy(crs);
2546 : }
2547 : }
2548 0 : proj_list_destroy(crsList);
2549 : }
2550 0 : proj_destroy(datum);
2551 : }
2552 : }
2553 0 : proj_list_destroy(datumList);
2554 : }
2555 :
2556 : // ----------------------------------------------------------------------
2557 : // Match GCS's COORD_REF_SYS_NAME by using 'ApproxString' over Datum
2558 : // ----------------------------------------------------------------------
2559 :
2560 0 : if (nEPSG == 0)
2561 : {
2562 0 : const PJ_TYPE nObjType = PJ_TYPE_GEOGRAPHIC_2D_CRS;
2563 : auto crsList =
2564 0 : proj_create_from_name(OSRGetProjTLSContext(), "EPSG", pszDatum,
2565 : &nObjType, 1, true, 1, nullptr);
2566 0 : if (crsList && proj_list_get_count(crsList) != 0)
2567 : {
2568 0 : auto crs = proj_list_get(OSRGetProjTLSContext(), crsList, 0);
2569 0 : if (crs)
2570 : {
2571 0 : const char *crsCode = proj_get_id_code(crs, 0);
2572 0 : if (crsCode)
2573 : {
2574 0 : nEPSG = atoi(crsCode);
2575 : }
2576 0 : proj_destroy(crs);
2577 : }
2578 : }
2579 0 : proj_list_destroy(crsList);
2580 : }
2581 :
2582 0 : if (nEPSG != 0)
2583 : {
2584 0 : oSRS.importFromEPSG(nEPSG);
2585 : }
2586 : else
2587 : {
2588 : // --------------------------------------------------
2589 : // Create GeogCS based on the georeference file info
2590 : // --------------------------------------------------
2591 :
2592 0 : oSRS.SetGeogCS(pszRefSystem, pszDatum, pszEllipsoid, dfSemiMajor,
2593 : (dfSemiMinor == dfSemiMajor)
2594 : ? 0.0
2595 0 : : (-1.0 / (dfSemiMinor / dfSemiMajor - 1.0)));
2596 : }
2597 :
2598 : // ----------------------------------------------------------------------
2599 : // Note: That will override EPSG info:
2600 : // ----------------------------------------------------------------------
2601 :
2602 0 : oSRS.SetTOWGS84(adfToWGS84[0], adfToWGS84[1], adfToWGS84[2]);
2603 : }
2604 :
2605 : // ----------------------------------------------------------------------
2606 : // If the georeference file tells that it is a non project system:
2607 : // ----------------------------------------------------------------------
2608 :
2609 0 : if (EQUAL(pszProjName, "none"))
2610 : {
2611 0 : CPLFree(pszGeorefName);
2612 0 : CPLFree(pszProjName);
2613 0 : CPLFree(pszDatum);
2614 0 : CPLFree(pszEllipsoid);
2615 :
2616 0 : return CE_None;
2617 : }
2618 :
2619 : // ----------------------------------------------------------------------
2620 : // Create Projection information based on georeference file info
2621 : // ----------------------------------------------------------------------
2622 :
2623 : // Idrisi user's Manual, Supported Projection:
2624 : //
2625 : // Mercator
2626 : // Transverse Mercator
2627 : // Gauss-Kruger
2628 : // Lambert Conformal Conic
2629 : // Plate Carree
2630 : // Hammer Aitoff
2631 : // Lambert North Polar Azimuthal Equal Area
2632 : // Lambert South Polar Azimuthal Equal Area
2633 : // Lambert Transverse Azimuthal Equal Area
2634 : // Lambert Oblique Polar Azimuthal Equal Area
2635 : // North Polar Stereographic
2636 : // South Polar Stereographic
2637 : // Transverse Stereographic
2638 : // Oblique Stereographic
2639 : // Albers Equal Area Conic
2640 : // Sinusoidal
2641 : // Cylindrical Equal Area
2642 :
2643 0 : if (EQUAL(pszProjName, "Mercator"))
2644 : {
2645 0 : oSRS.SetMercator(dfCenterLat, dfCenterLong, dfScale, dfFalseEasting,
2646 : dfFalseNorthing);
2647 : }
2648 0 : else if (EQUAL(pszProjName, "Transverse Mercator"))
2649 : {
2650 0 : oSRS.SetTM(dfCenterLat, dfCenterLong, dfScale, dfFalseEasting,
2651 : dfFalseNorthing);
2652 : }
2653 0 : else if (EQUAL(pszProjName, "Gauss-Kruger"))
2654 : {
2655 0 : oSRS.SetTM(dfCenterLat, dfCenterLong, dfScale, dfFalseEasting,
2656 : dfFalseNorthing);
2657 : }
2658 0 : else if (EQUAL(pszProjName, "Lambert Conformal Conic"))
2659 : {
2660 0 : oSRS.SetLCC(dfStdP1, dfStdP2, dfCenterLat, dfCenterLong, dfFalseEasting,
2661 : dfFalseNorthing);
2662 : }
2663 0 : else if (EQUAL(pszProjName, "Plate Carr"
2664 : "\xE9"
2665 : "e")) /* 'eacute' in ISO-8859-1 */
2666 : {
2667 0 : oSRS.SetEquirectangular(dfCenterLat, dfCenterLong, dfFalseEasting,
2668 : dfFalseNorthing);
2669 : }
2670 0 : else if (EQUAL(pszProjName, "Hammer Aitoff"))
2671 : {
2672 0 : oSRS.SetProjection(pszProjName);
2673 0 : oSRS.SetProjParm(SRS_PP_LATITUDE_OF_ORIGIN, dfCenterLat);
2674 0 : oSRS.SetProjParm(SRS_PP_CENTRAL_MERIDIAN, dfCenterLong);
2675 0 : oSRS.SetProjParm(SRS_PP_FALSE_EASTING, dfFalseEasting);
2676 0 : oSRS.SetProjParm(SRS_PP_FALSE_NORTHING, dfFalseNorthing);
2677 : }
2678 0 : else if (EQUAL(pszProjName, "Lambert North Polar Azimuthal Equal Area") ||
2679 0 : EQUAL(pszProjName, "Lambert South Polar Azimuthal Equal Area") ||
2680 0 : EQUAL(pszProjName, "Lambert Transverse Azimuthal Equal Area") ||
2681 0 : EQUAL(pszProjName, "Lambert Oblique Polar Azimuthal Equal Area"))
2682 : {
2683 0 : oSRS.SetLAEA(dfCenterLat, dfCenterLong, dfFalseEasting,
2684 : dfFalseNorthing);
2685 : }
2686 0 : else if (EQUAL(pszProjName, "North Polar Stereographic") ||
2687 0 : EQUAL(pszProjName, "South Polar Stereographic"))
2688 : {
2689 0 : oSRS.SetPS(dfCenterLat, dfCenterLong, dfScale, dfFalseEasting,
2690 : dfFalseNorthing);
2691 : }
2692 0 : else if (EQUAL(pszProjName, "Transverse Stereographic"))
2693 : {
2694 0 : oSRS.SetStereographic(dfCenterLat, dfCenterLong, dfScale,
2695 : dfFalseEasting, dfFalseNorthing);
2696 : }
2697 0 : else if (EQUAL(pszProjName, "Oblique Stereographic"))
2698 : {
2699 0 : oSRS.SetOS(dfCenterLat, dfCenterLong, dfScale, dfFalseEasting,
2700 : dfFalseNorthing);
2701 : }
2702 0 : else if (EQUAL(pszProjName, "Alber's Equal Area Conic") ||
2703 0 : EQUAL(pszProjName, "Albers Equal Area Conic"))
2704 : {
2705 0 : oSRS.SetACEA(dfStdP1, dfStdP2, dfCenterLat, dfCenterLong,
2706 : dfFalseEasting, dfFalseNorthing);
2707 : }
2708 0 : else if (EQUAL(pszProjName, "Sinusoidal"))
2709 : {
2710 0 : oSRS.SetSinusoidal(dfCenterLong, dfFalseEasting, dfFalseNorthing);
2711 : }
2712 0 : else if (EQUAL(pszProjName, "CylindricalEA") ||
2713 0 : EQUAL(pszProjName, "Cylindrical Equal Area"))
2714 : {
2715 0 : oSRS.SetCEA(dfStdP1, dfCenterLong, dfFalseEasting, dfFalseNorthing);
2716 : }
2717 : else
2718 : {
2719 0 : CPLError(
2720 : CE_Warning, CPLE_NotSupported,
2721 : "Projection not listed on Idrisi User's Manual( v.15.0/2005 ).\n\t"
2722 : "[\"%s\" in georeference file \"%s\"]",
2723 : pszProjName, pszFName);
2724 0 : oSRS.Clear();
2725 :
2726 0 : CPLFree(pszGeorefName);
2727 0 : CPLFree(pszProjName);
2728 0 : CPLFree(pszDatum);
2729 0 : CPLFree(pszEllipsoid);
2730 :
2731 0 : return CE_Warning;
2732 : }
2733 :
2734 : // ----------------------------------------------------------------------
2735 : // Set the Linear Units
2736 : // ----------------------------------------------------------------------
2737 :
2738 0 : int nUnit = GetUnitIndex(pszRefUnits);
2739 0 : if (nUnit > -1)
2740 : {
2741 0 : int nDeft = aoLinearUnitsConv[nUnit].nDefaultG;
2742 0 : oSRS.SetLinearUnits(aoLinearUnitsConv[nDeft].pszName,
2743 0 : aoLinearUnitsConv[nDeft].dfConv);
2744 : }
2745 : else
2746 : {
2747 0 : oSRS.SetLinearUnits("unknown", 1.0);
2748 : }
2749 :
2750 : // ----------------------------------------------------------------------
2751 : // Name ProjCS with the name on the georeference file
2752 : // ----------------------------------------------------------------------
2753 :
2754 0 : oSRS.SetProjCS(pszGeorefName);
2755 :
2756 0 : CPLFree(pszGeorefName);
2757 0 : CPLFree(pszProjName);
2758 0 : CPLFree(pszDatum);
2759 0 : CPLFree(pszEllipsoid);
2760 :
2761 0 : return CE_None;
2762 : }
2763 :
2764 : /************************************************************************/
2765 : /* Wkt2GeoReference() */
2766 : /************************************************************************/
2767 :
2768 : /***
2769 : * Converts OpenGIS WKT to Idrisi geographic reference information.
2770 : *
2771 : * That function will fill up the two parameters RefSystem and RefUnit
2772 : * that goes into the Idrisi metadata. But it could also create
2773 : * a accompanying georeference file to the output if necessary.
2774 : *
2775 : * First it will try to identify the ProjString as Local, WGS84 or
2776 : * one of the Idrisi name convention reference systems
2777 : * otherwise, if the projection system is supported by Idrisi,
2778 : * it will create a accompanying georeference files.
2779 : ***/
2780 :
2781 13 : CPLErr IdrisiDataset::Wkt2GeoReference(const OGRSpatialReference &oSRS,
2782 : char **pszRefSystem, char **pszRefUnit)
2783 : {
2784 : // -----------------------------------------------------
2785 : // Plane with default "Meters"
2786 : // -----------------------------------------------------
2787 :
2788 13 : if (oSRS.IsEmpty())
2789 : {
2790 0 : *pszRefSystem = CPLStrdup(rstPLANE);
2791 0 : *pszRefUnit = CPLStrdup(rstMETER);
2792 0 : return CE_None;
2793 : }
2794 :
2795 : // -----------------------------------------------------
2796 : // Local => Plane + Linear Unit
2797 : // -----------------------------------------------------
2798 :
2799 13 : if (oSRS.IsLocal())
2800 : {
2801 0 : *pszRefSystem = CPLStrdup(rstPLANE);
2802 0 : *pszRefUnit = GetUnitDefault(oSRS.GetAttrValue("UNIT"),
2803 : CPLSPrintf("%f", oSRS.GetLinearUnits()));
2804 0 : return CE_None;
2805 : }
2806 :
2807 : // -----------------------------------------------------
2808 : // Test to identify WGS84 => Latlong + Angular Unit
2809 : // -----------------------------------------------------
2810 :
2811 13 : if (oSRS.IsGeographic())
2812 : {
2813 13 : char *pszSpheroid = CPLStrdup(oSRS.GetAttrValue("SPHEROID"));
2814 13 : char *pszAuthName = CPLStrdup(oSRS.GetAuthorityName("GEOGCS"));
2815 13 : char *pszDatum = CPLStrdup(oSRS.GetAttrValue("DATUM"));
2816 13 : int nGCSCode = -1;
2817 13 : if (EQUAL(pszAuthName, "EPSG"))
2818 : {
2819 1 : nGCSCode = atoi(oSRS.GetAuthorityCode("GEOGCS"));
2820 : }
2821 13 : if ((nGCSCode == 4326) ||
2822 12 : ((STARTS_WITH_CI(pszSpheroid, "WGS")) &&
2823 12 : (strstr(pszSpheroid, "84")) && (STARTS_WITH_CI(pszDatum, "WGS")) &&
2824 12 : (strstr(pszDatum, "84"))))
2825 : {
2826 13 : *pszRefSystem = CPLStrdup(rstLATLONG);
2827 13 : *pszRefUnit = CPLStrdup(rstDEGREE);
2828 :
2829 13 : CPLFree(pszSpheroid);
2830 13 : CPLFree(pszAuthName);
2831 13 : CPLFree(pszDatum);
2832 :
2833 13 : return CE_None;
2834 : }
2835 :
2836 0 : CPLFree(pszSpheroid);
2837 0 : CPLFree(pszAuthName);
2838 0 : CPLFree(pszDatum);
2839 : }
2840 :
2841 : // -----------------------------------------------------
2842 : // Prepare to match some projections
2843 : // -----------------------------------------------------
2844 :
2845 0 : const char *pszProjName = oSRS.GetAttrValue("PROJECTION");
2846 :
2847 0 : if (pszProjName == nullptr)
2848 : {
2849 0 : pszProjName = "";
2850 : }
2851 :
2852 : // -----------------------------------------------------
2853 : // Check for UTM zones
2854 : // -----------------------------------------------------
2855 :
2856 0 : if (EQUAL(pszProjName, SRS_PT_TRANSVERSE_MERCATOR))
2857 : {
2858 0 : int nZone = oSRS.GetUTMZone();
2859 :
2860 0 : if ((nZone != 0) && (EQUAL(oSRS.GetAttrValue("DATUM"), SRS_DN_WGS84)))
2861 : {
2862 0 : double dfNorth = oSRS.GetProjParm(SRS_PP_FALSE_NORTHING);
2863 0 : *pszRefSystem = CPLStrdup(
2864 : CPLSPrintf(rstUTM, nZone, (dfNorth == 0.0 ? 'n' : 's')));
2865 0 : *pszRefUnit = CPLStrdup(rstMETER);
2866 0 : return CE_None;
2867 : }
2868 : }
2869 :
2870 : // -----------------------------------------------------
2871 : // Check for State Plane
2872 : // -----------------------------------------------------
2873 :
2874 0 : if (EQUAL(pszProjName, SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP) ||
2875 0 : EQUAL(pszProjName, SRS_PT_TRANSVERSE_MERCATOR))
2876 : {
2877 0 : CPLString osPCSCode;
2878 0 : const char *pszID = oSRS.GetAuthorityCode("PROJCS");
2879 0 : if (pszID != nullptr && strlen(pszID) > 0)
2880 : {
2881 : const char *pszPCSCode =
2882 0 : CSVGetField(CSVFilename("stateplane.csv"), "EPSG_PCS_CODE",
2883 : pszID, CC_Integer, "ID");
2884 0 : osPCSCode = (pszPCSCode) ? pszPCSCode : "";
2885 0 : if (!osPCSCode.empty())
2886 : {
2887 0 : int nZone = osPCSCode.back() - '0';
2888 0 : int nSPCode = atoi(osPCSCode);
2889 :
2890 0 : if (nZone == 0)
2891 0 : nZone = 1;
2892 : else
2893 0 : nSPCode = nSPCode - nZone + 1;
2894 :
2895 0 : int nNADYear = 83;
2896 0 : if (nSPCode > 10000)
2897 : {
2898 0 : nNADYear = 27;
2899 0 : nSPCode -= 10000;
2900 : }
2901 0 : char *pszState = CPLStrdup(GetStateName(nSPCode));
2902 0 : if (!EQUAL(pszState, ""))
2903 : {
2904 0 : *pszRefSystem = CPLStrdup(
2905 : CPLSPrintf(rstSPC, nNADYear, pszState, nZone));
2906 0 : *pszRefUnit =
2907 0 : GetUnitDefault(oSRS.GetAttrValue("UNIT"),
2908 : CPLSPrintf("%f", oSRS.GetLinearUnits()));
2909 0 : CPLFree(pszState);
2910 0 : return CE_None;
2911 : }
2912 0 : CPLFree(pszState);
2913 : }
2914 : } //
2915 :
2916 : // if EPSG code is missing, go to following steps to work with origin
2917 :
2918 0 : const char *pszNAD83 = "83";
2919 0 : const char *pszNAD27 = "27";
2920 0 : bool bIsOldNAD = false;
2921 :
2922 0 : const char *pszDatumValue = oSRS.GetAttrValue("DATUM", 0);
2923 0 : if ((strstr(pszDatumValue, pszNAD83) == nullptr) &&
2924 0 : (strstr(pszDatumValue, pszNAD27) != nullptr))
2925 : // strcpy(pszNAD, "27");
2926 0 : bIsOldNAD = true;
2927 :
2928 0 : if ((oSRS.FindProjParm("central_meridian", nullptr) != -1) &&
2929 0 : (oSRS.FindProjParm("latitude_of_origin", nullptr) != -1))
2930 : {
2931 0 : double dfLon = oSRS.GetProjParm("central_meridian");
2932 0 : double dfLat = oSRS.GetProjParm("latitude_of_origin");
2933 0 : dfLon = (int)(fabs(dfLon) * 100 + 0.5) / 100.0;
2934 0 : dfLat = (int)(fabs(dfLat) * 100 + 0.5) / 100.0;
2935 0 : *pszRefSystem = CPLStrdup(GetSpcs(dfLon, dfLat));
2936 : }
2937 :
2938 0 : if (*pszRefSystem != nullptr)
2939 : {
2940 : // Convert 83 TO 27
2941 0 : if (bIsOldNAD)
2942 : {
2943 : char pszOutRefSystem[9];
2944 0 : NAD83to27(pszOutRefSystem, *pszRefSystem);
2945 0 : *pszRefSystem = CPLStrdup(pszOutRefSystem);
2946 : }
2947 0 : *pszRefUnit =
2948 0 : GetUnitDefault(oSRS.GetAttrValue("UNIT"),
2949 : CPLSPrintf("%f", oSRS.GetLinearUnits()));
2950 0 : return CE_None;
2951 : }
2952 : }
2953 :
2954 0 : const char *pszProjectionOut = nullptr;
2955 :
2956 0 : if (oSRS.IsProjected())
2957 : {
2958 : // ---------------------------------------------------------
2959 : // Check for supported projections
2960 : // ---------------------------------------------------------
2961 :
2962 0 : if (EQUAL(pszProjName, SRS_PT_MERCATOR_1SP))
2963 : {
2964 0 : pszProjectionOut = "Mercator";
2965 : }
2966 0 : else if (EQUAL(pszProjName, SRS_PT_TRANSVERSE_MERCATOR))
2967 : {
2968 0 : pszProjectionOut = "Transverse Mercator";
2969 : }
2970 0 : else if (EQUAL(pszProjName, SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP))
2971 : {
2972 0 : pszProjectionOut = "Lambert Conformal Conic";
2973 : }
2974 0 : else if (EQUAL(pszProjName, SRS_PT_EQUIRECTANGULAR))
2975 : {
2976 0 : pszProjectionOut = "Plate Carr"
2977 : "\xE9"
2978 : "e"; /* 'eacute' in ISO-8859-1 */
2979 : }
2980 0 : else if (EQUAL(pszProjName, SRS_PT_LAMBERT_AZIMUTHAL_EQUAL_AREA))
2981 : {
2982 : double dfCenterLat =
2983 0 : oSRS.GetProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0, nullptr);
2984 0 : if (dfCenterLat == 0.0)
2985 0 : pszProjectionOut = "Lambert Transverse Azimuthal Equal Area";
2986 0 : else if (fabs(dfCenterLat) == 90.0)
2987 0 : pszProjectionOut = "Lambert Oblique Polar Azimuthal Equal Area";
2988 0 : else if (dfCenterLat > 0.0)
2989 0 : pszProjectionOut = "Lambert North Oblique Azimuthal Equal Area";
2990 : else
2991 0 : pszProjectionOut = "Lambert South Oblique Azimuthal Equal Area";
2992 : }
2993 0 : else if (EQUAL(pszProjName, SRS_PT_POLAR_STEREOGRAPHIC))
2994 : {
2995 0 : if (oSRS.GetProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0, nullptr) > 0)
2996 0 : pszProjectionOut = "North Polar Stereographic";
2997 : else
2998 0 : pszProjectionOut = "South Polar Stereographic";
2999 : }
3000 0 : else if (EQUAL(pszProjName, SRS_PT_STEREOGRAPHIC))
3001 : {
3002 0 : pszProjectionOut = "Transverse Stereographic";
3003 : }
3004 0 : else if (EQUAL(pszProjName, SRS_PT_OBLIQUE_STEREOGRAPHIC))
3005 : {
3006 0 : pszProjectionOut = "Oblique Stereographic";
3007 : }
3008 0 : else if (EQUAL(pszProjName, SRS_PT_SINUSOIDAL))
3009 : {
3010 0 : pszProjectionOut = "Sinusoidal";
3011 : }
3012 0 : else if (EQUAL(pszProjName, SRS_PT_ALBERS_CONIC_EQUAL_AREA))
3013 : {
3014 0 : pszProjectionOut = "Alber's Equal Area Conic";
3015 : }
3016 0 : else if (EQUAL(pszProjName, SRS_PT_CYLINDRICAL_EQUAL_AREA))
3017 : {
3018 0 : pszProjectionOut = "Cylindrical Equal Area";
3019 : }
3020 :
3021 : // ---------------------------------------------------------
3022 : // Failure, Projection system not supported
3023 : // ---------------------------------------------------------
3024 :
3025 0 : if (pszProjectionOut == nullptr)
3026 : {
3027 0 : CPLDebug("RST", "Not supported by RST driver: PROJECTION[\"%s\"]",
3028 : pszProjName);
3029 :
3030 0 : *pszRefSystem = CPLStrdup(rstPLANE);
3031 0 : *pszRefUnit = CPLStrdup(rstMETER);
3032 0 : return CE_Failure;
3033 : }
3034 : }
3035 : else
3036 : {
3037 0 : pszProjectionOut = "none";
3038 : }
3039 :
3040 : // ---------------------------------------------------------
3041 : // Prepare to write ref file
3042 : // ---------------------------------------------------------
3043 :
3044 0 : char *pszGeorefName = CPLStrdup("Unknown");
3045 0 : char *pszDatum = CPLStrdup(oSRS.GetAttrValue("DATUM"));
3046 0 : char *pszEllipsoid = CPLStrdup(oSRS.GetAttrValue("SPHEROID"));
3047 0 : double dfSemiMajor = oSRS.GetSemiMajor();
3048 0 : double dfSemiMinor = oSRS.GetSemiMinor();
3049 : double adfToWGS84[3];
3050 0 : oSRS.GetTOWGS84(adfToWGS84, 3);
3051 :
3052 0 : double dfCenterLat = 0.0;
3053 0 : double dfCenterLong = 0.0;
3054 0 : double dfFalseNorthing = 0.0;
3055 0 : double dfFalseEasting = 0.0;
3056 0 : double dfScale = 1.0;
3057 0 : int nParameters = 0;
3058 0 : double dfStdP1 = 0.0;
3059 0 : double dfStdP2 = 0.0;
3060 0 : char *pszAngularUnit = CPLStrdup(oSRS.GetAttrValue("GEOGCS|UNIT"));
3061 0 : char *pszLinearUnit = nullptr;
3062 :
3063 0 : if (oSRS.IsProjected())
3064 : {
3065 0 : CPLFree(pszGeorefName);
3066 0 : pszGeorefName = CPLStrdup(oSRS.GetAttrValue("PROJCS"));
3067 0 : dfCenterLat = oSRS.GetProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0, nullptr);
3068 0 : dfCenterLong = oSRS.GetProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0, nullptr);
3069 0 : dfFalseNorthing = oSRS.GetProjParm(SRS_PP_FALSE_NORTHING, 0.0, nullptr);
3070 0 : dfFalseEasting = oSRS.GetProjParm(SRS_PP_FALSE_EASTING, 0.0, nullptr);
3071 0 : dfScale = oSRS.GetProjParm(SRS_PP_SCALE_FACTOR, 0.0, nullptr);
3072 0 : dfStdP1 = oSRS.GetProjParm(SRS_PP_STANDARD_PARALLEL_1, -0.1, nullptr);
3073 0 : if (EQUAL(pszProjectionOut, "Cylindrical Equal Area"))
3074 : {
3075 0 : dfStdP2 = -dfStdP1;
3076 0 : dfScale = 1.0;
3077 : }
3078 : else
3079 : {
3080 : dfStdP2 =
3081 0 : oSRS.GetProjParm(SRS_PP_STANDARD_PARALLEL_2, -0.1, nullptr);
3082 : }
3083 0 : if (dfStdP1 != -0.1)
3084 : {
3085 0 : nParameters = 1;
3086 0 : if (dfStdP2 != -0.1)
3087 0 : nParameters = 2;
3088 : }
3089 0 : pszLinearUnit = GetUnitDefault(oSRS.GetAttrValue("PROJCS|UNIT"),
3090 : CPLSPrintf("%f", oSRS.GetLinearUnits()));
3091 : }
3092 : else
3093 : {
3094 0 : pszLinearUnit = GetUnitDefault(pszAngularUnit);
3095 : }
3096 :
3097 : // ---------------------------------------------------------
3098 : // Create a companion georeference file for this dataset
3099 : // ---------------------------------------------------------
3100 :
3101 0 : char **papszRef = nullptr;
3102 0 : papszRef = CSLAddNameValue(papszRef, refREF_SYSTEM, pszGeorefName);
3103 0 : papszRef = CSLAddNameValue(papszRef, refPROJECTION, pszProjectionOut);
3104 0 : papszRef = CSLAddNameValue(papszRef, refDATUM, pszDatum);
3105 0 : papszRef = CSLAddNameValue(papszRef, refDELTA_WGS84,
3106 : CPLSPrintf("%.3g %.3g %.3g", adfToWGS84[0],
3107 : adfToWGS84[1], adfToWGS84[2]));
3108 0 : papszRef = CSLAddNameValue(papszRef, refELLIPSOID, pszEllipsoid);
3109 0 : papszRef = CSLAddNameValue(papszRef, refMAJOR_SAX,
3110 : CPLSPrintf("%.3f", dfSemiMajor));
3111 0 : papszRef = CSLAddNameValue(papszRef, refMINOR_SAX,
3112 : CPLSPrintf("%.3f", dfSemiMinor));
3113 0 : papszRef = CSLAddNameValue(papszRef, refORIGIN_LONG,
3114 : CPLSPrintf("%.9g", dfCenterLong));
3115 0 : papszRef = CSLAddNameValue(papszRef, refORIGIN_LAT,
3116 : CPLSPrintf("%.9g", dfCenterLat));
3117 0 : papszRef = CSLAddNameValue(papszRef, refORIGIN_X,
3118 : CPLSPrintf("%.9g", dfFalseEasting));
3119 0 : papszRef = CSLAddNameValue(papszRef, refORIGIN_Y,
3120 : CPLSPrintf("%.9g", dfFalseNorthing));
3121 : papszRef =
3122 0 : CSLAddNameValue(papszRef, refSCALE_FAC, CPLSPrintf("%.9g", dfScale));
3123 0 : papszRef = CSLAddNameValue(papszRef, refUNITS, pszLinearUnit);
3124 0 : papszRef = CSLAddNameValue(papszRef, refPARAMETERS,
3125 : CPLSPrintf("%1d", nParameters));
3126 0 : if (nParameters > 0)
3127 : papszRef =
3128 0 : CSLAddNameValue(papszRef, refSTANDL_1, CPLSPrintf("%.9g", dfStdP1));
3129 0 : if (nParameters > 1)
3130 : papszRef =
3131 0 : CSLAddNameValue(papszRef, refSTANDL_2, CPLSPrintf("%.9g", dfStdP2));
3132 0 : myCSLSetNameValueSeparator(papszRef, ": ");
3133 0 : SaveAsCRLF(papszRef, CPLResetExtension(pszFilename, extREF));
3134 0 : CSLDestroy(papszRef);
3135 :
3136 0 : *pszRefSystem = CPLStrdup(CPLGetBasename(pszFilename));
3137 0 : *pszRefUnit = CPLStrdup(pszLinearUnit);
3138 :
3139 0 : CPLFree(pszGeorefName);
3140 0 : CPLFree(pszDatum);
3141 0 : CPLFree(pszEllipsoid);
3142 0 : CPLFree(pszLinearUnit);
3143 0 : CPLFree(pszAngularUnit);
3144 :
3145 0 : return CE_None;
3146 : }
3147 :
3148 : /************************************************************************/
3149 : /* FileExists() */
3150 : /************************************************************************/
3151 :
3152 60 : bool FileExists(const char *pszPath)
3153 : {
3154 : VSIStatBufL sStat;
3155 :
3156 60 : return VSIStatL(pszPath, &sStat) == 0;
3157 : }
3158 :
3159 : /************************************************************************/
3160 : /* GetStateCode() */
3161 : /************************************************************************/
3162 :
3163 0 : int GetStateCode(const char *pszState)
3164 : {
3165 0 : for (unsigned int i = 0; i < US_STATE_COUNT; i++)
3166 : {
3167 0 : if (EQUAL(pszState, aoUSStateTable[i].pszName))
3168 : {
3169 0 : return aoUSStateTable[i].nCode;
3170 : }
3171 : }
3172 0 : return -1;
3173 : }
3174 :
3175 : /************************************************************************/
3176 : /* GetStateName() */
3177 : /************************************************************************/
3178 :
3179 0 : const char *GetStateName(int nCode)
3180 : {
3181 0 : for (unsigned int i = 0; i < US_STATE_COUNT; i++)
3182 : {
3183 0 : if (nCode == aoUSStateTable[i].nCode)
3184 : {
3185 0 : return aoUSStateTable[i].pszName;
3186 : }
3187 : }
3188 0 : return nullptr;
3189 : }
3190 :
3191 : /************************************************************************/
3192 : /* GetSpcs() */
3193 : /************************************************************************/
3194 :
3195 0 : char *GetSpcs(double dfLon, double dfLat)
3196 : {
3197 0 : for (int i = 0; i < ORIGIN_COUNT; i++)
3198 : {
3199 0 : if ((dfLon == SPCS83Origin[i].longitude) &&
3200 0 : (dfLat == SPCS83Origin[i].latitude))
3201 : {
3202 0 : return (char *)SPCS83Origin[i].spcs;
3203 : }
3204 : }
3205 0 : return nullptr;
3206 : }
3207 :
3208 : /************************************************************************/
3209 : /* NAD83to27() */
3210 : /************************************************************************/
3211 0 : void NAD83to27(char *pszOutRef, char *pszInRef)
3212 : {
3213 0 : char *pOutput = pszOutRef;
3214 0 : char *pInput = pszInRef;
3215 0 : strncpy(pOutput, pInput, 3);
3216 :
3217 0 : pOutput = pOutput + 3;
3218 0 : pInput = pInput + 3;
3219 :
3220 0 : memcpy(pOutput, "27", 2);
3221 0 : pOutput = pOutput + 2;
3222 0 : pInput = pInput + 2;
3223 0 : strcpy(pOutput, pInput);
3224 0 : }
3225 :
3226 : /************************************************************************/
3227 : /* GetUnitIndex() */
3228 : /************************************************************************/
3229 :
3230 0 : int GetUnitIndex(const char *pszUnitName)
3231 : {
3232 0 : for (int i = 0; i < (int)LINEAR_UNITS_COUNT; i++)
3233 : {
3234 0 : if (EQUAL(pszUnitName, aoLinearUnitsConv[i].pszName))
3235 : {
3236 0 : return i;
3237 : }
3238 : }
3239 0 : return -1;
3240 : }
3241 :
3242 : /************************************************************************/
3243 : /* GetToMeterIndex() */
3244 : /************************************************************************/
3245 :
3246 0 : int GetToMeterIndex(const char *pszToMeter)
3247 : {
3248 0 : const double dfToMeter = CPLAtof_nz(pszToMeter);
3249 :
3250 0 : if (dfToMeter != 0.0)
3251 : {
3252 0 : for (int i = 0; i < (int)LINEAR_UNITS_COUNT; i++)
3253 : {
3254 0 : if (std::abs(aoLinearUnitsConv[i].dfConv - dfToMeter) < 0.00001)
3255 : {
3256 0 : return i;
3257 : }
3258 : }
3259 : }
3260 :
3261 0 : return -1;
3262 : }
3263 :
3264 : /************************************************************************/
3265 : /* GetUnitDefault() */
3266 : /************************************************************************/
3267 :
3268 0 : char *GetUnitDefault(const char *pszUnitName, const char *pszToMeter)
3269 : {
3270 0 : int nIndex = GetUnitIndex(pszUnitName);
3271 :
3272 0 : if (nIndex == -1 && pszToMeter != nullptr)
3273 : {
3274 0 : nIndex = GetToMeterIndex(pszToMeter);
3275 : }
3276 :
3277 0 : if (nIndex == -1)
3278 : {
3279 0 : return CPLStrdup("Unknown");
3280 : }
3281 :
3282 0 : return CPLStrdup(
3283 0 : aoLinearUnitsConv[aoLinearUnitsConv[nIndex].nDefaultI].pszName);
3284 : }
3285 :
3286 : /************************************************************************/
3287 : /* CSLSaveCRLF() */
3288 : /************************************************************************/
3289 :
3290 : /***
3291 : * Write a stringlist to a CR + LF terminated text file.
3292 : *
3293 : * Returns the number of lines written, or 0 if the file could not
3294 : * be written.
3295 : */
3296 :
3297 46 : int SaveAsCRLF(char **papszStrList, const char *pszFname)
3298 : {
3299 46 : VSILFILE *fp = VSIFOpenL(pszFname, "wt");
3300 46 : int nLines = 0;
3301 :
3302 46 : if (papszStrList)
3303 : {
3304 46 : if (fp != nullptr)
3305 : {
3306 800 : while (*papszStrList != nullptr)
3307 : {
3308 766 : if (VSIFPrintfL(fp, "%s\r\n", *papszStrList) < 1)
3309 : {
3310 10 : CPLError(CE_Failure, CPLE_FileIO,
3311 : "CSLSaveCRLF(\"%s\") failed: unable to write to "
3312 : "output file.",
3313 : pszFname);
3314 10 : break;
3315 : }
3316 :
3317 756 : nLines++;
3318 756 : papszStrList++;
3319 : }
3320 :
3321 44 : VSIFCloseL(fp);
3322 : }
3323 : else
3324 : {
3325 2 : CPLError(CE_Failure, CPLE_OpenFailed,
3326 : "CSLSaveCRLF(\"%s\") failed: unable to open output file.",
3327 : pszFname);
3328 : }
3329 : }
3330 :
3331 46 : return nLines;
3332 : }
3333 :
3334 : /************************************************************************/
3335 : /* GDALRegister_IDRISI() */
3336 : /************************************************************************/
3337 :
3338 1595 : void GDALRegister_IDRISI()
3339 : {
3340 1595 : if (GDALGetDriverByName("RST") != nullptr)
3341 302 : return;
3342 :
3343 1293 : GDALDriver *poDriver = new GDALDriver();
3344 :
3345 1293 : poDriver->SetDescription("RST");
3346 1293 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
3347 1293 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, rstVERSION);
3348 1293 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/Idrisi.html");
3349 1293 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, extRST);
3350 1293 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Byte Int16 Float32");
3351 :
3352 1293 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
3353 :
3354 1293 : poDriver->pfnOpen = IdrisiDataset::Open;
3355 1293 : poDriver->pfnCreate = IdrisiDataset::Create;
3356 1293 : poDriver->pfnCreateCopy = IdrisiDataset::CreateCopy;
3357 :
3358 1293 : GetGDALDriverManager()->RegisterDriver(poDriver);
3359 : }
|