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