1 : /******************************************************************************
2 : *
3 : * Project: ILWIS Driver
4 : * Purpose: GDALDataset driver for ILWIS translator for read/write support.
5 : * Author: Lichun Wang, lichun@itc.nl
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2004, ITC
9 : *
10 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : ****************************************************************************/
28 :
29 :
30 : #include "ilwisdataset.h"
31 : #include <float.h>
32 : #include <limits.h>
33 :
34 : #include <string>
35 :
36 : using namespace std;
37 :
38 : // IniFile.cpp: implementation of the IniFile class.
39 : //
40 : //////////////////////////////////////////////////////////////////////
41 0 : bool CompareAsNum::operator() (const string& s1, const string& s2) const
42 : {
43 0 : long Num1 = atoi(s1.c_str());
44 0 : long Num2 = atoi(s2.c_str());
45 0 : return Num1 < Num2;
46 : }
47 :
48 7925 : static string TrimSpaces(const string& input)
49 : {
50 : // find first non space
51 7925 : if ( input.empty())
52 0 : return string();
53 :
54 7925 : size_t iFirstNonSpace = input.find_first_not_of(' ');
55 7925 : size_t iFindLastSpace = input.find_last_not_of(' ');
56 7925 : if (iFirstNonSpace == string::npos || iFindLastSpace == string::npos)
57 0 : return string();
58 :
59 7925 : return input.substr(iFirstNonSpace, iFindLastSpace - iFirstNonSpace + 1);
60 : }
61 :
62 20424 : static string GetLine(VSILFILE* fil)
63 : {
64 20424 : const char *p = CPLReadLineL( fil );
65 20424 : if (p == NULL)
66 34 : return string();
67 :
68 20390 : CPLString osWrk = p;
69 20390 : osWrk.Trim();
70 20390 : return string(osWrk);
71 : }
72 :
73 : //////////////////////////////////////////////////////////////////////
74 : // Construction/Destruction
75 : //////////////////////////////////////////////////////////////////////
76 1828 : IniFile::IniFile(const string& filenam)
77 : {
78 1828 : filename = filenam;
79 1828 : Load();
80 1828 : bChanged = false; // Start tracking changes
81 1828 : }
82 :
83 1828 : IniFile::~IniFile()
84 : {
85 1828 : if (bChanged)
86 : {
87 1456 : Store();
88 1456 : bChanged = false;
89 : }
90 :
91 7308 : for (Sections::iterator iter = sections.begin(); iter != sections.end(); ++iter)
92 : {
93 5480 : (*(*iter).second).clear();
94 5480 : delete (*iter).second;
95 : }
96 :
97 1828 : sections.clear();
98 1828 : }
99 :
100 11936 : void IniFile::SetKeyValue(const string& section, const string& key, const string& value)
101 : {
102 11936 : Sections::iterator iterSect = sections.find(section);
103 11936 : if (iterSect == sections.end())
104 : {
105 : // Add a new section, with one new key/value entry
106 5480 : SectionEntries *entries = new SectionEntries;
107 5480 : (*entries)[key] = value;
108 5480 : sections[section] = entries;
109 : }
110 : else
111 : {
112 : // Add one new key/value entry in an existing section
113 6456 : SectionEntries *entries = (*iterSect).second;
114 6456 : (*entries)[key] = value;
115 : }
116 11936 : bChanged = true;
117 11936 : }
118 :
119 372 : string IniFile::GetKeyValue(const string& section, const string& key)
120 : {
121 372 : Sections::iterator iterSect = sections.find(section);
122 372 : if (iterSect != sections.end())
123 : {
124 359 : SectionEntries *entries = (*iterSect).second;
125 359 : SectionEntries::iterator iterEntry = (*entries).find(key);
126 359 : if (iterEntry != (*entries).end())
127 312 : return (*iterEntry).second;
128 : }
129 :
130 60 : return string();
131 : }
132 :
133 0 : void IniFile::RemoveKeyValue(const string& section, const string& key)
134 : {
135 0 : Sections::iterator iterSect = sections.find(section);
136 0 : if (iterSect != sections.end())
137 : {
138 : // The section exists, now erase entry "key"
139 0 : SectionEntries *entries = (*iterSect).second;
140 0 : (*entries).erase(key);
141 0 : bChanged = true;
142 : }
143 0 : }
144 :
145 0 : void IniFile::RemoveSection(const string& section)
146 : {
147 0 : Sections::iterator iterSect = sections.find(section);
148 0 : if (iterSect != sections.end())
149 : {
150 : // The section exists, so remove it and all its entries.
151 0 : SectionEntries *entries = (*iterSect).second;
152 0 : (*entries).clear();
153 0 : sections.erase(iterSect);
154 0 : bChanged = true;
155 : }
156 0 : }
157 :
158 1828 : void IniFile::Load()
159 : {
160 : enum ParseState { FindSection, FindKey, ReadFindKey, StoreKey, None } state;
161 1828 : VSILFILE *filIni = VSIFOpenL(filename.c_str(), "r");
162 1828 : if (filIni == NULL)
163 176 : return;
164 :
165 1652 : string section, key, value;
166 1652 : state = FindSection;
167 1652 : string s;
168 39716 : while (!VSIFEofL(filIni) || !s.empty() )
169 : {
170 36412 : switch (state)
171 : {
172 : case FindSection:
173 15452 : s = GetLine(filIni);
174 15452 : if (s.empty())
175 4972 : continue;
176 :
177 10480 : if (s[0] == '[')
178 : {
179 4972 : size_t iLast = s.find_first_of(']');
180 4972 : if (iLast != string::npos)
181 : {
182 4972 : section = s.substr(1, iLast - 1);
183 4972 : state = ReadFindKey;
184 : }
185 : }
186 : else
187 5508 : state = FindKey;
188 10480 : break;
189 : case ReadFindKey:
190 4972 : s = GetLine(filIni); // fall through (no break)
191 : case FindKey:
192 : {
193 10480 : size_t iEqu = s.find_first_of('=');
194 10480 : if (iEqu != string::npos)
195 : {
196 10480 : key = s.substr(0, iEqu);
197 10480 : value = s.substr(iEqu + 1);
198 10480 : state = StoreKey;
199 : }
200 : else
201 0 : state = ReadFindKey;
202 : }
203 10480 : break;
204 : case StoreKey:
205 10480 : SetKeyValue(section, key, value);
206 10480 : state = FindSection;
207 : break;
208 :
209 : case None:
210 : // Do we need to do anything? Perhaps this never occurs.
211 : break;
212 : }
213 : }
214 :
215 1652 : VSIFCloseL(filIni);
216 : }
217 :
218 1456 : void IniFile::Store()
219 : {
220 1456 : VSILFILE *filIni = VSIFOpenL(filename.c_str(), "w+");
221 1456 : if (filIni == NULL)
222 20 : return;
223 :
224 1436 : Sections::iterator iterSect;
225 5591 : for (iterSect = sections.begin(); iterSect != sections.end(); ++iterSect)
226 : {
227 4155 : CPLString osLine;
228 :
229 : // write the section name
230 4155 : osLine.Printf( "[%s]\r\n", (*iterSect).first.c_str());
231 4155 : VSIFWriteL( osLine.c_str(), 1, strlen(osLine), filIni );
232 4155 : SectionEntries *entries = (*iterSect).second;
233 4155 : SectionEntries::iterator iterEntry;
234 12080 : for (iterEntry = (*entries).begin(); iterEntry != (*entries).end(); ++iterEntry)
235 : {
236 7925 : string key = (*iterEntry).first;
237 : osLine.Printf( "%s=%s\r\n",
238 7925 : TrimSpaces(key).c_str(), (*iterEntry).second.c_str());
239 7925 : VSIFWriteL( osLine.c_str(), 1, strlen(osLine), filIni );
240 : }
241 :
242 4155 : VSIFWriteL( "\r\n", 1, 2, filIni );
243 : }
244 :
245 1436 : VSIFCloseL( filIni );
246 : }
247 :
248 : // End of the implementation of IniFile class. ///////////////////////
249 : //////////////////////////////////////////////////////////////////////
250 :
251 0 : static long longConv(double x) {
252 0 : if ((x == rUNDEF) || (x > LONG_MAX) || (x < LONG_MIN))
253 0 : return iUNDEF;
254 : else
255 0 : return (long)floor(x + 0.5);
256 : }
257 :
258 372 : string ReadElement(string section, string entry, string filename)
259 : {
260 372 : if (section.length() == 0)
261 0 : return string();
262 372 : if (entry.length() == 0)
263 0 : return string();
264 372 : if (filename.length() == 0)
265 0 : return string();
266 :
267 372 : IniFile MyIniFile (filename);
268 :
269 372 : return MyIniFile.GetKeyValue(section, entry);;
270 : }
271 :
272 1456 : bool WriteElement(string sSection, string sEntry,
273 : string fn, string sValue)
274 : {
275 1456 : if (0 == fn.length())
276 0 : return false;
277 :
278 1456 : IniFile MyIniFile (fn);
279 :
280 1456 : MyIniFile.SetKeyValue(sSection, sEntry, sValue);
281 1456 : return true;
282 : }
283 :
284 113 : bool WriteElement(string sSection, string sEntry,
285 : string fn, int nValue)
286 : {
287 113 : if (0 == fn.length())
288 0 : return false;
289 :
290 : char strdouble[45];
291 113 : sprintf(strdouble, "%d", nValue);
292 113 : string sValue = string(strdouble);
293 226 : return WriteElement(sSection, sEntry, fn, sValue) != 0;
294 : }
295 :
296 186 : bool WriteElement(string sSection, string sEntry,
297 : string fn, double dValue)
298 : {
299 186 : if (0 == fn.length())
300 0 : return false;
301 :
302 : char strdouble[45];
303 186 : sprintf(strdouble, "%.6f", dValue);
304 186 : string sValue = string(strdouble);
305 372 : return WriteElement(sSection, sEntry, fn, sValue) != 0;
306 : }
307 :
308 10 : static CPLErr GetRowCol(string str,int &Row, int &Col)
309 : {
310 10 : string delimStr = " ,;";
311 20 : size_t iPos = str.find_first_of(delimStr);
312 10 : if (iPos != string::npos)
313 : {
314 10 : Row = atoi(str.substr(0, iPos).c_str());
315 : }
316 : else
317 : {
318 : CPLError( CE_Failure, CPLE_AppDefined,
319 0 : "Read of RowCol failed.");
320 0 : return CE_Failure;
321 : }
322 20 : iPos = str.find_last_of(delimStr);
323 10 : if (iPos != string::npos)
324 : {
325 10 : Col = atoi(str.substr(iPos+1, str.length()-iPos).c_str());
326 : }
327 10 : return CE_None;
328 : }
329 :
330 : //! Converts ILWIS data type to GDAL data type.
331 67 : static GDALDataType ILWIS2GDALType(ilwisStoreType stStoreType)
332 : {
333 67 : GDALDataType eDataType = GDT_Unknown;
334 :
335 67 : switch (stStoreType){
336 : case stByte: {
337 36 : eDataType = GDT_Byte;
338 36 : break;
339 : }
340 : case stInt:{
341 10 : eDataType = GDT_Int16;
342 10 : break;
343 : }
344 : case stLong:{
345 10 : eDataType = GDT_Int32;
346 10 : break;
347 : }
348 : case stFloat:{
349 6 : eDataType = GDT_Float32;
350 6 : break;
351 : }
352 : case stReal:{
353 5 : eDataType = GDT_Float64;
354 : break;
355 : }
356 : default: {
357 : break;
358 : }
359 : }
360 :
361 67 : return eDataType;
362 : }
363 :
364 : //Determine store type of ILWIS raster
365 60 : static string GDALType2ILWIS(GDALDataType type)
366 : {
367 60 : string sStoreType;
368 60 : sStoreType = "";
369 60 : switch( type )
370 : {
371 : case GDT_Byte:{
372 35 : sStoreType = "Byte";
373 35 : break;
374 : }
375 : case GDT_Int16:
376 : case GDT_UInt16:{
377 8 : sStoreType = "Int";
378 8 : break;
379 : }
380 : case GDT_Int32:
381 : case GDT_UInt32:{
382 8 : sStoreType = "Long";
383 8 : break;
384 : }
385 : case GDT_Float32:{
386 5 : sStoreType = "Float";
387 5 : break;
388 : }
389 : case GDT_Float64:{
390 4 : sStoreType = "Real";
391 4 : break;
392 : }
393 : default:{
394 : CPLError( CE_Failure, CPLE_NotSupported,
395 : "Data type %s not supported by ILWIS format.\n",
396 0 : GDALGetDataTypeName( type ) );
397 : break;
398 : }
399 : }
400 0 : return sStoreType;
401 : }
402 :
403 86 : static CPLErr GetStoreType(string pszFileName, ilwisStoreType &stStoreType)
404 : {
405 86 : string st = ReadElement("MapStore", "Type", pszFileName.c_str());
406 :
407 172 : if( EQUAL(st.c_str(),"byte"))
408 : {
409 51 : stStoreType = stByte;
410 : }
411 35 : else if( EQUAL(st.c_str(),"int"))
412 : {
413 10 : stStoreType = stInt;
414 : }
415 25 : else if( EQUAL(st.c_str(),"long"))
416 : {
417 10 : stStoreType = stLong;
418 : }
419 15 : else if( EQUAL(st.c_str(),"float"))
420 : {
421 10 : stStoreType = stFloat;
422 : }
423 5 : else if( EQUAL(st.c_str(),"real"))
424 : {
425 5 : stStoreType = stReal;
426 : }
427 : else
428 : {
429 : CPLError( CE_Failure, CPLE_AppDefined,
430 0 : "Unsupported ILWIS store type.");
431 0 : return CE_Failure;
432 : }
433 86 : return CE_None;
434 : }
435 :
436 :
437 45 : ILWISDataset::ILWISDataset()
438 :
439 : {
440 45 : bGeoDirty = FALSE;
441 45 : bNewDataset = FALSE;
442 45 : pszProjection = CPLStrdup("");
443 45 : adfGeoTransform[0] = 0.0;
444 45 : adfGeoTransform[1] = 1.0;
445 45 : adfGeoTransform[2] = 0.0;
446 45 : adfGeoTransform[3] = 0.0;
447 45 : adfGeoTransform[4] = 0.0;
448 45 : adfGeoTransform[5] = 1.0;
449 45 : }
450 :
451 : /************************************************************************/
452 : /* ~ILWISDataset() */
453 : /************************************************************************/
454 :
455 45 : ILWISDataset::~ILWISDataset()
456 :
457 : {
458 45 : FlushCache();
459 45 : CPLFree( pszProjection );
460 45 : }
461 :
462 : /************************************************************************/
463 : /* CollectTransformCoef() */
464 : /* */
465 : /* Collect the geotransform, support for the GeoRefCorners */
466 : /* georeferencing only; We use the extent of the coordinates */
467 : /* to determine the pixelsize in X and Y direction. Then calculate */
468 : /* the transform coefficients from the extent and pixelsize */
469 : /************************************************************************/
470 :
471 10 : void ILWISDataset::CollectTransformCoef(string &pszRefName)
472 :
473 : {
474 10 : pszRefName = "";
475 10 : string georef;
476 10 : if ( EQUAL(pszFileType.c_str(),"Map") )
477 7 : georef = ReadElement("Map", "GeoRef", osFileName);
478 : else
479 3 : georef = ReadElement("MapList", "GeoRef", osFileName);
480 :
481 : //Capture the geotransform, only if the georef is not 'none',
482 : //otherwise, the default transform should be returned.
483 10 : if( (georef.length() != 0) && !EQUAL(georef.c_str(),"none"))
484 : {
485 : //Form the geo-referencing name
486 10 : string pszBaseName = string(CPLGetBasename(georef.c_str()) );
487 20 : string pszPath = string(CPLGetPath( osFileName ));
488 : pszRefName = string(CPLFormFilename(pszPath.c_str(),
489 20 : pszBaseName.c_str(),"grf" ));
490 :
491 : //Check the geo-reference type,support for the GeoRefCorners only
492 20 : string georeftype = ReadElement("GeoRef", "Type", pszRefName);
493 10 : if (EQUAL(georeftype.c_str(),"GeoRefCorners"))
494 : {
495 : //Center or top-left corner of the pixel approach?
496 5 : string IsCorner = ReadElement("GeoRefCorners", "CornersOfCorners", pszRefName);
497 :
498 : //Collect the extent of the coordinates
499 5 : string sMinX = ReadElement("GeoRefCorners", "MinX", pszRefName);
500 5 : string sMinY = ReadElement("GeoRefCorners", "MinY", pszRefName);
501 5 : string sMaxX = ReadElement("GeoRefCorners", "MaxX", pszRefName);
502 5 : string sMaxY = ReadElement("GeoRefCorners", "MaxY", pszRefName);
503 :
504 : //Calculate pixel size in X and Y direction from the extent
505 5 : double deltaX = atof(sMaxX.c_str()) - atof(sMinX.c_str());
506 5 : double deltaY = atof(sMaxY.c_str()) - atof(sMinY.c_str());
507 :
508 5 : double PixelSizeX = deltaX / (double)nRasterXSize;
509 5 : double PixelSizeY = deltaY / (double)nRasterYSize;
510 :
511 5 : if (EQUAL(IsCorner.c_str(),"Yes"))
512 : {
513 5 : adfGeoTransform[0] = atof(sMinX.c_str());
514 5 : adfGeoTransform[3] = atof(sMaxY.c_str());
515 : }
516 : else
517 : {
518 0 : adfGeoTransform[0] = atof(sMinX.c_str()) - PixelSizeX/2.0;
519 0 : adfGeoTransform[3] = atof(sMaxY.c_str()) + PixelSizeY/2.0;
520 : }
521 :
522 5 : adfGeoTransform[1] = PixelSizeX;
523 5 : adfGeoTransform[2] = 0.0;
524 5 : adfGeoTransform[4] = 0.0;
525 5 : adfGeoTransform[5] = -PixelSizeY;
526 10 : }
527 :
528 10 : }
529 :
530 10 : }
531 :
532 : /************************************************************************/
533 : /* WriteGeoReference() */
534 : /* */
535 : /* Try to write a geo-reference file for the dataset to create */
536 : /************************************************************************/
537 :
538 31 : CPLErr ILWISDataset::WriteGeoReference()
539 : {
540 : //check wheather we should write out a georeference file.
541 : //dataset must be north up
542 31 : if( adfGeoTransform[0] != 0.0 || adfGeoTransform[1] != 1.0
543 0 : || adfGeoTransform[2] != 0.0 || adfGeoTransform[3] != 0.0
544 0 : || adfGeoTransform[4] != 0.0 || fabs(adfGeoTransform[5]) != 1.0 )
545 : {
546 31 : SetGeoTransform( adfGeoTransform ); // is this needed?
547 31 : if (adfGeoTransform[2] == 0.0 && adfGeoTransform[4] == 0.0)
548 : {
549 31 : int nXSize = GetRasterXSize();
550 31 : int nYSize = GetRasterYSize();
551 31 : double dLLLat = (adfGeoTransform[3]
552 31 : + nYSize * adfGeoTransform[5] );
553 31 : double dLLLong = (adfGeoTransform[0] );
554 31 : double dURLat = (adfGeoTransform[3] );
555 31 : double dURLong = (adfGeoTransform[0]
556 31 : + nXSize * adfGeoTransform[1] );
557 :
558 31 : string grFileName = CPLResetExtension(osFileName, "grf" );
559 62 : WriteElement("Ilwis", "Type", grFileName, "GeoRef");
560 62 : WriteElement("GeoRef", "lines", grFileName, nYSize);
561 31 : WriteElement("GeoRef", "columns", grFileName, nXSize);
562 31 : WriteElement("GeoRef", "Type", grFileName, "GeoRefCorners");
563 62 : WriteElement("GeoRefCorners", "CornersOfCorners", grFileName, "Yes");
564 62 : WriteElement("GeoRefCorners", "MinX", grFileName, dLLLong);
565 31 : WriteElement("GeoRefCorners", "MinY", grFileName, dLLLat);
566 31 : WriteElement("GeoRefCorners", "MaxX", grFileName, dURLong);
567 31 : WriteElement("GeoRefCorners", "MaxY", grFileName, dURLat);
568 :
569 : //Re-write the GeoRef property to raster ODF
570 : //Form band file name
571 31 : string sBaseName = string(CPLGetBasename(osFileName) );
572 62 : string sPath = string(CPLGetPath(osFileName));
573 31 : if (nBands == 1)
574 : {
575 16 : WriteElement("Map", "GeoRef", osFileName, sBaseName + ".grf");
576 : }
577 : else
578 : {
579 61 : for( int iBand = 0; iBand < nBands; iBand++ )
580 : {
581 46 : if (iBand == 0)
582 14 : WriteElement("MapList", "GeoRef", osFileName, sBaseName + ".grf");
583 : char pszName[100];
584 46 : sprintf(pszName, "%s_band_%d", sBaseName.c_str(),iBand + 1 );
585 46 : string pszODFName = string(CPLFormFilename(sPath.c_str(),pszName,"mpr"));
586 92 : WriteElement("Map", "GeoRef", pszODFName, sBaseName + ".grf");
587 : }
588 31 : }
589 : }
590 : }
591 31 : return CE_None;
592 : }
593 :
594 : /************************************************************************/
595 : /* GetProjectionRef() */
596 : /************************************************************************/
597 :
598 32 : const char *ILWISDataset::GetProjectionRef()
599 :
600 : {
601 32 : return ( pszProjection );
602 : }
603 :
604 : /************************************************************************/
605 : /* SetProjection() */
606 : /************************************************************************/
607 :
608 31 : CPLErr ILWISDataset::SetProjection( const char * pszNewProjection )
609 :
610 : {
611 31 : CPLFree( pszProjection );
612 31 : pszProjection = CPLStrdup( pszNewProjection );
613 31 : bGeoDirty = TRUE;
614 :
615 31 : return CE_None;
616 : }
617 :
618 : /************************************************************************/
619 : /* GetGeoTransform() */
620 : /************************************************************************/
621 :
622 38 : CPLErr ILWISDataset::GetGeoTransform( double * padfTransform )
623 :
624 : {
625 38 : memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
626 38 : return( CE_None );
627 : }
628 :
629 : /************************************************************************/
630 : /* SetGeoTransform() */
631 : /************************************************************************/
632 :
633 62 : CPLErr ILWISDataset::SetGeoTransform( double * padfTransform )
634 :
635 : {
636 62 : memmove( adfGeoTransform, padfTransform, sizeof(double)*6 );
637 :
638 62 : if (adfGeoTransform[2] == 0.0 && adfGeoTransform[4] == 0.0)
639 62 : bGeoDirty = TRUE;
640 :
641 62 : return CE_None;
642 : }
643 :
644 10 : bool CheckASCII(unsigned char * buf, int size)
645 : {
646 2539 : for (int i = 0; i < size; ++i)
647 2529 : if (!isascii(buf[i]))
648 0 : return false;
649 :
650 10 : return true;
651 : }
652 : /************************************************************************/
653 : /* Open() */
654 : /************************************************************************/
655 :
656 12295 : GDALDataset *ILWISDataset::Open( GDALOpenInfo * poOpenInfo )
657 :
658 : {
659 : /* -------------------------------------------------------------------- */
660 : /* Does this look like an ILWIS file */
661 : /* -------------------------------------------------------------------- */
662 12295 : if( poOpenInfo->nHeaderBytes < 1 )
663 10699 : return NULL;
664 :
665 1596 : string sExt = CPLGetExtension( poOpenInfo->pszFilename );
666 3192 : if (!EQUAL(sExt.c_str(),"mpr") && !EQUAL(sExt.c_str(),"mpl"))
667 1586 : return NULL;
668 :
669 10 : if (!CheckASCII(poOpenInfo->pabyHeader, poOpenInfo->nHeaderBytes))
670 0 : return NULL;
671 :
672 10 : string ilwistype = ReadElement("Ilwis", "Type", poOpenInfo->pszFilename);
673 20 : if( ilwistype.length() == 0)
674 0 : return NULL;
675 :
676 10 : string sFileType; //map or map list
677 : int iBandCount;
678 10 : string mapsize;
679 10 : string maptype = ReadElement("BaseMap", "Type", poOpenInfo->pszFilename);
680 20 : string sBaseName = string(CPLGetBasename(poOpenInfo->pszFilename) );
681 20 : string sPath = string(CPLGetPath( poOpenInfo->pszFilename));
682 :
683 : //Verify whether it is a map list or a map
684 20 : if( EQUAL(ilwistype.c_str(),"MapList") )
685 : {
686 3 : sFileType = string("MapList");
687 6 : string sMaps = ReadElement("MapList", "Maps", poOpenInfo->pszFilename);
688 6 : iBandCount = atoi(sMaps.c_str());
689 3 : mapsize = ReadElement("MapList", "Size", poOpenInfo->pszFilename);
690 3 : for (int iBand = 0; iBand < iBandCount; ++iBand )
691 : {
692 : //Form the band file name.
693 : char cBandName[45];
694 6 : sprintf( cBandName, "Map%d", iBand);
695 6 : string sBandName = ReadElement("MapList", string(cBandName), poOpenInfo->pszFilename);
696 12 : string pszBandBaseName = string(CPLGetBasename(sBandName.c_str()) );
697 12 : string pszBandPath = string(CPLGetPath( sBandName.c_str()));
698 12 : if ( 0 == pszBandPath.length() )
699 : {
700 : sBandName = string(CPLFormFilename(sPath.c_str(),
701 6 : pszBandBaseName.c_str(),"mpr" ));
702 : }
703 : //Verify the file exetension, it must be an ILWIS raw data file
704 : //with extension .mp#, otherwise, unsupported
705 : //This drive only supports a map list which stores a set of ILWIS raster maps,
706 6 : string sMapStoreName = ReadElement("MapStore", "Data", sBandName);
707 6 : string sExt = CPLGetExtension( sMapStoreName.c_str() );
708 12 : if ( !EQUALN( sExt.c_str(), "mp#", 3 ))
709 : {
710 : CPLError( CE_Failure, CPLE_AppDefined,
711 : "Unsupported ILWIS data file. \n"
712 0 : "can't treat as raster.\n" );
713 0 : return FALSE;
714 : }
715 0 : }
716 : }
717 7 : else if(EQUAL(ilwistype.c_str(),"BaseMap") && EQUAL(maptype.c_str(),"Map"))
718 : {
719 7 : sFileType = "Map";
720 7 : iBandCount = 1;
721 7 : mapsize = ReadElement("Map", "Size", poOpenInfo->pszFilename);
722 14 : string sMapType = ReadElement("Map", "Type", poOpenInfo->pszFilename);
723 : ilwisStoreType stStoreType;
724 14 : if (
725 : GetStoreType(string(poOpenInfo->pszFilename), stStoreType) != CE_None )
726 : {
727 : //CPLError( CE_Failure, CPLE_AppDefined,
728 : // "Unsupported ILWIS data file. \n"
729 : // "can't treat as raster.\n" );
730 0 : return FALSE;
731 0 : }
732 : }
733 : else
734 : {
735 : CPLError( CE_Failure, CPLE_AppDefined,
736 : "Unsupported ILWIS data file. \n"
737 0 : "can't treat as raster.\n" );
738 0 : return FALSE;
739 : }
740 :
741 : /* -------------------------------------------------------------------- */
742 : /* Create a corresponding GDALDataset. */
743 : /* -------------------------------------------------------------------- */
744 : ILWISDataset *poDS;
745 10 : poDS = new ILWISDataset();
746 :
747 : /* -------------------------------------------------------------------- */
748 : /* Capture raster size from ILWIS file (.mpr). */
749 : /* -------------------------------------------------------------------- */
750 10 : int Row = 0, Col = 0;
751 20 : if ( GetRowCol(mapsize, Row, Col) != CE_None)
752 0 : return FALSE;
753 10 : poDS->nRasterXSize = Col;
754 10 : poDS->nRasterYSize = Row;
755 10 : poDS->osFileName = poOpenInfo->pszFilename;
756 10 : poDS->pszFileType = sFileType;
757 : /* -------------------------------------------------------------------- */
758 : /* Create band information objects. */
759 : /* -------------------------------------------------------------------- */
760 : //poDS->pszFileName = new char[strlen(poOpenInfo->pszFilename) + 1];
761 10 : poDS->nBands = iBandCount;
762 23 : for( int iBand = 0; iBand < poDS->nBands; iBand++ )
763 : {
764 13 : poDS->SetBand( iBand+1, new ILWISRasterBand( poDS, iBand+1 ) );
765 : }
766 :
767 : /* -------------------------------------------------------------------- */
768 : /* Collect the geotransform coefficients */
769 : /* -------------------------------------------------------------------- */
770 10 : string pszGeoRef;
771 10 : poDS->CollectTransformCoef(pszGeoRef);
772 :
773 : /* -------------------------------------------------------------------- */
774 : /* Translation from ILWIS coordinate system definition */
775 : /* -------------------------------------------------------------------- */
776 10 : if( (pszGeoRef.length() != 0) && !EQUAL(pszGeoRef.c_str(),"none"))
777 : {
778 :
779 : // Fetch coordinate system
780 10 : string csy = ReadElement("GeoRef", "CoordSystem", pszGeoRef);
781 10 : string pszProj;
782 :
783 10 : if( (csy.length() != 0) && !EQUAL(csy.c_str(),"unknown.csy"))
784 : {
785 :
786 : //Form the coordinate system file name
787 5 : if( !(EQUALN( csy.c_str(), "latlon.csy", 10 )) &&
788 : !(EQUALN( csy.c_str(), "LatlonWGS84.csy", 15 )))
789 : {
790 5 : string pszBaseName = string(CPLGetBasename(csy.c_str()) );
791 10 : string pszPath = string(CPLGetPath( poDS->osFileName ));
792 : csy = string(CPLFormFilename(pszPath.c_str(),
793 10 : pszBaseName.c_str(),"csy" ));
794 10 : pszProj = ReadElement("CoordSystem", "Type", csy);
795 5 : if (pszProj.length() == 0 ) //default to projection
796 0 : pszProj = "Projection";
797 : }
798 : else
799 : {
800 0 : pszProj = "LatLon";
801 : }
802 :
803 5 : if( (EQUALN( pszProj.c_str(), "LatLon", 6 )) ||
804 : (EQUALN( pszProj.c_str(), "Projection", 10 )))
805 5 : poDS->ReadProjection( csy );
806 10 : }
807 : }
808 :
809 : /* -------------------------------------------------------------------- */
810 : /* Initialize any PAM information. */
811 : /* -------------------------------------------------------------------- */
812 10 : poDS->SetDescription( poOpenInfo->pszFilename );
813 10 : poDS->TryLoadXML();
814 :
815 : /* -------------------------------------------------------------------- */
816 : /* Check for external overviews. */
817 : /* -------------------------------------------------------------------- */
818 10 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->papszSiblingFiles );
819 :
820 10 : return( poDS );
821 : }
822 :
823 : /************************************************************************/
824 : /* FlushCache() */
825 : /************************************************************************/
826 :
827 59 : void ILWISDataset::FlushCache()
828 :
829 : {
830 59 : GDALDataset::FlushCache();
831 :
832 59 : if( bGeoDirty == TRUE )
833 : {
834 31 : WriteGeoReference();
835 31 : WriteProjection();
836 31 : bGeoDirty = FALSE;
837 : }
838 59 : }
839 :
840 : /************************************************************************/
841 : /* Create() */
842 : /* */
843 : /* Create a new ILWIS file. */
844 : /************************************************************************/
845 :
846 49 : GDALDataset *ILWISDataset::Create(const char* pszFilename,
847 : int nXSize, int nYSize,
848 : int nBands, GDALDataType eType,
849 : char** papszParmList)
850 : {
851 : ILWISDataset *poDS;
852 : int iBand;
853 :
854 : /* -------------------------------------------------------------------- */
855 : /* Verify input options. */
856 : /* -------------------------------------------------------------------- */
857 49 : if( eType != GDT_Byte && eType != GDT_Int16 && eType != GDT_Int32
858 : && eType != GDT_Float32 && eType != GDT_Float64 && eType != GDT_UInt16 && eType != GDT_UInt32)
859 : {
860 : CPLError( CE_Failure, CPLE_AppDefined,
861 : "Attempt to create ILWIS dataset with an illegal\n"
862 : "data type (%s).\n",
863 12 : GDALGetDataTypeName(eType) );
864 :
865 12 : return NULL;
866 : }
867 :
868 : /* -------------------------------------------------------------------- */
869 : /* Translate the data type. */
870 : /* Determine store type of ILWIS raster */
871 : /* -------------------------------------------------------------------- */
872 37 : string sDomain= "value.dom";
873 37 : double stepsize = 1;
874 37 : string sStoreType = GDALType2ILWIS(eType);
875 37 : if( EQUAL(sStoreType.c_str(),""))
876 0 : return NULL;
877 37 : else if( EQUAL(sStoreType.c_str(),"Real") || EQUAL(sStoreType.c_str(),"float"))
878 7 : stepsize = 0;
879 :
880 37 : string pszBaseName = string(CPLGetBasename( pszFilename ));
881 74 : string pszPath = string(CPLGetPath( pszFilename ));
882 :
883 : /* -------------------------------------------------------------------- */
884 : /* Write out object definition file for each band */
885 : /* -------------------------------------------------------------------- */
886 37 : string pszODFName;
887 37 : string pszDataBaseName;
888 37 : string pszFileName;
889 :
890 : char strsize[45];
891 37 : sprintf(strsize, "%d %d", nYSize, nXSize);
892 :
893 : //Form map/maplist name.
894 37 : if ( nBands == 1 )
895 : {
896 19 : pszODFName = string(CPLFormFilename(pszPath.c_str(),pszBaseName.c_str(),"mpr"));
897 19 : pszDataBaseName = pszBaseName;
898 19 : pszFileName = CPLFormFilename(pszPath.c_str(),pszBaseName.c_str(),"mpr");
899 : }
900 : else
901 : {
902 18 : pszFileName = CPLFormFilename(pszPath.c_str(),pszBaseName.c_str(),"mpl");
903 18 : WriteElement("Ilwis", "Type", string(pszFileName), "MapList");
904 36 : WriteElement("MapList", "GeoRef", string(pszFileName), "none.grf");
905 36 : WriteElement("MapList", "Size", string(pszFileName), string(strsize));
906 36 : WriteElement("MapList", "Maps", string(pszFileName), nBands);
907 : }
908 :
909 37 : for( iBand = 0; iBand < nBands; iBand++ )
910 : {
911 68 : if ( nBands > 1 )
912 : {
913 : char pszBandName[100];
914 49 : sprintf(pszBandName, "%s_band_%d", pszBaseName.c_str(),iBand + 1 );
915 49 : pszODFName = string(pszBandName) + ".mpr";
916 98 : pszDataBaseName = string(pszBandName);
917 49 : sprintf(pszBandName, "Map%d", iBand);
918 98 : WriteElement("MapList", string(pszBandName), string(pszFileName), pszODFName);
919 49 : pszODFName = CPLFormFilename(pszPath.c_str(),pszDataBaseName.c_str(),"mpr");
920 : }
921 : /* -------------------------------------------------------------------- */
922 : /* Write data definition per band (.mpr) */
923 : /* -------------------------------------------------------------------- */
924 :
925 68 : WriteElement("Ilwis", "Type", pszODFName, "BaseMap");
926 136 : WriteElement("BaseMap", "Type", pszODFName, "Map");
927 136 : WriteElement("Map", "Type", pszODFName, "MapStore");
928 :
929 136 : WriteElement("BaseMap", "Domain", pszODFName, sDomain);
930 68 : string pszDataName = pszDataBaseName + ".mp#";
931 68 : WriteElement("MapStore", "Data", pszODFName, pszDataName);
932 68 : WriteElement("MapStore", "Structure", pszODFName, "Line");
933 : // sStoreType is used by ILWISRasterBand constructor to determine eDataType
934 136 : WriteElement("MapStore", "Type", pszODFName, sStoreType);
935 :
936 : // For now write-out a "Range" that is as broad as possible.
937 : // If later a better range is found (by inspecting metadata in the source dataset),
938 : // the "Range" will be overwritten by a better version.
939 : double adfMinMax[2];
940 68 : adfMinMax[0] = -9999999.9;
941 68 : adfMinMax[1] = 9999999.9;
942 : char strdouble[45];
943 68 : sprintf(strdouble, "%.3f:%.3f:%3f:offset=0", adfMinMax[0], adfMinMax[1],stepsize);
944 68 : string range = string(strdouble);
945 136 : WriteElement("BaseMap", "Range", pszODFName, range);
946 :
947 68 : WriteElement("Map", "GeoRef", pszODFName, "none.grf");
948 136 : WriteElement("Map", "Size", pszODFName, string(strsize));
949 :
950 : /* -------------------------------------------------------------------- */
951 : /* Try to create the data file. */
952 : /* -------------------------------------------------------------------- */
953 136 : pszDataName = CPLResetExtension(pszODFName.c_str(), "mp#" );
954 :
955 68 : VSILFILE *fp = VSIFOpenL( pszDataName.c_str(), "wb" );
956 :
957 68 : if( fp == NULL )
958 : {
959 : CPLError( CE_Failure, CPLE_OpenFailed,
960 2 : "Unable to create file %s.\n", pszDataName.c_str() );
961 2 : return NULL;
962 : }
963 66 : VSIFCloseL( fp );
964 : }
965 35 : poDS = new ILWISDataset();
966 35 : poDS->nRasterXSize = nXSize;
967 35 : poDS->nRasterYSize = nYSize;
968 35 : poDS->nBands = nBands;
969 35 : poDS->eAccess = GA_Update;
970 35 : poDS->bNewDataset = TRUE;
971 35 : poDS->SetDescription(pszFilename);
972 35 : poDS->osFileName = pszFileName;
973 35 : poDS->pszIlwFileName = string(pszFileName);
974 35 : if ( nBands == 1 )
975 17 : poDS->pszFileType = "Map";
976 : else
977 18 : poDS->pszFileType = "MapList";
978 :
979 : /* -------------------------------------------------------------------- */
980 : /* Create band information objects. */
981 : /* -------------------------------------------------------------------- */
982 :
983 101 : for( iBand = 1; iBand <= poDS->nBands; iBand++ )
984 : {
985 66 : poDS->SetBand( iBand, new ILWISRasterBand( poDS, iBand ) );
986 : }
987 :
988 35 : return poDS;
989 : //return (GDALDataset *) GDALOpen( pszFilename, GA_Update );
990 : }
991 :
992 : /************************************************************************/
993 : /* CreateCopy() */
994 : /************************************************************************/
995 :
996 : GDALDataset *
997 20 : ILWISDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
998 : int bStrict, char ** papszOptions,
999 : GDALProgressFunc pfnProgress, void * pProgressData )
1000 :
1001 : {
1002 :
1003 : ILWISDataset *poDS;
1004 20 : GDALDataType eType = GDT_Byte;
1005 : int iBand;
1006 : (void) bStrict;
1007 :
1008 :
1009 20 : int nXSize = poSrcDS->GetRasterXSize();
1010 20 : int nYSize = poSrcDS->GetRasterYSize();
1011 20 : int nBands = poSrcDS->GetRasterCount();
1012 :
1013 20 : if( !pfnProgress( 0.0, NULL, pProgressData ) )
1014 0 : return NULL;
1015 :
1016 : /* -------------------------------------------------------------------- */
1017 : /* Create the basic dataset. */
1018 : /* -------------------------------------------------------------------- */
1019 49 : for( iBand = 0; iBand < nBands; iBand++ )
1020 : {
1021 29 : GDALRasterBand *poBand = poSrcDS->GetRasterBand( iBand+1 );
1022 29 : eType = GDALDataTypeUnion( eType, poBand->GetRasterDataType() );
1023 : }
1024 :
1025 : poDS = (ILWISDataset *) Create( pszFilename,
1026 : poSrcDS->GetRasterXSize(),
1027 : poSrcDS->GetRasterYSize(),
1028 : nBands,
1029 20 : eType, papszOptions );
1030 :
1031 20 : if( poDS == NULL )
1032 6 : return NULL;
1033 14 : string pszBaseName = string(CPLGetBasename( pszFilename ));
1034 28 : string pszPath = string(CPLGetPath( pszFilename ));
1035 :
1036 : /* -------------------------------------------------------------------- */
1037 : /* Copy and geo-transform and projection information. */
1038 : /* -------------------------------------------------------------------- */
1039 : double adfGeoTransform[6];
1040 28 : string georef = "none.grf";
1041 :
1042 : //check wheather we should create georeference file.
1043 : //source dataset must be north up
1044 47 : if( poSrcDS->GetGeoTransform( adfGeoTransform ) == CE_None
1045 15 : && (adfGeoTransform[0] != 0.0 || adfGeoTransform[1] != 1.0
1046 2 : || adfGeoTransform[2] != 0.0 || adfGeoTransform[3] != 0.0
1047 2 : || adfGeoTransform[4] != 0.0 || fabs(adfGeoTransform[5]) != 1.0))
1048 : {
1049 13 : poDS->SetGeoTransform( adfGeoTransform );
1050 13 : if (adfGeoTransform[2] == 0.0 && adfGeoTransform[4] == 0.0)
1051 13 : georef = pszBaseName + ".grf";
1052 : }
1053 :
1054 14 : const char *pszProj = poSrcDS->GetProjectionRef();
1055 14 : if( pszProj != NULL && strlen(pszProj) > 0 )
1056 13 : poDS->SetProjection( pszProj );
1057 :
1058 : /* -------------------------------------------------------------------- */
1059 : /* Create the output raster files for each band */
1060 : /* -------------------------------------------------------------------- */
1061 :
1062 14 : for( iBand = 0; iBand < nBands; iBand++ )
1063 : {
1064 : VSILFILE *fpData;
1065 : GByte *pData;
1066 :
1067 23 : GDALRasterBand *poBand = poSrcDS->GetRasterBand( iBand+1 );
1068 23 : ILWISRasterBand *desBand = (ILWISRasterBand *) poDS->GetRasterBand( iBand+1 );
1069 :
1070 : /* -------------------------------------------------------------------- */
1071 : /* Translate the data type. */
1072 : /* -------------------------------------------------------------------- */
1073 23 : int nLineSize = nXSize * GDALGetDataTypeSize(eType) / 8;
1074 23 : pData = (GByte *) CPLMalloc( nLineSize );
1075 :
1076 : //Determine the nodata value
1077 : int bHasNoDataValue;
1078 23 : double dNoDataValue = poBand->GetNoDataValue(&bHasNoDataValue);
1079 :
1080 : //Determine store type of ILWIS raster
1081 23 : string sStoreType = GDALType2ILWIS( eType );
1082 23 : double stepsize = 1;
1083 23 : if( EQUAL(sStoreType.c_str(),""))
1084 0 : return NULL;
1085 23 : else if( EQUAL(sStoreType.c_str(),"Real") || EQUAL(sStoreType.c_str(),"float"))
1086 2 : stepsize = 0;
1087 :
1088 : //Form the image file name, create the object definition file.
1089 23 : string pszODFName;
1090 23 : string pszDataBaseName;
1091 23 : if (nBands == 1)
1092 : {
1093 9 : pszODFName = string(CPLFormFilename(pszPath.c_str(),pszBaseName.c_str(),"mpr"));
1094 9 : pszDataBaseName = pszBaseName;
1095 : }
1096 : else
1097 : {
1098 : char pszName[100];
1099 14 : sprintf(pszName, "%s_band_%d", pszBaseName.c_str(),iBand + 1 );
1100 14 : pszODFName = string(CPLFormFilename(pszPath.c_str(),pszName,"mpr"));
1101 28 : pszDataBaseName = string(pszName);
1102 : }
1103 : /* -------------------------------------------------------------------- */
1104 : /* Write data definition file for each band (.mpr) */
1105 : /* -------------------------------------------------------------------- */
1106 :
1107 : double adfMinMax[2];
1108 : int bGotMin, bGotMax;
1109 :
1110 23 : adfMinMax[0] = poBand->GetMinimum( &bGotMin );
1111 23 : adfMinMax[1] = poBand->GetMaximum( &bGotMax );
1112 23 : if( ! (bGotMin && bGotMax) )
1113 23 : GDALComputeRasterMinMax((GDALRasterBandH)poBand, FALSE, adfMinMax);
1114 23 : if ((!CPLIsNan(adfMinMax[0])) && CPLIsFinite(adfMinMax[0]) && (!CPLIsNan(adfMinMax[1])) && CPLIsFinite(adfMinMax[1]))
1115 : {
1116 : // only write a range if we got a correct one from the source dataset (otherwise ILWIS can't show the map properly)
1117 : char strdouble[45];
1118 23 : sprintf(strdouble, "%.3f:%.3f:%3f:offset=0", adfMinMax[0], adfMinMax[1],stepsize);
1119 23 : string range = string(strdouble);
1120 46 : WriteElement("BaseMap", "Range", pszODFName, range);
1121 : }
1122 23 : WriteElement("Map", "GeoRef", pszODFName, georef);
1123 :
1124 : /* -------------------------------------------------------------------- */
1125 : /* Loop over image, copy the image data. */
1126 : /* -------------------------------------------------------------------- */
1127 23 : CPLErr eErr = CE_None;
1128 :
1129 : //For file name for raw data, and create binary files.
1130 23 : string pszDataFileName = CPLResetExtension(pszODFName.c_str(), "mp#" );
1131 :
1132 23 : fpData = desBand->fpRaw;
1133 23 : if( fpData == NULL )
1134 : {
1135 : CPLError( CE_Failure, CPLE_OpenFailed,
1136 : "Attempt to create file `%s' failed.\n",
1137 0 : pszFilename );
1138 0 : return NULL;
1139 : }
1140 :
1141 273 : for( int iLine = 0; iLine < nYSize && eErr == CE_None; iLine++ )
1142 : {
1143 : eErr = poBand->RasterIO( GF_Read, 0, iLine, nXSize, 1,
1144 : pData, nXSize, 1, eType,
1145 250 : 0, 0 );
1146 :
1147 250 : if( eErr == CE_None )
1148 : {
1149 250 : if (bHasNoDataValue)
1150 : {
1151 : // pData may have entries with value = dNoDataValue
1152 : // ILWIS uses a fixed value for nodata, depending on the data-type
1153 : // Therefore translate the NoDataValue from each band to ILWIS
1154 0 : for (int iCol = 0; iCol < nXSize; iCol++ )
1155 : {
1156 0 : if( EQUAL(sStoreType.c_str(),"Byte"))
1157 : {
1158 0 : if ( ((GByte * )pData)[iCol] == dNoDataValue )
1159 0 : (( GByte * )pData)[iCol] = 0;
1160 : }
1161 0 : else if( EQUAL(sStoreType.c_str(),"Int"))
1162 : {
1163 0 : if ( ((GInt16 * )pData)[iCol] == dNoDataValue )
1164 0 : (( GInt16 * )pData)[iCol] = shUNDEF;
1165 : }
1166 0 : else if( EQUAL(sStoreType.c_str(),"Long"))
1167 : {
1168 0 : if ( ((GInt32 * )pData)[iCol] == dNoDataValue )
1169 0 : (( GInt32 * )pData)[iCol] = iUNDEF;
1170 : }
1171 0 : else if( EQUAL(sStoreType.c_str(),"float"))
1172 : {
1173 0 : if ((((float * )pData)[iCol] == dNoDataValue ) || (CPLIsNan((( float * )pData)[iCol])))
1174 0 : (( float * )pData)[iCol] = flUNDEF;
1175 : }
1176 0 : else if( EQUAL(sStoreType.c_str(),"Real"))
1177 : {
1178 0 : if ((((double * )pData)[iCol] == dNoDataValue ) || (CPLIsNan((( double * )pData)[iCol])))
1179 0 : (( double * )pData)[iCol] = rUNDEF;
1180 : }
1181 : }
1182 : }
1183 250 : int iSize = VSIFWriteL( pData, 1, nLineSize, desBand->fpRaw );
1184 250 : if ( iSize < 1 )
1185 : {
1186 0 : CPLFree( pData );
1187 : //CPLFree( pData32 );
1188 : CPLError( CE_Failure, CPLE_FileIO,
1189 0 : "Write of file failed with fwrite error.");
1190 0 : return NULL;
1191 : }
1192 : }
1193 250 : if( !pfnProgress(iLine / (nYSize * nBands), NULL, pProgressData ) )
1194 0 : return NULL;
1195 : }
1196 23 : VSIFFlushL( fpData );
1197 23 : CPLFree( pData );
1198 : }
1199 :
1200 14 : poDS->FlushCache();
1201 :
1202 14 : if( !pfnProgress( 1.0, NULL, pProgressData ) )
1203 : {
1204 : CPLError( CE_Failure, CPLE_UserInterrupt,
1205 0 : "User terminated" );
1206 0 : delete poDS;
1207 :
1208 : GDALDriver *poILWISDriver =
1209 0 : (GDALDriver *) GDALGetDriverByName( "ILWIS" );
1210 0 : poILWISDriver->Delete( pszFilename );
1211 0 : return NULL;
1212 : }
1213 :
1214 14 : poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
1215 :
1216 14 : return poDS;
1217 : }
1218 :
1219 : /************************************************************************/
1220 : /* ILWISRasterBand() */
1221 : /************************************************************************/
1222 :
1223 79 : ILWISRasterBand::ILWISRasterBand( ILWISDataset *poDS, int nBand )
1224 :
1225 : {
1226 79 : string sBandName;
1227 79 : if ( EQUAL(poDS->pszFileType.c_str(),"Map"))
1228 24 : sBandName = string(poDS->osFileName);
1229 : else //map list
1230 : {
1231 : //Form the band name
1232 : char cBandName[45];
1233 55 : sprintf( cBandName, "Map%d", nBand-1);
1234 55 : sBandName = ReadElement("MapList", string(cBandName), string(poDS->osFileName));
1235 55 : string sInputPath = string(CPLGetPath( poDS->osFileName));
1236 110 : string sBandPath = string(CPLGetPath( sBandName.c_str()));
1237 110 : string sBandBaseName = string(CPLGetBasename( sBandName.c_str()));
1238 110 : if ( 0==sBandPath.length() )
1239 55 : sBandName = string(CPLFormFilename(sInputPath.c_str(),sBandBaseName.c_str(),"mpr" ));
1240 : else
1241 0 : sBandName = string(CPLFormFilename(sBandPath.c_str(),sBandBaseName.c_str(),"mpr" ));
1242 : }
1243 :
1244 79 : if (poDS->bNewDataset)
1245 : {
1246 : // Called from Create():
1247 : // eDataType is defaulted to GDT_Byte by GDALRasterBand::GDALRasterBand
1248 : // Here we set it to match the value of sStoreType (that was set in ILWISDataset::Create)
1249 : // Unfortunately we can't take advantage of the ILWIS "ValueRange" object that would use
1250 : // the most compact storeType possible, without going through all values.
1251 66 : GetStoreType(sBandName, psInfo.stStoreType);
1252 66 : eDataType = ILWIS2GDALType(psInfo.stStoreType);
1253 : }
1254 : else // Called from Open(), thus convert ILWIS type from ODF to eDataType
1255 13 : GetILWISInfo(sBandName);
1256 79 : this->poDS = poDS;
1257 79 : this->nBand = nBand;
1258 79 : nBlockXSize = poDS->GetRasterXSize();
1259 79 : nBlockYSize = 1;
1260 79 : switch (psInfo.stStoreType)
1261 : {
1262 : case stByte:
1263 46 : nSizePerPixel = GDALGetDataTypeSize(GDT_Byte) / 8;
1264 46 : break;
1265 : case stInt:
1266 10 : nSizePerPixel = GDALGetDataTypeSize(GDT_Int16) / 8;
1267 10 : break;
1268 : case stLong:
1269 10 : nSizePerPixel = GDALGetDataTypeSize(GDT_Int32) / 8;
1270 10 : break;
1271 : case stFloat:
1272 8 : nSizePerPixel = GDALGetDataTypeSize(GDT_Float32) / 8;
1273 8 : break;
1274 : case stReal:
1275 5 : nSizePerPixel = GDALGetDataTypeSize(GDT_Float64) / 8;
1276 : break;
1277 : }
1278 79 : ILWISOpen(sBandName);
1279 79 : }
1280 :
1281 : /************************************************************************/
1282 : /* ~ILWISRasterBand() */
1283 : /************************************************************************/
1284 :
1285 79 : ILWISRasterBand::~ILWISRasterBand()
1286 :
1287 : {
1288 79 : if( fpRaw != NULL )
1289 : {
1290 79 : VSIFCloseL( fpRaw );
1291 79 : fpRaw = NULL;
1292 : }
1293 79 : }
1294 :
1295 :
1296 : /************************************************************************/
1297 : /* ILWISOpen() */
1298 : /************************************************************************/
1299 79 : void ILWISRasterBand::ILWISOpen( string pszFileName )
1300 : {
1301 79 : ILWISDataset* dataset = (ILWISDataset*) poDS;
1302 79 : string pszDataFile;
1303 79 : pszDataFile = string(CPLResetExtension( pszFileName.c_str(), "mp#" ));
1304 :
1305 145 : fpRaw = VSIFOpenL( pszDataFile.c_str(), (dataset->eAccess == GA_Update) ? "rb+" : "rb");
1306 79 : }
1307 :
1308 : /************************************************************************/
1309 : /* ReadValueDomainProperties() */
1310 : /************************************************************************/
1311 : // Helper function for GetILWISInfo, to avoid code-duplication
1312 : // Unfortunately with side-effect (changes members psInfo and eDataType)
1313 12 : void ILWISRasterBand::ReadValueDomainProperties(string pszFileName)
1314 : {
1315 12 : string rangeString = ReadElement("BaseMap", "Range", pszFileName.c_str());
1316 24 : psInfo.vr = ValueRange(rangeString);
1317 12 : double rStep = psInfo.vr.get_rStep();
1318 12 : if ( rStep != 0 )
1319 : {
1320 10 : psInfo.bUseValueRange = true; // use ILWIS ValueRange object to convert from "raw" to "value"
1321 10 : double rMin = psInfo.vr.get_rLo();
1322 10 : double rMax = psInfo.vr.get_rHi();
1323 10 : if (rStep - (long)rStep == 0.0) // Integer values
1324 : {
1325 14 : if ( rMin >= 0 && rMax <= UCHAR_MAX)
1326 4 : eDataType = GDT_Byte;
1327 6 : else if ( rMin >= SHRT_MIN && rMax <= SHRT_MAX)
1328 0 : eDataType = GDT_Int16;
1329 6 : else if ( rMin >= 0 && rMax <= USHRT_MAX)
1330 0 : eDataType = GDT_UInt16;
1331 12 : else if ( rMin >= INT_MIN && rMax <= INT_MAX)
1332 6 : eDataType = GDT_Int32;
1333 0 : else if ( rMin >= 0 && rMax <= UINT_MAX)
1334 0 : eDataType = GDT_UInt32;
1335 : else
1336 0 : eDataType = GDT_Float64;
1337 : }
1338 : else // Floating point values
1339 : {
1340 0 : if ((rMin >= -FLT_MAX) && (rMax <= FLT_MAX) && (fabs(rStep) >= FLT_EPSILON)) // is "float" good enough?
1341 0 : eDataType = GDT_Float32;
1342 : else
1343 0 : eDataType = GDT_Float64;
1344 : }
1345 : }
1346 : else
1347 : {
1348 2 : if (psInfo.stStoreType == stFloat) // is "float" good enough?
1349 2 : eDataType = GDT_Float32;
1350 : else
1351 0 : eDataType = GDT_Float64;
1352 12 : }
1353 12 : }
1354 :
1355 : /************************************************************************/
1356 : /* GetILWISInfo() */
1357 : /************************************************************************/
1358 : // Calculates members psInfo and eDataType
1359 13 : CPLErr ILWISRasterBand::GetILWISInfo(string pszFileName)
1360 : {
1361 : // Fill the psInfo struct with defaults.
1362 : // Get the store type from the ODF
1363 13 : if (GetStoreType(pszFileName, psInfo.stStoreType) != CE_None)
1364 : {
1365 0 : return CE_Failure;
1366 : }
1367 13 : psInfo.bUseValueRange = false;
1368 13 : psInfo.stDomain = "";
1369 :
1370 : // ILWIS has several (currently 22) predefined "system-domains", that influence the data-type
1371 : // The user can also create his own domains. The possible types for these are "class", "identifier", "bool" and "value"
1372 : // The last one has Type=DomainValue
1373 : // Here we make an effort to determine the most-compact gdal-type (eDataType) that is suitable
1374 : // for the data in the current ILWIS band.
1375 : // First check against all predefined domain names (the "system-domains")
1376 : // If no match is found, read the domain ODF from disk, and get its type
1377 : // We have hardcoded the system domains here, because ILWIS may not be installed, and even if it is,
1378 : // we don't know where (thus it is useless to attempt to read a system-domain-file).
1379 :
1380 13 : string domName = ReadElement("BaseMap", "Domain", pszFileName.c_str());
1381 26 : string pszBaseName = string(CPLGetBasename( domName.c_str() ));
1382 26 : string pszPath = string(CPLGetPath( pszFileName.c_str() ));
1383 :
1384 : // Check against all "system-domains"
1385 26 : if ( EQUAL(pszBaseName.c_str(),"value") // is it a system domain with Type=DomainValue?
1386 : || EQUAL(pszBaseName.c_str(),"count")
1387 : || EQUAL(pszBaseName.c_str(),"distance")
1388 : || EQUAL(pszBaseName.c_str(),"min1to1")
1389 : || EQUAL(pszBaseName.c_str(),"nilto1")
1390 : || EQUAL(pszBaseName.c_str(),"noaa")
1391 : || EQUAL(pszBaseName.c_str(),"perc")
1392 : || EQUAL(pszBaseName.c_str(),"radar") )
1393 : {
1394 12 : ReadValueDomainProperties(pszFileName);
1395 : }
1396 1 : else if( EQUAL(pszBaseName.c_str(),"bool")
1397 : || EQUAL(pszBaseName.c_str(),"byte")
1398 : || EQUAL(pszBaseName.c_str(),"bit")
1399 : || EQUAL(pszBaseName.c_str(),"image")
1400 : || EQUAL(pszBaseName.c_str(),"colorcmp")
1401 : || EQUAL(pszBaseName.c_str(),"flowdirection")
1402 : || EQUAL(pszBaseName.c_str(),"hortonratio")
1403 : || EQUAL(pszBaseName.c_str(),"yesno") )
1404 : {
1405 0 : eDataType = GDT_Byte;
1406 0 : if( EQUAL(pszBaseName.c_str(),"image")
1407 : || EQUAL(pszBaseName.c_str(),"colorcmp"))
1408 0 : psInfo.stDomain = pszBaseName;
1409 : }
1410 1 : else if( EQUAL(pszBaseName.c_str(),"color")
1411 : || EQUAL(pszBaseName.c_str(),"none" )
1412 : || EQUAL(pszBaseName.c_str(),"coordbuf")
1413 : || EQUAL(pszBaseName.c_str(),"binary")
1414 : || EQUAL(pszBaseName.c_str(),"string") )
1415 : {
1416 : CPLError( CE_Failure, CPLE_AppDefined,
1417 0 : "Unsupported ILWIS domain type.");
1418 0 : return CE_Failure;
1419 : }
1420 : else
1421 : {
1422 : // No match found. Assume it is a self-created domain. Read its type and decide the GDAL type.
1423 1 : string pszDomainFileName = string(CPLFormFilename(pszPath.c_str(),pszBaseName.c_str(),"dom" ));
1424 2 : string domType = ReadElement("Domain", "Type", pszDomainFileName.c_str());
1425 2 : if EQUAL(domType.c_str(),"domainvalue") // is it a self-created domain of type=DomainValue?
1426 : {
1427 0 : ReadValueDomainProperties(pszFileName);
1428 : }
1429 1 : else if((!EQUAL(domType.c_str(),"domainbit"))
1430 : && (!EQUAL(domType.c_str(),"domainstring"))
1431 : && (!EQUAL(domType.c_str(),"domaincolor"))
1432 : && (!EQUAL(domType.c_str(),"domainbinary"))
1433 : && (!EQUAL(domType.c_str(),"domaincoordBuf"))
1434 : && (!EQUAL(domType.c_str(),"domaincoord")))
1435 : {
1436 : // Type is "DomainClass", "DomainBool" or "DomainIdentifier".
1437 : // For now we set the GDAL storeType be the same as the ILWIS storeType
1438 : // The user will have to convert the classes manually.
1439 1 : eDataType = ILWIS2GDALType(psInfo.stStoreType);
1440 : }
1441 : else
1442 : {
1443 : CPLError( CE_Failure, CPLE_AppDefined,
1444 0 : "Unsupported ILWIS domain type.");
1445 0 : return CE_Failure;
1446 0 : }
1447 : }
1448 :
1449 13 : return CE_None;
1450 : }
1451 :
1452 : /** This driver defines a Block to be the entire raster; The method reads
1453 : each line as a block. it reads the data into pImage.
1454 :
1455 : @param nBlockXOff This must be zero for this driver
1456 : @param pImage Dump the data here
1457 :
1458 : @return A CPLErr code. This implementation returns a CE_Failure if the
1459 : block offsets are non-zero, If successful, returns CE_None. */
1460 : /************************************************************************/
1461 : /* IReadBlock() */
1462 : /************************************************************************/
1463 506 : CPLErr ILWISRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
1464 : void * pImage )
1465 : {
1466 : // pImage is empty; this function fills it with data from fpRaw
1467 : // (ILWIS data to foreign data)
1468 :
1469 : // If the x block offset is non-zero, something is wrong.
1470 506 : CPLAssert( nBlockXOff == 0 );
1471 :
1472 506 : int nBlockSize = nBlockXSize * nBlockYSize * nSizePerPixel;
1473 506 : if( fpRaw == NULL )
1474 : {
1475 : CPLError( CE_Failure, CPLE_OpenFailed,
1476 0 : "Failed to open ILWIS data file.");
1477 0 : return( CE_Failure );
1478 : }
1479 :
1480 : /* -------------------------------------------------------------------- */
1481 : /* Handle the case of a strip in a writable file that doesn't */
1482 : /* exist yet, but that we want to read. Just set to zeros and */
1483 : /* return. */
1484 : /* -------------------------------------------------------------------- */
1485 506 : ILWISDataset* poIDS = (ILWISDataset*) poDS;
1486 :
1487 : #ifdef notdef
1488 : if( poIDS->bNewDataset && (poIDS->eAccess == GA_Update))
1489 : {
1490 : FillWithNoData(pImage);
1491 : return CE_None;
1492 : }
1493 : #endif
1494 :
1495 506 : VSIFSeekL( fpRaw, nBlockSize*nBlockYOff, SEEK_SET );
1496 506 : void *pData = (char *)CPLMalloc(nBlockSize);
1497 506 : if (VSIFReadL( pData, 1, nBlockSize, fpRaw ) < 1)
1498 : {
1499 0 : if( poIDS->bNewDataset )
1500 : {
1501 0 : FillWithNoData(pImage);
1502 0 : return CE_None;
1503 : }
1504 : else
1505 : {
1506 0 : CPLFree( pData );
1507 : CPLError( CE_Failure, CPLE_FileIO,
1508 0 : "Read of file failed with fread error.");
1509 0 : return CE_Failure;
1510 : }
1511 : }
1512 :
1513 : // Copy the data from pData to pImage, and convert the store-type
1514 : // The data in pData has store-type = psInfo.stStoreType
1515 : // The data in pImage has store-type = eDataType
1516 : // They may not match, because we have chosen the most compact store-type,
1517 : // and for GDAL this may be different than for ILWIS.
1518 :
1519 506 : switch (psInfo.stStoreType)
1520 : {
1521 : int iCol;
1522 : case stByte:
1523 15030 : for( iCol = 0; iCol < nBlockXSize; iCol++ )
1524 : {
1525 14725 : double rV = psInfo.bUseValueRange ? psInfo.vr.rValue(((GByte *) pData)[iCol]) : ((GByte *) pData)[iCol];
1526 14725 : SetValue(pImage, iCol, rV);
1527 : }
1528 305 : break;
1529 : case stInt:
1530 0 : for( iCol = 0; iCol < nBlockXSize; iCol++ )
1531 : {
1532 0 : double rV = psInfo.bUseValueRange ? psInfo.vr.rValue(((GInt16 *) pData)[iCol]) : ((GInt16 *) pData)[iCol];
1533 0 : SetValue(pImage, iCol, rV);
1534 : }
1535 0 : break;
1536 : case stLong:
1537 0 : for( iCol = 0; iCol < nBlockXSize; iCol++ )
1538 : {
1539 0 : double rV = psInfo.bUseValueRange ? psInfo.vr.rValue(((GInt32 *) pData)[iCol]) : ((GInt32 *) pData)[iCol];
1540 0 : SetValue(pImage, iCol, rV);
1541 : }
1542 0 : break;
1543 : case stFloat:
1544 40602 : for( iCol = 0; iCol < nBlockXSize; iCol++ )
1545 40401 : ((float *) pImage)[iCol] = ((float *) pData)[iCol];
1546 201 : break;
1547 : case stReal:
1548 0 : for( iCol = 0; iCol < nBlockXSize; iCol++ )
1549 0 : ((double *) pImage)[iCol] = ((double *) pData)[iCol];
1550 0 : break;
1551 : default:
1552 0 : CPLAssert(0);
1553 : }
1554 :
1555 : // Officially we should also translate "nodata" values, but at this point
1556 : // we can't tell what's the "nodata" value of the destination (foreign) dataset
1557 :
1558 506 : CPLFree( pData );
1559 :
1560 506 : return CE_None;
1561 : }
1562 :
1563 14725 : void ILWISRasterBand::SetValue(void *pImage, int i, double rV) {
1564 14725 : switch ( eDataType ) {
1565 : case GDT_Byte:
1566 7225 : ((GByte *)pImage)[i] = (GByte) rV;
1567 7225 : break;
1568 : case GDT_UInt16:
1569 0 : ((GUInt16 *) pImage)[i] = (GUInt16) rV;
1570 0 : break;
1571 : case GDT_Int16:
1572 0 : ((GInt16 *) pImage)[i] = (GInt16) rV;
1573 0 : break;
1574 : case GDT_UInt32:
1575 0 : ((GUInt32 *) pImage)[i] = (GUInt32) rV;
1576 0 : break;
1577 : case GDT_Int32:
1578 7500 : ((GInt32 *) pImage)[i] = (GInt32) rV;
1579 7500 : break;
1580 : case GDT_Float32:
1581 0 : ((float *) pImage)[i] = (float) rV;
1582 0 : break;
1583 : case GDT_Float64:
1584 0 : ((double *) pImage)[i] = rV;
1585 0 : break;
1586 : default:
1587 0 : CPLAssert(0);
1588 : }
1589 14725 : }
1590 :
1591 7500 : double ILWISRasterBand::GetValue(void *pImage, int i) {
1592 7500 : double rV = 0; // Does GDAL have an official nodata value?
1593 7500 : switch ( eDataType ) {
1594 : case GDT_Byte:
1595 7500 : rV = ((GByte *)pImage)[i];
1596 7500 : break;
1597 : case GDT_UInt16:
1598 0 : rV = ((GUInt16 *) pImage)[i];
1599 0 : break;
1600 : case GDT_Int16:
1601 0 : rV = ((GInt16 *) pImage)[i];
1602 0 : break;
1603 : case GDT_UInt32:
1604 0 : rV = ((GUInt32 *) pImage)[i];
1605 0 : break;
1606 : case GDT_Int32:
1607 0 : rV = ((GInt32 *) pImage)[i];
1608 0 : break;
1609 : case GDT_Float32:
1610 0 : rV = ((float *) pImage)[i];
1611 0 : break;
1612 : case GDT_Float64:
1613 0 : rV = ((double *) pImage)[i];
1614 0 : break;
1615 : default:
1616 0 : CPLAssert(0);
1617 : }
1618 7500 : return rV;
1619 : }
1620 :
1621 0 : void ILWISRasterBand::FillWithNoData(void * pImage)
1622 : {
1623 0 : if (psInfo.stStoreType == stByte)
1624 0 : memset(pImage, 0, nBlockXSize * nBlockYSize);
1625 : else
1626 : {
1627 0 : switch (psInfo.stStoreType)
1628 : {
1629 : case stInt:
1630 0 : ((GInt16*)pImage)[0] = shUNDEF;
1631 0 : break;
1632 : case stLong:
1633 0 : ((GInt32*)pImage)[0] = iUNDEF;
1634 0 : break;
1635 : case stFloat:
1636 0 : ((float*)pImage)[0] = flUNDEF;
1637 0 : break;
1638 : case stReal:
1639 0 : ((double*)pImage)[0] = rUNDEF;
1640 : break;
1641 : default: // should there be handling for stByte?
1642 : break;
1643 : }
1644 0 : int iItemSize = GDALGetDataTypeSize(eDataType) / 8;
1645 0 : for (int i = 1; i < nBlockXSize * nBlockYSize; ++i)
1646 0 : memcpy( ((char*)pImage) + iItemSize * i, (char*)pImage + iItemSize * (i - 1), iItemSize);
1647 : }
1648 0 : }
1649 :
1650 : /************************************************************************/
1651 : /* IWriteBlock() */
1652 : /* */
1653 : /************************************************************************/
1654 :
1655 351 : CPLErr ILWISRasterBand::IWriteBlock(int nBlockXOff, int nBlockYOff,
1656 : void* pImage)
1657 : {
1658 : // pImage has data; this function reads this data and stores it to fpRaw
1659 : // (foreign data to ILWIS data)
1660 :
1661 : // Note that this function will not overwrite existing data in fpRaw, but
1662 : // it will "fill gaps" marked by "nodata" values
1663 :
1664 351 : ILWISDataset* dataset = (ILWISDataset*) poDS;
1665 :
1666 : CPLAssert( dataset != NULL
1667 : && nBlockXOff == 0
1668 : && nBlockYOff >= 0
1669 351 : && pImage != NULL );
1670 :
1671 351 : int nXSize = dataset->GetRasterXSize();
1672 351 : int nBlockSize = nBlockXSize * nBlockYSize * nSizePerPixel;
1673 351 : void *pData = CPLMalloc(nBlockSize);
1674 :
1675 351 : VSIFSeekL( fpRaw, nBlockSize * nBlockYOff, SEEK_SET );
1676 :
1677 351 : bool fDataExists = (VSIFReadL( pData, 1, nBlockSize, fpRaw ) >= 1);
1678 :
1679 : // Copy the data from pImage to pData, and convert the store-type
1680 : // The data in pData has store-type = psInfo.stStoreType
1681 : // The data in pImage has store-type = eDataType
1682 : // They may not match, because we have chosen the most compact store-type,
1683 : // and for GDAL this may be different than for ILWIS.
1684 :
1685 351 : if( fDataExists )
1686 : {
1687 : // fpRaw (thus pData) already has data
1688 : // Take care to not overwrite it
1689 : // thus only fill in gaps (nodata values)
1690 0 : switch (psInfo.stStoreType)
1691 : {
1692 : int iCol;
1693 : case stByte:
1694 0 : for (iCol = 0; iCol < nXSize; iCol++ )
1695 0 : if ((( GByte * )pData)[iCol] == 0)
1696 : {
1697 0 : double rV = GetValue(pImage, iCol);
1698 0 : (( GByte * )pData)[iCol] = (GByte)
1699 0 : (psInfo.bUseValueRange ? psInfo.vr.iRaw(rV) : rV);
1700 : }
1701 0 : break;
1702 : case stInt:
1703 0 : for (iCol = 0; iCol < nXSize; iCol++ )
1704 0 : if ((( GInt16 * )pData)[iCol] == shUNDEF)
1705 : {
1706 0 : double rV = GetValue(pImage, iCol);
1707 0 : (( GInt16 * )pData)[iCol] = (GInt16)
1708 0 : (psInfo.bUseValueRange ? psInfo.vr.iRaw(rV) : rV);
1709 : }
1710 0 : break;
1711 : case stLong:
1712 0 : for (iCol = 0; iCol < nXSize; iCol++ )
1713 0 : if ((( GInt32 * )pData)[iCol] == iUNDEF)
1714 : {
1715 0 : double rV = GetValue(pImage, iCol);
1716 0 : (( GInt32 * )pData)[iCol] = (GInt32)
1717 0 : (psInfo.bUseValueRange ? psInfo.vr.iRaw(rV) : rV);
1718 : }
1719 0 : break;
1720 : case stFloat:
1721 0 : for (iCol = 0; iCol < nXSize; iCol++ )
1722 0 : if ((( float * )pData)[iCol] == flUNDEF)
1723 0 : (( float * )pData)[iCol] = ((float* )pImage)[iCol];
1724 0 : break;
1725 : case stReal:
1726 0 : for (iCol = 0; iCol < nXSize; iCol++ )
1727 0 : if ((( double * )pData)[iCol] == rUNDEF)
1728 0 : (( double * )pData)[iCol] = ((double* )pImage)[iCol];
1729 : break;
1730 : }
1731 : }
1732 : else
1733 : {
1734 : // fpRaw (thus pData) is still empty, just write the data
1735 351 : switch (psInfo.stStoreType)
1736 : {
1737 : int iCol;
1738 : case stByte:
1739 7650 : for (iCol = 0; iCol < nXSize; iCol++ )
1740 : {
1741 7500 : double rV = GetValue(pImage, iCol);
1742 7500 : (( GByte * )pData)[iCol] = (GByte)
1743 7500 : (psInfo.bUseValueRange ? psInfo.vr.iRaw(rV) : rV);
1744 : }
1745 150 : break;
1746 : case stInt:
1747 0 : for (iCol = 0; iCol < nXSize; iCol++ )
1748 : {
1749 0 : double rV = GetValue(pImage, iCol);
1750 0 : (( GInt16 * )pData)[iCol] = (GInt16)
1751 0 : (psInfo.bUseValueRange ? psInfo.vr.iRaw(rV) : rV);
1752 : }
1753 0 : break;
1754 : case stLong:
1755 0 : for (iCol = 0; iCol < nXSize; iCol++ )
1756 : {
1757 0 : double rV = GetValue(pImage, iCol);
1758 0 : ((GInt32 *)pData)[iCol] = (GInt32)
1759 0 : (psInfo.bUseValueRange ? psInfo.vr.iRaw(rV) : rV);
1760 : }
1761 0 : break;
1762 : case stFloat:
1763 40602 : for (iCol = 0; iCol < nXSize; iCol++ )
1764 40401 : (( float * )pData)[iCol] = ((float* )pImage)[iCol];
1765 201 : break;
1766 : case stReal:
1767 0 : for (iCol = 0; iCol < nXSize; iCol++ )
1768 0 : (( double * )pData)[iCol] = ((double* )pImage)[iCol];
1769 : break;
1770 : }
1771 : }
1772 :
1773 : // Officially we should also translate "nodata" values, but at this point
1774 : // we can't tell what's the "nodata" value of the source (foreign) dataset
1775 :
1776 351 : VSIFSeekL( fpRaw, nBlockSize * nBlockYOff, SEEK_SET );
1777 :
1778 351 : if (VSIFWriteL( pData, 1, nBlockSize, fpRaw ) < 1)
1779 : {
1780 0 : CPLFree( pData );
1781 : CPLError( CE_Failure, CPLE_FileIO,
1782 0 : "Write of file failed with fwrite error.");
1783 0 : return CE_Failure;
1784 : }
1785 :
1786 351 : CPLFree( pData );
1787 351 : return CE_None;
1788 : }
1789 :
1790 : /************************************************************************/
1791 : /* GetNoDataValue() */
1792 : /************************************************************************/
1793 12 : double ILWISRasterBand::GetNoDataValue( int *pbSuccess )
1794 :
1795 : {
1796 12 : if( pbSuccess != NULL )
1797 12 : *pbSuccess = TRUE;
1798 :
1799 12 : if( eDataType == GDT_Float64 )
1800 0 : return rUNDEF;
1801 12 : else if( eDataType == GDT_Int32)
1802 3 : return iUNDEF;
1803 9 : else if( eDataType == GDT_Int16)
1804 0 : return shUNDEF;
1805 9 : else if( eDataType == GDT_Float32)
1806 2 : return flUNDEF;
1807 7 : else if( EQUAL(psInfo.stDomain.c_str(),"image")
1808 : || EQUAL(psInfo.stDomain.c_str(),"colorcmp"))
1809 : {
1810 0 : *pbSuccess = false;
1811 0 : return 0;
1812 : }
1813 : else
1814 7 : return 0;
1815 : }
1816 :
1817 : /************************************************************************/
1818 : /* ValueRange() */
1819 : /************************************************************************/
1820 0 : double Max(double a, double b)
1821 0 : { return (a>=b && a!=rUNDEF) ? a : b; }
1822 :
1823 24 : static double doubleConv(const char* s)
1824 : {
1825 24 : if (s == 0) return rUNDEF;
1826 : char *endptr;
1827 24 : char *begin = const_cast<char*>(s);
1828 :
1829 : // skip leading spaces; strtol will return 0 on a string with only spaces
1830 : // which is not what we want
1831 24 : while (isspace((unsigned char)*begin)) ++begin;
1832 :
1833 24 : if (strlen(begin) == 0) return rUNDEF;
1834 24 : errno = 0;
1835 24 : double r = strtod(begin, &endptr);
1836 24 : if ((0 == *endptr) && (errno==0))
1837 24 : return r;
1838 0 : while (*endptr != 0) { // check trailing spaces
1839 0 : if (*endptr != ' ')
1840 0 : return rUNDEF;
1841 0 : endptr++;
1842 : }
1843 0 : return r;
1844 : }
1845 :
1846 12 : ValueRange::ValueRange(string sRng)
1847 : {
1848 12 : char* sRange = new char[sRng.length() + 1];
1849 476 : for (unsigned int i = 0; i < sRng.length(); ++i)
1850 464 : sRange[i] = sRng[i];
1851 12 : sRange[sRng.length()] = 0;
1852 :
1853 12 : char *p1 = strchr(sRange, ':');
1854 12 : if (0 == p1)
1855 0 : return;
1856 :
1857 12 : char *p3 = strstr(sRange, ",offset=");
1858 12 : if (0 == p3)
1859 12 : p3 = strstr(sRange, ":offset=");
1860 12 : _r0 = rUNDEF;
1861 12 : if (0 != p3) {
1862 12 : _r0 = doubleConv(p3+8);
1863 12 : *p3 = 0;
1864 : }
1865 12 : char *p2 = strrchr(sRange, ':');
1866 12 : _rStep = 1;
1867 12 : if (p1 != p2) { // step
1868 12 : _rStep = doubleConv(p2+1);
1869 12 : *p2 = 0;
1870 : }
1871 :
1872 12 : p2 = strchr(sRange, ':');
1873 12 : if (p2 != 0) {
1874 12 : *p2 = 0;
1875 12 : _rLo = atof(sRange);
1876 12 : _rHi = atof(p2+1);
1877 : }
1878 : else {
1879 0 : _rLo = atof(sRange);
1880 0 : _rHi = _rLo;
1881 : }
1882 12 : init(_r0);
1883 :
1884 12 : delete [] sRange;
1885 : }
1886 :
1887 79 : ValueRange::ValueRange(double min, double max) // step = 1
1888 : {
1889 79 : _rLo = min;
1890 79 : _rHi = max;
1891 79 : _rStep = 1;
1892 79 : init();
1893 79 : }
1894 :
1895 0 : ValueRange::ValueRange(double min, double max, double step)
1896 : {
1897 0 : _rLo = min;
1898 0 : _rHi = max;
1899 0 : _rStep = step;
1900 0 : init();
1901 0 : }
1902 :
1903 89 : static ilwisStoreType stNeeded(unsigned long iNr)
1904 : {
1905 89 : if (iNr <= 256)
1906 83 : return stByte;
1907 6 : if (iNr <= SHRT_MAX)
1908 0 : return stInt;
1909 6 : return stLong;
1910 : }
1911 :
1912 79 : void ValueRange::init()
1913 : {
1914 79 : init(rUNDEF);
1915 79 : }
1916 :
1917 91 : void ValueRange::init(double rRaw0)
1918 : {
1919 : try {
1920 91 : _iDec = 0;
1921 91 : if (_rStep < 0)
1922 0 : _rStep = 0;
1923 91 : double r = _rStep;
1924 91 : if (r <= 1e-20)
1925 2 : _iDec = 3;
1926 178 : else while (r - floor(r) > 1e-20) {
1927 0 : r *= 10;
1928 0 : _iDec++;
1929 0 : if (_iDec > 10)
1930 0 : break;
1931 : }
1932 :
1933 91 : short iBeforeDec = 1;
1934 91 : double rMax = MAX(fabs(get_rLo()), fabs(get_rHi()));
1935 91 : if (rMax != 0)
1936 12 : iBeforeDec = (short)floor(log10(rMax)) + 1;
1937 91 : if (get_rLo() < 0)
1938 8 : iBeforeDec++;
1939 91 : _iWidth = (short) (iBeforeDec + _iDec);
1940 91 : if (_iDec > 0)
1941 2 : _iWidth++;
1942 91 : if (_iWidth > 12)
1943 0 : _iWidth = 12;
1944 91 : if (_rStep < 1e-06)
1945 : {
1946 2 : st = stReal;
1947 2 : _rStep = 0;
1948 : }
1949 : else {
1950 89 : r = get_rHi() - get_rLo();
1951 89 : if (r <= ULONG_MAX) {
1952 89 : r /= _rStep;
1953 89 : r += 1;
1954 : }
1955 89 : r += 1;
1956 89 : if (r > LONG_MAX)
1957 0 : st = stReal;
1958 : else {
1959 89 : st = stNeeded((unsigned long)floor(r+0.5));
1960 89 : if (st < stByte)
1961 0 : st = stByte;
1962 : }
1963 : }
1964 91 : if (rUNDEF != rRaw0)
1965 12 : _r0 = rRaw0;
1966 : else {
1967 79 : _r0 = 0;
1968 79 : if (st <= stByte)
1969 79 : _r0 = -1;
1970 : }
1971 91 : if (st > stInt)
1972 8 : iRawUndef = iUNDEF;
1973 83 : else if (st == stInt)
1974 0 : iRawUndef = shUNDEF;
1975 : else
1976 83 : iRawUndef = 0;
1977 : }
1978 0 : catch (std::exception*) {
1979 0 : st = stReal;
1980 0 : _r0 = 0;
1981 0 : _rStep = 0.0001;
1982 0 : _rHi = 1e300;
1983 0 : _rLo = -1e300;
1984 0 : iRawUndef = iUNDEF;
1985 : }
1986 91 : }
1987 :
1988 0 : string ValueRange::ToString()
1989 : {
1990 : char buffer[200];
1991 0 : if (fabs(get_rLo()) > 1.0e20 || fabs(get_rHi()) > 1.0e20)
1992 0 : sprintf(buffer, "%g:%g:%f:offset=%g", get_rLo(), get_rHi(), get_rStep(), get_rRaw0());
1993 0 : else if (get_iDec() >= 0)
1994 0 : sprintf(buffer, "%.*f:%.*f:%.*f:offset=%.0f", get_iDec(), get_rLo(), get_iDec(), get_rHi(), get_iDec(), get_rStep(), get_rRaw0());
1995 : else
1996 0 : sprintf(buffer, "%f:%f:%f:offset=%.0f", get_rLo(), get_rHi(), get_rStep(), get_rRaw0());
1997 0 : return string(buffer);
1998 : }
1999 :
2000 8300 : double ValueRange::rValue(int iRaw)
2001 : {
2002 8300 : if (iRaw == iUNDEF || iRaw == iRawUndef)
2003 0 : return rUNDEF;
2004 8300 : double rVal = iRaw + _r0;
2005 8300 : rVal *= _rStep;
2006 8300 : if (get_rLo() == get_rHi())
2007 0 : return rVal;
2008 8300 : double rEpsilon = _rStep == 0.0 ? 1e-6 : _rStep / 3.0; // avoid any rounding problems with an epsilon directly based on the
2009 : // the stepsize
2010 8300 : if ((rVal - get_rLo() < -rEpsilon) || (rVal - get_rHi() > rEpsilon))
2011 0 : return rUNDEF;
2012 8300 : return rVal;
2013 : }
2014 :
2015 0 : int ValueRange::iRaw(double rValue)
2016 : {
2017 0 : if (rValue == rUNDEF) // || !fContains(rValue))
2018 0 : return iUNDEF;
2019 0 : double rEpsilon = _rStep == 0.0 ? 1e-6 : _rStep / 3.0;
2020 0 : if (rValue - get_rLo() < -rEpsilon) // take a little rounding tolerance
2021 0 : return iUNDEF;
2022 0 : else if (rValue - get_rHi() > rEpsilon) // take a little rounding tolerance
2023 0 : return iUNDEF;
2024 0 : rValue /= _rStep;
2025 0 : double rVal = floor(rValue+0.5);
2026 0 : rVal -= _r0;
2027 : long iVal;
2028 0 : iVal = longConv(rVal);
2029 0 : return iVal;
2030 : }
2031 :
2032 :
2033 : /************************************************************************/
2034 : /* GDALRegister_ILWIS() */
2035 : /************************************************************************/
2036 :
2037 558 : void GDALRegister_ILWIS()
2038 :
2039 : {
2040 : GDALDriver *poDriver;
2041 :
2042 558 : if( GDALGetDriverByName( "ILWIS" ) == NULL )
2043 : {
2044 537 : poDriver = new GDALDriver();
2045 :
2046 537 : poDriver->SetDescription( "ILWIS" );
2047 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
2048 537 : "ILWIS Raster Map" );
2049 537 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "mpr/mpl" );
2050 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
2051 537 : "Byte Int16 Int32 Float64" );
2052 537 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
2053 :
2054 537 : poDriver->pfnOpen = ILWISDataset::Open;
2055 537 : poDriver->pfnCreate = ILWISDataset::Create;
2056 537 : poDriver->pfnCreateCopy = ILWISDataset::CreateCopy;
2057 :
2058 537 : GetGDALDriverManager()->RegisterDriver( poDriver );
2059 : }
2060 558 : }
|