Line data Source code
1 : /**********************************************************************
2 : *
3 : * Name: mitab_mapobjectblock.cpp
4 : * Project: MapInfo TAB Read/Write library
5 : * Language: C++
6 : * Purpose: Implementation of the TABMAPObjectBlock class used to handle
7 : * reading/writing of the .MAP files' object data blocks
8 : * Author: Daniel Morissette, dmorissette@dmsolutions.ca
9 : *
10 : **********************************************************************
11 : * Copyright (c) 1999-2001, Daniel Morissette
12 : * Copyright (c) 2014, Even Rouault <even.rouault at spatialys.com>
13 : *
14 : * SPDX-License-Identifier: MIT
15 : **********************************************************************/
16 :
17 : #include "cpl_port.h"
18 : #include "mitab.h"
19 :
20 : #include <algorithm>
21 : #include <limits.h>
22 : #include <stddef.h>
23 :
24 : #include "cpl_conv.h"
25 : #include "cpl_error.h"
26 : #include "cpl_vsi.h"
27 : #include "mitab_priv.h"
28 : #include "mitab_utils.h"
29 :
30 : /*=====================================================================
31 : * class TABMAPObjectBlock
32 : *====================================================================*/
33 :
34 : constexpr int MAP_OBJECT_HEADER_SIZE = 20;
35 :
36 : /**********************************************************************
37 : * TABMAPObjectBlock::TABMAPObjectBlock()
38 : *
39 : * Constructor.
40 : **********************************************************************/
41 39519 : TABMAPObjectBlock::TABMAPObjectBlock(TABAccess eAccessMode /*= TABRead*/)
42 : : TABRawBinBlock(eAccessMode, TRUE), m_numDataBytes(0),
43 : m_nFirstCoordBlock(0), m_nLastCoordBlock(0), m_nCenterX(0), m_nCenterY(0),
44 : m_nMinX(0), m_nMinY(0), m_nMaxX(0), m_nMaxY(0), m_nCurObjectOffset(0),
45 39519 : m_nCurObjectId(0), m_nCurObjectType(TAB_GEOM_UNSET), m_bLockCenter(FALSE)
46 : {
47 39519 : }
48 :
49 : /**********************************************************************
50 : * TABMAPObjectBlock::~TABMAPObjectBlock()
51 : *
52 : * Destructor.
53 : **********************************************************************/
54 118557 : TABMAPObjectBlock::~TABMAPObjectBlock()
55 : {
56 : // TODO(schwehr): Why set these? Should remove.
57 39519 : m_nMinX = 1000000000;
58 39519 : m_nMinY = 1000000000;
59 39519 : m_nMaxX = -1000000000;
60 39519 : m_nMaxY = -1000000000;
61 79038 : }
62 :
63 : /**********************************************************************
64 : * TABMAPObjectBlock::InitBlockFromData()
65 : *
66 : * Perform some initialization on the block after its binary data has
67 : * been set or changed (or loaded from a file).
68 : *
69 : * Returns 0 if successful or -1 if an error happened, in which case
70 : * CPLError() will have been called.
71 : **********************************************************************/
72 47657 : int TABMAPObjectBlock::InitBlockFromData(GByte *pabyBuf, int nBlockSize,
73 : int nSizeUsed,
74 : GBool bMakeCopy /* = TRUE */,
75 : VSILFILE *fpSrc /* = NULL */,
76 : int nOffset /* = 0 */)
77 : {
78 : /*-----------------------------------------------------------------
79 : * First of all, we must call the base class' InitBlockFromData()
80 : *----------------------------------------------------------------*/
81 47657 : const int nStatus = TABRawBinBlock::InitBlockFromData(
82 : pabyBuf, nBlockSize, nSizeUsed, bMakeCopy, fpSrc, nOffset);
83 47657 : if (nStatus != 0)
84 0 : return nStatus;
85 :
86 : /*-----------------------------------------------------------------
87 : * Validate block type
88 : *----------------------------------------------------------------*/
89 47657 : if (m_nBlockType != TABMAP_OBJECT_BLOCK)
90 : {
91 0 : CPLError(CE_Failure, CPLE_FileIO,
92 : "InitBlockFromData(): Invalid Block Type: got %d expected %d",
93 : m_nBlockType, TABMAP_OBJECT_BLOCK);
94 0 : CPLFree(m_pabyBuf);
95 0 : m_pabyBuf = nullptr;
96 0 : return -1;
97 : }
98 :
99 : /*-----------------------------------------------------------------
100 : * Init member variables
101 : *----------------------------------------------------------------*/
102 47657 : GotoByteInBlock(0x002);
103 47657 : m_numDataBytes = ReadInt16(); /* Excluding 4 bytes header */
104 47657 : if (m_numDataBytes < 0 ||
105 47657 : m_numDataBytes + MAP_OBJECT_HEADER_SIZE > nBlockSize)
106 : {
107 0 : CPLError(CE_Failure, CPLE_FileIO,
108 : "TABMAPObjectBlock::InitBlockFromData(): m_numDataBytes=%d "
109 : "incompatible with block size %d",
110 : m_numDataBytes, nBlockSize);
111 0 : CPLFree(m_pabyBuf);
112 0 : m_pabyBuf = nullptr;
113 0 : return -1;
114 : }
115 :
116 47657 : m_nCenterX = ReadInt32();
117 47657 : m_nCenterY = ReadInt32();
118 :
119 47657 : m_nFirstCoordBlock = ReadInt32();
120 47657 : m_nLastCoordBlock = ReadInt32();
121 :
122 47657 : m_nCurObjectOffset = -1;
123 47657 : m_nCurObjectId = -1;
124 47657 : m_nCurObjectType = TAB_GEOM_UNSET;
125 :
126 47657 : m_nMinX = 1000000000;
127 47657 : m_nMinY = 1000000000;
128 47657 : m_nMaxX = -1000000000;
129 47657 : m_nMaxY = -1000000000;
130 47657 : m_bLockCenter = FALSE;
131 :
132 : /*-----------------------------------------------------------------
133 : * Set real value for m_nSizeUsed to allow random update
134 : * (By default TABRawBinBlock thinks all bytes are used)
135 : *----------------------------------------------------------------*/
136 47657 : m_nSizeUsed = m_numDataBytes + MAP_OBJECT_HEADER_SIZE;
137 :
138 47657 : return 0;
139 : }
140 :
141 : /************************************************************************
142 : * ClearObjects()
143 : *
144 : * Cleans existing objects from the block. This method is used when
145 : * compacting a page that has deleted records.
146 : ************************************************************************/
147 272 : void TABMAPObjectBlock::ClearObjects()
148 : {
149 272 : GotoByteInBlock(MAP_OBJECT_HEADER_SIZE);
150 272 : WriteZeros(m_nBlockSize - MAP_OBJECT_HEADER_SIZE);
151 272 : GotoByteInBlock(MAP_OBJECT_HEADER_SIZE);
152 272 : m_nSizeUsed = MAP_OBJECT_HEADER_SIZE;
153 272 : m_bModified = TRUE;
154 272 : }
155 :
156 : /************************************************************************
157 : * LockCenter()
158 : *
159 : * Prevents the m_nCenterX and m_nCenterY to be adjusted by other methods.
160 : * Useful when editing pages that have compressed geometries.
161 : * This is a bit band-aid. Proper support of compressed geometries should
162 : * handle center moves.
163 : ************************************************************************/
164 11815 : void TABMAPObjectBlock::LockCenter()
165 : {
166 11815 : m_bLockCenter = TRUE;
167 11815 : }
168 :
169 : /************************************************************************
170 : * SetCenterFromOtherBlock()
171 : *
172 : * Sets the m_nCenterX and m_nCenterY from the one of another block and
173 : * lock them. See LockCenter() as well.
174 : * Used when splitting a page.
175 : ************************************************************************/
176 253 : void TABMAPObjectBlock::SetCenterFromOtherBlock(
177 : TABMAPObjectBlock *poOtherObjBlock)
178 : {
179 253 : m_nCenterX = poOtherObjBlock->m_nCenterX;
180 253 : m_nCenterY = poOtherObjBlock->m_nCenterY;
181 253 : LockCenter();
182 253 : }
183 :
184 : /************************************************************************/
185 : /* Rewind() */
186 : /************************************************************************/
187 778 : void TABMAPObjectBlock::Rewind()
188 : {
189 778 : m_nCurObjectId = -1;
190 778 : m_nCurObjectOffset = -1;
191 778 : m_nCurObjectType = TAB_GEOM_UNSET;
192 778 : }
193 :
194 : /************************************************************************/
195 : /* AdvanceToNextObject() */
196 : /************************************************************************/
197 :
198 428085 : int TABMAPObjectBlock::AdvanceToNextObject(TABMAPHeaderBlock *poHeader)
199 :
200 : {
201 428085 : if (m_nCurObjectId == -1)
202 : {
203 15996 : m_nCurObjectOffset = 20;
204 : }
205 : else
206 : {
207 412089 : m_nCurObjectOffset += poHeader->GetMapObjectSize(m_nCurObjectType);
208 : }
209 :
210 428085 : if (m_nCurObjectOffset + 5 < m_numDataBytes + 20)
211 : {
212 412589 : GotoByteInBlock(m_nCurObjectOffset);
213 412589 : const GByte byVal = ReadByte();
214 412589 : if (TABMAPFile::IsValidObjType(byVal))
215 : {
216 412589 : m_nCurObjectType = static_cast<TABGeomType>(byVal);
217 : }
218 : else
219 : {
220 0 : CPLError(
221 : CE_Warning,
222 : static_cast<CPLErrorNum>(TAB_WarningFeatureTypeNotSupported),
223 : "Unsupported object type %d (0x%2.2x). Feature will be "
224 : "returned with NONE geometry.",
225 : byVal, byVal);
226 0 : m_nCurObjectType = TAB_GEOM_NONE;
227 : }
228 : }
229 : else
230 : {
231 15496 : m_nCurObjectType = TAB_GEOM_UNSET;
232 : }
233 :
234 428085 : if (m_nCurObjectType <= 0 || m_nCurObjectType >= TAB_GEOM_MAX_TYPE)
235 : {
236 15496 : m_nCurObjectType = TAB_GEOM_UNSET;
237 15496 : m_nCurObjectId = -1;
238 15496 : m_nCurObjectOffset = -1;
239 : }
240 : else
241 : {
242 412589 : m_nCurObjectId = ReadInt32();
243 :
244 : // Is this object marked as deleted? If so, skip it.
245 : // I check both the top bits but I have only seen this occur
246 : // with the second highest bit set (i.e. in usa/states.tab). NFW.
247 :
248 412589 : if ((static_cast<GUInt32>(m_nCurObjectId) & 0xC0000000U) != 0)
249 : {
250 15101 : m_nCurObjectId = AdvanceToNextObject(poHeader);
251 : }
252 : }
253 :
254 428085 : return m_nCurObjectId;
255 : }
256 :
257 : /**********************************************************************
258 : * TABMAPObjectBlock::CommitToFile()
259 : *
260 : * Commit the current state of the binary block to the file to which
261 : * it has been previously attached.
262 : *
263 : * This method makes sure all values are properly set in the map object
264 : * block header and then calls TABRawBinBlock::CommitToFile() to do
265 : * the actual writing to disk.
266 : *
267 : * Returns 0 if successful or -1 if an error happened, in which case
268 : * CPLError() will have been called.
269 : **********************************************************************/
270 17145 : int TABMAPObjectBlock::CommitToFile()
271 : {
272 17145 : if (m_pabyBuf == nullptr)
273 : {
274 0 : CPLError(CE_Failure, CPLE_AssertionFailed,
275 : "TABMAPObjectBlock::CommitToFile(): Block has not been "
276 : "initialized yet!");
277 0 : return -1;
278 : }
279 :
280 : /*-----------------------------------------------------------------
281 : * Nothing to do here if block has not been modified
282 : *----------------------------------------------------------------*/
283 17145 : if (!m_bModified)
284 390 : return 0;
285 :
286 : /*-----------------------------------------------------------------
287 : * Make sure 20 bytes block header is up to date.
288 : *----------------------------------------------------------------*/
289 16755 : GotoByteInBlock(0x000);
290 :
291 16755 : WriteInt16(TABMAP_OBJECT_BLOCK); // Block type code
292 16755 : m_numDataBytes = m_nSizeUsed - MAP_OBJECT_HEADER_SIZE;
293 16755 : CPLAssert(m_numDataBytes >= 0 && m_numDataBytes < 32768);
294 16755 : WriteInt16(static_cast<GInt16>(m_numDataBytes)); // num. bytes used
295 :
296 16755 : WriteInt32(m_nCenterX);
297 16755 : WriteInt32(m_nCenterY);
298 :
299 16755 : WriteInt32(m_nFirstCoordBlock);
300 16755 : WriteInt32(m_nLastCoordBlock);
301 :
302 16755 : int nStatus = CPLGetLastErrorType() == CE_Failure ? -1 : 0;
303 :
304 : /*-----------------------------------------------------------------
305 : * OK, all object data has already been written in the block.
306 : * Call the base class to write the block to disk.
307 : *----------------------------------------------------------------*/
308 16755 : if (nStatus == 0)
309 : {
310 : #ifdef DEBUG_VERBOSE
311 : CPLDebug("MITAB", "Committing OBJECT block to offset %d",
312 : m_nFileOffset);
313 : #endif
314 16755 : nStatus = TABRawBinBlock::CommitToFile();
315 : }
316 :
317 16755 : return nStatus;
318 : }
319 :
320 : /**********************************************************************
321 : * TABMAPObjectBlock::InitNewBlock()
322 : *
323 : * Initialize a newly created block so that it knows to which file it
324 : * is attached, its block size, etc . and then perform any specific
325 : * initialization for this block type, including writing a default
326 : * block header, etc. and leave the block ready to receive data.
327 : *
328 : * This is an alternative to calling ReadFromFile() or InitBlockFromData()
329 : * that puts the block in a stable state without loading any initial
330 : * data in it.
331 : *
332 : * Returns 0 if successful or -1 if an error happened, in which case
333 : * CPLError() will have been called.
334 : **********************************************************************/
335 1979 : int TABMAPObjectBlock::InitNewBlock(VSILFILE *fpSrc, int nBlockSize,
336 : int nFileOffset /* = 0*/)
337 : {
338 : /*-----------------------------------------------------------------
339 : * Start with the default initialization
340 : *----------------------------------------------------------------*/
341 1979 : if (TABRawBinBlock::InitNewBlock(fpSrc, nBlockSize, nFileOffset) != 0)
342 0 : return -1;
343 :
344 : /*-----------------------------------------------------------------
345 : * And then set default values for the block header.
346 : *----------------------------------------------------------------*/
347 : // Set block MBR to extreme values to force an update on the first
348 : // UpdateMBR() call.
349 1979 : m_nMinX = 1000000000;
350 1979 : m_nMaxX = -1000000000;
351 1979 : m_nMinY = 1000000000;
352 1979 : m_nMaxY = -1000000000;
353 :
354 : // Reset current object refs
355 1979 : m_nCurObjectId = -1;
356 1979 : m_nCurObjectOffset = -1;
357 1979 : m_nCurObjectType = TAB_GEOM_UNSET;
358 :
359 1979 : m_numDataBytes = 0; /* Data size excluding header */
360 1979 : m_nCenterX = 0;
361 1979 : m_nCenterY = 0;
362 1979 : m_nFirstCoordBlock = 0;
363 1979 : m_nLastCoordBlock = 0;
364 :
365 1979 : if (m_eAccess != TABRead && nFileOffset != 0)
366 : {
367 689 : GotoByteInBlock(0x000);
368 :
369 689 : WriteInt16(TABMAP_OBJECT_BLOCK); // Block type code
370 689 : WriteInt16(0); // num. bytes used, excluding header
371 :
372 : // MBR center here... will be written in CommitToFile()
373 689 : WriteInt32(0);
374 689 : WriteInt32(0);
375 :
376 : // First/last coord block ref... will be written in CommitToFile()
377 689 : WriteInt32(0);
378 689 : WriteInt32(0);
379 : }
380 :
381 1979 : if (CPLGetLastErrorType() == CE_Failure)
382 0 : return -1;
383 :
384 1979 : return 0;
385 : }
386 :
387 : /**********************************************************************
388 : * TABMAPObjectBlock::ReadCoord()
389 : *
390 : * Read the next pair of integer coordinates value from the block, and
391 : * apply the translation relative to to the center of the data block
392 : * if bCompressed=TRUE.
393 : *
394 : * This means that the returned coordinates are always absolute integer
395 : * coordinates, even when the source coords are in compressed form.
396 : *
397 : * Returns 0 if successful or -1 if an error happened, in which case
398 : * CPLError() will have been called.
399 : **********************************************************************/
400 546899 : int TABMAPObjectBlock::ReadIntCoord(GBool bCompressed, GInt32 &nX, GInt32 &nY)
401 : {
402 546899 : if (bCompressed)
403 : {
404 13822 : nX = ReadInt16();
405 13822 : nY = ReadInt16();
406 13822 : TABSaturatedAdd(nX, m_nCenterX);
407 13822 : TABSaturatedAdd(nY, m_nCenterY);
408 : }
409 : else
410 : {
411 533077 : nX = ReadInt32();
412 533077 : nY = ReadInt32();
413 : }
414 :
415 546899 : if (CPLGetLastErrorType() == CE_Failure)
416 0 : return -1;
417 :
418 546899 : return 0;
419 : }
420 :
421 : /**********************************************************************
422 : * TABMAPObjectBlock::WriteIntCoord()
423 : *
424 : * Write a pair of integer coordinates values to the current position in the
425 : * the block. If bCompr=TRUE then the coordinates are written relative to
426 : * the object block center... otherwise they're written as 32 bits int.
427 : *
428 : * This function does not maintain the block's MBR and center... it is
429 : * assumed to have been set before the first call to WriteIntCoord()
430 : *
431 : * Returns 0 if successful or -1 if an error happened, in which case
432 : * CPLError() will have been called.
433 : **********************************************************************/
434 25705 : int TABMAPObjectBlock::WriteIntCoord(GInt32 nX, GInt32 nY,
435 : GBool bCompressed /*=FALSE*/)
436 : {
437 :
438 : /*-----------------------------------------------------------------
439 : * Write coords to the file.
440 : *----------------------------------------------------------------*/
441 26370 : if ((!bCompressed && (WriteInt32(nX) != 0 || WriteInt32(nY) != 0)) ||
442 665 : (bCompressed &&
443 665 : (WriteInt16(static_cast<GInt16>(nX - m_nCenterX)) != 0 ||
444 665 : WriteInt16(static_cast<GInt16>(nY - m_nCenterY)) != 0)))
445 : {
446 0 : return -1;
447 : }
448 :
449 25705 : return 0;
450 : }
451 :
452 : /**********************************************************************
453 : * TABMAPObjectBlock::WriteIntMBRCoord()
454 : *
455 : * Write 2 pairs of integer coordinates values to the current position
456 : * in the block after making sure that min values are smaller than
457 : * max values. Use this function to write MBR coordinates for an object.
458 : *
459 : * If bCompr=TRUE then the coordinates are written relative to
460 : * the object block center... otherwise they're written as 32 bits int.
461 : *
462 : * This function does not maintain the block's MBR and center... it is
463 : * assumed to have been set before the first call to WriteIntCoord()
464 : *
465 : * Returns 0 if successful or -1 if an error happened, in which case
466 : * CPLError() will have been called.
467 : **********************************************************************/
468 4 : int TABMAPObjectBlock::WriteIntMBRCoord(GInt32 nXMin, GInt32 nYMin,
469 : GInt32 nXMax, GInt32 nYMax,
470 : GBool bCompressed /*=FALSE*/)
471 : {
472 4 : if (WriteIntCoord(std::min(nXMin, nXMax), std::min(nYMin, nYMax),
473 8 : bCompressed) != 0 ||
474 4 : WriteIntCoord(std::max(nXMin, nXMax), std::max(nYMin, nYMax),
475 : bCompressed) != 0)
476 : {
477 0 : return -1;
478 : }
479 :
480 4 : return 0;
481 : }
482 :
483 : /**********************************************************************
484 : * TABMAPObjectBlock::UpdateMBR()
485 : *
486 : * Update the block's MBR and center.
487 : *
488 : * Returns 0 if successful or -1 if an error happened, in which case
489 : * CPLError() will have been called.
490 : **********************************************************************/
491 52352 : int TABMAPObjectBlock::UpdateMBR(GInt32 nX, GInt32 nY)
492 : {
493 :
494 52352 : if (nX < m_nMinX)
495 1381 : m_nMinX = nX;
496 52352 : if (nX > m_nMaxX)
497 3680 : m_nMaxX = nX;
498 :
499 52352 : if (nY < m_nMinY)
500 1075 : m_nMinY = nY;
501 52352 : if (nY > m_nMaxY)
502 3400 : m_nMaxY = nY;
503 :
504 52352 : if (!m_bLockCenter)
505 : {
506 6918 : m_nCenterX =
507 6918 : static_cast<int>((static_cast<GIntBig>(m_nMinX) + m_nMaxX) / 2);
508 6918 : m_nCenterY =
509 6918 : static_cast<int>((static_cast<GIntBig>(m_nMinY) + m_nMaxY) / 2);
510 : }
511 :
512 52352 : return 0;
513 : }
514 :
515 : /**********************************************************************
516 : * TABMAPObjectBlock::AddCoordBlockRef()
517 : *
518 : * Update the first/last coord block fields in this object to contain
519 : * the specified block address.
520 : **********************************************************************/
521 766 : void TABMAPObjectBlock::AddCoordBlockRef(GInt32 nNewBlockAddress)
522 : {
523 : /*-----------------------------------------------------------------
524 : * Normally, new blocks are added to the end of the list, except
525 : * the first one which is the beginning and the end of the list at
526 : * the same time.
527 : *----------------------------------------------------------------*/
528 766 : if (m_nFirstCoordBlock == 0)
529 59 : m_nFirstCoordBlock = nNewBlockAddress;
530 :
531 766 : m_nLastCoordBlock = nNewBlockAddress;
532 766 : m_bModified = TRUE;
533 766 : }
534 :
535 : /**********************************************************************
536 : * TABMAPObjectBlock::SetMBR()
537 : *
538 : * Set the MBR for the current block.
539 : **********************************************************************/
540 48491 : void TABMAPObjectBlock::SetMBR(GInt32 nXMin, GInt32 nYMin, GInt32 nXMax,
541 : GInt32 nYMax)
542 : {
543 48491 : m_nMinX = nXMin;
544 48491 : m_nMinY = nYMin;
545 48491 : m_nMaxX = nXMax;
546 48491 : m_nMaxY = nYMax;
547 :
548 48491 : if (!m_bLockCenter)
549 : {
550 3471 : m_nCenterX =
551 3471 : static_cast<int>((static_cast<GIntBig>(m_nMinX) + m_nMaxX) / 2);
552 3471 : m_nCenterY =
553 3471 : static_cast<int>((static_cast<GIntBig>(m_nMinY) + m_nMaxY) / 2);
554 : }
555 48491 : }
556 :
557 : /**********************************************************************
558 : * TABMAPObjectBlock::GetMBR()
559 : *
560 : * Return the MBR for the current block.
561 : **********************************************************************/
562 66086 : void TABMAPObjectBlock::GetMBR(GInt32 &nXMin, GInt32 &nYMin, GInt32 &nXMax,
563 : GInt32 &nYMax)
564 : {
565 66086 : nXMin = m_nMinX;
566 66086 : nYMin = m_nMinY;
567 66086 : nXMax = m_nMaxX;
568 66086 : nYMax = m_nMaxY;
569 66086 : }
570 :
571 : /**********************************************************************
572 : * TABMAPObjectBlock::PrepareNewObject()
573 : *
574 : * Prepare this block to receive this new object. We only reserve space for
575 : * it in this call. Actual data will be written only when CommitNewObject()
576 : * is called.
577 : *
578 : * Returns the position at which the new object starts
579 : **********************************************************************/
580 26176 : int TABMAPObjectBlock::PrepareNewObject(TABMAPObjHdr *poObjHdr)
581 : {
582 26176 : int nStartAddress = 0;
583 :
584 : // Nothing to do for NONE objects
585 26176 : if (poObjHdr->m_nType == TAB_GEOM_NONE)
586 : {
587 0 : return 0;
588 : }
589 :
590 : // Maintain MBR of this object block.
591 26176 : UpdateMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY);
592 26176 : UpdateMBR(poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
593 :
594 : /*-----------------------------------------------------------------
595 : * Keep track of object type, ID and start address for use by
596 : * CommitNewObject()
597 : *----------------------------------------------------------------*/
598 26176 : nStartAddress = GetFirstUnusedByteOffset();
599 :
600 : // Backup MBR and bLockCenter as they will be reset by GotoByteInFile()
601 : // that will call InitBlockFromData()
602 : GInt32 nXMin, nYMin, nXMax, nYMax;
603 26176 : GetMBR(nXMin, nYMin, nXMax, nYMax);
604 26176 : int bLockCenter = m_bLockCenter;
605 26176 : GotoByteInFile(nStartAddress);
606 26176 : m_bLockCenter = bLockCenter;
607 26176 : SetMBR(nXMin, nYMin, nXMax, nYMax);
608 26176 : m_nCurObjectOffset = nStartAddress - GetStartAddress();
609 :
610 26176 : m_nCurObjectType = poObjHdr->m_nType;
611 26176 : m_nCurObjectId = poObjHdr->m_nId;
612 :
613 26176 : return nStartAddress;
614 : }
615 :
616 : /**********************************************************************
617 : * TABMAPObjectBlock::CommitCurObjData()
618 : *
619 : * Write the ObjHdr to this block. This is usually called after
620 : * PrepareNewObject() once all members of the ObjHdr have
621 : * been set.
622 : *
623 : * Returns 0 if successful or -1 if an error happened, in which case
624 : * CPLError() will have been called.
625 : **********************************************************************/
626 26176 : int TABMAPObjectBlock::CommitNewObject(TABMAPObjHdr *poObjHdr)
627 : {
628 26176 : int nStatus = 0;
629 :
630 26176 : CPLAssert(poObjHdr->m_nType != TAB_GEOM_NONE);
631 :
632 : // Nothing to do for NONE objects
633 26176 : if (poObjHdr->m_nType == TAB_GEOM_NONE)
634 : {
635 0 : return 0;
636 : }
637 :
638 26176 : CPLAssert(m_nCurObjectId == poObjHdr->m_nId);
639 26176 : GotoByteInBlock(m_nCurObjectOffset);
640 :
641 26176 : nStatus = poObjHdr->WriteObj(this);
642 :
643 26176 : if (nStatus == 0)
644 26176 : m_numDataBytes = m_nSizeUsed - MAP_OBJECT_HEADER_SIZE;
645 :
646 26176 : return nStatus;
647 : }
648 :
649 : /**********************************************************************
650 : * TABMAPObjectBlock::Dump()
651 : *
652 : * Dump block contents... available only in DEBUG mode.
653 : **********************************************************************/
654 : #ifdef DEBUG
655 :
656 0 : void TABMAPObjectBlock::Dump(FILE *fpOut, GBool bDetails)
657 : {
658 0 : CPLErrorReset();
659 :
660 0 : if (fpOut == nullptr)
661 0 : fpOut = stdout;
662 :
663 0 : fprintf(fpOut, "----- TABMAPObjectBlock::Dump() -----\n");
664 0 : if (m_pabyBuf == nullptr)
665 : {
666 0 : fprintf(fpOut, "Block has not been initialized yet.");
667 : }
668 : else
669 : {
670 0 : fprintf(fpOut, "Object Data Block (type %d) at offset %d.\n",
671 : m_nBlockType, m_nFileOffset);
672 0 : fprintf(fpOut, " m_numDataBytes = %d\n", m_numDataBytes);
673 0 : fprintf(fpOut, " m_nCenterX = %d\n", m_nCenterX);
674 0 : fprintf(fpOut, " m_nCenterY = %d\n", m_nCenterY);
675 0 : fprintf(fpOut, " m_nFirstCoordBlock = %d\n", m_nFirstCoordBlock);
676 0 : fprintf(fpOut, " m_nLastCoordBlock = %d\n", m_nLastCoordBlock);
677 : }
678 :
679 0 : if (bDetails)
680 : {
681 : /* We need the mapfile's header block */
682 : TABRawBinBlock *poBlock =
683 0 : TABCreateMAPBlockFromFile(m_fp, 0, m_nBlockSize);
684 0 : if (poBlock == nullptr ||
685 0 : poBlock->GetBlockClass() != TABMAP_HEADER_BLOCK)
686 : {
687 0 : CPLError(CE_Failure, CPLE_AssertionFailed,
688 : "Failed reading header block.");
689 0 : return;
690 : }
691 : TABMAPHeaderBlock *poHeader =
692 0 : cpl::down_cast<TABMAPHeaderBlock *>(poBlock);
693 :
694 0 : Rewind();
695 0 : TABMAPObjHdr *poObjHdr = nullptr;
696 0 : while ((poObjHdr = TABMAPObjHdr::ReadNextObj(this, poHeader)) !=
697 : nullptr)
698 : {
699 0 : fprintf(fpOut,
700 : " object id=%d, type=%d, offset=%d (%d), size=%d\n"
701 : " MBR=(%d, %d, %d, %d)\n",
702 0 : m_nCurObjectId, m_nCurObjectType, m_nCurObjectOffset,
703 0 : m_nFileOffset + m_nCurObjectOffset,
704 0 : poHeader->GetMapObjectSize(m_nCurObjectType),
705 : poObjHdr->m_nMinX, poObjHdr->m_nMinY, poObjHdr->m_nMaxX,
706 : poObjHdr->m_nMaxY);
707 0 : delete poObjHdr;
708 : }
709 :
710 0 : delete poHeader;
711 : }
712 :
713 0 : fflush(fpOut);
714 : }
715 :
716 : #endif // DEBUG
717 :
718 : /*=====================================================================
719 : * class TABMAPObjHdr and family
720 : *====================================================================*/
721 :
722 : /**********************************************************************
723 : * class TABMAPObjHdr
724 : *
725 : * Virtual base class... contains static methods used to allocate instance
726 : * of the derived classes.
727 : *
728 : **********************************************************************/
729 :
730 : /**********************************************************************
731 : * TABMAPObjHdr::NewObj()
732 : *
733 : * Alloc a new object of specified type or NULL for NONE types or if type
734 : * is not supported.
735 : **********************************************************************/
736 564335 : TABMAPObjHdr *TABMAPObjHdr::NewObj(TABGeomType nNewObjType, GInt32 nId /*=0*/)
737 : {
738 564335 : TABMAPObjHdr *poObj = nullptr;
739 :
740 564335 : switch (nNewObjType)
741 : {
742 214 : case TAB_GEOM_NONE:
743 214 : poObj = new TABMAPObjNone;
744 214 : break;
745 561452 : case TAB_GEOM_SYMBOL_C:
746 : case TAB_GEOM_SYMBOL:
747 561452 : poObj = new TABMAPObjPoint;
748 561452 : break;
749 8 : case TAB_GEOM_FONTSYMBOL_C:
750 : case TAB_GEOM_FONTSYMBOL:
751 8 : poObj = new TABMAPObjFontPoint;
752 8 : break;
753 8 : case TAB_GEOM_CUSTOMSYMBOL_C:
754 : case TAB_GEOM_CUSTOMSYMBOL:
755 8 : poObj = new TABMAPObjCustomPoint;
756 8 : break;
757 44 : case TAB_GEOM_LINE_C:
758 : case TAB_GEOM_LINE:
759 44 : poObj = new TABMAPObjLine;
760 44 : break;
761 2569 : case TAB_GEOM_PLINE_C:
762 : case TAB_GEOM_PLINE:
763 : case TAB_GEOM_REGION_C:
764 : case TAB_GEOM_REGION:
765 : case TAB_GEOM_MULTIPLINE_C:
766 : case TAB_GEOM_MULTIPLINE:
767 : case TAB_GEOM_V450_REGION_C:
768 : case TAB_GEOM_V450_REGION:
769 : case TAB_GEOM_V450_MULTIPLINE_C:
770 : case TAB_GEOM_V450_MULTIPLINE:
771 : case TAB_GEOM_V800_REGION_C:
772 : case TAB_GEOM_V800_REGION:
773 : case TAB_GEOM_V800_MULTIPLINE_C:
774 : case TAB_GEOM_V800_MULTIPLINE:
775 2569 : poObj = new TABMAPObjPLine;
776 2569 : break;
777 8 : case TAB_GEOM_ARC_C:
778 : case TAB_GEOM_ARC:
779 8 : poObj = new TABMAPObjArc;
780 8 : break;
781 12 : case TAB_GEOM_RECT_C:
782 : case TAB_GEOM_RECT:
783 : case TAB_GEOM_ROUNDRECT_C:
784 : case TAB_GEOM_ROUNDRECT:
785 : case TAB_GEOM_ELLIPSE_C:
786 : case TAB_GEOM_ELLIPSE:
787 12 : poObj = new TABMAPObjRectEllipse;
788 12 : break;
789 12 : case TAB_GEOM_TEXT_C:
790 : case TAB_GEOM_TEXT:
791 12 : poObj = new TABMAPObjText;
792 12 : break;
793 4 : case TAB_GEOM_MULTIPOINT_C:
794 : case TAB_GEOM_MULTIPOINT:
795 : case TAB_GEOM_V800_MULTIPOINT_C:
796 : case TAB_GEOM_V800_MULTIPOINT:
797 4 : poObj = new TABMAPObjMultiPoint;
798 4 : break;
799 4 : case TAB_GEOM_COLLECTION_C:
800 : case TAB_GEOM_COLLECTION:
801 : case TAB_GEOM_V800_COLLECTION_C:
802 : case TAB_GEOM_V800_COLLECTION:
803 4 : poObj = new TABMAPObjCollection();
804 4 : break;
805 0 : default:
806 0 : CPLError(CE_Failure, CPLE_AssertionFailed,
807 : "TABMAPObjHdr::NewObj(): Unsupported object type %d",
808 : nNewObjType);
809 : }
810 :
811 564335 : if (poObj)
812 : {
813 564335 : poObj->m_nType = nNewObjType;
814 564335 : poObj->m_nId = nId;
815 564335 : poObj->m_nMinX = poObj->m_nMinY = poObj->m_nMaxX = poObj->m_nMaxY = 0;
816 : }
817 :
818 564335 : return poObj;
819 : }
820 :
821 : /**********************************************************************
822 : * TABMAPObjHdr::ReadNextObj()
823 : *
824 : * Read next object in this block and allocate/init a new object for it
825 : * if successful.
826 : * Returns NULL in case of error or if we reached end of block.
827 : **********************************************************************/
828 20600 : TABMAPObjHdr *TABMAPObjHdr::ReadNextObj(TABMAPObjectBlock *poObjBlock,
829 : TABMAPHeaderBlock *poHeader)
830 : {
831 20600 : TABMAPObjHdr *poObjHdr = nullptr;
832 :
833 20600 : if (poObjBlock->AdvanceToNextObject(poHeader) != -1)
834 : {
835 19822 : poObjHdr = TABMAPObjHdr::NewObj(poObjBlock->GetCurObjectType());
836 39644 : if (poObjHdr &&
837 19822 : ((poObjHdr->m_nId = poObjBlock->GetCurObjectId()) == -1 ||
838 19822 : poObjHdr->ReadObj(poObjBlock) != 0))
839 : {
840 : // Failed reading object in block... an error was already produced
841 0 : delete poObjHdr;
842 0 : return nullptr;
843 : }
844 : }
845 :
846 20600 : return poObjHdr;
847 : }
848 :
849 : /**********************************************************************
850 : * TABMAPObjHdr::IsCompressedType()
851 : *
852 : * Returns TRUE if the current object type uses compressed coordinates
853 : * or FALSE otherwise.
854 : **********************************************************************/
855 580751 : GBool TABMAPObjHdr::IsCompressedType()
856 : {
857 : // Compressed types are 1, 4, 7, etc.
858 580751 : return (m_nType % 3) == 1 ? TRUE : FALSE;
859 : }
860 :
861 : /**********************************************************************
862 : * TABMAPObjHdr::WriteObjTypeAndId()
863 : *
864 : * Writetype+object id information... should be called only by the derived
865 : * classes' WriteObj() methods.
866 : *
867 : * Returns 0 on success, -1 on error.
868 : **********************************************************************/
869 26176 : int TABMAPObjHdr::WriteObjTypeAndId(TABMAPObjectBlock *poObjBlock)
870 : {
871 26176 : poObjBlock->WriteByte(static_cast<GByte>(m_nType));
872 26176 : return poObjBlock->WriteInt32(m_nId);
873 : }
874 :
875 : /**********************************************************************
876 : * TABMAPObjHdr::SetMBR()
877 : *
878 : **********************************************************************/
879 561987 : void TABMAPObjHdr::SetMBR(GInt32 nMinX, GInt32 nMinY, GInt32 nMaxX,
880 : GInt32 nMaxY)
881 : {
882 561987 : m_nMinX = std::min(nMinX, nMaxX);
883 561987 : m_nMinY = std::min(nMinY, nMaxY);
884 561987 : m_nMaxX = std::max(nMinX, nMaxX);
885 561987 : m_nMaxY = std::max(nMinY, nMaxY);
886 561987 : }
887 :
888 : /**********************************************************************
889 : * class TABMAPObjLine
890 : *
891 : * Applies to 2-points LINEs only
892 : **********************************************************************/
893 :
894 : /**********************************************************************
895 : * TABMAPObjLine::ReadObj()
896 : *
897 : * Read Object information starting after the object id which should
898 : * have been read by TABMAPObjHdr::ReadNextObj() already.
899 : * This function should be called only by TABMAPObjHdr::ReadNextObj().
900 : *
901 : * Returns 0 on success, -1 on error.
902 : **********************************************************************/
903 21 : int TABMAPObjLine::ReadObj(TABMAPObjectBlock *poObjBlock)
904 : {
905 21 : poObjBlock->ReadIntCoord(IsCompressedType(), m_nX1, m_nY1);
906 21 : poObjBlock->ReadIntCoord(IsCompressedType(), m_nX2, m_nY2);
907 :
908 21 : m_nPenId = poObjBlock->ReadByte(); // Pen index
909 :
910 21 : SetMBR(m_nX1, m_nY1, m_nX2, m_nY2);
911 :
912 21 : if (CPLGetLastErrorType() == CE_Failure)
913 0 : return -1;
914 :
915 21 : return 0;
916 : }
917 :
918 : /**********************************************************************
919 : * TABMAPObjLine::WriteObj()
920 : *
921 : * Write Object information with the type+object id
922 : *
923 : * Returns 0 on success, -1 on error.
924 : **********************************************************************/
925 23 : int TABMAPObjLine::WriteObj(TABMAPObjectBlock *poObjBlock)
926 : {
927 : // Write object type and id
928 23 : TABMAPObjHdr::WriteObjTypeAndId(poObjBlock);
929 :
930 23 : poObjBlock->WriteIntCoord(m_nX1, m_nY1, IsCompressedType());
931 23 : poObjBlock->WriteIntCoord(m_nX2, m_nY2, IsCompressedType());
932 :
933 23 : poObjBlock->WriteByte(m_nPenId); // Pen index
934 :
935 23 : if (CPLGetLastErrorType() == CE_Failure)
936 0 : return -1;
937 :
938 23 : return 0;
939 : }
940 :
941 : /**********************************************************************
942 : * class TABMAPObjPLine
943 : *
944 : * Applies to PLINE, MULTIPLINE and REGION object types
945 : **********************************************************************/
946 :
947 : /**********************************************************************
948 : * TABMAPObjPLine::ReadObj()
949 : *
950 : * Read Object information starting after the object id which should
951 : * have been read by TABMAPObjHdr::ReadNextObj() already.
952 : * This function should be called only by TABMAPObjHdr::ReadNextObj().
953 : *
954 : * Returns 0 on success, -1 on error.
955 : **********************************************************************/
956 2266 : int TABMAPObjPLine::ReadObj(TABMAPObjectBlock *poObjBlock)
957 : {
958 2266 : m_nCoordBlockPtr = poObjBlock->ReadInt32();
959 2266 : m_nCoordDataSize = poObjBlock->ReadInt32();
960 :
961 2266 : if (m_nCoordDataSize & 0x80000000)
962 : {
963 4 : m_bSmooth = TRUE;
964 4 : m_nCoordDataSize &= 0x7FFFFFFF; // Take smooth flag out of the value
965 : }
966 : else
967 : {
968 2262 : m_bSmooth = FALSE;
969 : }
970 :
971 : #ifdef TABDUMP
972 : printf("TABMAPObjPLine::ReadObj: m_nCoordDataSize = %d @ %d\n", /*ok*/
973 : m_nCoordDataSize, m_nCoordBlockPtr);
974 : #endif
975 :
976 : // Number of line segments applies only to MULTIPLINE/REGION but not PLINE
977 2266 : if (m_nType == TAB_GEOM_PLINE_C || m_nType == TAB_GEOM_PLINE)
978 : {
979 1741 : m_numLineSections = 1;
980 : }
981 525 : else if (m_nType == TAB_GEOM_V800_REGION ||
982 525 : m_nType == TAB_GEOM_V800_REGION_C ||
983 525 : m_nType == TAB_GEOM_V800_MULTIPLINE ||
984 525 : m_nType == TAB_GEOM_V800_MULTIPLINE_C)
985 : {
986 : /* V800 REGIONS/MULTIPLINES use an int32 */
987 0 : m_numLineSections = poObjBlock->ReadInt32();
988 : /* ... followed by 33 unknown bytes */
989 0 : poObjBlock->ReadInt32();
990 0 : poObjBlock->ReadInt32();
991 0 : poObjBlock->ReadInt32();
992 0 : poObjBlock->ReadInt32();
993 0 : poObjBlock->ReadInt32();
994 0 : poObjBlock->ReadInt32();
995 0 : poObjBlock->ReadInt32();
996 0 : poObjBlock->ReadInt32();
997 0 : poObjBlock->ReadByte();
998 : }
999 : else
1000 : {
1001 : /* V300 and V450 REGIONS/MULTIPLINES use an int16 */
1002 525 : m_numLineSections = poObjBlock->ReadInt16();
1003 : }
1004 :
1005 2266 : if (m_numLineSections < 0)
1006 : {
1007 0 : CPLError(CE_Failure, CPLE_AssertionFailed, "Invalid numLineSections");
1008 0 : return -1;
1009 : }
1010 :
1011 : #ifdef TABDUMP
1012 : printf("PLINE/REGION: id=%d, type=%d, " /*ok*/
1013 : "CoordBlockPtr=%d, CoordDataSize=%d, numLineSect=%d, bSmooth=%d\n",
1014 : m_nId, m_nType, m_nCoordBlockPtr, m_nCoordDataSize,
1015 : m_numLineSections, m_bSmooth);
1016 : #endif
1017 :
1018 2266 : if (IsCompressedType())
1019 : {
1020 : // Region center/label point, relative to compr. coord. origin
1021 : // No it is not relative to the Object block center
1022 2205 : m_nLabelX = poObjBlock->ReadInt16();
1023 2205 : m_nLabelY = poObjBlock->ReadInt16();
1024 :
1025 : // Compressed coordinate origin (present only in compressed case!)
1026 2205 : m_nComprOrgX = poObjBlock->ReadInt32();
1027 2205 : m_nComprOrgY = poObjBlock->ReadInt32();
1028 :
1029 2205 : TABSaturatedAdd(m_nLabelX, m_nComprOrgX);
1030 2205 : TABSaturatedAdd(m_nLabelY, m_nComprOrgY);
1031 :
1032 2205 : m_nMinX = poObjBlock->ReadInt16(); // Read MBR
1033 2205 : m_nMinY = poObjBlock->ReadInt16();
1034 2205 : m_nMaxX = poObjBlock->ReadInt16();
1035 2205 : m_nMaxY = poObjBlock->ReadInt16();
1036 2205 : TABSaturatedAdd(m_nMinX, m_nComprOrgX);
1037 2205 : TABSaturatedAdd(m_nMinY, m_nComprOrgY);
1038 2205 : TABSaturatedAdd(m_nMaxX, m_nComprOrgX);
1039 2205 : TABSaturatedAdd(m_nMaxY, m_nComprOrgY);
1040 : }
1041 : else
1042 : {
1043 : // Region center/label point, relative to compr. coord. origin
1044 : // No it is not relative to the Object block center
1045 61 : m_nLabelX = poObjBlock->ReadInt32();
1046 61 : m_nLabelY = poObjBlock->ReadInt32();
1047 :
1048 61 : m_nMinX = poObjBlock->ReadInt32(); // Read MBR
1049 61 : m_nMinY = poObjBlock->ReadInt32();
1050 61 : m_nMaxX = poObjBlock->ReadInt32();
1051 61 : m_nMaxY = poObjBlock->ReadInt32();
1052 : }
1053 :
1054 2266 : if (!IsCompressedType())
1055 : {
1056 : // Init. Compr. Origin to a default value in case type is ever changed
1057 61 : m_nComprOrgX =
1058 61 : static_cast<GInt32>((static_cast<GIntBig>(m_nMinX) + m_nMaxX) / 2);
1059 61 : m_nComprOrgY =
1060 61 : static_cast<GInt32>((static_cast<GIntBig>(m_nMinY) + m_nMaxY) / 2);
1061 : }
1062 :
1063 2266 : m_nPenId = poObjBlock->ReadByte(); // Pen index
1064 :
1065 2266 : if (m_nType == TAB_GEOM_REGION || m_nType == TAB_GEOM_REGION_C ||
1066 1747 : m_nType == TAB_GEOM_V450_REGION || m_nType == TAB_GEOM_V450_REGION_C ||
1067 1747 : m_nType == TAB_GEOM_V800_REGION || m_nType == TAB_GEOM_V800_REGION_C)
1068 : {
1069 519 : m_nBrushId = poObjBlock->ReadByte(); // Brush index... REGION only
1070 : }
1071 : else
1072 : {
1073 1747 : m_nBrushId = 0;
1074 : }
1075 :
1076 2266 : if (CPLGetLastErrorType() == CE_Failure)
1077 0 : return -1;
1078 :
1079 2266 : return 0;
1080 : }
1081 :
1082 : /**********************************************************************
1083 : * TABMAPObjPLine::WriteObj()
1084 : *
1085 : * Write Object information with the type+object id
1086 : *
1087 : * Returns 0 on success, -1 on error.
1088 : **********************************************************************/
1089 502 : int TABMAPObjPLine::WriteObj(TABMAPObjectBlock *poObjBlock)
1090 : {
1091 : // Write object type and id
1092 502 : TABMAPObjHdr::WriteObjTypeAndId(poObjBlock);
1093 :
1094 502 : poObjBlock->WriteInt32(m_nCoordBlockPtr);
1095 :
1096 : // Combine smooth flag in the coord data size.
1097 502 : if (m_bSmooth)
1098 0 : poObjBlock->WriteInt32(m_nCoordDataSize | 0x80000000);
1099 : else
1100 502 : poObjBlock->WriteInt32(m_nCoordDataSize);
1101 :
1102 : // Number of line segments applies only to MULTIPLINE/REGION but not PLINE
1103 502 : if (m_nType == TAB_GEOM_V800_REGION || m_nType == TAB_GEOM_V800_REGION_C ||
1104 502 : m_nType == TAB_GEOM_V800_MULTIPLINE ||
1105 502 : m_nType == TAB_GEOM_V800_MULTIPLINE_C)
1106 : {
1107 : /* V800 REGIONS/MULTIPLINES use an int32 */
1108 0 : poObjBlock->WriteInt32(m_numLineSections);
1109 : /* ... followed by 33 unknown bytes */
1110 0 : poObjBlock->WriteZeros(33);
1111 : }
1112 502 : else if (m_nType != TAB_GEOM_PLINE_C && m_nType != TAB_GEOM_PLINE)
1113 : {
1114 : /* V300 and V450 REGIONS/MULTIPLINES use an int16 */
1115 105 : poObjBlock->WriteInt16(static_cast<GInt16>(m_numLineSections));
1116 : }
1117 :
1118 502 : if (IsCompressedType())
1119 : {
1120 : // Region center/label point, relative to compr. coord. origin
1121 : // No it is not relative to the Object block center
1122 492 : poObjBlock->WriteInt16(TABInt16Diff(m_nLabelX, m_nComprOrgX));
1123 492 : poObjBlock->WriteInt16(TABInt16Diff(m_nLabelY, m_nComprOrgY));
1124 :
1125 : // Compressed coordinate origin (present only in compressed case!)
1126 492 : poObjBlock->WriteInt32(m_nComprOrgX);
1127 492 : poObjBlock->WriteInt32(m_nComprOrgY);
1128 : }
1129 : else
1130 : {
1131 : // Region center/label point
1132 10 : poObjBlock->WriteInt32(m_nLabelX);
1133 10 : poObjBlock->WriteInt32(m_nLabelY);
1134 : }
1135 :
1136 : // MBR
1137 502 : if (IsCompressedType())
1138 : {
1139 : // MBR relative to PLINE origin (and not object block center)
1140 492 : poObjBlock->WriteInt16(TABInt16Diff(m_nMinX, m_nComprOrgX));
1141 492 : poObjBlock->WriteInt16(TABInt16Diff(m_nMinY, m_nComprOrgY));
1142 492 : poObjBlock->WriteInt16(TABInt16Diff(m_nMaxX, m_nComprOrgX));
1143 492 : poObjBlock->WriteInt16(TABInt16Diff(m_nMaxY, m_nComprOrgY));
1144 : }
1145 : else
1146 : {
1147 10 : poObjBlock->WriteInt32(m_nMinX);
1148 10 : poObjBlock->WriteInt32(m_nMinY);
1149 10 : poObjBlock->WriteInt32(m_nMaxX);
1150 10 : poObjBlock->WriteInt32(m_nMaxY);
1151 : }
1152 :
1153 502 : poObjBlock->WriteByte(m_nPenId); // Pen index
1154 :
1155 502 : if (m_nType == TAB_GEOM_REGION || m_nType == TAB_GEOM_REGION_C ||
1156 405 : m_nType == TAB_GEOM_V450_REGION || m_nType == TAB_GEOM_V450_REGION_C ||
1157 405 : m_nType == TAB_GEOM_V800_REGION || m_nType == TAB_GEOM_V800_REGION_C)
1158 : {
1159 97 : poObjBlock->WriteByte(m_nBrushId); // Brush index... REGION only
1160 : }
1161 :
1162 502 : if (CPLGetLastErrorType() == CE_Failure)
1163 0 : return -1;
1164 :
1165 502 : return 0;
1166 : }
1167 :
1168 : /**********************************************************************
1169 : * class TABMAPObjPoint
1170 : *
1171 : **********************************************************************/
1172 :
1173 : /**********************************************************************
1174 : * TABMAPObjPoint::ReadObj()
1175 : *
1176 : * Read Object information starting after the object id
1177 : **********************************************************************/
1178 546765 : int TABMAPObjPoint::ReadObj(TABMAPObjectBlock *poObjBlock)
1179 : {
1180 546765 : poObjBlock->ReadIntCoord(IsCompressedType(), m_nX, m_nY);
1181 :
1182 546765 : m_nSymbolId = poObjBlock->ReadByte(); // Symbol index
1183 :
1184 546765 : SetMBR(m_nX, m_nY, m_nX, m_nY);
1185 :
1186 546765 : if (CPLGetLastErrorType() == CE_Failure)
1187 0 : return -1;
1188 :
1189 546765 : return 0;
1190 : }
1191 :
1192 : /**********************************************************************
1193 : * TABMAPObjPoint::WriteObj()
1194 : *
1195 : * Write Object information with the type+object id
1196 : *
1197 : * Returns 0 on success, -1 on error.
1198 : **********************************************************************/
1199 25643 : int TABMAPObjPoint::WriteObj(TABMAPObjectBlock *poObjBlock)
1200 : {
1201 : // Write object type and id
1202 25643 : TABMAPObjHdr::WriteObjTypeAndId(poObjBlock);
1203 :
1204 25643 : poObjBlock->WriteIntCoord(m_nX, m_nY, IsCompressedType());
1205 :
1206 25643 : poObjBlock->WriteByte(m_nSymbolId); // Symbol index
1207 :
1208 25643 : if (CPLGetLastErrorType() == CE_Failure)
1209 0 : return -1;
1210 :
1211 25643 : return 0;
1212 : }
1213 :
1214 : /**********************************************************************
1215 : * class TABMAPObjFontPoint
1216 : *
1217 : **********************************************************************/
1218 :
1219 : /**********************************************************************
1220 : * TABMAPObjFontPoint::ReadObj()
1221 : *
1222 : * Read Object information starting after the object id
1223 : **********************************************************************/
1224 6 : int TABMAPObjFontPoint::ReadObj(TABMAPObjectBlock *poObjBlock)
1225 : {
1226 6 : m_nSymbolId = poObjBlock->ReadByte(); // Symbol index
1227 6 : m_nPointSize = poObjBlock->ReadByte();
1228 6 : m_nFontStyle = poObjBlock->ReadInt16(); // font style
1229 :
1230 6 : m_nR = poObjBlock->ReadByte();
1231 6 : m_nG = poObjBlock->ReadByte();
1232 6 : m_nB = poObjBlock->ReadByte();
1233 :
1234 6 : poObjBlock->ReadByte(); // ??? BG Color ???
1235 6 : poObjBlock->ReadByte(); // ???
1236 6 : poObjBlock->ReadByte(); // ???
1237 :
1238 6 : m_nAngle = poObjBlock->ReadInt16();
1239 :
1240 6 : poObjBlock->ReadIntCoord(IsCompressedType(), m_nX, m_nY);
1241 :
1242 6 : m_nFontId = poObjBlock->ReadByte(); // Font name index
1243 :
1244 6 : SetMBR(m_nX, m_nY, m_nX, m_nY);
1245 :
1246 6 : if (CPLGetLastErrorType() == CE_Failure)
1247 0 : return -1;
1248 :
1249 6 : return 0;
1250 : }
1251 :
1252 : /**********************************************************************
1253 : * TABMAPObjFontPoint::WriteObj()
1254 : *
1255 : * Write Object information with the type+object id
1256 : *
1257 : * Returns 0 on success, -1 on error.
1258 : **********************************************************************/
1259 2 : int TABMAPObjFontPoint::WriteObj(TABMAPObjectBlock *poObjBlock)
1260 : {
1261 : // Write object type and id
1262 2 : TABMAPObjHdr::WriteObjTypeAndId(poObjBlock);
1263 :
1264 2 : poObjBlock->WriteByte(m_nSymbolId); // symbol shape
1265 2 : poObjBlock->WriteByte(m_nPointSize);
1266 2 : poObjBlock->WriteInt16(m_nFontStyle); // font style
1267 :
1268 2 : poObjBlock->WriteByte(m_nR);
1269 2 : poObjBlock->WriteByte(m_nG);
1270 2 : poObjBlock->WriteByte(m_nB);
1271 :
1272 2 : poObjBlock->WriteByte(0);
1273 2 : poObjBlock->WriteByte(0);
1274 2 : poObjBlock->WriteByte(0);
1275 :
1276 2 : poObjBlock->WriteInt16(m_nAngle);
1277 :
1278 2 : poObjBlock->WriteIntCoord(m_nX, m_nY, IsCompressedType());
1279 :
1280 2 : poObjBlock->WriteByte(m_nFontId); // Font name index
1281 :
1282 2 : if (CPLGetLastErrorType() == CE_Failure)
1283 0 : return -1;
1284 :
1285 2 : return 0;
1286 : }
1287 :
1288 : /**********************************************************************
1289 : * class TABMAPObjCustomPoint
1290 : *
1291 : **********************************************************************/
1292 :
1293 : /**********************************************************************
1294 : * TABMAPObjCustomPoint::ReadObj()
1295 : *
1296 : * Read Object information starting after the object id
1297 : **********************************************************************/
1298 6 : int TABMAPObjCustomPoint::ReadObj(TABMAPObjectBlock *poObjBlock)
1299 : {
1300 6 : m_nUnknown_ = poObjBlock->ReadByte(); // ???
1301 6 : m_nCustomStyle = poObjBlock->ReadByte(); // 0x01=Show BG, 0x02=Apply Color
1302 :
1303 6 : poObjBlock->ReadIntCoord(IsCompressedType(), m_nX, m_nY);
1304 :
1305 6 : m_nSymbolId = poObjBlock->ReadByte(); // Symbol index
1306 6 : m_nFontId = poObjBlock->ReadByte(); // Font index
1307 :
1308 6 : SetMBR(m_nX, m_nY, m_nX, m_nY);
1309 :
1310 6 : if (CPLGetLastErrorType() == CE_Failure)
1311 0 : return -1;
1312 :
1313 6 : return 0;
1314 : }
1315 :
1316 : /**********************************************************************
1317 : * TABMAPObjCustomPoint::WriteObj()
1318 : *
1319 : * Write Object information with the type+object id
1320 : *
1321 : * Returns 0 on success, -1 on error.
1322 : **********************************************************************/
1323 2 : int TABMAPObjCustomPoint::WriteObj(TABMAPObjectBlock *poObjBlock)
1324 : {
1325 : // Write object type and id
1326 2 : TABMAPObjHdr::WriteObjTypeAndId(poObjBlock);
1327 :
1328 2 : poObjBlock->WriteByte(m_nUnknown_); // ???
1329 2 : poObjBlock->WriteByte(m_nCustomStyle); // 0x01=Show BG, 0x02=Apply Color
1330 2 : poObjBlock->WriteIntCoord(m_nX, m_nY, IsCompressedType());
1331 :
1332 2 : poObjBlock->WriteByte(m_nSymbolId); // Symbol index
1333 2 : poObjBlock->WriteByte(m_nFontId); // Font index
1334 :
1335 2 : if (CPLGetLastErrorType() == CE_Failure)
1336 0 : return -1;
1337 :
1338 2 : return 0;
1339 : }
1340 :
1341 : /**********************************************************************
1342 : * class TABMAPObjRectEllipse
1343 : *
1344 : **********************************************************************/
1345 :
1346 : /**********************************************************************
1347 : * TABMAPObjRectEllipse::ReadObj()
1348 : *
1349 : * Read Object information starting after the object id
1350 : **********************************************************************/
1351 12 : int TABMAPObjRectEllipse::ReadObj(TABMAPObjectBlock *poObjBlock)
1352 : {
1353 12 : if (m_nType == TAB_GEOM_ROUNDRECT || m_nType == TAB_GEOM_ROUNDRECT_C)
1354 : {
1355 4 : if (IsCompressedType())
1356 : {
1357 0 : m_nCornerWidth = poObjBlock->ReadInt16();
1358 0 : m_nCornerHeight = poObjBlock->ReadInt16();
1359 : }
1360 : else
1361 : {
1362 4 : m_nCornerWidth = poObjBlock->ReadInt32();
1363 4 : m_nCornerHeight = poObjBlock->ReadInt32();
1364 : }
1365 : }
1366 :
1367 12 : poObjBlock->ReadIntCoord(IsCompressedType(), m_nMinX, m_nMinY);
1368 12 : poObjBlock->ReadIntCoord(IsCompressedType(), m_nMaxX, m_nMaxY);
1369 :
1370 12 : m_nPenId = poObjBlock->ReadByte(); // Pen index
1371 12 : m_nBrushId = poObjBlock->ReadByte(); // Brush index
1372 :
1373 12 : if (CPLGetLastErrorType() == CE_Failure)
1374 0 : return -1;
1375 :
1376 12 : return 0;
1377 : }
1378 :
1379 : /**********************************************************************
1380 : * TABMAPObjRectEllipse::WriteObj()
1381 : *
1382 : * Write Object information with the type+object id
1383 : *
1384 : * Returns 0 on success, -1 on error.
1385 : **********************************************************************/
1386 0 : int TABMAPObjRectEllipse::WriteObj(TABMAPObjectBlock *poObjBlock)
1387 : {
1388 : // Write object type and id
1389 0 : TABMAPObjHdr::WriteObjTypeAndId(poObjBlock);
1390 :
1391 0 : if (m_nType == TAB_GEOM_ROUNDRECT || m_nType == TAB_GEOM_ROUNDRECT_C)
1392 : {
1393 0 : if (IsCompressedType())
1394 : {
1395 0 : poObjBlock->WriteInt16(static_cast<GInt16>(m_nCornerWidth));
1396 0 : poObjBlock->WriteInt16(static_cast<GInt16>(m_nCornerHeight));
1397 : }
1398 : else
1399 : {
1400 0 : poObjBlock->WriteInt32(m_nCornerWidth);
1401 0 : poObjBlock->WriteInt32(m_nCornerHeight);
1402 : }
1403 : }
1404 :
1405 0 : poObjBlock->WriteIntMBRCoord(m_nMinX, m_nMinY, m_nMaxX, m_nMaxY,
1406 : IsCompressedType());
1407 :
1408 0 : poObjBlock->WriteByte(m_nPenId); // Pen index
1409 0 : poObjBlock->WriteByte(m_nBrushId); // Brush index
1410 :
1411 0 : if (CPLGetLastErrorType() == CE_Failure)
1412 0 : return -1;
1413 :
1414 0 : return 0;
1415 : }
1416 :
1417 : /**********************************************************************
1418 : * class TABMAPObjArc
1419 : *
1420 : **********************************************************************/
1421 :
1422 : /**********************************************************************
1423 : * TABMAPObjArc::ReadObj()
1424 : *
1425 : * Read Object information starting after the object id
1426 : **********************************************************************/
1427 8 : int TABMAPObjArc::ReadObj(TABMAPObjectBlock *poObjBlock)
1428 : {
1429 8 : m_nStartAngle = poObjBlock->ReadInt16();
1430 8 : m_nEndAngle = poObjBlock->ReadInt16();
1431 :
1432 : // An arc is defined by its defining ellipse's MBR:
1433 8 : poObjBlock->ReadIntCoord(IsCompressedType(), m_nArcEllipseMinX,
1434 8 : m_nArcEllipseMinY);
1435 8 : poObjBlock->ReadIntCoord(IsCompressedType(), m_nArcEllipseMaxX,
1436 8 : m_nArcEllipseMaxY);
1437 :
1438 : // Read the Arc's actual MBR
1439 8 : poObjBlock->ReadIntCoord(IsCompressedType(), m_nMinX, m_nMinY);
1440 8 : poObjBlock->ReadIntCoord(IsCompressedType(), m_nMaxX, m_nMaxY);
1441 :
1442 8 : m_nPenId = poObjBlock->ReadByte(); // Pen index
1443 :
1444 8 : if (CPLGetLastErrorType() == CE_Failure)
1445 0 : return -1;
1446 :
1447 8 : return 0;
1448 : }
1449 :
1450 : /**********************************************************************
1451 : * TABMAPObjArc::WriteObj()
1452 : *
1453 : * Write Object information with the type+object id
1454 : *
1455 : * Returns 0 on success, -1 on error.
1456 : **********************************************************************/
1457 0 : int TABMAPObjArc::WriteObj(TABMAPObjectBlock *poObjBlock)
1458 : {
1459 : // Write object type and id
1460 0 : TABMAPObjHdr::WriteObjTypeAndId(poObjBlock);
1461 :
1462 0 : poObjBlock->WriteInt16(static_cast<GInt16>(m_nStartAngle));
1463 0 : poObjBlock->WriteInt16(static_cast<GInt16>(m_nEndAngle));
1464 :
1465 : // An arc is defined by its defining ellipse's MBR:
1466 0 : poObjBlock->WriteIntMBRCoord(m_nArcEllipseMinX, m_nArcEllipseMinY,
1467 : m_nArcEllipseMaxX, m_nArcEllipseMaxY,
1468 : IsCompressedType());
1469 :
1470 : // Write the Arc's actual MBR
1471 0 : poObjBlock->WriteIntMBRCoord(m_nMinX, m_nMinY, m_nMaxX, m_nMaxY,
1472 : IsCompressedType());
1473 :
1474 0 : poObjBlock->WriteByte(m_nPenId); // Pen index
1475 :
1476 0 : if (CPLGetLastErrorType() == CE_Failure)
1477 0 : return -1;
1478 :
1479 0 : return 0;
1480 : }
1481 :
1482 : /**********************************************************************
1483 : * class TABMAPObjText
1484 : *
1485 : **********************************************************************/
1486 :
1487 : /**********************************************************************
1488 : * TABMAPObjText::ReadObj()
1489 : *
1490 : * Read Object information starting after the object id
1491 : **********************************************************************/
1492 8 : int TABMAPObjText::ReadObj(TABMAPObjectBlock *poObjBlock)
1493 : {
1494 8 : m_nCoordBlockPtr = poObjBlock->ReadInt32(); // String position
1495 8 : m_nCoordDataSize = poObjBlock->ReadInt16(); // String length
1496 8 : if (m_nCoordDataSize < 0)
1497 : {
1498 0 : CPLError(CE_Failure, CPLE_AssertionFailed, "m_nCoordDataSize < 0");
1499 0 : return -1;
1500 : }
1501 8 : m_nTextAlignment = poObjBlock->ReadInt16(); // just./spacing/arrow
1502 :
1503 8 : m_nAngle = poObjBlock->ReadInt16(); // Tenths of degree
1504 :
1505 8 : m_nFontStyle = poObjBlock->ReadInt16(); // Font style/effect
1506 :
1507 8 : m_nFGColorR = poObjBlock->ReadByte();
1508 8 : m_nFGColorG = poObjBlock->ReadByte();
1509 8 : m_nFGColorB = poObjBlock->ReadByte();
1510 :
1511 8 : m_nBGColorR = poObjBlock->ReadByte();
1512 8 : m_nBGColorG = poObjBlock->ReadByte();
1513 8 : m_nBGColorB = poObjBlock->ReadByte();
1514 :
1515 : // Label line end point
1516 8 : poObjBlock->ReadIntCoord(IsCompressedType(), m_nLineEndX, m_nLineEndY);
1517 :
1518 : // Text Height
1519 8 : if (IsCompressedType())
1520 0 : m_nHeight = poObjBlock->ReadInt16();
1521 : else
1522 8 : m_nHeight = poObjBlock->ReadInt32();
1523 :
1524 : // Font name
1525 8 : m_nFontId = poObjBlock->ReadByte(); // Font name index
1526 :
1527 : // MBR after rotation
1528 8 : poObjBlock->ReadIntCoord(IsCompressedType(), m_nMinX, m_nMinY);
1529 8 : poObjBlock->ReadIntCoord(IsCompressedType(), m_nMaxX, m_nMaxY);
1530 :
1531 8 : m_nPenId = poObjBlock->ReadByte(); // Pen index
1532 :
1533 8 : if (CPLGetLastErrorType() == CE_Failure)
1534 0 : return -1;
1535 :
1536 8 : return 0;
1537 : }
1538 :
1539 : /**********************************************************************
1540 : * TABMAPObjText::WriteObj()
1541 : *
1542 : * Write Object information with the type+object id
1543 : *
1544 : * Returns 0 on success, -1 on error.
1545 : **********************************************************************/
1546 4 : int TABMAPObjText::WriteObj(TABMAPObjectBlock *poObjBlock)
1547 : {
1548 : // Write object type and id
1549 4 : TABMAPObjHdr::WriteObjTypeAndId(poObjBlock);
1550 :
1551 4 : poObjBlock->WriteInt32(m_nCoordBlockPtr); // String position
1552 4 : poObjBlock->WriteInt16(
1553 4 : static_cast<GInt16>(m_nCoordDataSize)); // String length
1554 4 : poObjBlock->WriteInt16(
1555 4 : static_cast<GInt16>(m_nTextAlignment)); // just./spacing/arrow
1556 :
1557 4 : poObjBlock->WriteInt16(static_cast<GInt16>(m_nAngle)); // Tenths of degree
1558 :
1559 4 : poObjBlock->WriteInt16(m_nFontStyle); // Font style/effect
1560 :
1561 4 : poObjBlock->WriteByte(m_nFGColorR);
1562 4 : poObjBlock->WriteByte(m_nFGColorG);
1563 4 : poObjBlock->WriteByte(m_nFGColorB);
1564 :
1565 4 : poObjBlock->WriteByte(m_nBGColorR);
1566 4 : poObjBlock->WriteByte(m_nBGColorG);
1567 4 : poObjBlock->WriteByte(m_nBGColorB);
1568 :
1569 : // Label line end point
1570 4 : poObjBlock->WriteIntCoord(m_nLineEndX, m_nLineEndY, IsCompressedType());
1571 :
1572 : // Text Height
1573 4 : if (IsCompressedType())
1574 0 : poObjBlock->WriteInt16(static_cast<GInt16>(m_nHeight));
1575 : else
1576 4 : poObjBlock->WriteInt32(m_nHeight);
1577 :
1578 : // Font name
1579 4 : poObjBlock->WriteByte(m_nFontId); // Font name index
1580 :
1581 : // MBR after rotation
1582 4 : poObjBlock->WriteIntMBRCoord(m_nMinX, m_nMinY, m_nMaxX, m_nMaxY,
1583 : IsCompressedType());
1584 :
1585 4 : poObjBlock->WriteByte(m_nPenId); // Pen index
1586 :
1587 4 : if (CPLGetLastErrorType() == CE_Failure)
1588 0 : return -1;
1589 :
1590 4 : return 0;
1591 : }
1592 :
1593 : /**********************************************************************
1594 : * class TABMAPObjMultiPoint
1595 : *
1596 : * Applies to PLINE, MULTIPLINE and REGION object types
1597 : **********************************************************************/
1598 :
1599 : /**********************************************************************
1600 : * TABMAPObjMultiPoint::ReadObj()
1601 : *
1602 : * Read Object information starting after the object id which should
1603 : * have been read by TABMAPObjHdr::ReadNextObj() already.
1604 : * This function should be called only by TABMAPObjHdr::ReadNextObj().
1605 : *
1606 : * Returns 0 on success, -1 on error.
1607 : **********************************************************************/
1608 4 : int TABMAPObjMultiPoint::ReadObj(TABMAPObjectBlock *poObjBlock)
1609 : {
1610 4 : m_nCoordBlockPtr = poObjBlock->ReadInt32();
1611 4 : m_nNumPoints = poObjBlock->ReadInt32();
1612 :
1613 4 : const int nPointSize = (IsCompressedType()) ? 2 * 2 : 2 * 4;
1614 4 : if (m_nNumPoints < 0 || m_nNumPoints > INT_MAX / nPointSize)
1615 : {
1616 0 : CPLError(CE_Failure, CPLE_AssertionFailed, "Invalid m_nNumPoints = %d",
1617 : m_nNumPoints);
1618 0 : return -1;
1619 : }
1620 4 : m_nCoordDataSize = m_nNumPoints * nPointSize;
1621 :
1622 : #ifdef TABDUMP
1623 : printf("MULTIPOINT: id=%d, type=%d, " /*ok*/
1624 : "CoordBlockPtr=%d, CoordDataSize=%d, numPoints=%d\n",
1625 : m_nId, m_nType, m_nCoordBlockPtr, m_nCoordDataSize, m_nNumPoints);
1626 : #endif
1627 :
1628 : // ?????
1629 4 : poObjBlock->ReadInt32();
1630 4 : poObjBlock->ReadInt32();
1631 4 : poObjBlock->ReadInt32();
1632 4 : poObjBlock->ReadByte();
1633 4 : poObjBlock->ReadByte();
1634 4 : poObjBlock->ReadByte();
1635 :
1636 4 : if (m_nType == TAB_GEOM_V800_MULTIPOINT ||
1637 4 : m_nType == TAB_GEOM_V800_MULTIPOINT_C)
1638 : {
1639 : /* V800 MULTIPOINTS have another 33 unknown bytes... all zeros */
1640 0 : poObjBlock->ReadInt32();
1641 0 : poObjBlock->ReadInt32();
1642 0 : poObjBlock->ReadInt32();
1643 0 : poObjBlock->ReadInt32();
1644 0 : poObjBlock->ReadInt32();
1645 0 : poObjBlock->ReadInt32();
1646 0 : poObjBlock->ReadInt32();
1647 0 : poObjBlock->ReadInt32();
1648 0 : poObjBlock->ReadByte();
1649 : }
1650 :
1651 4 : m_nSymbolId = poObjBlock->ReadByte();
1652 :
1653 : // ?????
1654 4 : poObjBlock->ReadByte();
1655 :
1656 4 : if (IsCompressedType())
1657 : {
1658 : // Region center/label point, relative to compr. coord. origin
1659 : // No it is not relative to the Object block center
1660 4 : m_nLabelX = poObjBlock->ReadInt16();
1661 4 : m_nLabelY = poObjBlock->ReadInt16();
1662 :
1663 : // Compressed coordinate origin
1664 4 : m_nComprOrgX = poObjBlock->ReadInt32();
1665 4 : m_nComprOrgY = poObjBlock->ReadInt32();
1666 :
1667 4 : TABSaturatedAdd(m_nLabelX, m_nComprOrgX);
1668 4 : TABSaturatedAdd(m_nLabelY, m_nComprOrgY);
1669 :
1670 4 : m_nMinX = poObjBlock->ReadInt16(); // Read MBR
1671 4 : m_nMinY = poObjBlock->ReadInt16();
1672 4 : m_nMaxX = poObjBlock->ReadInt16();
1673 4 : m_nMaxY = poObjBlock->ReadInt16();
1674 4 : TABSaturatedAdd(m_nMinX, m_nComprOrgX);
1675 4 : TABSaturatedAdd(m_nMinY, m_nComprOrgY);
1676 4 : TABSaturatedAdd(m_nMaxX, m_nComprOrgX);
1677 4 : TABSaturatedAdd(m_nMaxY, m_nComprOrgY);
1678 : }
1679 : else
1680 : {
1681 : // Region center/label point
1682 0 : m_nLabelX = poObjBlock->ReadInt32();
1683 0 : m_nLabelY = poObjBlock->ReadInt32();
1684 :
1685 0 : m_nMinX = poObjBlock->ReadInt32(); // Read MBR
1686 0 : m_nMinY = poObjBlock->ReadInt32();
1687 0 : m_nMaxX = poObjBlock->ReadInt32();
1688 0 : m_nMaxY = poObjBlock->ReadInt32();
1689 :
1690 : // Init. Compr. Origin to a default value in case type is ever changed
1691 0 : m_nComprOrgX =
1692 0 : static_cast<GInt32>((static_cast<GIntBig>(m_nMinX) + m_nMaxX) / 2);
1693 0 : m_nComprOrgY =
1694 0 : static_cast<GInt32>((static_cast<GIntBig>(m_nMinY) + m_nMaxY) / 2);
1695 : }
1696 :
1697 4 : if (CPLGetLastErrorType() == CE_Failure)
1698 0 : return -1;
1699 :
1700 4 : return 0;
1701 : }
1702 :
1703 : /**********************************************************************
1704 : * TABMAPObjMultiPoint::WriteObj()
1705 : *
1706 : * Write Object information with the type+object id
1707 : *
1708 : * Returns 0 on success, -1 on error.
1709 : **********************************************************************/
1710 0 : int TABMAPObjMultiPoint::WriteObj(TABMAPObjectBlock *poObjBlock)
1711 : {
1712 : // Write object type and id
1713 0 : TABMAPObjHdr::WriteObjTypeAndId(poObjBlock);
1714 :
1715 0 : poObjBlock->WriteInt32(m_nCoordBlockPtr);
1716 :
1717 : // Number of points
1718 0 : poObjBlock->WriteInt32(m_nNumPoints);
1719 :
1720 : // unknown bytes
1721 0 : poObjBlock->WriteZeros(15);
1722 :
1723 0 : if (m_nType == TAB_GEOM_V800_MULTIPOINT ||
1724 0 : m_nType == TAB_GEOM_V800_MULTIPOINT_C)
1725 : {
1726 : /* V800 MULTIPOINTS have another 33 unknown bytes... all zeros */
1727 0 : poObjBlock->WriteZeros(33);
1728 : }
1729 :
1730 : // Symbol Id
1731 0 : poObjBlock->WriteByte(m_nSymbolId);
1732 :
1733 : // ????
1734 0 : poObjBlock->WriteByte(0);
1735 :
1736 : // MBR
1737 0 : if (IsCompressedType())
1738 : {
1739 : // Region center/label point, relative to compr. coord. origin
1740 : // No it is not relative to the Object block center
1741 0 : poObjBlock->WriteInt16(TABInt16Diff(m_nLabelX, m_nComprOrgX));
1742 0 : poObjBlock->WriteInt16(TABInt16Diff(m_nLabelY, m_nComprOrgY));
1743 :
1744 0 : poObjBlock->WriteInt32(m_nComprOrgX);
1745 0 : poObjBlock->WriteInt32(m_nComprOrgY);
1746 :
1747 : // MBR relative to object origin (and not object block center)
1748 0 : poObjBlock->WriteInt16(TABInt16Diff(m_nMinX, m_nComprOrgX));
1749 0 : poObjBlock->WriteInt16(TABInt16Diff(m_nMinY, m_nComprOrgY));
1750 0 : poObjBlock->WriteInt16(TABInt16Diff(m_nMaxX, m_nComprOrgX));
1751 0 : poObjBlock->WriteInt16(TABInt16Diff(m_nMaxY, m_nComprOrgY));
1752 : }
1753 : else
1754 : {
1755 : // Region center/label point
1756 0 : poObjBlock->WriteInt32(m_nLabelX);
1757 0 : poObjBlock->WriteInt32(m_nLabelY);
1758 :
1759 0 : poObjBlock->WriteInt32(m_nMinX);
1760 0 : poObjBlock->WriteInt32(m_nMinY);
1761 0 : poObjBlock->WriteInt32(m_nMaxX);
1762 0 : poObjBlock->WriteInt32(m_nMaxY);
1763 : }
1764 :
1765 0 : if (CPLGetLastErrorType() == CE_Failure)
1766 0 : return -1;
1767 :
1768 0 : return 0;
1769 : }
1770 :
1771 : /**********************************************************************
1772 : * class TABMAPObjCollection
1773 : *
1774 : **********************************************************************/
1775 :
1776 : /**********************************************************************
1777 : * TABMAPObjCollection::ReadObj()
1778 : *
1779 : * Read Object information starting after the object id which should
1780 : * have been read by TABMAPObjHdr::ReadNextObj() already.
1781 : * This function should be called only by TABMAPObjHdr::ReadNextObj().
1782 : *
1783 : * Returns 0 on success, -1 on error.
1784 : **********************************************************************/
1785 4 : int TABMAPObjCollection::ReadObj(TABMAPObjectBlock *poObjBlock)
1786 : {
1787 4 : int SIZE_OF_REGION_PLINE_MINI_HDR = 24, SIZE_OF_MPOINT_MINI_HDR = 24;
1788 4 : int nVersion = TAB_GEOM_GET_VERSION(m_nType);
1789 :
1790 : /* Figure the size of the mini-header that we find for each of the
1791 : * 3 optional components (center x,y and mbr)
1792 : */
1793 4 : if (IsCompressedType())
1794 : {
1795 : /* 6 * int16 */
1796 4 : SIZE_OF_REGION_PLINE_MINI_HDR = SIZE_OF_MPOINT_MINI_HDR = 12;
1797 : }
1798 : else
1799 : {
1800 : /* 6 * int32 */
1801 0 : SIZE_OF_REGION_PLINE_MINI_HDR = SIZE_OF_MPOINT_MINI_HDR = 24;
1802 : }
1803 :
1804 4 : if (nVersion >= 800)
1805 : {
1806 : /* extra 4 bytes for num_segments in Region/Pline mini-headers */
1807 0 : SIZE_OF_REGION_PLINE_MINI_HDR += 4;
1808 : }
1809 :
1810 4 : m_nCoordBlockPtr = poObjBlock->ReadInt32(); // pointer into coord block
1811 4 : m_nNumMultiPoints = poObjBlock->ReadInt32(); // no. points in multi point
1812 4 : m_nRegionDataSize =
1813 4 : poObjBlock->ReadInt32(); // size of region data inc. section hdrs
1814 4 : m_nPolylineDataSize =
1815 4 : poObjBlock->ReadInt32(); // size of multipline data inc. section hdrs
1816 :
1817 4 : if (m_nRegionDataSize < 0)
1818 : {
1819 0 : CPLError(CE_Failure, CPLE_AssertionFailed, "Invalid m_nRegionDataSize");
1820 0 : return -1;
1821 : }
1822 :
1823 4 : if (m_nPolylineDataSize < 0)
1824 : {
1825 0 : CPLError(CE_Failure, CPLE_AssertionFailed, "Invalid m_nRegionDataSize");
1826 0 : return -1;
1827 : }
1828 :
1829 4 : if (nVersion < 800)
1830 : {
1831 : // Num Region/Pline section headers (int16 in V650)
1832 4 : m_nNumRegSections = poObjBlock->ReadInt16();
1833 4 : m_nNumPLineSections = poObjBlock->ReadInt16();
1834 : }
1835 : else
1836 : {
1837 : // Num Region/Pline section headers (int32 in V800)
1838 0 : m_nNumRegSections = poObjBlock->ReadInt32();
1839 0 : m_nNumPLineSections = poObjBlock->ReadInt32();
1840 : }
1841 :
1842 4 : const int nPointSize = (IsCompressedType()) ? 2 * 2 : 2 * 4;
1843 4 : if (m_nNumMultiPoints < 0 || m_nNumMultiPoints > INT_MAX / nPointSize)
1844 : {
1845 0 : CPLError(CE_Failure, CPLE_AssertionFailed, "Invalid m_nNumMultiPoints");
1846 0 : return -1;
1847 : }
1848 :
1849 4 : m_nMPointDataSize = m_nNumMultiPoints * nPointSize;
1850 :
1851 : /* NB. MapInfo counts 2 extra bytes per Region and Pline section header
1852 : * in the RegionDataSize and PolylineDataSize values but those 2 extra
1853 : * bytes are not present in the section hdr (possibly due to an alignment
1854 : * to a 4 byte boundary in memory in MapInfo?). The real data size in
1855 : * the CoordBlock is actually 2 bytes shorter per section header than
1856 : * what is written in RegionDataSize and PolylineDataSize values.
1857 : *
1858 : * We'll adjust the values in memory to be the corrected values.
1859 : */
1860 4 : if (m_nNumRegSections < 0 || m_nNumRegSections > INT_MAX / 2 ||
1861 4 : m_nRegionDataSize < 2 * m_nNumRegSections)
1862 : {
1863 0 : CPLError(CE_Failure, CPLE_AssertionFailed,
1864 : "Invalid m_nNumRegSections / m_nRegionDataSize");
1865 0 : return -1;
1866 : }
1867 4 : m_nRegionDataSize = m_nRegionDataSize - (2 * m_nNumRegSections);
1868 :
1869 4 : if (m_nNumPLineSections < 0 || m_nNumPLineSections > INT_MAX / 2 ||
1870 4 : m_nPolylineDataSize < 2 * m_nNumPLineSections)
1871 : {
1872 0 : CPLError(CE_Failure, CPLE_AssertionFailed,
1873 : "Invalid m_nNumPLineSections / m_nPolylineDataSize");
1874 0 : return -1;
1875 : }
1876 4 : m_nPolylineDataSize = m_nPolylineDataSize - (2 * m_nNumPLineSections);
1877 :
1878 : /* Compute total coord block data size, required when splitting blocks */
1879 4 : m_nCoordDataSize = 0;
1880 :
1881 4 : if (m_nNumRegSections > 0)
1882 : {
1883 4 : if (m_nRegionDataSize > INT_MAX - SIZE_OF_REGION_PLINE_MINI_HDR ||
1884 4 : m_nCoordDataSize >
1885 4 : INT_MAX - (SIZE_OF_REGION_PLINE_MINI_HDR + m_nRegionDataSize))
1886 : {
1887 0 : CPLError(CE_Failure, CPLE_AssertionFailed,
1888 : "Invalid m_nCoordDataSize / m_nRegionDataSize");
1889 0 : return -1;
1890 : }
1891 4 : m_nCoordDataSize += SIZE_OF_REGION_PLINE_MINI_HDR + m_nRegionDataSize;
1892 : }
1893 4 : if (m_nNumPLineSections > 0)
1894 : {
1895 4 : if (m_nPolylineDataSize > INT_MAX - SIZE_OF_REGION_PLINE_MINI_HDR ||
1896 4 : m_nCoordDataSize >
1897 4 : INT_MAX - (SIZE_OF_REGION_PLINE_MINI_HDR + m_nPolylineDataSize))
1898 : {
1899 0 : CPLError(CE_Failure, CPLE_AssertionFailed,
1900 : "Invalid m_nCoordDataSize / m_nPolylineDataSize");
1901 0 : return -1;
1902 : }
1903 4 : m_nCoordDataSize += SIZE_OF_REGION_PLINE_MINI_HDR + m_nPolylineDataSize;
1904 : }
1905 4 : if (m_nNumMultiPoints > 0)
1906 : {
1907 4 : if (m_nMPointDataSize > INT_MAX - SIZE_OF_MPOINT_MINI_HDR ||
1908 4 : m_nCoordDataSize >
1909 4 : INT_MAX - (SIZE_OF_MPOINT_MINI_HDR + m_nMPointDataSize))
1910 : {
1911 0 : CPLError(CE_Failure, CPLE_AssertionFailed,
1912 : "Invalid m_nCoordDataSize / m_nMPointDataSize");
1913 0 : return -1;
1914 : }
1915 4 : m_nCoordDataSize += SIZE_OF_MPOINT_MINI_HDR + m_nMPointDataSize;
1916 : }
1917 :
1918 : #ifdef TABDUMP
1919 : printf("COLLECTION: id=%d, type=%d (0x%x), " /*ok*/
1920 : "CoordBlockPtr=%d, numRegionSections=%d (size=%d+%d), "
1921 : "numPlineSections=%d (size=%d+%d), numPoints=%d (size=%d+%d)\n",
1922 : m_nId, m_nType, m_nType, m_nCoordBlockPtr, m_nNumRegSections,
1923 : m_nRegionDataSize, SIZE_OF_REGION_PLINE_MINI_HDR,
1924 : m_nNumPLineSections, m_nPolylineDataSize,
1925 : SIZE_OF_REGION_PLINE_MINI_HDR, m_nNumMultiPoints, m_nMPointDataSize,
1926 : SIZE_OF_MPOINT_MINI_HDR);
1927 : #endif
1928 :
1929 4 : if (nVersion >= 800)
1930 : {
1931 : // Extra byte in V800 files... value always 4???
1932 0 : int nValue = poObjBlock->ReadByte();
1933 0 : if (nValue != 4)
1934 : {
1935 0 : CPLError(CE_Failure, CPLE_AssertionFailed,
1936 : "TABMAPObjCollection::ReadObj(): Byte 29 in Collection "
1937 : "object header not equal to 4 as expected. Value is %d. "
1938 : "Please report this error to the MITAB list so that "
1939 : "MITAB can be extended to support this case.",
1940 : nValue);
1941 : // We don't return right away, the error should be caught at the
1942 : // end of this function.
1943 : }
1944 : }
1945 :
1946 : // ??? All zeros ???
1947 4 : poObjBlock->ReadInt32();
1948 4 : poObjBlock->ReadInt32();
1949 4 : poObjBlock->ReadInt32();
1950 4 : poObjBlock->ReadByte();
1951 4 : poObjBlock->ReadByte();
1952 4 : poObjBlock->ReadByte();
1953 :
1954 4 : m_nMultiPointSymbolId = poObjBlock->ReadByte();
1955 :
1956 4 : poObjBlock->ReadByte(); // ???
1957 4 : m_nRegionPenId = poObjBlock->ReadByte();
1958 4 : m_nPolylinePenId = poObjBlock->ReadByte();
1959 4 : m_nRegionBrushId = poObjBlock->ReadByte();
1960 :
1961 4 : if (IsCompressedType())
1962 : {
1963 : #ifdef TABDUMP
1964 : printf("COLLECTION: READING ComprOrg @ %d\n", /*ok*/
1965 : poObjBlock->GetCurAddress());
1966 : #endif
1967 : // Compressed coordinate origin
1968 4 : m_nComprOrgX = poObjBlock->ReadInt32();
1969 4 : m_nComprOrgY = poObjBlock->ReadInt32();
1970 :
1971 4 : m_nMinX = poObjBlock->ReadInt16(); // Read MBR
1972 4 : m_nMinY = poObjBlock->ReadInt16();
1973 4 : m_nMaxX = poObjBlock->ReadInt16();
1974 4 : m_nMaxY = poObjBlock->ReadInt16();
1975 4 : TABSaturatedAdd(m_nMinX, m_nComprOrgX);
1976 4 : TABSaturatedAdd(m_nMinY, m_nComprOrgY);
1977 4 : TABSaturatedAdd(m_nMaxX, m_nComprOrgX);
1978 4 : TABSaturatedAdd(m_nMaxY, m_nComprOrgY);
1979 : #ifdef TABDUMP
1980 : printf("COLLECTION: ComprOrgX,Y= (%d,%d)\n", /*ok*/
1981 : m_nComprOrgX, m_nComprOrgY);
1982 : #endif
1983 : }
1984 : else
1985 : {
1986 0 : m_nMinX = poObjBlock->ReadInt32(); // Read MBR
1987 0 : m_nMinY = poObjBlock->ReadInt32();
1988 0 : m_nMaxX = poObjBlock->ReadInt32();
1989 0 : m_nMaxY = poObjBlock->ReadInt32();
1990 :
1991 : // Init. Compr. Origin to a default value in case type is ever changed
1992 0 : m_nComprOrgX =
1993 0 : static_cast<GInt32>((static_cast<GIntBig>(m_nMinX) + m_nMaxX) / 2);
1994 0 : m_nComprOrgY =
1995 0 : static_cast<GInt32>((static_cast<GIntBig>(m_nMinY) + m_nMaxY) / 2);
1996 : }
1997 :
1998 4 : if (CPLGetLastErrorType() == CE_Failure)
1999 0 : return -1;
2000 :
2001 4 : return 0;
2002 : }
2003 :
2004 : /**********************************************************************
2005 : * TABMAPObjCollection::WriteObj()
2006 : *
2007 : * Write Object information with the type+object id
2008 : *
2009 : * Returns 0 on success, -1 on error.
2010 : **********************************************************************/
2011 0 : int TABMAPObjCollection::WriteObj(TABMAPObjectBlock *poObjBlock)
2012 : {
2013 : // Write object type and id
2014 0 : TABMAPObjHdr::WriteObjTypeAndId(poObjBlock);
2015 :
2016 0 : int nVersion = TAB_GEOM_GET_VERSION(m_nType);
2017 :
2018 : /* NB. MapInfo counts 2 extra bytes per Region and Pline section header
2019 : * in the RegionDataSize and PolylineDataSize values but those 2 extra
2020 : * bytes are not present in the section hdr (possibly due to an alignment
2021 : * to a 4 byte boundary in memory in MapInfo?). The real data size in
2022 : * the CoordBlock is actually 2 bytes shorter per section header than
2023 : * what is written in RegionDataSize and PolylineDataSize values.
2024 : *
2025 : * The values in memory are the corrected values so we need to add 2 bytes
2026 : * per section header in the values that we write on disk to emulate
2027 : * MapInfo's behavior.
2028 : */
2029 0 : GInt32 nRegionDataSizeMI = m_nRegionDataSize + (2 * m_nNumRegSections);
2030 0 : GInt32 nPolylineDataSizeMI =
2031 0 : m_nPolylineDataSize + (2 * m_nNumPLineSections);
2032 :
2033 0 : poObjBlock->WriteInt32(m_nCoordBlockPtr); // pointer into coord block
2034 0 : poObjBlock->WriteInt32(m_nNumMultiPoints); // no. points in multi point
2035 0 : poObjBlock->WriteInt32(
2036 : nRegionDataSizeMI); // size of region data inc. section hdrs
2037 0 : poObjBlock->WriteInt32(
2038 : nPolylineDataSizeMI); // size of Mpolyline data inc. section hdrs
2039 :
2040 0 : if (nVersion < 800)
2041 : {
2042 : // Num Region/Pline section headers (int16 in V650)
2043 0 : poObjBlock->WriteInt16(static_cast<GInt16>(m_nNumRegSections));
2044 0 : poObjBlock->WriteInt16(static_cast<GInt16>(m_nNumPLineSections));
2045 : }
2046 : else
2047 : {
2048 : // Num Region/Pline section headers (int32 in V800)
2049 0 : poObjBlock->WriteInt32(m_nNumRegSections);
2050 0 : poObjBlock->WriteInt32(m_nNumPLineSections);
2051 : }
2052 :
2053 0 : if (nVersion >= 800)
2054 : {
2055 : // Extra byte in V800 files... value always 4???
2056 0 : poObjBlock->WriteByte(4);
2057 : }
2058 :
2059 : // Unknown data ?????
2060 0 : poObjBlock->WriteInt32(0);
2061 0 : poObjBlock->WriteInt32(0);
2062 0 : poObjBlock->WriteInt32(0);
2063 0 : poObjBlock->WriteByte(0);
2064 0 : poObjBlock->WriteByte(0);
2065 0 : poObjBlock->WriteByte(0);
2066 :
2067 0 : poObjBlock->WriteByte(m_nMultiPointSymbolId);
2068 :
2069 0 : poObjBlock->WriteByte(0);
2070 0 : poObjBlock->WriteByte(m_nRegionPenId);
2071 0 : poObjBlock->WriteByte(m_nPolylinePenId);
2072 0 : poObjBlock->WriteByte(m_nRegionBrushId);
2073 :
2074 0 : if (IsCompressedType())
2075 : {
2076 : #ifdef TABDUMP
2077 : printf("COLLECTION: WRITING ComprOrgX,Y= (%d,%d) @ %d\n", /*ok*/
2078 : m_nComprOrgX, m_nComprOrgY, poObjBlock->GetCurAddress());
2079 : #endif
2080 : // Compressed coordinate origin
2081 0 : poObjBlock->WriteInt32(m_nComprOrgX);
2082 0 : poObjBlock->WriteInt32(m_nComprOrgY);
2083 :
2084 0 : poObjBlock->WriteInt16(TABInt16Diff(m_nMinX, m_nComprOrgX)); // MBR
2085 0 : poObjBlock->WriteInt16(TABInt16Diff(m_nMinY, m_nComprOrgY));
2086 0 : poObjBlock->WriteInt16(TABInt16Diff(m_nMaxX, m_nComprOrgX));
2087 0 : poObjBlock->WriteInt16(TABInt16Diff(m_nMaxY, m_nComprOrgY));
2088 : }
2089 : else
2090 : {
2091 0 : poObjBlock->WriteInt32(m_nMinX); // MBR
2092 0 : poObjBlock->WriteInt32(m_nMinY);
2093 0 : poObjBlock->WriteInt32(m_nMaxX);
2094 0 : poObjBlock->WriteInt32(m_nMaxY);
2095 : }
2096 :
2097 0 : if (CPLGetLastErrorType() == CE_Failure)
2098 0 : return -1;
2099 :
2100 0 : return 0;
2101 : }
|