1 /******************************************************************************
2 *
3 * Project: RPF A.TOC read Library
4 * Purpose: Module responsible for opening a RPF TOC file, populating RPFToc
5 * structure
6 * Author: Even Rouault, even.rouault at spatialys.com
7 *
8 **********************************************************************
9 * Copyright (c) 2007-2010, Even Rouault <even dot rouault at spatialys.com>
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 /* Portions of code are placed under the following copyright : */
31 /*
32 ******************************************************************************
33 * Copyright (C) 1995 Logiciels et Applications Scientifiques (L.A.S.) Inc
34 * Permission to use, copy, modify and distribute this software and
35 * its documentation for any purpose and without fee is hereby granted,
36 * provided that the above copyright notice appear in all copies, that
37 * both the copyright notice and this permission notice appear in
38 * supporting documentation, and that the name of L.A.S. Inc not be used
39 * in advertising or publicity pertaining to distribution of the software
40 * without specific, written prior permission. L.A.S. Inc. makes no
41 * representations about the suitability of this software for any purpose.
42 * It is provided "as is" without express or implied warranty.
43 ******************************************************************************
44 */
45
46 #include "cpl_port.h"
47 #include "rpftoclib.h"
48
49 #include <climits>
50 #include <cstring>
51 #if HAVE_FCNTL_H
52 # include <fcntl.h>
53 #endif
54
55 #include "cpl_conv.h"
56 #include "cpl_error.h"
57 #include "cpl_string.h"
58 #include "cpl_vsi.h"
59 #include "nitflib.h"
60
61 CPL_CVSID("$Id: rpftocfile.cpp df398e80769422a4bbd5d4a295f4ede443c9fec6 2021-04-04 00:17:15 +0200 Even Rouault $")
62
63 /************************************************************************/
64 /* RPFTOCTrim() */
65 /************************************************************************/
66
RPFTOCTrim(char * str)67 static void RPFTOCTrim(char* str)
68 {
69 char* c = str;
70 if (str == nullptr || *str == 0)
71 return;
72
73 while(*c == ' ')
74 {
75 c++;
76 }
77 if (c != str)
78 {
79 memmove(str, c, strlen(c)+1);
80 }
81
82 int i = static_cast<int>(strlen(str)) - 1;
83 while (i >= 0 && str[i] == ' ')
84 {
85 str[i] = 0;
86 i--;
87 }
88 }
89
90 /************************************************************************/
91 /* RPFTOCRead() */
92 /************************************************************************/
93
RPFTOCRead(const char * pszFilename,NITFFile * psFile)94 RPFToc* RPFTOCRead(const char* pszFilename, NITFFile* psFile)
95 {
96 int nTRESize;
97 const char* pachTRE = NITFFindTRE( psFile->pachTRE, psFile->nTREBytes,
98 "RPFHDR", &nTRESize );
99 if (pachTRE == nullptr)
100 {
101 CPLError( CE_Failure, CPLE_NotSupported,
102 "Invalid TOC file. Can't find RPFHDR." );
103 return nullptr;
104 }
105
106 if (nTRESize != 48)
107 {
108 CPLError( CE_Failure, CPLE_NotSupported,
109 "RPFHDR TRE wrong size." );
110 return nullptr;
111 }
112
113 return RPFTOCReadFromBuffer(pszFilename, psFile->fp, pachTRE);
114 }
115
116 /* This function is directly inspired by function parse_toc coming from ogdi/driver/rpf/utils.c */
117
RPFTOCReadFromBuffer(const char * pszFilename,VSILFILE * fp,const char * tocHeader)118 RPFToc* RPFTOCReadFromBuffer(const char* pszFilename, VSILFILE* fp, const char* tocHeader)
119 {
120 tocHeader += 1; /* skip endian */
121 tocHeader += 2; /* skip header length */
122 tocHeader += 12; /* skip file name : this should be A.TOC (padded) */
123 tocHeader += 1; /* skip new */
124 tocHeader += 15; /* skip standard_num */
125 tocHeader += 8; /* skip standard_date */
126 tocHeader += 1; /* skip classification */
127 tocHeader += 2; /* skip country */
128 tocHeader += 2; /* skip release */
129
130 unsigned int locationSectionPhysicalLocation;
131 memcpy(&locationSectionPhysicalLocation, tocHeader, sizeof(unsigned int));
132 CPL_MSBPTR32(&locationSectionPhysicalLocation);
133
134 if( VSIFSeekL( fp, locationSectionPhysicalLocation, SEEK_SET ) != 0)
135 {
136 CPLError( CE_Failure, CPLE_NotSupported,
137 "Invalid TOC file. Unable to seek to locationSectionPhysicalLocation at offset %d.",
138 locationSectionPhysicalLocation );
139 return nullptr;
140 }
141
142 int nSections;
143 NITFLocation* pasLocations = NITFReadRPFLocationTable(fp, &nSections);
144
145 unsigned int boundaryRectangleSectionSubHeaderPhysIndex = 0;
146 unsigned int boundaryRectangleTablePhysIndex = 0;
147 unsigned int frameFileIndexSectionSubHeaderPhysIndex = 0;
148 unsigned int frameFileIndexSubsectionPhysIndex = 0;
149
150 for( int i = 0; i < nSections; i++ )
151 {
152 if (pasLocations[i].nLocId == LID_BoundaryRectangleSectionSubheader)
153 {
154 boundaryRectangleSectionSubHeaderPhysIndex = pasLocations[i].nLocOffset;
155 }
156 else if (pasLocations[i].nLocId == LID_BoundaryRectangleTable)
157 {
158 boundaryRectangleTablePhysIndex = pasLocations[i].nLocOffset;
159 }
160 else if (pasLocations[i].nLocId == LID_FrameFileIndexSectionSubHeader)
161 {
162 frameFileIndexSectionSubHeaderPhysIndex = pasLocations[i].nLocOffset;
163 }
164 else if (pasLocations[i].nLocId == LID_FrameFileIndexSubsection)
165 {
166 frameFileIndexSubsectionPhysIndex = pasLocations[i].nLocOffset;
167 }
168 }
169
170 CPLFree(pasLocations);
171
172 if (boundaryRectangleSectionSubHeaderPhysIndex == 0)
173 {
174 CPLError( CE_Failure, CPLE_NotSupported,
175 "Invalid TOC file. Can't find LID_BoundaryRectangleSectionSubheader." );
176 return nullptr;
177 }
178 if (boundaryRectangleTablePhysIndex == 0)
179 {
180 CPLError( CE_Failure, CPLE_NotSupported,
181 "Invalid TOC file. Can't find LID_BoundaryRectangleTable." );
182 return nullptr;
183 }
184 if (frameFileIndexSectionSubHeaderPhysIndex == 0)
185 {
186 CPLError( CE_Failure, CPLE_NotSupported,
187 "Invalid TOC file. Can't find LID_FrameFileIndexSectionSubHeader." );
188 return nullptr;
189 }
190 if (frameFileIndexSubsectionPhysIndex == 0)
191 {
192 CPLError( CE_Failure, CPLE_NotSupported,
193 "Invalid TOC file. Can't find LID_FrameFileIndexSubsection." );
194 return nullptr;
195 }
196
197 if( VSIFSeekL( fp, boundaryRectangleSectionSubHeaderPhysIndex, SEEK_SET ) != 0)
198 {
199 CPLError( CE_Failure, CPLE_NotSupported,
200 "Invalid TOC file. Unable to seek to boundaryRectangleSectionSubHeaderPhysIndex at offset %d.",
201 boundaryRectangleSectionSubHeaderPhysIndex );
202 return nullptr;
203 }
204
205 unsigned int boundaryRectangleTableOffset;
206 bool bOK = VSIFReadL( &boundaryRectangleTableOffset, sizeof(boundaryRectangleTableOffset), 1, fp) == 1;
207 CPL_MSBPTR32( &boundaryRectangleTableOffset );
208
209 unsigned short boundaryRectangleCount;
210 bOK &= VSIFReadL( &boundaryRectangleCount, sizeof(boundaryRectangleCount), 1, fp) == 1;
211 CPL_MSBPTR16( &boundaryRectangleCount );
212
213 if( !bOK || VSIFSeekL( fp, boundaryRectangleTablePhysIndex, SEEK_SET ) != 0)
214 {
215 CPLError( CE_Failure, CPLE_NotSupported,
216 "Invalid TOC file. Unable to seek to boundaryRectangleTablePhysIndex at offset %d.",
217 boundaryRectangleTablePhysIndex );
218 return nullptr;
219 }
220
221 RPFToc* toc = reinterpret_cast<RPFToc *>( CPLMalloc( sizeof( RPFToc ) ) );
222 toc->nEntries = boundaryRectangleCount;
223 toc->entries = reinterpret_cast<RPFTocEntry *>(
224 CPLMalloc( boundaryRectangleCount * sizeof(RPFTocEntry) ) );
225 memset(toc->entries, 0, boundaryRectangleCount * sizeof(RPFTocEntry));
226
227 for( int i = 0; i < toc->nEntries; i++ )
228 {
229 toc->entries[i].isOverviewOrLegend = 0;
230
231 bOK &= VSIFReadL( toc->entries[i].type, 1, 5, fp) == 5;
232 toc->entries[i].type[5] = 0;
233 RPFTOCTrim(toc->entries[i].type);
234
235 bOK &= VSIFReadL( toc->entries[i].compression, 1, 5, fp) == 5;
236 toc->entries[i].compression[5] = 0;
237 RPFTOCTrim(toc->entries[i].compression);
238
239 bOK &= VSIFReadL( toc->entries[i].scale, 1, 12, fp) == 12;
240 toc->entries[i].scale[12] = 0;
241 RPFTOCTrim(toc->entries[i].scale);
242 if (toc->entries[i].scale[0] == '1' &&
243 toc->entries[i].scale[1] == ':')
244 {
245 memmove(toc->entries[i].scale,
246 toc->entries[i].scale+2,
247 strlen(toc->entries[i].scale+2)+1);
248 }
249
250 bOK &= VSIFReadL( toc->entries[i].zone, 1, 1, fp) == 1;
251 toc->entries[i].zone[1] = 0;
252 RPFTOCTrim(toc->entries[i].zone);
253
254 bOK &= VSIFReadL( toc->entries[i].producer, 1, 5, fp) == 5;
255 toc->entries[i].producer[5] = 0;
256 RPFTOCTrim(toc->entries[i].producer);
257
258 bOK &= VSIFReadL( &toc->entries[i].nwLat, sizeof(double), 1, fp) == 1;
259 CPL_MSBPTR64( &toc->entries[i].nwLat);
260
261 bOK &= VSIFReadL( &toc->entries[i].nwLong, sizeof(double), 1, fp) == 1;
262 CPL_MSBPTR64( &toc->entries[i].nwLong);
263
264 bOK &= VSIFReadL( &toc->entries[i].swLat, sizeof(double), 1, fp) == 1;
265 CPL_MSBPTR64( &toc->entries[i].swLat);
266
267 bOK &= VSIFReadL( &toc->entries[i].swLong, sizeof(double), 1, fp) == 1;
268 CPL_MSBPTR64( &toc->entries[i].swLong);
269
270 bOK &= VSIFReadL( &toc->entries[i].neLat, sizeof(double), 1, fp) == 1;
271 CPL_MSBPTR64( &toc->entries[i].neLat);
272
273 bOK &= VSIFReadL( &toc->entries[i].neLong, sizeof(double), 1, fp) == 1;
274 CPL_MSBPTR64( &toc->entries[i].neLong);
275
276 bOK &= VSIFReadL( &toc->entries[i].seLat, sizeof(double), 1, fp) == 1;
277 CPL_MSBPTR64( &toc->entries[i].seLat);
278
279 bOK &= VSIFReadL( &toc->entries[i].seLong, sizeof(double), 1, fp) == 1;
280 CPL_MSBPTR64( &toc->entries[i].seLong);
281
282 bOK &= VSIFReadL( &toc->entries[i].vertResolution, sizeof(double), 1, fp) == 1;
283 CPL_MSBPTR64( &toc->entries[i].vertResolution);
284
285 bOK &= VSIFReadL( &toc->entries[i].horizResolution, sizeof(double), 1, fp) == 1;
286 CPL_MSBPTR64( &toc->entries[i].horizResolution);
287
288 bOK &= VSIFReadL( &toc->entries[i].vertInterval, sizeof(double), 1, fp) == 1;
289 CPL_MSBPTR64( &toc->entries[i].vertInterval);
290
291 bOK &= VSIFReadL( &toc->entries[i].horizInterval, sizeof(double), 1, fp) == 1;
292 CPL_MSBPTR64( &toc->entries[i].horizInterval);
293
294 bOK &= VSIFReadL( &toc->entries[i].nVertFrames, sizeof(int), 1, fp) == 1;
295 CPL_MSBPTR32( &toc->entries[i].nVertFrames );
296
297 bOK &= VSIFReadL( &toc->entries[i].nHorizFrames, sizeof(int), 1, fp) == 1;
298 CPL_MSBPTR32( &toc->entries[i].nHorizFrames );
299
300 if( !bOK )
301 {
302 CPLError(CE_Failure, CPLE_FileIO, "I/O error");
303 toc->entries[i].nVertFrames = 0;
304 toc->entries[i].nHorizFrames = 0;
305 RPFTOCFree(toc);
306 return nullptr;
307 }
308
309 if( toc->entries[i].vertInterval <= 1e-10 ||
310 !CPLIsFinite(toc->entries[i].vertInterval) ||
311 toc->entries[i].horizInterval <= 1e-10 ||
312 !CPLIsFinite(toc->entries[i].horizInterval) ||
313 !(fabs(toc->entries[i].seLong) <= 360.0) ||
314 !(fabs(toc->entries[i].nwLong) <= 360.0) ||
315 !(fabs(toc->entries[i].nwLat) <= 90.0) ||
316 !(fabs(toc->entries[i].seLat) <= 90.0) ||
317 toc->entries[i].seLong < toc->entries[i].nwLong ||
318 toc->entries[i].nwLat < toc->entries[i].seLat ||
319 toc->entries[i].nHorizFrames == 0 ||
320 toc->entries[i].nVertFrames == 0 ||
321 toc->entries[i].nHorizFrames > INT_MAX / toc->entries[i].nVertFrames )
322 {
323 CPLError(CE_Failure, CPLE_FileIO, "Invalid TOC entry");
324 toc->entries[i].nVertFrames = 0;
325 toc->entries[i].nHorizFrames = 0;
326 RPFTOCFree(toc);
327 return nullptr;
328 }
329
330 // TODO: We could probably use another data structure, like a list,
331 // instead of an array referenced by the frame coordinate...
332 if( static_cast<int>(toc->entries[i].nHorizFrames *
333 toc->entries[i].nVertFrames) >
334 atoi(CPLGetConfigOption("RPFTOC_MAX_FRAME_COUNT", "1000000")) )
335 {
336 CPLError(CE_Failure, CPLE_AppDefined,
337 "nHorizFrames=%d x nVertFrames=%d > %d. Please raise "
338 "the value of the RPFTOC_MAX_FRAME_COUNT configuration "
339 "option to more than %d if this dataset is legitimate.",
340 toc->entries[i].nHorizFrames, toc->entries[i].nVertFrames,
341 atoi(CPLGetConfigOption("RPFTOC_MAX_FRAME_COUNT", "1000000")),
342 toc->entries[i].nHorizFrames * toc->entries[i].nVertFrames );
343 toc->entries[i].frameEntries = nullptr;
344 }
345 else
346 {
347 toc->entries[i].frameEntries = reinterpret_cast<RPFTocFrameEntry*>(
348 VSI_CALLOC_VERBOSE( toc->entries[i].nVertFrames * toc->entries[i].nHorizFrames,
349 sizeof(RPFTocFrameEntry) ) );
350 }
351 if (toc->entries[i].frameEntries == nullptr)
352 {
353 toc->entries[i].nVertFrames = 0;
354 toc->entries[i].nHorizFrames = 0;
355 RPFTOCFree(toc);
356 return nullptr;
357 }
358
359 CPLDebug("RPFTOC", "[%d] type=%s, compression=%s, scale=%s, zone=%s, producer=%s, nVertFrames=%d, nHorizFrames=%d",
360 i, toc->entries[i].type, toc->entries[i].compression, toc->entries[i].scale,
361 toc->entries[i].zone, toc->entries[i].producer, toc->entries[i].nVertFrames, toc->entries[i].nHorizFrames);
362 }
363
364 if( VSIFSeekL( fp, frameFileIndexSectionSubHeaderPhysIndex, SEEK_SET ) != 0)
365 {
366 CPLError( CE_Failure, CPLE_NotSupported,
367 "Invalid TOC file. Unable to seek to frameFileIndexSectionSubHeaderPhysIndex at offset %d.",
368 frameFileIndexSectionSubHeaderPhysIndex );
369 RPFTOCFree(toc);
370 return nullptr;
371 }
372
373 /* Skip 1 byte security classification */
374 bOK &= VSIFSeekL( fp, 1, SEEK_CUR ) == 0;
375
376 unsigned int frameIndexTableOffset;
377 bOK &= VSIFReadL( &frameIndexTableOffset, sizeof(frameIndexTableOffset), 1, fp) == 1;
378 CPL_MSBPTR32( &frameIndexTableOffset );
379
380 unsigned int nFrameFileIndexRecords;
381 bOK &= VSIFReadL( &nFrameFileIndexRecords, sizeof(nFrameFileIndexRecords), 1, fp) == 1;
382 CPL_MSBPTR32( &nFrameFileIndexRecords );
383
384 unsigned short nFrameFilePathnameRecords;
385 bOK &= VSIFReadL( &nFrameFilePathnameRecords, sizeof(nFrameFilePathnameRecords), 1, fp) == 1;
386 CPL_MSBPTR16( &nFrameFilePathnameRecords );
387
388 unsigned short frameFileIndexRecordLength;
389 bOK &= VSIFReadL( &frameFileIndexRecordLength, sizeof(frameFileIndexRecordLength), 1, fp) == 1;
390 CPL_MSBPTR16( &frameFileIndexRecordLength );
391 if( frameFileIndexRecordLength < 3 * sizeof(short) )
392 {
393 CPLError(CE_Failure, CPLE_FileIO, "Invalid file");
394 RPFTOCFree(toc);
395 return nullptr;
396 }
397
398 if( !bOK )
399 {
400 CPLError(CE_Failure, CPLE_FileIO, "I/O error");
401 RPFTOCFree(toc);
402 return nullptr;
403 }
404
405 int newBoundaryId = 0;
406
407 for( int i = 0; i < static_cast<int>( nFrameFileIndexRecords ); i++ )
408 {
409 vsi_l_offset nFrameOffset = static_cast<vsi_l_offset>(
410 frameFileIndexSubsectionPhysIndex) + static_cast<vsi_l_offset>(frameFileIndexRecordLength) * i;
411 if( VSIFSeekL( fp, nFrameOffset, SEEK_SET ) != 0)
412 {
413 CPLError( CE_Failure, CPLE_NotSupported,
414 "Invalid TOC file. Unable to seek to frameFileIndexSubsectionPhysIndex(%d) at offset " CPL_FRMT_GUIB ".",
415 i, static_cast<GUIntBig>(nFrameOffset));
416 RPFTOCFree(toc);
417 return nullptr;
418 }
419
420 unsigned short boundaryId;
421 if( VSIFReadL( &boundaryId, sizeof(boundaryId), 1, fp) != 1 )
422 {
423 CPLError(CE_Failure, CPLE_FileIO, "I/O error");
424 RPFTOCFree(toc);
425 return nullptr;
426 }
427 CPL_MSBPTR16( &boundaryId );
428
429 if (i == 0 && boundaryId == 0)
430 newBoundaryId = 1;
431 if (newBoundaryId == 0)
432 boundaryId--;
433
434 if (boundaryId >= toc->nEntries)
435 {
436 CPLError( CE_Failure, CPLE_NotSupported,
437 "Invalid TOC file. Bad boundary id (%d) for frame file index %d.",
438 boundaryId, i);
439 RPFTOCFree(toc);
440 return nullptr;
441 }
442
443 RPFTocEntry* entry = &toc->entries[boundaryId];
444 entry->boundaryId = boundaryId;
445
446 unsigned short frameRow;
447 bOK &= VSIFReadL( &frameRow, sizeof(frameRow), 1, fp) == 1;
448 CPL_MSBPTR16( &frameRow );
449
450 unsigned short frameCol;
451 bOK &= VSIFReadL( &frameCol, sizeof(frameCol), 1, fp) == 1;
452 CPL_MSBPTR16( &frameCol );
453 if( !bOK )
454 {
455 CPLError(CE_Failure, CPLE_FileIO, "I/O error");
456 RPFTOCFree(toc);
457 return nullptr;
458 }
459
460 if (newBoundaryId == 0)
461 {
462 frameRow--;
463 frameCol--;
464 }
465 else
466 {
467 /* Trick so that frames are numbered north to south */
468 if( entry->nVertFrames-1 < frameRow )
469 {
470 CPLError(CE_Failure, CPLE_FileIO, "Invalid nVertFrames vs frameRow");
471 RPFTOCFree(toc);
472 return nullptr;
473 }
474 frameRow = (unsigned short)((entry->nVertFrames-1) - frameRow);
475 }
476
477 if (frameRow >= entry->nVertFrames)
478 {
479 CPLError( CE_Failure, CPLE_NotSupported,
480 "Invalid TOC file. Bad row num (%d) for frame file index %d.",
481 frameRow, i);
482 RPFTOCFree(toc);
483 return nullptr;
484 }
485
486 if (frameCol >= entry->nHorizFrames)
487 {
488 CPLError( CE_Failure, CPLE_NotSupported,
489 "Invalid TOC file. Bad col num (%d) for frame file index %d.",
490 frameCol, i);
491 RPFTOCFree(toc);
492 return nullptr;
493 }
494
495 RPFTocFrameEntry* frameEntry
496 = &entry->frameEntries[frameRow * entry->nHorizFrames + frameCol ];
497 frameEntry->frameRow = frameRow;
498 frameEntry->frameCol = frameCol;
499
500 if (frameEntry->exists)
501 {
502 CPLError( CE_Warning, CPLE_AppDefined,
503 "Frame entry(%d,%d) for frame file index %d was already found.",
504 frameRow, frameCol, i);
505 CPLFree(frameEntry->directory);
506 frameEntry->directory = nullptr;
507 CPLFree(frameEntry->fullFilePath);
508 frameEntry->fullFilePath = nullptr;
509 frameEntry->exists = 0;
510 }
511
512 unsigned int offsetFrameFilePathName;
513 bOK &= VSIFReadL( &offsetFrameFilePathName, sizeof(offsetFrameFilePathName), 1, fp) == 1;
514 CPL_MSBPTR32( &offsetFrameFilePathName );
515
516 bOK &= VSIFReadL( frameEntry->filename, 1, 12, fp) == 12;
517 if( !bOK )
518 {
519 CPLError(CE_Failure, CPLE_FileIO, "I/O error");
520 RPFTOCFree(toc);
521 return nullptr;
522 }
523 frameEntry->filename[12] = '\0';
524 bOK &= strlen(frameEntry->filename) > 0;
525
526 /* Check if the filename is an overview or legend */
527 for( int j = 0; j < 12; j++ )
528 {
529 if (strcmp(&(frameEntry->filename[j]),".OVR") == 0 ||
530 strcmp(&(frameEntry->filename[j]),".ovr") == 0 ||
531 strcmp(&(frameEntry->filename[j]),".LGD") == 0 ||
532 strcmp(&(frameEntry->filename[j]),".lgd") == 0)
533 {
534 entry->isOverviewOrLegend = TRUE;
535 break;
536 }
537 }
538
539 /* Extract series code */
540 if (entry->seriesAbbreviation == nullptr)
541 {
542 const NITFSeries* series = NITFGetSeriesInfo(frameEntry->filename);
543 if (series)
544 {
545 entry->seriesAbbreviation = series->abbreviation;
546 entry->seriesName = series->name;
547 }
548 }
549
550 /* Get file geo reference */
551 bOK &= VSIFReadL( frameEntry->georef, 1, 6, fp) == 6;
552 frameEntry->georef[6] = '\0';
553
554 /* Go to start of pathname record */
555 /* New path_off offset from start of frame file index section of TOC?? */
556 /* Add pathoffset wrt frame file index table subsection (loc[3]) */
557 if( !bOK || VSIFSeekL( fp, static_cast<vsi_l_offset>(frameFileIndexSubsectionPhysIndex) + offsetFrameFilePathName, SEEK_SET ) != 0)
558 {
559 CPLError( CE_Failure, CPLE_NotSupported,
560 "Invalid TOC file. Unable to seek to "
561 "frameFileIndexSubsectionPhysIndex + "
562 "offsetFrameFilePathName(%d) at offset " CPL_FRMT_GUIB ".",
563 i, static_cast<GUIntBig>(frameFileIndexSubsectionPhysIndex) + offsetFrameFilePathName);
564 RPFTOCFree(toc);
565 return nullptr;
566 }
567
568 unsigned short pathLength;
569 bOK &= VSIFReadL( &pathLength, sizeof(pathLength), 1, fp) == 1;
570 CPL_MSBPTR16( &pathLength );
571
572 /* if nFrameFileIndexRecords == 65535 and pathLength == 65535 for each record,
573 this leads to 4 GB allocation... Protect against this case */
574 if (!bOK || pathLength == 0 || pathLength > 256)
575 {
576 CPLError( CE_Failure, CPLE_NotSupported,
577 "Path length is invalid : %d. Probably corrupted TOC file.",
578 static_cast<int>( pathLength ) );
579 RPFTOCFree(toc);
580 return nullptr;
581 }
582
583 frameEntry->directory = reinterpret_cast<char *>( CPLMalloc(pathLength+1) );
584 bOK &= VSIFReadL( frameEntry->directory, 1, pathLength, fp) == pathLength;
585 if( !bOK )
586 {
587 CPLError(CE_Failure, CPLE_FileIO, "I/O error");
588 RPFTOCFree(toc);
589 return nullptr;
590 }
591 frameEntry->directory[pathLength] = 0;
592 if (frameEntry->directory[pathLength-1] == '/')
593 frameEntry->directory[pathLength-1] = 0;
594
595 if (frameEntry->directory[0] == '.' && frameEntry->directory[1] == '/')
596 {
597 memmove(frameEntry->directory, frameEntry->directory+2, strlen(frameEntry->directory+2)+1);
598
599 // Some A.TOC have subdirectory names like ".//X/" ... (#5979)
600 // Check if it was not intended to be "./X/" instead.
601 VSIStatBufL sStatBuf;
602 if( frameEntry->directory[0] == '/' &&
603 VSIStatL(CPLFormFilename(CPLGetDirname(pszFilename), frameEntry->directory+1, nullptr), &sStatBuf) == 0 &&
604 VSI_ISDIR(sStatBuf.st_mode) )
605 {
606 memmove(frameEntry->directory, frameEntry->directory+1, strlen(frameEntry->directory+1)+1);
607 }
608 }
609
610 {
611 char* baseDir = CPLStrdup(CPLGetDirname(pszFilename));
612 VSIStatBufL sStatBuf;
613 char* subdir = nullptr;
614 if (CPLIsFilenameRelative(frameEntry->directory) == FALSE)
615 subdir = CPLStrdup(frameEntry->directory);
616 else if (frameEntry->directory[0] == '.' && frameEntry->directory[1] == 0)
617 subdir = CPLStrdup(baseDir);
618 else
619 subdir = CPLStrdup(CPLFormFilename(baseDir, frameEntry->directory, nullptr));
620 #if !defined(_WIN32) && !defined(_WIN32_CE)
621 if( VSIStatL( subdir, &sStatBuf ) != 0 && strlen(subdir) > strlen(baseDir) && subdir[strlen(baseDir)] != 0)
622 {
623 char* c = subdir + strlen(baseDir)+1;
624 while(*c)
625 {
626 if (*c >= 'A' && *c <= 'Z')
627 *c += 'a' - 'A';
628 c++;
629 }
630 }
631 #endif
632 frameEntry->fullFilePath = CPLStrdup(CPLFormFilename(
633 subdir,
634 frameEntry->filename, nullptr));
635 if( VSIStatL( frameEntry->fullFilePath, &sStatBuf ) != 0 )
636 {
637 #if !defined(_WIN32) && !defined(_WIN32_CE)
638 if( strlen(frameEntry->fullFilePath) > strlen(subdir) )
639 {
640 char* c = frameEntry->fullFilePath + strlen(subdir)+1;
641 while(*c)
642 {
643 if (*c >= 'A' && *c <= 'Z')
644 *c += 'a' - 'A';
645 c++;
646 }
647 }
648 if( VSIStatL( frameEntry->fullFilePath, &sStatBuf ) != 0 )
649 #endif
650 {
651 frameEntry->fileExists = 0;
652 CPLError( CE_Warning, CPLE_AppDefined,
653 "File %s does not exist.", frameEntry->fullFilePath );
654 }
655 #if !defined(_WIN32) && !defined(_WIN32_CE)
656 else
657 {
658 frameEntry->fileExists = 1;
659 }
660 #endif
661 }
662 else
663 {
664 frameEntry->fileExists = 1;
665 }
666 CPLFree(subdir);
667 CPLFree(baseDir);
668 }
669
670 CPLDebug("RPFTOC", "Entry %d : %s,%s (%d, %d)", boundaryId, frameEntry->directory, frameEntry->filename, frameRow, frameCol);
671
672 frameEntry->exists = 1;
673 }
674
675 return toc;
676 }
677
678 /************************************************************************/
679 /* RPFTOCFree() */
680 /************************************************************************/
681
RPFTOCFree(RPFToc * toc)682 void RPFTOCFree(RPFToc* toc)
683 {
684 if (!toc)
685 return;
686
687 for( int i = 0; i < toc->nEntries; i++ )
688 {
689 for( int j = 0;
690 j < static_cast<int>(toc->entries[i].nVertFrames
691 * toc->entries[i].nHorizFrames);
692 j++)
693 {
694 CPLFree(toc->entries[i].frameEntries[j].fullFilePath);
695 CPLFree(toc->entries[i].frameEntries[j].directory);
696 }
697 CPLFree(toc->entries[i].frameEntries);
698 }
699
700 CPLFree(toc->entries);
701 CPLFree(toc);
702 }
703