1 : /******************************************************************************
2 : * $Id: ozidataset.cpp 25310 2012-12-15 12:26:10Z rouault $
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 25310 2012-12-15 12:26:10Z rouault $");
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** papoOvrBands;
57 : vsi_l_offset nFileSize;
58 :
59 : int bOzi3;
60 : GByte nKeyInit;
61 :
62 : public:
63 : OZIDataset();
64 : virtual ~OZIDataset();
65 :
66 : static GDALDataset *Open( GDALOpenInfo * );
67 : static int Identify( GDALOpenInfo * );
68 : };
69 :
70 : /************************************************************************/
71 : /* ==================================================================== */
72 : /* OZIRasterBand */
73 : /* ==================================================================== */
74 : /************************************************************************/
75 :
76 : class OZIRasterBand : public GDALPamRasterBand
77 : {
78 : friend class OZIDataset;
79 :
80 : int nXBlocks;
81 : int nZoomLevel;
82 : GDALColorTable* poColorTable;
83 : GByte* pabyTranslationTable;
84 :
85 : public:
86 :
87 : OZIRasterBand( OZIDataset *, int nZoomLevel,
88 : int nRasterXSize, int nRasterYSize,
89 : int nXBlocks,
90 : GDALColorTable* poColorTable);
91 : virtual ~OZIRasterBand();
92 :
93 : virtual CPLErr IReadBlock( int, int, void * );
94 : virtual GDALColorInterp GetColorInterpretation();
95 : virtual GDALColorTable *GetColorTable();
96 :
97 : virtual int GetOverviewCount();
98 : virtual GDALRasterBand* GetOverview(int nLevel);
99 : };
100 :
101 :
102 : /************************************************************************/
103 : /* I/O functions */
104 : /************************************************************************/
105 :
106 : static const GByte abyKey[] =
107 : {
108 : 0x2D, 0x4A, 0x43, 0xF1, 0x27, 0x9B, 0x69, 0x4F,
109 : 0x36, 0x52, 0x87, 0xEC, 0x5F, 0x42, 0x53, 0x22,
110 : 0x9E, 0x8B, 0x2D, 0x83, 0x3D, 0xD2, 0x84, 0xBA,
111 : 0xD8, 0x5B
112 : };
113 :
114 0 : static void OZIDecrypt(void *pabyVal, int n, GByte nKeyInit)
115 : {
116 : int i;
117 0 : for(i = 0; i < n; i++)
118 : {
119 0 : ((GByte*)pabyVal)[i] ^= abyKey[i % sizeof(abyKey)] + nKeyInit;
120 : }
121 0 : }
122 :
123 9 : static int ReadInt(GByte**pptr)
124 : {
125 : int nVal;
126 9 : memcpy(&nVal, *pptr, 4);
127 9 : *pptr += 4;
128 : CPL_LSBPTR32(&nVal);
129 9 : return nVal;
130 : }
131 :
132 2 : static short ReadShort(GByte**pptr)
133 : {
134 : short nVal;
135 2 : memcpy(&nVal, *pptr, 2);
136 2 : *pptr += 2;
137 : CPL_LSBPTR16(&nVal);
138 2 : return nVal;
139 : }
140 :
141 894 : static int ReadInt(VSILFILE* fp, int bOzi3 = FALSE, int nKeyInit = 0)
142 : {
143 : int nVal;
144 894 : VSIFReadL(&nVal, 1, 4, fp);
145 894 : if (bOzi3) OZIDecrypt(&nVal, 4, (GByte) nKeyInit);
146 : CPL_LSBPTR32(&nVal);
147 894 : return nVal;
148 : }
149 :
150 19 : static short ReadShort(VSILFILE* fp, int bOzi3 = FALSE, int nKeyInit = 0)
151 : {
152 : short nVal;
153 19 : VSIFReadL(&nVal, 1, 2, fp);
154 19 : if (bOzi3) OZIDecrypt(&nVal, 2, (GByte) nKeyInit);
155 : CPL_LSBPTR16(&nVal);
156 19 : return nVal;
157 : }
158 :
159 : /************************************************************************/
160 : /* OZIRasterBand() */
161 : /************************************************************************/
162 :
163 9 : OZIRasterBand::OZIRasterBand( OZIDataset *poDS, int nZoomLevel,
164 : int nRasterXSize, int nRasterYSize,
165 : int nXBlocks,
166 9 : GDALColorTable* poColorTable )
167 :
168 : {
169 9 : this->poDS = poDS;
170 9 : this->nBand = 1;
171 :
172 9 : eDataType = GDT_Byte;
173 :
174 9 : nBlockXSize = 64;
175 9 : nBlockYSize = 64;
176 :
177 9 : this->nZoomLevel = nZoomLevel;
178 9 : this->nRasterXSize = nRasterXSize;
179 9 : this->nRasterYSize = nRasterYSize;
180 9 : this->poColorTable = poColorTable;
181 9 : this->nXBlocks = nXBlocks;
182 :
183 9 : pabyTranslationTable = NULL;
184 9 : }
185 :
186 : /************************************************************************/
187 : /* ~OZIRasterBand() */
188 : /************************************************************************/
189 :
190 9 : OZIRasterBand::~OZIRasterBand()
191 : {
192 9 : delete poColorTable;
193 9 : CPLFree(pabyTranslationTable);
194 9 : }
195 :
196 :
197 : /************************************************************************/
198 : /* GetColorInterpretation() */
199 : /************************************************************************/
200 :
201 16 : GDALColorInterp OZIRasterBand::GetColorInterpretation()
202 : {
203 16 : return GCI_PaletteIndex;
204 : }
205 :
206 : /************************************************************************/
207 : /* GetColorTable() */
208 : /************************************************************************/
209 :
210 16 : GDALColorTable* OZIRasterBand::GetColorTable()
211 : {
212 16 : return poColorTable;
213 : }
214 :
215 : /************************************************************************/
216 : /* IReadBlock() */
217 : /************************************************************************/
218 :
219 432 : CPLErr OZIRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
220 : void * pImage )
221 :
222 : {
223 432 : OZIDataset *poGDS = (OZIDataset *) poDS;
224 :
225 432 : int nBlock = nBlockYOff * nXBlocks + nBlockXOff;
226 :
227 432 : VSIFSeekL(poGDS->fp, poGDS->panZoomLevelOffsets[nZoomLevel] +
228 432 : 12 + 1024 + 4 * nBlock, SEEK_SET);
229 432 : int nPointer = ReadInt(poGDS->fp, poGDS->bOzi3, poGDS->nKeyInit);
230 432 : if (nPointer < 0 || (vsi_l_offset)nPointer >= poGDS->nFileSize)
231 : {
232 : CPLError(CE_Failure, CPLE_AppDefined,
233 : "Invalid offset for block (%d, %d) : %d",
234 0 : nBlockXOff, nBlockYOff, nPointer);
235 0 : return CE_Failure;
236 : }
237 432 : int nNextPointer = ReadInt(poGDS->fp, poGDS->bOzi3, poGDS->nKeyInit);
238 432 : if (nNextPointer <= nPointer + 16 ||
239 : (vsi_l_offset)nNextPointer >= poGDS->nFileSize ||
240 : nNextPointer - nPointer > 10 * 64 * 64)
241 : {
242 : CPLError(CE_Failure, CPLE_AppDefined,
243 : "Invalid next offset for block (%d, %d) : %d",
244 0 : nBlockXOff, nBlockYOff, nNextPointer);
245 0 : return CE_Failure;
246 : }
247 :
248 432 : VSIFSeekL(poGDS->fp, nPointer, SEEK_SET);
249 :
250 432 : int nToRead = nNextPointer - nPointer;
251 432 : GByte* pabyZlibBuffer = (GByte*)CPLMalloc(nToRead);
252 432 : if (VSIFReadL(pabyZlibBuffer, nToRead, 1, poGDS->fp) != 1)
253 : {
254 : CPLError(CE_Failure, CPLE_AppDefined,
255 : "Not enough byte read for block (%d, %d)",
256 0 : nBlockXOff, nBlockYOff);
257 0 : CPLFree(pabyZlibBuffer);
258 0 : return CE_Failure;
259 : }
260 :
261 432 : if (poGDS->bOzi3)
262 0 : OZIDecrypt(pabyZlibBuffer, 16, poGDS->nKeyInit);
263 :
264 864 : if (pabyZlibBuffer[0] != 0x78 ||
265 432 : pabyZlibBuffer[1] != 0xDA)
266 : {
267 : CPLError(CE_Failure, CPLE_AppDefined,
268 : "Bad ZLIB signature for block (%d, %d) : 0x%02X 0x%02X",
269 0 : nBlockXOff, nBlockYOff, pabyZlibBuffer[0], pabyZlibBuffer[1]);
270 0 : CPLFree(pabyZlibBuffer);
271 0 : return CE_Failure;
272 : }
273 :
274 : z_stream stream;
275 432 : stream.zalloc = (alloc_func)0;
276 432 : stream.zfree = (free_func)0;
277 432 : stream.opaque = (voidpf)0;
278 432 : stream.next_in = pabyZlibBuffer + 2;
279 432 : stream.avail_in = nToRead - 2;
280 :
281 432 : int err = inflateInit2(&(stream), -MAX_WBITS);
282 :
283 : int i;
284 28080 : for(i=0;i<64 && err == Z_OK;i++)
285 : {
286 27648 : stream.next_out = (Bytef*)pImage + (63 - i) * 64;
287 27648 : stream.avail_out = 64;
288 27648 : err = inflate(& (stream), Z_NO_FLUSH);
289 27648 : if (err != Z_OK && err != Z_STREAM_END)
290 0 : break;
291 :
292 27648 : if (pabyTranslationTable)
293 : {
294 : int j;
295 0 : GByte* ptr = ((GByte*)pImage) + (63 - i) * 64;
296 0 : for(j=0;j<64;j++)
297 : {
298 0 : *ptr = pabyTranslationTable[*ptr];
299 0 : ptr ++;
300 : }
301 : }
302 : }
303 :
304 432 : inflateEnd(&stream);
305 :
306 432 : CPLFree(pabyZlibBuffer);
307 :
308 432 : return (err == Z_OK || err == Z_STREAM_END) ? CE_None : CE_Failure;
309 : }
310 :
311 : /************************************************************************/
312 : /* GetOverviewCount() */
313 : /************************************************************************/
314 :
315 0 : int OZIRasterBand::GetOverviewCount()
316 : {
317 0 : if (nZoomLevel != 0)
318 0 : return 0;
319 :
320 0 : OZIDataset *poGDS = (OZIDataset *) poDS;
321 0 : return poGDS->nZoomLevelCount - 1;
322 : }
323 :
324 : /************************************************************************/
325 : /* GetOverview() */
326 : /************************************************************************/
327 :
328 0 : GDALRasterBand* OZIRasterBand::GetOverview(int nLevel)
329 : {
330 0 : if (nZoomLevel != 0)
331 0 : return NULL;
332 :
333 0 : OZIDataset *poGDS = (OZIDataset *) poDS;
334 0 : if (nLevel < 0 || nLevel >= poGDS->nZoomLevelCount - 1)
335 0 : return NULL;
336 :
337 0 : return poGDS->papoOvrBands[nLevel + 1];
338 : }
339 :
340 : /************************************************************************/
341 : /* ~OZIDataset() */
342 : /************************************************************************/
343 :
344 1 : OZIDataset::OZIDataset()
345 : {
346 1 : fp = NULL;
347 1 : nZoomLevelCount = 0;
348 1 : panZoomLevelOffsets = NULL;
349 1 : papoOvrBands = NULL;
350 1 : bOzi3 = FALSE;
351 1 : nKeyInit = 0;
352 1 : }
353 :
354 : /************************************************************************/
355 : /* ~OZIDataset() */
356 : /************************************************************************/
357 :
358 1 : OZIDataset::~OZIDataset()
359 : {
360 1 : if (fp)
361 1 : VSIFCloseL(fp);
362 1 : if (papoOvrBands != NULL )
363 : {
364 : /* start at 1: do not destroy the base band ! */
365 9 : for(int i=1;i<nZoomLevelCount;i++)
366 8 : delete papoOvrBands[i];
367 1 : CPLFree(papoOvrBands);
368 : }
369 1 : CPLFree(panZoomLevelOffsets);
370 1 : }
371 :
372 : /************************************************************************/
373 : /* Identify() */
374 : /************************************************************************/
375 :
376 11410 : int OZIDataset::Identify( GDALOpenInfo * poOpenInfo )
377 : {
378 11410 : if (poOpenInfo->nHeaderBytes < 14)
379 11213 : return FALSE;
380 :
381 197 : if (EQUALN((const char*)poOpenInfo->pabyHeader,
382 : "OziExplorer Map Data File Version ", 34) )
383 0 : return TRUE;
384 :
385 197 : if (poOpenInfo->pabyHeader[0] == 0x80 &&
386 0 : poOpenInfo->pabyHeader[1] == 0x77)
387 0 : return TRUE;
388 :
389 197 : return poOpenInfo->pabyHeader[0] == 0x78 &&
390 1 : poOpenInfo->pabyHeader[1] == 0x77 &&
391 1 : poOpenInfo->pabyHeader[6] == 0x40 &&
392 1 : poOpenInfo->pabyHeader[7] == 0x00 &&
393 1 : poOpenInfo->pabyHeader[8] == 0x01 &&
394 1 : poOpenInfo->pabyHeader[9] == 0x00 &&
395 1 : poOpenInfo->pabyHeader[10] == 0x36 &&
396 1 : poOpenInfo->pabyHeader[11] == 0x04 &&
397 1 : poOpenInfo->pabyHeader[12] == 0x00 &&
398 205 : poOpenInfo->pabyHeader[13] == 0x00;
399 : }
400 :
401 : /************************************************************************/
402 : /* Open() */
403 : /************************************************************************/
404 :
405 1346 : GDALDataset *OZIDataset::Open( GDALOpenInfo * poOpenInfo )
406 :
407 : {
408 1346 : if (!Identify(poOpenInfo))
409 1345 : return NULL;
410 :
411 : GByte abyHeader[14];
412 1 : CPLString osImgFilename = poOpenInfo->pszFilename;
413 1 : memcpy(abyHeader, poOpenInfo->pabyHeader, 14);
414 :
415 1 : int bOzi3 = (abyHeader[0] == 0x80 &&
416 1 : abyHeader[1] == 0x77);
417 :
418 1 : VSILFILE* fp = VSIFOpenL(osImgFilename.c_str(), "rb");
419 1 : if (fp == NULL)
420 0 : return NULL;
421 :
422 1 : OZIDataset* poDS = new OZIDataset();
423 1 : poDS->fp = fp;
424 :
425 1 : GByte nRandomNumber = 0;
426 1 : GByte nKeyInit = 0;
427 1 : if (bOzi3)
428 : {
429 0 : VSIFSeekL(fp, 14, SEEK_SET);
430 0 : VSIFReadL(&nRandomNumber, 1, 1, fp);
431 : //printf("nRandomNumber = %d\n", nRandomNumber);
432 0 : if (nRandomNumber < 0x94)
433 : {
434 0 : delete poDS;
435 0 : return NULL;
436 : }
437 0 : VSIFSeekL(fp, 0x93, SEEK_CUR);
438 0 : VSIFReadL(&nKeyInit, 1, 1, fp);
439 :
440 0 : VSIFSeekL(fp, 0, SEEK_SET);
441 0 : VSIFReadL(abyHeader, 1, 14, fp);
442 0 : OZIDecrypt(abyHeader, 14, nKeyInit);
443 0 : if (!(abyHeader[6] == 0x40 &&
444 0 : abyHeader[7] == 0x00 &&
445 0 : abyHeader[8] == 0x01 &&
446 0 : abyHeader[9] == 0x00 &&
447 0 : abyHeader[10] == 0x36 &&
448 0 : abyHeader[11] == 0x04 &&
449 0 : abyHeader[12] == 0x00 &&
450 0 : abyHeader[13] == 0x00))
451 : {
452 0 : delete poDS;
453 0 : return NULL;
454 : }
455 :
456 0 : VSIFSeekL(fp, 14 + 1 + nRandomNumber, SEEK_SET);
457 0 : int nMagic = ReadInt(fp, bOzi3, nKeyInit);
458 0 : CPLDebug("OZI", "OZI version code : 0x%08X", nMagic);
459 :
460 0 : poDS->bOzi3 = bOzi3;
461 : }
462 : else
463 : {
464 1 : VSIFSeekL(fp, 14, SEEK_SET);
465 : }
466 :
467 : GByte abyHeader2[40], abyHeader2_Backup[40];
468 1 : VSIFReadL(abyHeader2, 40, 1, fp);
469 1 : memcpy(abyHeader2_Backup, abyHeader2, 40);
470 :
471 : /* There's apparently a relationship between the nMagic number */
472 : /* and the nKeyInit, but I'm too lazy to add switch/cases that might */
473 : /* be not exhaustive, so let's try the 'brute force' attack !!! */
474 : /* It is much so funny to be able to run one in a few microseconds :-) */
475 : int i;
476 2 : for(i = 0; i < 256; i ++)
477 : {
478 1 : nKeyInit = (GByte)i;
479 1 : GByte* pabyHeader2 = abyHeader2;
480 1 : if (bOzi3)
481 0 : OZIDecrypt(abyHeader2, 40, nKeyInit);
482 :
483 1 : int nHeaderSize = ReadInt(&pabyHeader2); /* should be 40 */
484 1 : poDS->nRasterXSize = ReadInt(&pabyHeader2);
485 1 : poDS->nRasterYSize = ReadInt(&pabyHeader2);
486 1 : int nDepth = ReadShort(&pabyHeader2); /* should be 1 */
487 1 : int nBPP = ReadShort(&pabyHeader2); /* should be 8 */
488 1 : ReadInt(&pabyHeader2); /* reserved */
489 1 : ReadInt(&pabyHeader2); /* pixel number (height * width) : unused */
490 1 : ReadInt(&pabyHeader2); /* reserved */
491 1 : ReadInt(&pabyHeader2); /* reserved */
492 1 : ReadInt(&pabyHeader2); /* ?? 0x100 */
493 1 : ReadInt(&pabyHeader2); /* ?? 0x100 */
494 :
495 1 : if (nHeaderSize != 40 || nDepth != 1 || nBPP != 8)
496 : {
497 0 : if (bOzi3)
498 : {
499 0 : if (nKeyInit != 255)
500 : {
501 0 : memcpy(abyHeader2, abyHeader2_Backup,40);
502 0 : continue;
503 : }
504 : else
505 : {
506 0 : CPLDebug("OZI", "Cannot decypher 2nd header. Sorry...");
507 0 : delete poDS;
508 0 : return NULL;
509 : }
510 : }
511 : else
512 : {
513 : CPLDebug("OZI", "nHeaderSize = %d, nDepth = %d, nBPP = %d",
514 0 : nHeaderSize, nDepth, nBPP);
515 0 : delete poDS;
516 0 : return NULL;
517 : }
518 : }
519 : else
520 1 : break;
521 : }
522 1 : poDS->nKeyInit = nKeyInit;
523 :
524 1 : int nSeparator = ReadInt(fp);
525 1 : if (!bOzi3 && nSeparator != 0x77777777)
526 : {
527 0 : CPLDebug("OZI", "didn't get end of header2 marker");
528 0 : delete poDS;
529 0 : return NULL;
530 : }
531 :
532 1 : poDS->nZoomLevelCount = ReadShort(fp);
533 : //CPLDebug("OZI", "nZoomLevelCount = %d", poDS->nZoomLevelCount);
534 1 : if (poDS->nZoomLevelCount < 0 || poDS->nZoomLevelCount >= 256)
535 : {
536 0 : CPLDebug("OZI", "nZoomLevelCount = %d", poDS->nZoomLevelCount);
537 0 : delete poDS;
538 0 : return NULL;
539 : }
540 :
541 : /* Skip array of zoom level percentage. We don't need it for GDAL */
542 1 : VSIFSeekL(fp, sizeof(float) * poDS->nZoomLevelCount, SEEK_CUR);
543 :
544 1 : nSeparator = ReadInt(fp);
545 1 : if (!bOzi3 && nSeparator != 0x77777777)
546 : {
547 : /* Some files have 8 extra bytes before the marker. I'm not sure */
548 : /* what they are used for. So just skeep them and hope that */
549 : /* we'll find the marker */
550 0 : nSeparator = ReadInt(fp);
551 0 : nSeparator = ReadInt(fp);
552 0 : if (nSeparator != 0x77777777)
553 : {
554 0 : CPLDebug("OZI", "didn't get end of zoom levels marker");
555 0 : delete poDS;
556 0 : return NULL;
557 : }
558 : }
559 :
560 1 : VSIFSeekL(fp, 0, SEEK_END);
561 1 : vsi_l_offset nFileSize = VSIFTellL(fp);
562 1 : poDS->nFileSize = nFileSize;
563 1 : VSIFSeekL(fp, nFileSize - 4, SEEK_SET);
564 1 : int nZoomLevelTableOffset = ReadInt(fp, bOzi3, nKeyInit);
565 1 : if (nZoomLevelTableOffset < 0 ||
566 : (vsi_l_offset)nZoomLevelTableOffset >= nFileSize)
567 : {
568 : CPLDebug("OZI", "nZoomLevelTableOffset = %d",
569 0 : nZoomLevelTableOffset);
570 0 : delete poDS;
571 0 : return NULL;
572 : }
573 :
574 1 : VSIFSeekL(fp, nZoomLevelTableOffset, SEEK_SET);
575 :
576 : poDS->panZoomLevelOffsets =
577 1 : (int*)CPLMalloc(sizeof(int) * poDS->nZoomLevelCount);
578 :
579 10 : for(i=0;i<poDS->nZoomLevelCount;i++)
580 : {
581 9 : poDS->panZoomLevelOffsets[i] = ReadInt(fp, bOzi3, nKeyInit);
582 18 : if (poDS->panZoomLevelOffsets[i] < 0 ||
583 9 : (vsi_l_offset)poDS->panZoomLevelOffsets[i] >= nFileSize)
584 : {
585 : CPLDebug("OZI", "panZoomLevelOffsets[%d] = %d",
586 0 : i, poDS->panZoomLevelOffsets[i]);
587 0 : delete poDS;
588 0 : return NULL;
589 : }
590 : }
591 :
592 : poDS->papoOvrBands =
593 1 : (OZIRasterBand**)CPLCalloc(sizeof(OZIRasterBand*), poDS->nZoomLevelCount);
594 :
595 10 : for(i=0;i<poDS->nZoomLevelCount;i++)
596 : {
597 9 : VSIFSeekL(fp, poDS->panZoomLevelOffsets[i], SEEK_SET);
598 9 : int nW = ReadInt(fp, bOzi3, nKeyInit);
599 9 : int nH = ReadInt(fp, bOzi3, nKeyInit);
600 9 : short nTileX = ReadShort(fp, bOzi3, nKeyInit);
601 9 : short nTileY = ReadShort(fp, bOzi3, nKeyInit);
602 9 : if (i == 0 && (nW != poDS->nRasterXSize || nH != poDS->nRasterYSize))
603 : {
604 : CPLDebug("OZI", "zoom[%d] inconsistant dimensions for zoom level 0 : nW=%d, nH=%d, nTileX=%d, nTileY=%d, nRasterXSize=%d, nRasterYSize=%d",
605 0 : i, nW, nH, nTileX, nTileY, poDS->nRasterXSize, poDS->nRasterYSize);
606 0 : delete poDS;
607 0 : return NULL;
608 : }
609 : /* Note (#3895): some files such as world.ozf2 provided with OziExplorer */
610 : /* expose nTileY=33, but have nH=2048, so only require 32 tiles in vertical dimension. */
611 : /* So there's apparently one extra and useless tile that will be ignored */
612 : /* without causing apparent issues */
613 : /* Some other files have more tile in horizontal direction than needed, so let's */
614 : /* accept that. But in that case we really need to keep the nTileX value for IReadBlock() */
615 : /* to work properly */
616 9 : if ((nW + 63) / 64 > nTileX || (nH + 63) / 64 > nTileY)
617 : {
618 : CPLDebug("OZI", "zoom[%d] unexpected number of tiles : nW=%d, nH=%d, nTileX=%d, nTileY=%d",
619 0 : i, nW, nH, nTileX, nTileY);
620 0 : delete poDS;
621 0 : return NULL;
622 : }
623 :
624 9 : GDALColorTable* poColorTable = new GDALColorTable();
625 : GByte abyColorTable[256*4];
626 9 : VSIFReadL(abyColorTable, 1, 1024, fp);
627 9 : if (bOzi3)
628 0 : OZIDecrypt(abyColorTable, 1024, nKeyInit);
629 : int j;
630 2313 : for(j=0;j<256;j++)
631 : {
632 : GDALColorEntry sEntry;
633 2304 : sEntry.c1 = abyColorTable[4*j + 2];
634 2304 : sEntry.c2 = abyColorTable[4*j + 1];
635 2304 : sEntry.c3 = abyColorTable[4*j + 0];
636 2304 : sEntry.c4 = 255;
637 2304 : poColorTable->SetColorEntry(j, &sEntry);
638 : }
639 :
640 9 : poDS->papoOvrBands[i] = new OZIRasterBand(poDS, i, nW, nH, nTileX, poColorTable);
641 :
642 9 : if (i > 0)
643 : {
644 : GByte* pabyTranslationTable =
645 8 : poDS->papoOvrBands[i]->GetIndexColorTranslationTo(poDS->papoOvrBands[0], NULL, NULL);
646 :
647 8 : delete poDS->papoOvrBands[i]->poColorTable;
648 8 : poDS->papoOvrBands[i]->poColorTable = poDS->papoOvrBands[0]->poColorTable->Clone();
649 8 : poDS->papoOvrBands[i]->pabyTranslationTable = pabyTranslationTable;
650 : }
651 :
652 : }
653 :
654 1 : poDS->SetBand(1, poDS->papoOvrBands[0]);
655 :
656 : /* -------------------------------------------------------------------- */
657 : /* Initialize any PAM information. */
658 : /* -------------------------------------------------------------------- */
659 1 : poDS->SetDescription( poOpenInfo->pszFilename );
660 1 : poDS->TryLoadXML();
661 :
662 : /* -------------------------------------------------------------------- */
663 : /* Support overviews. */
664 : /* -------------------------------------------------------------------- */
665 1 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
666 1 : return( poDS );
667 : }
668 :
669 : /************************************************************************/
670 : /* GDALRegister_OZI() */
671 : /************************************************************************/
672 :
673 582 : void GDALRegister_OZI()
674 :
675 : {
676 : GDALDriver *poDriver;
677 :
678 582 : if (! GDAL_CHECK_VERSION("OZI driver"))
679 0 : return;
680 :
681 582 : if( GDALGetDriverByName( "OZI" ) == NULL )
682 : {
683 561 : poDriver = new GDALDriver();
684 :
685 561 : poDriver->SetDescription( "OZI" );
686 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
687 561 : "OziExplorer Image File" );
688 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
689 561 : "frmt_ozi.html" );
690 :
691 561 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
692 :
693 561 : poDriver->pfnOpen = OZIDataset::Open;
694 561 : poDriver->pfnIdentify = OZIDataset::Identify;
695 :
696 561 : GetGDALDriverManager()->RegisterDriver( poDriver );
697 : }
698 : }
699 :
|