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