1 : /******************************************************************************
2 : * $Id: ozidataset.cpp 21930 2011-03-11 13:27:22Z dron $
3 : *
4 : * Project: OZF2 and OZFx3 binary files driver
5 : * Purpose: GDALDataset driver for OZF2 and OZFx3 binary files.
6 : * Author: Even Rouault, <even dot rouault at mines dash paris dot org>
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2010, Even Rouault
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "gdal_pam.h"
31 : #include "zlib.h"
32 :
33 : /* g++ -fPIC -g -Wall frmts/ozi/ozidataset.cpp -shared -o gdal_OZI.so -Iport -Igcore -Iogr -L. -lgdal */
34 :
35 : CPL_CVSID("$Id: ozidataset.cpp 21930 2011-03-11 13:27:22Z dron $");
36 :
37 : CPL_C_START
38 : void GDALRegister_OZI(void);
39 : CPL_C_END
40 :
41 : /************************************************************************/
42 : /* ==================================================================== */
43 : /* OZIDataset */
44 : /* ==================================================================== */
45 : /************************************************************************/
46 :
47 : class OZIRasterBand;
48 :
49 : class OZIDataset : public GDALPamDataset
50 : {
51 : friend class OZIRasterBand;
52 :
53 : VSILFILE* fp;
54 : int nZoomLevelCount;
55 : int* panZoomLevelOffsets;
56 : OZIRasterBand** papoBands;
57 : vsi_l_offset nFileSize;
58 :
59 : int bOzi3;
60 : GByte nKeyInit;
61 :
62 : double adfGeoTransform[6];
63 : char* pszWKT;
64 : int nGCPCount;
65 : GDAL_GCP* pasGCPs;
66 : int bReadMapFileSuccess;
67 :
68 : public:
69 : OZIDataset();
70 : virtual ~OZIDataset();
71 :
72 : virtual const char* GetProjectionRef();
73 : virtual CPLErr GetGeoTransform( double * );
74 :
75 : virtual int GetGCPCount();
76 : virtual const char *GetGCPProjection();
77 : virtual const GDAL_GCP *GetGCPs();
78 :
79 : static GDALDataset *Open( GDALOpenInfo * );
80 : static int Identify( GDALOpenInfo * );
81 : };
82 :
83 : /************************************************************************/
84 : /* ==================================================================== */
85 : /* OZIRasterBand */
86 : /* ==================================================================== */
87 : /************************************************************************/
88 :
89 : class OZIRasterBand : public GDALPamRasterBand
90 : {
91 : friend class OZIDataset;
92 :
93 : int nXBlocks;
94 : int nZoomLevel;
95 : GDALColorTable* poColorTable;
96 : GByte* pabyTranslationTable;
97 :
98 : public:
99 :
100 : OZIRasterBand( OZIDataset *, int nZoomLevel,
101 : int nRasterXSize, int nRasterYSize,
102 : int nXBlocks,
103 : GDALColorTable* poColorTable);
104 : virtual ~OZIRasterBand();
105 :
106 : virtual CPLErr IReadBlock( int, int, void * );
107 : virtual GDALColorInterp GetColorInterpretation();
108 : virtual GDALColorTable *GetColorTable();
109 :
110 : virtual int GetOverviewCount();
111 : virtual GDALRasterBand* GetOverview(int nLevel);
112 : };
113 :
114 :
115 : /************************************************************************/
116 : /* I/O functions */
117 : /************************************************************************/
118 :
119 : static const GByte abyKey[] =
120 : {
121 : 0x2D, 0x4A, 0x43, 0xF1, 0x27, 0x9B, 0x69, 0x4F,
122 : 0x36, 0x52, 0x87, 0xEC, 0x5F, 0x42, 0x53, 0x22,
123 : 0x9E, 0x8B, 0x2D, 0x83, 0x3D, 0xD2, 0x84, 0xBA,
124 : 0xD8, 0x5B
125 : };
126 :
127 0 : static void OZIDecrypt(void *pabyVal, int n, GByte nKeyInit)
128 : {
129 : int i;
130 0 : for(i = 0; i < n; i++)
131 : {
132 0 : ((GByte*)pabyVal)[i] ^= abyKey[i % sizeof(abyKey)] + nKeyInit;
133 : }
134 0 : }
135 :
136 18 : static int ReadInt(GByte**pptr)
137 : {
138 : int nVal;
139 18 : memcpy(&nVal, *pptr, 4);
140 18 : *pptr += 4;
141 : CPL_LSBPTR32(&nVal);
142 18 : return nVal;
143 : }
144 :
145 4 : static short ReadShort(GByte**pptr)
146 : {
147 : short nVal;
148 4 : memcpy(&nVal, *pptr, 2);
149 4 : *pptr += 2;
150 : CPL_LSBPTR16(&nVal);
151 4 : return nVal;
152 : }
153 :
154 1788 : static int ReadInt(VSILFILE* fp, int bOzi3 = FALSE, int nKeyInit = 0)
155 : {
156 : int nVal;
157 1788 : VSIFReadL(&nVal, 1, 4, fp);
158 1788 : if (bOzi3) OZIDecrypt(&nVal, 4, (GByte) nKeyInit);
159 : CPL_LSBPTR32(&nVal);
160 1788 : return nVal;
161 : }
162 :
163 38 : static short ReadShort(VSILFILE* fp, int bOzi3 = FALSE, int nKeyInit = 0)
164 : {
165 : short nVal;
166 38 : VSIFReadL(&nVal, 1, 2, fp);
167 38 : if (bOzi3) OZIDecrypt(&nVal, 2, (GByte) nKeyInit);
168 : CPL_LSBPTR16(&nVal);
169 38 : return nVal;
170 : }
171 :
172 : /************************************************************************/
173 : /* OZIRasterBand() */
174 : /************************************************************************/
175 :
176 18 : OZIRasterBand::OZIRasterBand( OZIDataset *poDS, int nZoomLevel,
177 : int nRasterXSize, int nRasterYSize,
178 : int nXBlocks,
179 18 : GDALColorTable* poColorTable )
180 :
181 : {
182 18 : this->poDS = poDS;
183 18 : this->nBand = 1;
184 :
185 18 : eDataType = GDT_Byte;
186 :
187 18 : nBlockXSize = 64;
188 18 : nBlockYSize = 64;
189 :
190 18 : this->nZoomLevel = nZoomLevel;
191 18 : this->nRasterXSize = nRasterXSize;
192 18 : this->nRasterYSize = nRasterYSize;
193 18 : this->poColorTable = poColorTable;
194 18 : this->nXBlocks = nXBlocks;
195 :
196 18 : pabyTranslationTable = NULL;
197 18 : }
198 :
199 : /************************************************************************/
200 : /* ~OZIRasterBand() */
201 : /************************************************************************/
202 :
203 18 : OZIRasterBand::~OZIRasterBand()
204 : {
205 18 : delete poColorTable;
206 18 : CPLFree(pabyTranslationTable);
207 18 : }
208 :
209 :
210 : /************************************************************************/
211 : /* GetColorInterpretation() */
212 : /************************************************************************/
213 :
214 32 : GDALColorInterp OZIRasterBand::GetColorInterpretation()
215 : {
216 32 : return GCI_PaletteIndex;
217 : }
218 :
219 : /************************************************************************/
220 : /* GetColorTable() */
221 : /************************************************************************/
222 :
223 32 : GDALColorTable* OZIRasterBand::GetColorTable()
224 : {
225 32 : return poColorTable;
226 : }
227 :
228 : /************************************************************************/
229 : /* IReadBlock() */
230 : /************************************************************************/
231 :
232 864 : CPLErr OZIRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
233 : void * pImage )
234 :
235 : {
236 864 : OZIDataset *poGDS = (OZIDataset *) poDS;
237 :
238 864 : int nBlock = nBlockYOff * nXBlocks + nBlockXOff;
239 :
240 864 : VSIFSeekL(poGDS->fp, poGDS->panZoomLevelOffsets[nZoomLevel] +
241 864 : 12 + 1024 + 4 * nBlock, SEEK_SET);
242 864 : int nPointer = ReadInt(poGDS->fp, poGDS->bOzi3, poGDS->nKeyInit);
243 864 : if (nPointer < 0 || (vsi_l_offset)nPointer >= poGDS->nFileSize)
244 : {
245 : CPLError(CE_Failure, CPLE_AppDefined,
246 : "Invalid offset for block (%d, %d) : %d",
247 0 : nBlockXOff, nBlockYOff, nPointer);
248 0 : return CE_Failure;
249 : }
250 864 : int nNextPointer = ReadInt(poGDS->fp, poGDS->bOzi3, poGDS->nKeyInit);
251 864 : if (nNextPointer <= nPointer + 16 ||
252 : (vsi_l_offset)nNextPointer >= poGDS->nFileSize)
253 : {
254 : CPLError(CE_Failure, CPLE_AppDefined,
255 : "Invalid next offset for block (%d, %d) : %d",
256 0 : nBlockXOff, nBlockYOff, nNextPointer);
257 0 : return CE_Failure;
258 : }
259 :
260 864 : VSIFSeekL(poGDS->fp, nPointer, SEEK_SET);
261 :
262 864 : int nToRead = nNextPointer - nPointer;
263 864 : GByte* pabyZlibBuffer = (GByte*)CPLMalloc(nToRead);
264 864 : if (VSIFReadL(pabyZlibBuffer, nToRead, 1, poGDS->fp) != 1)
265 : {
266 : CPLError(CE_Failure, CPLE_AppDefined,
267 : "Not enough byte read for block (%d, %d)",
268 0 : nBlockXOff, nBlockYOff);
269 0 : CPLFree(pabyZlibBuffer);
270 0 : return CE_Failure;
271 : }
272 :
273 864 : if (poGDS->bOzi3)
274 0 : OZIDecrypt(pabyZlibBuffer, 16, poGDS->nKeyInit);
275 :
276 1728 : if (pabyZlibBuffer[0] != 0x78 ||
277 864 : pabyZlibBuffer[1] != 0xDA)
278 : {
279 : CPLError(CE_Failure, CPLE_AppDefined,
280 : "Bad ZLIB signature for block (%d, %d) : 0x%02X 0x%02X",
281 0 : nBlockXOff, nBlockYOff, pabyZlibBuffer[0], pabyZlibBuffer[1]);
282 0 : CPLFree(pabyZlibBuffer);
283 0 : return CE_Failure;
284 : }
285 :
286 : z_stream stream;
287 864 : stream.zalloc = (alloc_func)0;
288 864 : stream.zfree = (free_func)0;
289 864 : stream.opaque = (voidpf)0;
290 864 : stream.next_in = pabyZlibBuffer + 2;
291 864 : stream.avail_in = nToRead - 2;
292 :
293 864 : int err = inflateInit2(&(stream), -MAX_WBITS);
294 :
295 : int i;
296 56160 : for(i=0;i<64 && err == Z_OK;i++)
297 : {
298 55296 : stream.next_out = (Bytef*)pImage + (63 - i) * 64;
299 55296 : stream.avail_out = 64;
300 55296 : err = inflate(& (stream), Z_NO_FLUSH);
301 55296 : if (err != Z_OK && err != Z_STREAM_END)
302 0 : break;
303 :
304 55296 : if (pabyTranslationTable)
305 : {
306 : int j;
307 0 : GByte* ptr = ((GByte*)pImage) + (63 - i) * 64;
308 0 : for(j=0;j<64;j++)
309 : {
310 0 : *ptr = pabyTranslationTable[*ptr];
311 0 : ptr ++;
312 : }
313 : }
314 : }
315 :
316 864 : inflateEnd(&stream);
317 :
318 864 : CPLFree(pabyZlibBuffer);
319 :
320 864 : return (err == Z_OK || err == Z_STREAM_END) ? CE_None : CE_Failure;
321 : }
322 :
323 : /************************************************************************/
324 : /* GetOverviewCount() */
325 : /************************************************************************/
326 :
327 0 : int OZIRasterBand::GetOverviewCount()
328 : {
329 0 : if (nZoomLevel != 0)
330 0 : return 0;
331 :
332 0 : OZIDataset *poGDS = (OZIDataset *) poDS;
333 0 : return poGDS->nZoomLevelCount - 1;
334 : }
335 :
336 : /************************************************************************/
337 : /* GetOverview() */
338 : /************************************************************************/
339 :
340 0 : GDALRasterBand* OZIRasterBand::GetOverview(int nLevel)
341 : {
342 0 : if (nZoomLevel != 0)
343 0 : return NULL;
344 :
345 0 : OZIDataset *poGDS = (OZIDataset *) poDS;
346 0 : if (nLevel < 0 || nLevel >= poGDS->nZoomLevelCount - 1)
347 0 : return NULL;
348 :
349 0 : return poGDS->papoBands[nLevel + 1];
350 : }
351 :
352 : /************************************************************************/
353 : /* ~OZIDataset() */
354 : /************************************************************************/
355 :
356 2 : OZIDataset::OZIDataset()
357 : {
358 2 : fp = NULL;
359 2 : nZoomLevelCount = 0;
360 2 : panZoomLevelOffsets = NULL;
361 2 : papoBands = NULL;
362 2 : bOzi3 = FALSE;
363 2 : nKeyInit = 0;
364 2 : adfGeoTransform[0] = 0;
365 2 : adfGeoTransform[1] = 1;
366 2 : adfGeoTransform[2] = 0;
367 2 : adfGeoTransform[3] = 0;
368 2 : adfGeoTransform[4] = 0;
369 2 : adfGeoTransform[5] = 1;
370 2 : pszWKT = NULL;
371 2 : nGCPCount = 0;
372 2 : pasGCPs = NULL;
373 2 : bReadMapFileSuccess = FALSE;
374 2 : }
375 :
376 : /************************************************************************/
377 : /* ~OZIDataset() */
378 : /************************************************************************/
379 :
380 2 : OZIDataset::~OZIDataset()
381 : {
382 2 : if (fp)
383 2 : VSIFCloseL(fp);
384 2 : CPLFree(panZoomLevelOffsets);
385 : int i;
386 2 : if (papoBands)
387 : {
388 18 : for(i=1;i<nZoomLevelCount;i++)
389 16 : delete papoBands[i];
390 2 : CPLFree(papoBands);
391 : }
392 2 : CPLFree(pszWKT);
393 2 : if (nGCPCount)
394 : {
395 2 : GDALDeinitGCPs( nGCPCount, pasGCPs );
396 2 : CPLFree(pasGCPs);
397 : }
398 2 : }
399 :
400 : /************************************************************************/
401 : /* Identify() */
402 : /************************************************************************/
403 :
404 21506 : int OZIDataset::Identify( GDALOpenInfo * poOpenInfo )
405 : {
406 21506 : if (poOpenInfo->nHeaderBytes < 14)
407 21138 : return FALSE;
408 :
409 368 : if (EQUALN((const char*)poOpenInfo->pabyHeader,
410 : "OziExplorer Map Data File Version ", 34) )
411 2 : return TRUE;
412 :
413 366 : if (poOpenInfo->pabyHeader[0] == 0x80 &&
414 0 : poOpenInfo->pabyHeader[1] == 0x77)
415 0 : return TRUE;
416 :
417 366 : return poOpenInfo->pabyHeader[0] == 0x78 &&
418 2 : poOpenInfo->pabyHeader[1] == 0x77 &&
419 2 : poOpenInfo->pabyHeader[6] == 0x40 &&
420 2 : poOpenInfo->pabyHeader[7] == 0x00 &&
421 2 : poOpenInfo->pabyHeader[8] == 0x01 &&
422 2 : poOpenInfo->pabyHeader[9] == 0x00 &&
423 2 : poOpenInfo->pabyHeader[10] == 0x36 &&
424 2 : poOpenInfo->pabyHeader[11] == 0x04 &&
425 2 : poOpenInfo->pabyHeader[12] == 0x00 &&
426 382 : poOpenInfo->pabyHeader[13] == 0x00;
427 : }
428 :
429 : /************************************************************************/
430 : /* Open() */
431 : /************************************************************************/
432 :
433 2610 : GDALDataset *OZIDataset::Open( GDALOpenInfo * poOpenInfo )
434 :
435 : {
436 2610 : if (!Identify(poOpenInfo))
437 2608 : return NULL;
438 :
439 : GByte abyHeader[14];
440 2 : CPLString osImgFilename = poOpenInfo->pszFilename;
441 2 : int bIsMap = FALSE;
442 2 : if (EQUALN((const char*)poOpenInfo->pabyHeader,
443 : "OziExplorer Map Data File Version ", 34) )
444 : {
445 2 : char** papszLines = CSLLoad2( poOpenInfo->pszFilename, 1000, 200, NULL );
446 2 : if ( !papszLines || CSLCount(papszLines) < 5)
447 : {
448 0 : CSLDestroy(papszLines);
449 0 : return FALSE;
450 : }
451 :
452 2 : bIsMap = TRUE;
453 :
454 2 : osImgFilename = papszLines[2];
455 : VSIStatBufL sStat;
456 2 : if (VSIStatL(osImgFilename, &sStat) != 0)
457 : {
458 2 : if (CPLIsFilenameRelative(osImgFilename))
459 : {
460 2 : CPLString osPath = CPLGetPath(poOpenInfo->pszFilename);
461 2 : osImgFilename = CPLFormFilename(osPath, osImgFilename, NULL);
462 : }
463 : else
464 : {
465 0 : CPLString osPath = CPLGetPath(poOpenInfo->pszFilename);
466 0 : osImgFilename = CPLGetFilename(osImgFilename);
467 0 : osImgFilename = CPLFormFilename(osPath, osImgFilename, NULL);
468 : }
469 : }
470 :
471 2 : CSLDestroy(papszLines);
472 :
473 2 : GDALOpenInfo oOpenInfo(osImgFilename, GA_ReadOnly);
474 2 : if (!Identify(&oOpenInfo))
475 0 : return NULL;
476 2 : memcpy(abyHeader, oOpenInfo.pabyHeader, 14);
477 : }
478 : else
479 0 : memcpy(abyHeader, poOpenInfo->pabyHeader, 14);
480 :
481 2 : int bOzi3 = (abyHeader[0] == 0x80 &&
482 2 : abyHeader[1] == 0x77);
483 :
484 2 : VSILFILE* fp = VSIFOpenL(osImgFilename.c_str(), "rb");
485 2 : if (fp == NULL)
486 0 : return NULL;
487 :
488 2 : OZIDataset* poDS = new OZIDataset();
489 2 : poDS->fp = fp;
490 :
491 2 : if (bIsMap)
492 : {
493 : poDS->bReadMapFileSuccess =
494 : GDALLoadOziMapFile( poOpenInfo->pszFilename,
495 : poDS->adfGeoTransform,
496 : &poDS->pszWKT,
497 : &poDS->nGCPCount,
498 2 : &poDS->pasGCPs );
499 : }
500 :
501 2 : GByte nRandomNumber = 0;
502 2 : GByte nKeyInit = 0;
503 2 : if (bOzi3)
504 : {
505 0 : VSIFSeekL(fp, 14, SEEK_SET);
506 0 : VSIFReadL(&nRandomNumber, 1, 1, fp);
507 : //printf("nRandomNumber = %d\n", nRandomNumber);
508 0 : if (nRandomNumber < 0x94)
509 : {
510 0 : delete poDS;
511 0 : return NULL;
512 : }
513 0 : VSIFSeekL(fp, 0x93, SEEK_CUR);
514 0 : VSIFReadL(&nKeyInit, 1, 1, fp);
515 :
516 0 : VSIFSeekL(fp, 0, SEEK_SET);
517 0 : VSIFReadL(abyHeader, 1, 14, fp);
518 0 : OZIDecrypt(abyHeader, 14, nKeyInit);
519 0 : if (!(abyHeader[6] == 0x40 &&
520 0 : abyHeader[7] == 0x00 &&
521 0 : abyHeader[8] == 0x01 &&
522 0 : abyHeader[9] == 0x00 &&
523 0 : abyHeader[10] == 0x36 &&
524 0 : abyHeader[11] == 0x04 &&
525 0 : abyHeader[12] == 0x00 &&
526 0 : abyHeader[13] == 0x00))
527 : {
528 0 : delete poDS;
529 0 : return NULL;
530 : }
531 :
532 0 : VSIFSeekL(fp, 14 + 1 + nRandomNumber, SEEK_SET);
533 0 : int nMagic = ReadInt(fp, bOzi3, nKeyInit);
534 0 : CPLDebug("OZI", "OZI version code : 0x%08X", nMagic);
535 :
536 0 : poDS->bOzi3 = bOzi3;
537 : }
538 : else
539 : {
540 2 : VSIFSeekL(fp, 14, SEEK_SET);
541 : }
542 :
543 : GByte abyHeader2[40], abyHeader2_Backup[40];
544 2 : VSIFReadL(abyHeader2, 40, 1, fp);
545 2 : memcpy(abyHeader2_Backup, abyHeader2, 40);
546 :
547 : /* There's apparently a relationship between the nMagic number */
548 : /* and the nKeyInit, but I'm too lazy to add switch/cases that might */
549 : /* be not exhaustive, so let's try the 'brute force' attack !!! */
550 : /* It is much so funny to be able to run one in a few microseconds :-) */
551 2 : for(nKeyInit = 0; nKeyInit < 256; nKeyInit ++)
552 : {
553 2 : GByte* pabyHeader2 = abyHeader2;
554 2 : if (bOzi3)
555 0 : OZIDecrypt(abyHeader2, 40, nKeyInit);
556 :
557 2 : int nHeaderSize = ReadInt(&pabyHeader2); /* should be 40 */
558 2 : poDS->nRasterXSize = ReadInt(&pabyHeader2);
559 2 : poDS->nRasterYSize = ReadInt(&pabyHeader2);
560 2 : int nDepth = ReadShort(&pabyHeader2); /* should be 1 */
561 2 : int nBPP = ReadShort(&pabyHeader2); /* should be 8 */
562 2 : ReadInt(&pabyHeader2); /* reserved */
563 2 : ReadInt(&pabyHeader2); /* pixel number (height * width) : unused */
564 2 : ReadInt(&pabyHeader2); /* reserved */
565 2 : ReadInt(&pabyHeader2); /* reserved */
566 2 : ReadInt(&pabyHeader2); /* ?? 0x100 */
567 2 : ReadInt(&pabyHeader2); /* ?? 0x100 */
568 :
569 2 : if (nHeaderSize != 40 || nDepth != 1 || nBPP != 8)
570 : {
571 0 : if (bOzi3)
572 : {
573 0 : if (nKeyInit != 255)
574 : {
575 0 : memcpy(abyHeader2, abyHeader2_Backup,40);
576 0 : continue;
577 : }
578 : else
579 : {
580 0 : CPLDebug("OZI", "Cannot decypher 2nd header. Sorry...");
581 0 : delete poDS;
582 0 : return NULL;
583 : }
584 : }
585 : else
586 : {
587 : CPLDebug("OZI", "nHeaderSize = %d, nDepth = %d, nBPP = %d",
588 0 : nHeaderSize, nDepth, nBPP);
589 0 : delete poDS;
590 0 : return NULL;
591 : }
592 : }
593 : else
594 : break;
595 : }
596 2 : poDS->nKeyInit = nKeyInit;
597 :
598 2 : int nSeparator = ReadInt(fp);
599 2 : if (!bOzi3 && nSeparator != 0x77777777)
600 : {
601 0 : CPLDebug("OZI", "didn't get end of header2 marker");
602 0 : delete poDS;
603 0 : return NULL;
604 : }
605 :
606 2 : poDS->nZoomLevelCount = ReadShort(fp);
607 : //CPLDebug("OZI", "nZoomLevelCount = %d", poDS->nZoomLevelCount);
608 2 : if (poDS->nZoomLevelCount < 0 || poDS->nZoomLevelCount >= 256)
609 : {
610 0 : CPLDebug("OZI", "nZoomLevelCount = %d", poDS->nZoomLevelCount);
611 0 : delete poDS;
612 0 : return NULL;
613 : }
614 :
615 : /* Skip array of zoom level percentage. We don't need it for GDAL */
616 2 : VSIFSeekL(fp, sizeof(float) * poDS->nZoomLevelCount, SEEK_CUR);
617 :
618 2 : nSeparator = ReadInt(fp);
619 2 : if (!bOzi3 && nSeparator != 0x77777777)
620 : {
621 : /* Some files have 8 extra bytes before the marker. I'm not sure */
622 : /* what they are used for. So just skeep them and hope that */
623 : /* we'll find the marker */
624 0 : nSeparator = ReadInt(fp);
625 0 : nSeparator = ReadInt(fp);
626 0 : if (nSeparator != 0x77777777)
627 : {
628 0 : CPLDebug("OZI", "didn't get end of zoom levels marker");
629 0 : delete poDS;
630 0 : return NULL;
631 : }
632 : }
633 :
634 2 : VSIFSeekL(fp, 0, SEEK_END);
635 2 : vsi_l_offset nFileSize = VSIFTellL(fp);
636 2 : poDS->nFileSize = nFileSize;
637 2 : VSIFSeekL(fp, nFileSize - 4, SEEK_SET);
638 2 : int nZoomLevelTableOffset = ReadInt(fp, bOzi3, nKeyInit);
639 2 : if (nZoomLevelTableOffset < 0 ||
640 : (vsi_l_offset)nZoomLevelTableOffset >= nFileSize)
641 : {
642 : CPLDebug("OZI", "nZoomLevelTableOffset = %d",
643 0 : nZoomLevelTableOffset);
644 0 : delete poDS;
645 0 : return NULL;
646 : }
647 :
648 2 : VSIFSeekL(fp, nZoomLevelTableOffset, SEEK_SET);
649 :
650 : poDS->panZoomLevelOffsets =
651 2 : (int*)CPLMalloc(sizeof(int) * poDS->nZoomLevelCount);
652 : int i;
653 20 : for(i=0;i<poDS->nZoomLevelCount;i++)
654 : {
655 18 : poDS->panZoomLevelOffsets[i] = ReadInt(fp, bOzi3, nKeyInit);
656 36 : if (poDS->panZoomLevelOffsets[i] < 0 ||
657 18 : (vsi_l_offset)poDS->panZoomLevelOffsets[i] >= nFileSize)
658 : {
659 : CPLDebug("OZI", "panZoomLevelOffsets[%d] = %d",
660 0 : i, poDS->panZoomLevelOffsets[i]);
661 0 : delete poDS;
662 0 : return NULL;
663 : }
664 : }
665 :
666 : poDS->papoBands =
667 2 : (OZIRasterBand**)CPLCalloc(sizeof(OZIRasterBand*), poDS->nZoomLevelCount);
668 :
669 20 : for(i=0;i<poDS->nZoomLevelCount;i++)
670 : {
671 18 : VSIFSeekL(fp, poDS->panZoomLevelOffsets[i], SEEK_SET);
672 18 : int nW = ReadInt(fp, bOzi3, nKeyInit);
673 18 : int nH = ReadInt(fp, bOzi3, nKeyInit);
674 18 : short nTileX = ReadShort(fp, bOzi3, nKeyInit);
675 18 : short nTileY = ReadShort(fp, bOzi3, nKeyInit);
676 18 : if (i == 0 && (nW != poDS->nRasterXSize || nH != poDS->nRasterYSize))
677 : {
678 : CPLDebug("OZI", "zoom[%d] inconsistant dimensions for zoom level 0 : nW=%d, nH=%d, nTileX=%d, nTileY=%d, nRasterXSize=%d, nRasterYSize=%d",
679 0 : i, nW, nH, nTileX, nTileY, poDS->nRasterXSize, poDS->nRasterYSize);
680 0 : delete poDS;
681 0 : return NULL;
682 : }
683 : /* Note (#3895): some files such as world.ozf2 provided with OziExplorer */
684 : /* expose nTileY=33, but have nH=2048, so only require 32 tiles in vertical dimension. */
685 : /* So there's apparently one extra and useless tile that will be ignored */
686 : /* without causing apparent issues */
687 : /* Some other files have more tile in horizontal direction than needed, so let's */
688 : /* accept that. But in that case we really need to keep the nTileX value for IReadBlock() */
689 : /* to work properly */
690 18 : if ((nW + 63) / 64 > nTileX || (nH + 63) / 64 > nTileY)
691 : {
692 : CPLDebug("OZI", "zoom[%d] unexpected number of tiles : nW=%d, nH=%d, nTileX=%d, nTileY=%d",
693 0 : i, nW, nH, nTileX, nTileY);
694 0 : delete poDS;
695 0 : return NULL;
696 : }
697 :
698 18 : GDALColorTable* poColorTable = new GDALColorTable();
699 : GByte abyColorTable[256*4];
700 18 : VSIFReadL(abyColorTable, 1, 1024, fp);
701 18 : if (bOzi3)
702 0 : OZIDecrypt(abyColorTable, 1024, nKeyInit);
703 : int j;
704 4626 : for(j=0;j<256;j++)
705 : {
706 : GDALColorEntry sEntry;
707 4608 : sEntry.c1 = abyColorTable[4*j + 2];
708 4608 : sEntry.c2 = abyColorTable[4*j + 1];
709 4608 : sEntry.c3 = abyColorTable[4*j + 0];
710 4608 : sEntry.c4 = 255;
711 4608 : poColorTable->SetColorEntry(j, &sEntry);
712 : }
713 :
714 18 : poDS->papoBands[i] = new OZIRasterBand(poDS, i, nW, nH, nTileX, poColorTable);
715 :
716 18 : if (i > 0)
717 : {
718 : GByte* pabyTranslationTable =
719 16 : poDS->papoBands[i]->GetIndexColorTranslationTo(poDS->papoBands[0], NULL, NULL);
720 :
721 16 : delete poDS->papoBands[i]->poColorTable;
722 16 : poDS->papoBands[i]->poColorTable = poDS->papoBands[0]->poColorTable->Clone();
723 16 : poDS->papoBands[i]->pabyTranslationTable = pabyTranslationTable;
724 : }
725 :
726 : }
727 :
728 2 : poDS->SetBand(1, poDS->papoBands[0]);
729 :
730 : /* -------------------------------------------------------------------- */
731 : /* Initialize any PAM information. */
732 : /* -------------------------------------------------------------------- */
733 2 : poDS->SetDescription( poOpenInfo->pszFilename );
734 2 : poDS->TryLoadXML();
735 :
736 : /* -------------------------------------------------------------------- */
737 : /* Support overviews. */
738 : /* -------------------------------------------------------------------- */
739 2 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
740 2 : return( poDS );
741 : }
742 :
743 : /************************************************************************/
744 : /* GetProjectionRef() */
745 : /************************************************************************/
746 :
747 0 : const char* OZIDataset::GetProjectionRef()
748 : {
749 0 : return (pszWKT && nGCPCount == 0) ? pszWKT : "";
750 : }
751 :
752 : /************************************************************************/
753 : /* GetGeoTransform() */
754 : /************************************************************************/
755 :
756 0 : CPLErr OZIDataset::GetGeoTransform( double * padfTransform )
757 :
758 : {
759 0 : memcpy(padfTransform, adfGeoTransform, 6 * sizeof(double));
760 :
761 0 : return( (bReadMapFileSuccess && nGCPCount == 0) ? CE_None : CE_Failure );
762 : }
763 :
764 : /************************************************************************/
765 : /* GetGCPCount() */
766 : /************************************************************************/
767 :
768 2 : int OZIDataset::GetGCPCount()
769 : {
770 2 : return nGCPCount;
771 : }
772 :
773 : /************************************************************************/
774 : /* GetGCPProjection() */
775 : /************************************************************************/
776 :
777 2 : const char * OZIDataset::GetGCPProjection()
778 : {
779 2 : return (pszWKT && nGCPCount != 0) ? pszWKT : "";
780 : }
781 :
782 : /************************************************************************/
783 : /* GetGCPs() */
784 : /************************************************************************/
785 :
786 2 : const GDAL_GCP * OZIDataset::GetGCPs()
787 : {
788 2 : return pasGCPs;
789 : }
790 :
791 : /************************************************************************/
792 : /* GDALRegister_OZI() */
793 : /************************************************************************/
794 :
795 1135 : void GDALRegister_OZI()
796 :
797 : {
798 : GDALDriver *poDriver;
799 :
800 1135 : if (! GDAL_CHECK_VERSION("OZI driver"))
801 0 : return;
802 :
803 1135 : if( GDALGetDriverByName( "OZI" ) == NULL )
804 : {
805 1093 : poDriver = new GDALDriver();
806 :
807 1093 : poDriver->SetDescription( "OZI" );
808 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
809 1093 : "OziExplorer Image File" );
810 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
811 1093 : "frmt_ozi.html" );
812 :
813 1093 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
814 :
815 1093 : poDriver->pfnOpen = OZIDataset::Open;
816 1093 : poDriver->pfnIdentify = OZIDataset::Identify;
817 :
818 1093 : GetGDALDriverManager()->RegisterDriver( poDriver );
819 : }
820 : }
821 :
|