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