Coverage Report

Created: 2025-12-31 08:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/ogr/ogrsf_frmts/mitab/mitab_priv.h
Line
Count
Source
1
/**********************************************************************
2
 *
3
 * Name:     mitab_priv.h
4
 * Project:  MapInfo TAB Read/Write library
5
 * Language: C++
6
 * Purpose:  Header file containing private definitions for the library.
7
 * Author:   Daniel Morissette, dmorissette@dmsolutions.ca
8
 *
9
 **********************************************************************
10
 * Copyright (c) 1999-2003, Daniel Morissette
11
 * Copyright (c) 2014, Even Rouault <even.rouault at spatialys.com>
12
 *
13
 * SPDX-License-Identifier: MIT
14
 **********************************************************************/
15
16
#ifndef MITAB_PRIV_H_INCLUDED_
17
#define MITAB_PRIV_H_INCLUDED_
18
19
#include "cpl_conv.h"
20
#include "cpl_string.h"
21
#include "ogr_feature.h"
22
#include "ogrmitabspatialref.h"
23
24
#include <set>
25
26
class TABFile;
27
class TABFeature;
28
class TABMAPToolBlock;
29
class TABMAPIndexBlock;
30
31
/*---------------------------------------------------------------------
32
 * Access mode: Read or Write
33
 *--------------------------------------------------------------------*/
34
typedef enum
35
{
36
    TABRead,
37
    TABWrite,
38
    TABReadWrite
39
} TABAccess;
40
41
/*---------------------------------------------------------------------
42
 * Supported .MAP block types (the first byte at the beginning of a block)
43
 *--------------------------------------------------------------------*/
44
0
#define TAB_RAWBIN_BLOCK -1
45
11.3k
#define TABMAP_HEADER_BLOCK 0
46
789
#define TABMAP_INDEX_BLOCK 1
47
3.09k
#define TABMAP_OBJECT_BLOCK 2
48
1.51k
#define TABMAP_COORD_BLOCK 3
49
0
#define TABMAP_GARB_BLOCK 4
50
287
#define TABMAP_TOOL_BLOCK 5
51
0
#define TABMAP_LAST_VALID_BLOCK_TYPE 5
52
53
/*---------------------------------------------------------------------
54
 * Drawing Tool types
55
 *--------------------------------------------------------------------*/
56
388
#define TABMAP_TOOL_PEN 1
57
369
#define TABMAP_TOOL_BRUSH 2
58
11
#define TABMAP_TOOL_FONT 3
59
381
#define TABMAP_TOOL_SYMBOL 4
60
61
/*---------------------------------------------------------------------
62
 * Limits related to .TAB version number.  If we pass any of those limits
63
 * then we have to use larger object types
64
 *--------------------------------------------------------------------*/
65
10.9k
#define TAB_REGION_PLINE_300_MAX_VERTICES 32767
66
67
21.8k
#define TAB_REGION_PLINE_450_MAX_SEGMENTS 32767
68
10.9k
#define TAB_REGION_PLINE_450_MAX_VERTICES 1048575
69
70
0
#define TAB_MULTIPOINT_650_MAX_VERTICES 1048576
71
72
/* Use this macro to test whether the number of segments and vertices
73
 * in this object exceeds the V450/650 limits and requires a V800 object
74
 */
75
#define TAB_REGION_PLINE_REQUIRES_V800(numSegments, numVerticesTotal)          \
76
10.9k
    ((numSegments) > TAB_REGION_PLINE_450_MAX_SEGMENTS ||                      \
77
10.9k
     ((numSegments)*3 + numVerticesTotal) > TAB_REGION_PLINE_450_MAX_VERTICES)
78
79
/*---------------------------------------------------------------------
80
 * Codes for the known MapInfo Geometry types
81
 *--------------------------------------------------------------------*/
82
typedef enum
83
{
84
    TAB_GEOM_UNSET = -1,
85
86
    TAB_GEOM_NONE = 0,
87
    TAB_GEOM_SYMBOL_C = 0x01,
88
    TAB_GEOM_SYMBOL = 0x02,
89
    TAB_GEOM_LINE_C = 0x04,
90
    TAB_GEOM_LINE = 0x05,
91
    TAB_GEOM_PLINE_C = 0x07,
92
    TAB_GEOM_PLINE = 0x08,
93
    TAB_GEOM_ARC_C = 0x0a,
94
    TAB_GEOM_ARC = 0x0b,
95
    TAB_GEOM_REGION_C = 0x0d,
96
    TAB_GEOM_REGION = 0x0e,
97
    TAB_GEOM_TEXT_C = 0x10,
98
    TAB_GEOM_TEXT = 0x11,
99
    TAB_GEOM_RECT_C = 0x13,
100
    TAB_GEOM_RECT = 0x14,
101
    TAB_GEOM_ROUNDRECT_C = 0x16,
102
    TAB_GEOM_ROUNDRECT = 0x17,
103
    TAB_GEOM_ELLIPSE_C = 0x19,
104
    TAB_GEOM_ELLIPSE = 0x1a,
105
    TAB_GEOM_MULTIPLINE_C = 0x25,
106
    TAB_GEOM_MULTIPLINE = 0x26,
107
    TAB_GEOM_FONTSYMBOL_C = 0x28,
108
    TAB_GEOM_FONTSYMBOL = 0x29,
109
    TAB_GEOM_CUSTOMSYMBOL_C = 0x2b,
110
    TAB_GEOM_CUSTOMSYMBOL = 0x2c,
111
    /* Version 450 object types: */
112
    TAB_GEOM_V450_REGION_C = 0x2e,
113
    TAB_GEOM_V450_REGION = 0x2f,
114
    TAB_GEOM_V450_MULTIPLINE_C = 0x31,
115
    TAB_GEOM_V450_MULTIPLINE = 0x32,
116
    /* Version 650 object types: */
117
    TAB_GEOM_MULTIPOINT_C = 0x34,
118
    TAB_GEOM_MULTIPOINT = 0x35,
119
    TAB_GEOM_COLLECTION_C = 0x37,
120
    TAB_GEOM_COLLECTION = 0x38,
121
    /* Version 800 object types: */
122
    TAB_GEOM_UNKNOWN1_C = 0x3a,  // ???
123
    TAB_GEOM_UNKNOWN1 = 0x3b,    // ???
124
    TAB_GEOM_V800_REGION_C = 0x3d,
125
    TAB_GEOM_V800_REGION = 0x3e,
126
    TAB_GEOM_V800_MULTIPLINE_C = 0x40,
127
    TAB_GEOM_V800_MULTIPLINE = 0x41,
128
    TAB_GEOM_V800_MULTIPOINT_C = 0x43,
129
    TAB_GEOM_V800_MULTIPOINT = 0x44,
130
    TAB_GEOM_V800_COLLECTION_C = 0x46,
131
    TAB_GEOM_V800_COLLECTION = 0x47,
132
    TAB_GEOM_MAX_TYPE /* TODo: Does this need to be 0x80? */
133
} TABGeomType;
134
135
#define TAB_GEOM_GET_VERSION(nGeomType)                                        \
136
16.7k
    (((nGeomType) < TAB_GEOM_V450_REGION_C)  ? 300                             \
137
16.7k
     : ((nGeomType) < TAB_GEOM_MULTIPOINT_C) ? 450                             \
138
39
     : ((nGeomType) < TAB_GEOM_UNKNOWN1_C)   ? 650                             \
139
32
                                             : 800)
140
141
/*---------------------------------------------------------------------
142
 * struct TABMAPIndexEntry - Entries found in type 1 blocks of .MAP files
143
 *
144
 * We will use this struct to rebuild the geographic index in memory
145
 *--------------------------------------------------------------------*/
146
typedef struct TABMAPIndexEntry_t
147
{
148
    // These members refer to the info we find in the file
149
    GInt32 XMin;
150
    GInt32 YMin;
151
    GInt32 XMax;
152
    GInt32 YMax;
153
    GInt32 nBlockPtr;
154
} TABMAPIndexEntry;
155
156
8.37k
#define TAB_MIN_BLOCK_SIZE 512
157
262
#define TAB_MAX_BLOCK_SIZE (32768 - 512)
158
159
#define TAB_MAX_ENTRIES_INDEX_BLOCK ((TAB_MAX_BLOCK_SIZE - 4) / 20)
160
161
/*---------------------------------------------------------------------
162
 * TABVertex
163
 *--------------------------------------------------------------------*/
164
typedef struct TABVertex_t
165
{
166
    double x{};
167
    double y{};
168
} TABVertex;
169
170
/*---------------------------------------------------------------------
171
 * TABTableType - Attribute table format
172
 *--------------------------------------------------------------------*/
173
typedef enum
174
{
175
    TABTableNative,  // The default
176
    TABTableDBF,
177
    TABTableAccess
178
} TABTableType;
179
180
/*---------------------------------------------------------------------
181
 * TABFieldType - Native MapInfo attribute field types
182
 *--------------------------------------------------------------------*/
183
typedef enum
184
{
185
    TABFUnknown = 0,
186
    TABFChar,
187
    TABFInteger,
188
    TABFSmallInt,
189
    TABFDecimal,
190
    TABFFloat,
191
    TABFDate,
192
    TABFLogical,
193
    TABFTime,
194
    TABFDateTime,
195
    TABFLargeInt
196
} TABFieldType;
197
198
#define TABFIELDTYPE_2_STRING(type)                                            \
199
146
    (type == TABFChar       ? "Char"                                           \
200
146
     : type == TABFInteger  ? "Integer"                                        \
201
146
     : type == TABFSmallInt ? "SmallInt"                                       \
202
0
     : type == TABFLargeInt ? "LargeInt"                                       \
203
0
     : type == TABFDecimal  ? "Decimal"                                        \
204
0
     : type == TABFFloat    ? "Float"                                          \
205
0
     : type == TABFDate     ? "Date"                                           \
206
0
     : type == TABFLogical  ? "Logical"                                        \
207
0
     : type == TABFTime     ? "Time"                                           \
208
0
     : type == TABFDateTime ? "DateTime"                                       \
209
0
                            : "Unknown field type")
210
211
/*---------------------------------------------------------------------
212
 * TABDATFieldDef
213
 *--------------------------------------------------------------------*/
214
typedef struct TABDATFieldDef_t
215
{
216
    char szName[11];
217
    char cType;
218
    GByte
219
        byLength; /* caution: for a native .dat file, this is a binary width for most types */
220
    GByte byDecimals;
221
222
    TABFieldType eTABType;
223
} TABDATFieldDef;
224
225
/*---------------------------------------------------------------------
226
 * TABMAPCoordSecHdr
227
 * struct used in the TABMAPCoordBlock to store info about the coordinates
228
 * for a section of a PLINE MULTIPLE or a REGION.
229
 *--------------------------------------------------------------------*/
230
typedef struct TABMAPCoordSecHdr_t
231
{
232
    GInt32 numVertices;
233
    GInt32 numHoles;
234
    GInt32 nXMin;
235
    GInt32 nYMin;
236
    GInt32 nXMax;
237
    GInt32 nYMax;
238
239
    GInt32 nDataOffset;
240
    int nVertexOffset;
241
} TABMAPCoordSecHdr;
242
243
/*---------------------------------------------------------------------
244
 * TABPenDef - Pen definition information
245
 *--------------------------------------------------------------------*/
246
typedef struct TABPenDef_t
247
{
248
    GInt32 nRefCount;
249
    GByte nPixelWidth;
250
    GByte nLinePattern;
251
    int nPointWidth;
252
    GInt32 rgbColor;
253
} TABPenDef;
254
255
/* MI Default = PEN(1,2,0) */
256
#define MITAB_PEN_DEFAULT                                                      \
257
332
    {                                                                          \
258
332
        0, 1, 2, 0, 0x000000                                                   \
259
332
    }
260
261
/*---------------------------------------------------------------------
262
 * TABBrushDef - Brush definition information
263
 *--------------------------------------------------------------------*/
264
typedef struct TABBrushDef_t
265
{
266
    GInt32 nRefCount;
267
    GByte nFillPattern;
268
    GByte bTransparentFill;  // 1 = Transparent
269
    GInt32 rgbFGColor;
270
    GInt32 rgbBGColor;
271
} TABBrushDef;
272
273
/* MI Default = BRUSH(1,0,16777215) */
274
#define MITAB_BRUSH_DEFAULT                                                    \
275
107
    {                                                                          \
276
107
        0, 1, 0, 0, 0xffffff                                                   \
277
107
    }
278
279
/*---------------------------------------------------------------------
280
 * TABFontDef - Font Name information
281
 *--------------------------------------------------------------------*/
282
typedef struct TABFontDef_t
283
{
284
    GInt32 nRefCount;
285
    char szFontName[33];
286
} TABFontDef;
287
288
/* MI Default = FONT("Arial",0,0,0) */
289
#define MITAB_FONT_DEFAULT                                                     \
290
144
    {                                                                          \
291
144
        0, "Arial"                                                             \
292
144
    }
293
294
/*---------------------------------------------------------------------
295
 * TABSymbolDef - Symbol definition information
296
 *--------------------------------------------------------------------*/
297
typedef struct TABSymbolDef_t
298
{
299
    GInt32 nRefCount;
300
    GInt16 nSymbolNo;
301
    GInt16 nPointSize;
302
    GByte _nUnknownValue_;  // Style???
303
    GInt32 rgbColor;
304
} TABSymbolDef;
305
306
/* MI Default = SYMBOL(35,0,12) */
307
#define MITAB_SYMBOL_DEFAULT                                                   \
308
95
    {                                                                          \
309
95
        0, 35, 12, 0, 0x000000                                                 \
310
95
    }
311
312
/*---------------------------------------------------------------------
313
 *                      class TABToolDefTable
314
 *
315
 * Class to handle the list of Drawing Tool Definitions for a dataset
316
 *
317
 * This class also contains methods to read tool defs from the file and
318
 * write them to the file.
319
 *--------------------------------------------------------------------*/
320
321
class TABToolDefTable
322
{
323
    CPL_DISALLOW_COPY_ASSIGN(TABToolDefTable)
324
325
  protected:
326
    TABPenDef **m_papsPen;
327
    int m_numPen;
328
    int m_numAllocatedPen;
329
    TABBrushDef **m_papsBrush;
330
    int m_numBrushes;
331
    int m_numAllocatedBrushes;
332
    TABFontDef **m_papsFont;
333
    int m_numFonts;
334
    int m_numAllocatedFonts;
335
    TABSymbolDef **m_papsSymbol;
336
    int m_numSymbols;
337
    int m_numAllocatedSymbols;
338
339
  public:
340
    TABToolDefTable();
341
    ~TABToolDefTable();
342
343
    int ReadAllToolDefs(TABMAPToolBlock *poToolBlock);
344
    int WriteAllToolDefs(TABMAPToolBlock *poToolBlock);
345
346
    TABPenDef *GetPenDefRef(int nIndex);
347
    int AddPenDefRef(TABPenDef *poPenDef);
348
    int GetNumPen();
349
350
    TABBrushDef *GetBrushDefRef(int nIndex);
351
    int AddBrushDefRef(TABBrushDef *poBrushDef);
352
    int GetNumBrushes();
353
354
    TABFontDef *GetFontDefRef(int nIndex);
355
    int AddFontDefRef(TABFontDef *poFontDef);
356
    int GetNumFonts();
357
358
    TABSymbolDef *GetSymbolDefRef(int nIndex);
359
    int AddSymbolDefRef(TABSymbolDef *poSymbolDef);
360
    int GetNumSymbols();
361
362
    int GetMinVersionNumber();
363
};
364
365
/*=====================================================================
366
          Classes to handle Object Headers inside TABMAPObjectBlocks
367
 =====================================================================*/
368
369
class TABMAPObjectBlock;
370
class TABMAPHeaderBlock;
371
372
class TABMAPObjHdr
373
{
374
  public:
375
    TABGeomType m_nType;
376
    GInt32 m_nId;
377
    GInt32 m_nMinX; /* Object MBR */
378
    GInt32 m_nMinY;
379
    GInt32 m_nMaxX;
380
    GInt32 m_nMaxY;
381
382
    TABMAPObjHdr()
383
290k
        : m_nType(TAB_GEOM_NONE), m_nId(0), m_nMinX(0), m_nMinY(0), m_nMaxX(0),
384
290k
          m_nMaxY(0)
385
290k
    {
386
290k
    }
387
388
    virtual ~TABMAPObjHdr();
389
390
    static TABMAPObjHdr *NewObj(TABGeomType nNewObjType, GInt32 nId = 0);
391
    static TABMAPObjHdr *ReadNextObj(TABMAPObjectBlock *poObjBlock,
392
                                     TABMAPHeaderBlock *poHeader);
393
394
    GBool IsCompressedType();
395
    int WriteObjTypeAndId(TABMAPObjectBlock *);
396
    void SetMBR(GInt32 nMinX, GInt32 nMinY, GInt32 nMaxX, GInt32 mMaxY);
397
398
    virtual int WriteObj(TABMAPObjectBlock *)
399
0
    {
400
0
        return -1;
401
0
    }
402
403
    //  protected:
404
    virtual int ReadObj(TABMAPObjectBlock *)
405
0
    {
406
0
        return -1;
407
0
    }
408
};
409
410
class TABMAPObjHdrWithCoord : public TABMAPObjHdr
411
{
412
  public:
413
    GInt32 m_nCoordBlockPtr = 0;
414
    GInt32 m_nCoordDataSize = 0;
415
416
    /* Eventually this class may have methods to help maintaining refs to
417
     * coord. blocks when splitting object blocks.
418
     */
419
420
    ~TABMAPObjHdrWithCoord() override;
421
};
422
423
class TABMAPObjNone final : public TABMAPObjHdr
424
{
425
  public:
426
279k
    TABMAPObjNone() = default;
427
428
    int WriteObj(TABMAPObjectBlock *) override
429
0
    {
430
0
        return 0;
431
0
    }
432
433
    //  protected:
434
    int ReadObj(TABMAPObjectBlock *) override;
435
};
436
437
class TABMAPObjPoint /* non final */ : public TABMAPObjHdr
438
{
439
  public:
440
    GInt32 m_nX;
441
    GInt32 m_nY;
442
    GByte m_nSymbolId;
443
444
3.44k
    TABMAPObjPoint() : m_nX(0), m_nY(0), m_nSymbolId(0)
445
3.44k
    {
446
3.44k
    }
447
448
    int WriteObj(TABMAPObjectBlock *) override;
449
450
    //  protected:
451
    int ReadObj(TABMAPObjectBlock *) override;
452
};
453
454
class TABMAPObjFontPoint final : public TABMAPObjPoint
455
{
456
  public:
457
    GByte m_nPointSize;
458
    GInt16 m_nFontStyle;
459
    GByte m_nR;
460
    GByte m_nG;
461
    GByte m_nB;
462
    GInt16 m_nAngle; /* In tenths of degree */
463
    GByte m_nFontId;
464
465
    TABMAPObjFontPoint()
466
69
        : m_nPointSize(0), m_nFontStyle(0), m_nR(0), m_nG(0), m_nB(0),
467
69
          m_nAngle(0), m_nFontId(0)
468
69
    {
469
69
    }
470
471
    int WriteObj(TABMAPObjectBlock *) override;
472
473
    //  protected:
474
    int ReadObj(TABMAPObjectBlock *) override;
475
};
476
477
class TABMAPObjCustomPoint final : public TABMAPObjPoint
478
{
479
  public:
480
    GByte m_nUnknown_;
481
    GByte m_nCustomStyle;
482
    GByte m_nFontId;
483
484
71
    TABMAPObjCustomPoint() : m_nUnknown_(0), m_nCustomStyle(0), m_nFontId(0)
485
71
    {
486
71
    }
487
488
    int WriteObj(TABMAPObjectBlock *) override;
489
490
    //  protected:
491
    int ReadObj(TABMAPObjectBlock *) override;
492
};
493
494
class TABMAPObjLine final : public TABMAPObjHdr
495
{
496
  public:
497
    GInt32 m_nX1;
498
    GInt32 m_nY1;
499
    GInt32 m_nX2;
500
    GInt32 m_nY2;
501
    GByte m_nPenId;
502
503
367
    TABMAPObjLine() : m_nX1(0), m_nY1(0), m_nX2(0), m_nY2(0), m_nPenId(0)
504
367
    {
505
367
    }
506
507
    int WriteObj(TABMAPObjectBlock *) override;
508
509
    //  protected:
510
    int ReadObj(TABMAPObjectBlock *) override;
511
};
512
513
class TABMAPObjPLine final : public TABMAPObjHdrWithCoord
514
{
515
  public:
516
    GInt32 m_numLineSections; /* MULTIPLINE/REGION only. Not in PLINE */
517
    GInt32 m_nLabelX;         /* Centroid/label location */
518
    GInt32 m_nLabelY;
519
    GInt32 m_nComprOrgX; /* Present only in compressed coord. case */
520
    GInt32 m_nComprOrgY;
521
    GByte m_nPenId;
522
    GByte m_nBrushId;
523
    GBool m_bSmooth; /* TRUE if (m_nCoordDataSize & 0x80000000) */
524
525
    TABMAPObjPLine()
526
7.17k
        : m_numLineSections(0), m_nLabelX(0), m_nLabelY(0), m_nComprOrgX(0),
527
7.17k
          m_nComprOrgY(0), m_nPenId(0), m_nBrushId(0), m_bSmooth(0)
528
7.17k
    {
529
7.17k
    }
530
531
    int WriteObj(TABMAPObjectBlock *) override;
532
533
    //  protected:
534
    int ReadObj(TABMAPObjectBlock *) override;
535
};
536
537
class TABMAPObjRectEllipse final : public TABMAPObjHdr
538
{
539
  public:
540
    GInt32 m_nCornerWidth; /* For rounded rect only */
541
    GInt32 m_nCornerHeight;
542
    GByte m_nPenId;
543
    GByte m_nBrushId;
544
545
    TABMAPObjRectEllipse()
546
93
        : m_nCornerWidth(0), m_nCornerHeight(0), m_nPenId(0), m_nBrushId(0)
547
93
    {
548
93
    }
549
550
    int WriteObj(TABMAPObjectBlock *) override;
551
552
    //  protected:
553
    int ReadObj(TABMAPObjectBlock *) override;
554
};
555
556
class TABMAPObjArc final : public TABMAPObjHdr
557
{
558
  public:
559
    GInt32 m_nStartAngle;
560
    GInt32 m_nEndAngle;
561
    GInt32 m_nArcEllipseMinX; /* MBR of the arc defining ellipse */
562
    GInt32 m_nArcEllipseMinY; /* Only present in arcs            */
563
    GInt32 m_nArcEllipseMaxX;
564
    GInt32 m_nArcEllipseMaxY;
565
    GByte m_nPenId;
566
567
    TABMAPObjArc()
568
49
        : m_nStartAngle(0), m_nEndAngle(0), m_nArcEllipseMinX(0),
569
49
          m_nArcEllipseMinY(0), m_nArcEllipseMaxX(0), m_nArcEllipseMaxY(0),
570
49
          m_nPenId(0)
571
49
    {
572
49
    }
573
574
    int WriteObj(TABMAPObjectBlock *) override;
575
576
    //  protected:
577
    int ReadObj(TABMAPObjectBlock *) override;
578
};
579
580
class TABMAPObjText final : public TABMAPObjHdrWithCoord
581
{
582
  public:
583
    /* String and its len stored in the nCoordPtr and nCoordSize */
584
585
    GInt16 m_nTextAlignment;
586
    GInt32 m_nAngle;
587
    GInt16 m_nFontStyle;
588
589
    GByte m_nFGColorR;
590
    GByte m_nFGColorG;
591
    GByte m_nFGColorB;
592
    GByte m_nBGColorR;
593
    GByte m_nBGColorG;
594
    GByte m_nBGColorB;
595
596
    GInt32 m_nLineEndX;
597
    GInt32 m_nLineEndY;
598
599
    GInt32 m_nHeight;
600
    GByte m_nFontId;
601
602
    GByte m_nPenId;
603
604
    TABMAPObjText()
605
19
        : m_nTextAlignment(0), m_nAngle(0), m_nFontStyle(0), m_nFGColorR(0),
606
19
          m_nFGColorG(0), m_nFGColorB(0), m_nBGColorR(0), m_nBGColorG(0),
607
19
          m_nBGColorB(0), m_nLineEndX(0), m_nLineEndY(0), m_nHeight(0),
608
19
          m_nFontId(0), m_nPenId(0)
609
19
    {
610
19
    }
611
612
    int WriteObj(TABMAPObjectBlock *) override;
613
614
    //  protected:
615
    int ReadObj(TABMAPObjectBlock *) override;
616
};
617
618
class TABMAPObjMultiPoint final : public TABMAPObjHdrWithCoord
619
{
620
  public:
621
    GInt32 m_nNumPoints;
622
    GInt32 m_nComprOrgX; /* Present only in compressed coord. case */
623
    GInt32 m_nComprOrgY;
624
    GByte m_nSymbolId;
625
    GInt32 m_nLabelX; /* Not sure if it is a label point, but */
626
    GInt32 m_nLabelY; /* it is similar to what we find in PLINE */
627
628
    TABMAPObjMultiPoint()
629
21
        : m_nNumPoints(0), m_nComprOrgX(0), m_nComprOrgY(0), m_nSymbolId(0),
630
21
          m_nLabelX(0), m_nLabelY(0)
631
21
    {
632
21
    }
633
634
    int WriteObj(TABMAPObjectBlock *) override;
635
636
    //  protected:
637
    int ReadObj(TABMAPObjectBlock *) override;
638
};
639
640
class TABMAPObjCollection final : public TABMAPObjHdrWithCoord
641
{
642
  public:
643
    GInt32 m_nRegionDataSize;
644
    GInt32 m_nPolylineDataSize;
645
    GInt32 m_nMPointDataSize;
646
    GInt32 m_nComprOrgX; /* Present only in compressed coord. case */
647
    GInt32 m_nComprOrgY;
648
    GInt32 m_nNumMultiPoints;
649
    GInt32 m_nNumRegSections;
650
    GInt32 m_nNumPLineSections;
651
652
    GByte m_nMultiPointSymbolId;
653
    GByte m_nRegionPenId;
654
    GByte m_nRegionBrushId;
655
    GByte m_nPolylinePenId;
656
657
    TABMAPObjCollection()
658
17
        : m_nRegionDataSize(0), m_nPolylineDataSize(0), m_nMPointDataSize(0),
659
17
          m_nComprOrgX(0), m_nComprOrgY(0), m_nNumMultiPoints(0),
660
17
          m_nNumRegSections(0), m_nNumPLineSections(0),
661
17
          m_nMultiPointSymbolId(0), m_nRegionPenId(0), m_nRegionBrushId(0),
662
17
          m_nPolylinePenId(0)
663
17
    {
664
17
    }
665
666
    int WriteObj(TABMAPObjectBlock *) override;
667
668
    //  protected:
669
    int ReadObj(TABMAPObjectBlock *) override;
670
671
  private:
672
    // private copy ctor and assignment operator to prevent shallow copying
673
    TABMAPObjCollection &operator=(const TABMAPObjCollection &rhs);
674
    TABMAPObjCollection(const TABMAPObjCollection &rhs);
675
};
676
677
/*=====================================================================
678
          Classes to handle .MAP files low-level blocks
679
 =====================================================================*/
680
681
typedef struct TABBlockRef_t
682
{
683
    GInt32 nBlockPtr;
684
    struct TABBlockRef_t *psPrev;
685
    struct TABBlockRef_t *psNext;
686
} TABBlockRef;
687
688
/*---------------------------------------------------------------------
689
 *                      class TABBinBlockManager
690
 *
691
 * This class is used to keep track of allocated blocks and is used
692
 * by various classes that need to allocate a new block in a .MAP file.
693
 *--------------------------------------------------------------------*/
694
class TABBinBlockManager final
695
{
696
    CPL_DISALLOW_COPY_ASSIGN(TABBinBlockManager)
697
698
  protected:
699
    int m_nBlockSize;
700
    GInt32 m_nLastAllocatedBlock;
701
    TABBlockRef *m_psGarbageBlocksFirst;
702
    TABBlockRef *m_psGarbageBlocksLast;
703
    char m_szName[32]; /* for debug purposes */
704
705
  public:
706
    TABBinBlockManager();
707
    ~TABBinBlockManager();
708
709
    void SetBlockSize(int nBlockSize);
710
711
    int GetBlockSize() const
712
0
    {
713
0
        return m_nBlockSize;
714
0
    }
715
716
    GInt32 AllocNewBlock(const char *pszReason = "");
717
    void Reset();
718
719
    void SetLastPtr(int nBlockPtr)
720
131
    {
721
131
        m_nLastAllocatedBlock = nBlockPtr;
722
131
    }
723
724
    void PushGarbageBlockAsFirst(GInt32 nBlockPtr);
725
    void PushGarbageBlockAsLast(GInt32 nBlockPtr);
726
    GInt32 GetFirstGarbageBlock();
727
    GInt32 PopGarbageBlock();
728
729
    void SetName(const char *pszName);
730
};
731
732
/*---------------------------------------------------------------------
733
 *                      class TABRawBinBlock
734
 *
735
 * This is the base class used for all other data block types... it
736
 * contains all the base functions to handle binary data.
737
 *--------------------------------------------------------------------*/
738
739
class TABRawBinBlock /* non final */
740
{
741
    CPL_DISALLOW_COPY_ASSIGN(TABRawBinBlock)
742
743
  protected:
744
    VSILFILE *m_fp;      /* Associated file handle               */
745
    TABAccess m_eAccess; /* Read/Write access mode               */
746
747
    int m_nBlockType;
748
749
    GByte *m_pabyBuf;       /* Buffer to contain the block's data    */
750
    int m_nBlockSize;       /* Size of current block (and buffer)    */
751
    int m_nSizeUsed;        /* Number of bytes used in buffer        */
752
    GBool m_bHardBlockSize; /* TRUE=Blocks MUST always be nSize bytes  */
753
                            /* FALSE=last block may be less than nSize */
754
    int m_nFileOffset;      /* Location of current block in the file */
755
    int m_nCurPos;          /* Next byte to read from m_pabyBuf[]    */
756
    int m_nFirstBlockPtr;   /* Size of file header when different from */
757
                            /* block size (used by GotoByteInFile())   */
758
    int m_nFileSize;
759
760
    int m_bModified; /* Used only to detect changes        */
761
762
  public:
763
    explicit TABRawBinBlock(TABAccess eAccessMode = TABRead,
764
                            GBool bHardBlockSize = TRUE);
765
    virtual ~TABRawBinBlock();
766
767
    virtual int ReadFromFile(VSILFILE *fpSrc, int nOffset, int nSize);
768
    virtual int CommitToFile();
769
    int CommitAsDeleted(GInt32 nNextBlockPtr);
770
771
    virtual int InitBlockFromData(GByte *pabyBuf, int nBlockSize, int nSizeUsed,
772
                                  GBool bMakeCopy = TRUE,
773
                                  VSILFILE *fpSrc = nullptr, int nOffset = 0);
774
    virtual int InitNewBlock(VSILFILE *fpSrc, int nBlockSize,
775
                             int nFileOffset = 0);
776
777
    int GetBlockType();
778
779
    virtual int GetBlockClass()
780
0
    {
781
0
        return TAB_RAWBIN_BLOCK;
782
0
    }
783
784
    GInt32 GetStartAddress()
785
27.8k
    {
786
27.8k
        return m_nFileOffset;
787
27.8k
    }
788
#ifdef DEBUG
789
    virtual void Dump(FILE *fpOut = nullptr);
790
#endif
791
    static void DumpBytes(GInt32 nValue, int nOffset = 0,
792
                          FILE *fpOut = nullptr);
793
794
    int GotoByteRel(int nOffset);
795
    int GotoByteInBlock(int nOffset);
796
    int GotoByteInFile(int nOffset, GBool bForceReadFromFile = FALSE,
797
                       GBool bOffsetIsEndOfData = FALSE);
798
    void SetFirstBlockPtr(int nOffset);
799
800
    int GetNumUnusedBytes();
801
    int GetFirstUnusedByteOffset();
802
    int GetCurAddress();
803
804
    virtual int ReadBytes(int numBytes, GByte *pabyDstBuf);
805
    GByte ReadByte();
806
    // cppcheck-suppress functionStatic
807
    GInt16 ReadInt16();
808
    // cppcheck-suppress functionStatic
809
    GInt32 ReadInt32();
810
    // cppcheck-suppress functionStatic
811
    GInt64 ReadInt64();
812
    // cppcheck-suppress functionStatic
813
    float ReadFloat();
814
    // cppcheck-suppress functionStatic
815
    double ReadDouble();
816
817
    virtual int WriteBytes(int nBytesToWrite, const GByte *pBuf);
818
    int WriteByte(GByte byValue);
819
    // cppcheck-suppress functionStatic
820
    int WriteInt16(GInt16 n16Value);
821
    // cppcheck-suppress functionStatic
822
    int WriteInt32(GInt32 n32Value);
823
    // cppcheck-suppress functionStatic
824
    int WriteInt64(GInt64 n64Value);
825
    // cppcheck-suppress functionStatic
826
    int WriteFloat(float fValue);
827
    // cppcheck-suppress functionStatic
828
    int WriteDouble(double dValue);
829
    int WriteZeros(int nBytesToWrite);
830
    int WritePaddedString(int nFieldSize, const char *pszString);
831
832
    void SetModifiedFlag(GBool bModified)
833
0
    {
834
0
        m_bModified = bModified;
835
0
    }
836
837
    // This semi-private method gives a direct access to the internal
838
    // buffer... to be used with extreme care!!!!!!!!!
839
    GByte *GetCurDataPtr()
840
0
    {
841
0
        return (m_pabyBuf + m_nCurPos);
842
0
    }
843
};
844
845
/*---------------------------------------------------------------------
846
 *                      class TABMAPHeaderBlock
847
 *
848
 * Class to handle Read/Write operation on .MAP Header Blocks
849
 *--------------------------------------------------------------------*/
850
851
class TABMAPHeaderBlock final : public TABRawBinBlock
852
{
853
    void InitMembersWithDefaultValues();
854
    void UpdatePrecision();
855
856
  protected:
857
#if defined(__GNUC__)
858
#pragma GCC diagnostic push
859
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
860
#endif
861
    TABProjInfo m_sProj{};
862
#if defined(__GNUC__)
863
#pragma GCC diagnostic pop
864
#endif
865
866
  public:
867
    explicit TABMAPHeaderBlock(TABAccess eAccessMode = TABRead);
868
    ~TABMAPHeaderBlock() override;
869
870
    int CommitToFile() override;
871
872
    virtual int InitBlockFromData(GByte *pabyBuf, int nBlockSize, int nSizeUsed,
873
                                  GBool bMakeCopy = TRUE,
874
                                  VSILFILE *fpSrc = nullptr,
875
                                  int nOffset = 0) override;
876
    virtual int InitNewBlock(VSILFILE *fpSrc, int nBlockSize,
877
                             int nFileOffset = 0) override;
878
879
    int GetBlockClass() override
880
2.05k
    {
881
2.05k
        return TABMAP_HEADER_BLOCK;
882
2.05k
    }
883
884
    int Int2Coordsys(GInt32 nX, GInt32 nY, double &dX, double &dY);
885
    int Coordsys2Int(double dX, double dY, GInt32 &nX, GInt32 &nY,
886
                     GBool bIgnoreOverflow = FALSE);
887
    int ComprInt2Coordsys(GInt32 nCenterX, GInt32 nCenterY, int nDeltaX,
888
                          int nDeltaY, double &dX, double &dY);
889
    int Int2CoordsysDist(GInt32 nX, GInt32 nY, double &dX, double &dY);
890
    int Coordsys2IntDist(double dX, double dY, GInt32 &nX, GInt32 &nY);
891
    int SetCoordsysBounds(double dXMin, double dYMin, double dXMax,
892
                          double dYMax);
893
894
    int GetMapObjectSize(int nObjType);
895
    GBool MapObjectUsesCoordBlock(int nObjType);
896
897
    int GetProjInfo(TABProjInfo *psProjInfo);
898
    int SetProjInfo(TABProjInfo *psProjInfo);
899
900
#ifdef DEBUG
901
    void Dump(FILE *fpOut = nullptr) override;
902
#endif
903
904
    // Instead of having over 30 get/set methods, we'll make all data
905
    // members public and we will initialize them in the overloaded
906
    // LoadFromFile().  For this reason, this class should be used with care.
907
908
    GInt16 m_nMAPVersionNumber{};
909
    GInt16 m_nRegularBlockSize{};
910
911
    double m_dCoordsys2DistUnits{};
912
    GInt32 m_nXMin{};
913
    GInt32 m_nYMin{};
914
    GInt32 m_nXMax{};
915
    GInt32 m_nYMax{};
916
    GBool m_bIntBoundsOverflow{};  // Set to TRUE if coordinates
917
                                   // outside of bounds were written
918
919
    GInt32 m_nFirstIndexBlock{};
920
    GInt32 m_nFirstGarbageBlock{};
921
    GInt32 m_nFirstToolBlock{};
922
    GInt32 m_numPointObjects{};
923
    GInt32 m_numLineObjects{};
924
    GInt32 m_numRegionObjects{};
925
    GInt32 m_numTextObjects{};
926
    GInt32 m_nMaxCoordBufSize{};
927
928
    GByte m_nDistUnitsCode{};  // See Appendix F
929
    GByte m_nMaxSpIndexDepth{};
930
    GByte m_nCoordPrecision{};  // Num. decimal places on coord.
931
    GByte m_nCoordOriginQuadrant{};
932
    GByte m_nReflectXAxisCoord{};
933
    GByte m_nMaxObjLenArrayId{};  // See gabyObjLenArray[]
934
    GByte m_numPenDefs{};
935
    GByte m_numBrushDefs{};
936
    GByte m_numSymbolDefs{};
937
    GByte m_numFontDefs{};
938
    GInt16 m_numMapToolBlocks{};
939
940
    double m_XScale{};
941
    double m_YScale{};
942
    double m_XDispl{};
943
    double m_YDispl{};
944
    double m_XPrecision{};  // maximum achievable precision along X axis
945
                            // depending on bounds extent
946
    double m_YPrecision{};  // maximum achievable precision along Y axis
947
                            // depending on bounds extent
948
};
949
950
/*---------------------------------------------------------------------
951
 *                      class TABMAPIndexBlock
952
 *
953
 * Class to handle Read/Write operation on .MAP Index Blocks (Type 01)
954
 *--------------------------------------------------------------------*/
955
956
class TABMAPIndexBlock final : public TABRawBinBlock
957
{
958
    CPL_DISALLOW_COPY_ASSIGN(TABMAPIndexBlock)
959
960
  protected:
961
    int m_numEntries;
962
    TABMAPIndexEntry m_asEntries[TAB_MAX_ENTRIES_INDEX_BLOCK];
963
964
    int ReadNextEntry(TABMAPIndexEntry *psEntry);
965
    int WriteNextEntry(TABMAPIndexEntry *psEntry);
966
967
    // Use these to keep track of current block's MBR
968
    GInt32 m_nMinX;
969
    GInt32 m_nMinY;
970
    GInt32 m_nMaxX;
971
    GInt32 m_nMaxY;
972
973
    TABBinBlockManager *m_poBlockManagerRef;
974
975
    // Info about child currently loaded
976
    std::unique_ptr<TABMAPIndexBlock> m_poCurChild{};
977
    int m_nCurChildIndex;
978
    // Also need to know about its parent
979
    TABMAPIndexBlock *m_poParentRef;
980
981
    int ReadAllEntries();
982
983
    int GetMaxEntries() const
984
46
    {
985
46
        return ((m_nBlockSize - 4) / 20);
986
46
    }
987
988
  public:
989
    explicit TABMAPIndexBlock(TABAccess eAccessMode = TABRead);
990
    ~TABMAPIndexBlock() override;
991
992
    virtual int InitBlockFromData(GByte *pabyBuf, int nBlockSize, int nSizeUsed,
993
                                  GBool bMakeCopy = TRUE,
994
                                  VSILFILE *fpSrc = nullptr,
995
                                  int nOffset = 0) override;
996
    virtual int InitNewBlock(VSILFILE *fpSrc, int nBlockSize,
997
                             int nFileOffset = 0) override;
998
    int CommitToFile() override;
999
1000
    int GetBlockClass() override
1001
1
    {
1002
1
        return TABMAP_INDEX_BLOCK;
1003
1
    }
1004
1005
    void UnsetCurChild();
1006
1007
    int GetNumFreeEntries();
1008
1009
    int GetNumEntries()
1010
23
    {
1011
23
        return m_numEntries;
1012
23
    }
1013
1014
    TABMAPIndexEntry *GetEntry(int iIndex);
1015
    int AddEntry(GInt32 XMin, GInt32 YMin, GInt32 XMax, GInt32 YMax,
1016
                 GInt32 nBlockPtr, GBool bAddInThisNodeOnly = FALSE);
1017
    int GetCurMaxDepth();
1018
    void GetMBR(GInt32 &nXMin, GInt32 &nYMin, GInt32 &nXMax, GInt32 &nYMax);
1019
    void SetMBR(GInt32 nXMin, GInt32 nYMin, GInt32 nXMax, GInt32 nYMax);
1020
1021
    GInt32 GetNodeBlockPtr()
1022
128
    {
1023
128
        return GetStartAddress();
1024
128
    }
1025
1026
    void SetMAPBlockManagerRef(TABBinBlockManager *poBlockMgr);
1027
    void SetParentRef(TABMAPIndexBlock *poParent);
1028
    void SetCurChild(std::unique_ptr<TABMAPIndexBlock> &&poChild,
1029
                     int nChildIndex);
1030
1031
    int GetCurChildIndex()
1032
0
    {
1033
0
        return m_nCurChildIndex;
1034
0
    }
1035
1036
    TABMAPIndexBlock *GetCurChild()
1037
0
    {
1038
0
        return m_poCurChild.get();
1039
0
    }
1040
1041
    TABMAPIndexBlock *GetParentRef()
1042
0
    {
1043
0
        return m_poParentRef;
1044
0
    }
1045
1046
    int SplitNode(GInt32 nNewEntryXMin, GInt32 nNewEntryYMin,
1047
                  GInt32 nNewEntryXMax, GInt32 nNewEntryYMax);
1048
    int SplitRootNode(GInt32 nNewEntryXMin, GInt32 nNewEntryYMin,
1049
                      GInt32 nNewEntryXMax, GInt32 nNewEntryYMax);
1050
    void UpdateCurChildMBR(GInt32 nXMin, GInt32 nYMin, GInt32 nXMax,
1051
                           GInt32 nYMax, GInt32 nBlockPtr);
1052
    void RecomputeMBR();
1053
    int InsertEntry(GInt32 XMin, GInt32 YMin, GInt32 XMax, GInt32 YMax,
1054
                    GInt32 nBlockPtr);
1055
    int ChooseSubEntryForInsert(GInt32 nXMin, GInt32 nYMin, GInt32 nXMax,
1056
                                GInt32 nYMax);
1057
    GInt32 ChooseLeafForInsert(GInt32 nXMin, GInt32 nYMin, GInt32 nXMax,
1058
                               GInt32 nYMax);
1059
    int UpdateLeafEntry(GInt32 nBlockPtr, GInt32 nXMin, GInt32 nYMin,
1060
                        GInt32 nXMax, GInt32 nYMax);
1061
    int GetCurLeafEntryMBR(GInt32 nBlockPtr, GInt32 &nXMin, GInt32 &nYMin,
1062
                           GInt32 &nXMax, GInt32 &nYMax);
1063
1064
    // Static utility functions for node splitting, also used by
1065
    // the TABMAPObjectBlock class.
1066
    static double ComputeAreaDiff(GInt32 nNodeXMin, GInt32 nNodeYMin,
1067
                                  GInt32 nNodeXMax, GInt32 nNodeYMax,
1068
                                  GInt32 nEntryXMin, GInt32 nEntryYMin,
1069
                                  GInt32 nEntryXMax, GInt32 nEntryYMax);
1070
    static int PickSeedsForSplit(TABMAPIndexEntry *pasEntries, int numEntries,
1071
                                 int nSrcCurChildIndex, GInt32 nNewEntryXMin,
1072
                                 GInt32 nNewEntryYMin, GInt32 nNewEntryXMax,
1073
                                 GInt32 nNewEntryYMax, int &nSeed1,
1074
                                 int &nSeed2);
1075
#ifdef DEBUG
1076
    void Dump(FILE *fpOut = nullptr) override;
1077
#endif
1078
};
1079
1080
/*---------------------------------------------------------------------
1081
 *                      class TABMAPObjectBlock
1082
 *
1083
 * Class to handle Read/Write operation on .MAP Object data Blocks (Type 02)
1084
 *--------------------------------------------------------------------*/
1085
1086
class TABMAPObjectBlock final : public TABRawBinBlock
1087
{
1088
    CPL_DISALLOW_COPY_ASSIGN(TABMAPObjectBlock)
1089
1090
  protected:
1091
    int m_numDataBytes; /* Excluding first 4 bytes header */
1092
    GInt32 m_nFirstCoordBlock;
1093
    GInt32 m_nLastCoordBlock;
1094
    GInt32 m_nCenterX;
1095
    GInt32 m_nCenterY;
1096
1097
    // In order to compute block center, we need to keep track of MBR
1098
    GInt32 m_nMinX;
1099
    GInt32 m_nMinY;
1100
    GInt32 m_nMaxX;
1101
    GInt32 m_nMaxY;
1102
1103
    // Keep track of current object either in read or read/write mode
1104
    int m_nCurObjectOffset;  // -1 if there is no current object.
1105
    int m_nCurObjectId;      // -1 if there is no current object.
1106
    TABGeomType
1107
        m_nCurObjectType;  // TAB_GEOM_UNSET if there is no current object.
1108
1109
    int m_bLockCenter;
1110
1111
  public:
1112
    explicit TABMAPObjectBlock(TABAccess eAccessMode = TABRead);
1113
    ~TABMAPObjectBlock() override;
1114
1115
    int CommitToFile() override;
1116
    virtual int InitBlockFromData(GByte *pabyBuf, int nBlockSize, int nSizeUsed,
1117
                                  GBool bMakeCopy = TRUE,
1118
                                  VSILFILE *fpSrc = nullptr,
1119
                                  int nOffset = 0) override;
1120
    virtual int InitNewBlock(VSILFILE *fpSrc, int nBlockSize,
1121
                             int nFileOffset = 0) override;
1122
1123
    int GetBlockClass() override
1124
534
    {
1125
534
        return TABMAP_OBJECT_BLOCK;
1126
534
    }
1127
1128
    int ReadIntCoord(GBool bCompressed, GInt32 &nX, GInt32 &nY);
1129
    int WriteIntCoord(GInt32 nX, GInt32 nY, GBool bCompressed);
1130
    int WriteIntMBRCoord(GInt32 nXMin, GInt32 nYMin, GInt32 nXMax, GInt32 nYMax,
1131
                         GBool bCompressed);
1132
    int UpdateMBR(GInt32 nX, GInt32 nY);
1133
1134
    int PrepareNewObject(TABMAPObjHdr *poObjHdr);
1135
    int CommitNewObject(TABMAPObjHdr *poObjHdr);
1136
1137
    void AddCoordBlockRef(GInt32 nCoordBlockAddress);
1138
1139
    GInt32 GetFirstCoordBlockAddress()
1140
0
    {
1141
0
        return m_nFirstCoordBlock;
1142
0
    }
1143
1144
    GInt32 GetLastCoordBlockAddress()
1145
6.41k
    {
1146
6.41k
        return m_nLastCoordBlock;
1147
6.41k
    }
1148
1149
    void GetMBR(GInt32 &nXMin, GInt32 &nYMin, GInt32 &nXMax, GInt32 &nYMax);
1150
    void SetMBR(GInt32 nXMin, GInt32 nYMin, GInt32 nXMax, GInt32 nYMax);
1151
1152
    void Rewind();
1153
    void ClearObjects();
1154
    void LockCenter();
1155
    void SetCenterFromOtherBlock(TABMAPObjectBlock *poOtherObjBlock);
1156
    int AdvanceToNextObject(TABMAPHeaderBlock *);
1157
1158
    int GetCurObjectOffset()
1159
0
    {
1160
0
        return m_nCurObjectOffset;
1161
0
    }
1162
1163
    int GetCurObjectId()
1164
0
    {
1165
0
        return m_nCurObjectId;
1166
0
    }
1167
1168
    TABGeomType GetCurObjectType()
1169
0
    {
1170
0
        return m_nCurObjectType;
1171
0
    }
1172
1173
#ifdef DEBUG
1174
    void Dump(FILE *fpOut = nullptr) override
1175
    {
1176
        Dump(fpOut, FALSE);
1177
    }
1178
1179
    void Dump(FILE *fpOut, GBool bDetails);
1180
#endif
1181
};
1182
1183
/*---------------------------------------------------------------------
1184
 *                      class TABMAPCoordBlock
1185
 *
1186
 * Class to handle Read/Write operation on .MAP Coordinate Blocks (Type 03)
1187
 *--------------------------------------------------------------------*/
1188
1189
class TABMAPCoordBlock final : public TABRawBinBlock
1190
{
1191
    CPL_DISALLOW_COPY_ASSIGN(TABMAPCoordBlock)
1192
1193
  protected:
1194
    int m_numDataBytes; /* Excluding first 8 bytes header */
1195
    GInt32 m_nNextCoordBlock;
1196
    int m_numBlocksInChain;
1197
1198
    GInt32 m_nComprOrgX;
1199
    GInt32 m_nComprOrgY;
1200
1201
    // In order to compute block center, we need to keep track of MBR
1202
    GInt32 m_nMinX;
1203
    GInt32 m_nMinY;
1204
    GInt32 m_nMaxX;
1205
    GInt32 m_nMaxY;
1206
1207
    TABBinBlockManager *m_poBlockManagerRef;
1208
1209
    int m_nTotalDataSize;    // Num bytes in whole chain of blocks
1210
    int m_nFeatureDataSize;  // Num bytes for current feature coords
1211
1212
    GInt32 m_nFeatureXMin;  // Used to keep track of current
1213
    GInt32 m_nFeatureYMin;  // feature MBR.
1214
    GInt32 m_nFeatureXMax;
1215
    GInt32 m_nFeatureYMax;
1216
1217
  public:
1218
    explicit TABMAPCoordBlock(TABAccess eAccessMode = TABRead);
1219
    ~TABMAPCoordBlock() override;
1220
1221
    virtual int InitBlockFromData(GByte *pabyBuf, int nBlockSize, int nSizeUsed,
1222
                                  GBool bMakeCopy = TRUE,
1223
                                  VSILFILE *fpSrc = nullptr,
1224
                                  int nOffset = 0) override;
1225
    virtual int InitNewBlock(VSILFILE *fpSrc, int nBlockSize,
1226
                             int nFileOffset = 0) override;
1227
    int CommitToFile() override;
1228
1229
    int GetBlockClass() override
1230
0
    {
1231
0
        return TABMAP_COORD_BLOCK;
1232
0
    }
1233
1234
    void SetMAPBlockManagerRef(TABBinBlockManager *poBlockManager);
1235
    int ReadBytes(int numBytes, GByte *pabyDstBuf) override;
1236
    int WriteBytes(int nBytesToWrite, const GByte *pBuf) override;
1237
    void SetComprCoordOrigin(GInt32 nX, GInt32 nY);
1238
    int ReadIntCoord(GBool bCompressed, GInt32 &nX, GInt32 &nY);
1239
    int ReadIntCoords(GBool bCompressed, int numCoords, GInt32 *panXY);
1240
    int ReadCoordSecHdrs(GBool bCompressed, int nVersion, int numSections,
1241
                         TABMAPCoordSecHdr *pasHdrs, GInt32 &numVerticesTotal);
1242
    int WriteCoordSecHdrs(int nVersion, int numSections,
1243
                          TABMAPCoordSecHdr *pasHdrs, GBool bCompressed);
1244
1245
    void SetNextCoordBlock(GInt32 nNextCoordBlockAddress);
1246
1247
    GInt32 GetNextCoordBlock()
1248
0
    {
1249
0
        return m_nNextCoordBlock;
1250
0
    }
1251
1252
    int WriteIntCoord(GInt32 nX, GInt32 nY, GBool bCompressed);
1253
1254
    int GetNumBlocksInChain()
1255
650
    {
1256
650
        return m_numBlocksInChain;
1257
650
    }
1258
1259
    void ResetTotalDataSize()
1260
0
    {
1261
0
        m_nTotalDataSize = 0;
1262
0
    }
1263
1264
    int GetTotalDataSize()
1265
0
    {
1266
0
        return m_nTotalDataSize;
1267
0
    }
1268
1269
    void SeekEnd();
1270
    void StartNewFeature();
1271
1272
    int GetFeatureDataSize()
1273
6.39k
    {
1274
6.39k
        return m_nFeatureDataSize;
1275
6.39k
    }
1276
1277
    //__TODO__ Can we flush GetFeatureMBR() and all MBR tracking in this
1278
    // class???
1279
    void GetFeatureMBR(GInt32 &nXMin, GInt32 &nYMin, GInt32 &nXMax,
1280
                       GInt32 &nYMax);
1281
1282
#ifdef DEBUG
1283
    void Dump(FILE *fpOut = nullptr) override;
1284
#endif
1285
};
1286
1287
/*---------------------------------------------------------------------
1288
 *                      class TABMAPToolBlock
1289
 *
1290
 * Class to handle Read/Write operation on .MAP Drawing Tool Blocks (Type 05)
1291
 *
1292
 * In addition to handling the I/O, this class also maintains the list
1293
 * of Tool definitions in memory.
1294
 *--------------------------------------------------------------------*/
1295
1296
class TABMAPToolBlock final : public TABRawBinBlock
1297
{
1298
    CPL_DISALLOW_COPY_ASSIGN(TABMAPToolBlock)
1299
1300
  protected:
1301
    int m_numDataBytes; /* Excluding first 8 bytes header */
1302
    GInt32 m_nNextToolBlock;
1303
    int m_numBlocksInChain;
1304
1305
    TABBinBlockManager *m_poBlockManagerRef;
1306
1307
  public:
1308
    explicit TABMAPToolBlock(TABAccess eAccessMode = TABRead);
1309
    ~TABMAPToolBlock() override;
1310
1311
    virtual int InitBlockFromData(GByte *pabyBuf, int nBlockSize, int nSizeUsed,
1312
                                  GBool bMakeCopy = TRUE,
1313
                                  VSILFILE *fpSrc = nullptr,
1314
                                  int nOffset = 0) override;
1315
    virtual int InitNewBlock(VSILFILE *fpSrc, int nBlockSize,
1316
                             int nFileOffset = 0) override;
1317
    int CommitToFile() override;
1318
1319
    int GetBlockClass() override
1320
0
    {
1321
0
        return TABMAP_TOOL_BLOCK;
1322
0
    }
1323
1324
    void SetMAPBlockManagerRef(TABBinBlockManager *poBlockManager);
1325
    int ReadBytes(int numBytes, GByte *pabyDstBuf) override;
1326
    int WriteBytes(int nBytesToWrite, const GByte *pBuf) override;
1327
1328
    void SetNextToolBlock(GInt32 nNextCoordBlockAddress);
1329
1330
    GBool EndOfChain();
1331
1332
    int GetNumBlocksInChain()
1333
123
    {
1334
123
        return m_numBlocksInChain;
1335
123
    }
1336
1337
    int CheckAvailableSpace(int nToolType);
1338
1339
#ifdef DEBUG
1340
    void Dump(FILE *fpOut = nullptr) override;
1341
#endif
1342
};
1343
1344
/*=====================================================================
1345
       Classes to deal with .MAP files at the MapInfo object level
1346
 =====================================================================*/
1347
1348
/*---------------------------------------------------------------------
1349
 *                      class TABIDFile
1350
 *
1351
 * Class to handle Read/Write operation on .ID files... the .ID file
1352
 * contains an index to the objects in the .MAP file by object id.
1353
 *--------------------------------------------------------------------*/
1354
1355
class TABIDFile
1356
{
1357
    CPL_DISALLOW_COPY_ASSIGN(TABIDFile)
1358
1359
  private:
1360
    char *m_pszFname;
1361
    VSILFILE *m_fp;
1362
    TABAccess m_eAccessMode;
1363
1364
    TABRawBinBlock *m_poIDBlock;
1365
    int m_nBlockSize;
1366
    GInt32 m_nMaxId;
1367
1368
  public:
1369
    TABIDFile();
1370
    ~TABIDFile();
1371
1372
    int Open(const char *pszFname, const char *pszAccess);
1373
    int Open(const char *pszFname, TABAccess eAccess);
1374
    int Close();
1375
1376
    int SyncToDisk();
1377
1378
    GInt32 GetObjPtr(GInt32 nObjId);
1379
    int SetObjPtr(GInt32 nObjId, GInt32 nObjPtr);
1380
    GInt32 GetMaxObjId();
1381
1382
#ifdef DEBUG
1383
    void Dump(FILE *fpOut = nullptr);
1384
#endif
1385
};
1386
1387
/*---------------------------------------------------------------------
1388
 *                      class TABMAPFile
1389
 *
1390
 * Class to handle Read/Write operation on .MAP files... this class hides
1391
 * all the dealings with blocks, indexes, etc.
1392
 * Use this class to deal with MapInfo objects directly.
1393
 *--------------------------------------------------------------------*/
1394
1395
class TABMAPFile
1396
{
1397
    CPL_DISALLOW_COPY_ASSIGN(TABMAPFile)
1398
1399
  private:
1400
    int m_nMinTABVersion;
1401
    char *m_pszFname;
1402
    VSILFILE *m_fp;
1403
    TABAccess m_eAccessMode;
1404
1405
    TABBinBlockManager m_oBlockManager{};
1406
1407
    TABMAPHeaderBlock *m_poHeader;
1408
1409
    // Members used to access objects using the spatial index
1410
    TABMAPIndexBlock *m_poSpIndex;
1411
1412
    // Defaults to FALSE, i.e. optimized spatial index
1413
    GBool m_bQuickSpatialIndexMode;
1414
1415
    // Member used to access objects using the object ids (.ID file)
1416
    TABIDFile *m_poIdIndex;
1417
1418
    // Current object data block.
1419
    TABMAPObjectBlock *m_poCurObjBlock;
1420
    int m_nCurObjPtr;
1421
    TABGeomType m_nCurObjType;
1422
    int m_nCurObjId;
1423
    TABMAPCoordBlock *m_poCurCoordBlock;
1424
1425
    // Drawing Tool Def. table (takes care of all drawing tools in memory)
1426
    TABToolDefTable *m_poToolDefTable;
1427
1428
    // Coordinates filter... default is MBR of the whole file
1429
    TABVertex m_sMinFilter{};
1430
    TABVertex m_sMaxFilter{};
1431
    GInt32 m_XMinFilter;
1432
    GInt32 m_YMinFilter;
1433
    GInt32 m_XMaxFilter;
1434
    GInt32 m_YMaxFilter;
1435
1436
    int m_bUpdated;
1437
    int m_bLastOpWasRead;
1438
    int m_bLastOpWasWrite;
1439
1440
    int CommitObjAndCoordBlocks(GBool bDeleteObjects = FALSE);
1441
    int LoadObjAndCoordBlocks(GInt32 nBlockPtr);
1442
    TABMAPObjectBlock *SplitObjBlock(TABMAPObjHdr *poObjHdrToAdd,
1443
                                     int nSizeOfObjToAdd);
1444
    int MoveObjToBlock(TABMAPObjHdr *poObjHdr,
1445
                       TABMAPCoordBlock *poSrcCoordBlock,
1446
                       TABMAPObjectBlock *poDstObjBlock,
1447
                       TABMAPCoordBlock **ppoDstCoordBlock);
1448
    int PrepareCoordBlock(int nObjType, TABMAPObjectBlock *poObjBlock,
1449
                          TABMAPCoordBlock **ppoCoordBlock);
1450
1451
    int InitDrawingTools();
1452
    int CommitDrawingTools();
1453
1454
    int CommitSpatialIndex();
1455
1456
    // Stuff related to traversing spatial index.
1457
    TABMAPIndexBlock *m_poSpIndexLeaf;
1458
1459
    // Strings encoding
1460
    CPLString m_osEncoding;
1461
1462
    int LoadNextMatchingObjectBlock(int bFirstObject);
1463
    TABRawBinBlock *PushBlock(int nFileOffset);
1464
1465
    int ReOpenReadWrite();
1466
1467
  public:
1468
    explicit TABMAPFile(const char *pszEncoding);
1469
    ~TABMAPFile();
1470
1471
    int Open(const char *pszFname, const char *pszAccess,
1472
             GBool bNoErrorMsg = FALSE, int nBlockSizeForCreate = 512);
1473
    int Open(const char *pszFname, TABAccess eAccess, GBool bNoErrorMsg = FALSE,
1474
             int nBlockSizeForCreate = 512);
1475
    int Close();
1476
1477
    GUInt32 GetFileSize();
1478
1479
    int SyncToDisk();
1480
1481
    int SetQuickSpatialIndexMode(GBool bQuickSpatialIndexMode = TRUE);
1482
1483
    int Int2Coordsys(GInt32 nX, GInt32 nY, double &dX, double &dY);
1484
    int Coordsys2Int(double dX, double dY, GInt32 &nX, GInt32 &nY,
1485
                     GBool bIgnoreOverflow = FALSE);
1486
    int Int2CoordsysDist(GInt32 nX, GInt32 nY, double &dX, double &dY);
1487
    int Coordsys2IntDist(double dX, double dY, GInt32 &nX, GInt32 &nY);
1488
    void SetCoordFilter(TABVertex sMin, TABVertex sMax);
1489
    // cppcheck-suppress functionStatic
1490
    void GetCoordFilter(TABVertex &sMin, TABVertex &sMax) const;
1491
    void ResetCoordFilter();
1492
    int SetCoordsysBounds(double dXMin, double dYMin, double dXMax,
1493
                          double dYMax);
1494
1495
    GInt32 GetMaxObjId();
1496
    int MoveToObjId(int nObjId);
1497
    void UpdateMapHeaderInfo(TABGeomType nObjType);
1498
    int PrepareNewObj(TABMAPObjHdr *poObjHdr);
1499
    int PrepareNewObjViaSpatialIndex(TABMAPObjHdr *poObjHdr);
1500
    int PrepareNewObjViaObjBlock(TABMAPObjHdr *poObjHdr);
1501
    int CommitNewObj(TABMAPObjHdr *poObjHdr);
1502
1503
    void ResetReading();
1504
    int GetNextFeatureId(int nPrevId);
1505
1506
    int MarkAsDeleted();
1507
1508
    TABGeomType GetCurObjType();
1509
    int GetCurObjId();
1510
    TABMAPObjectBlock *GetCurObjBlock();
1511
    TABMAPCoordBlock *GetCurCoordBlock();
1512
    TABMAPCoordBlock *GetCoordBlock(int nFileOffset);
1513
    TABMAPHeaderBlock *GetHeaderBlock();
1514
    TABIDFile *GetIDFileRef();
1515
    TABRawBinBlock *GetIndexObjectBlock(int nFileOffset);
1516
1517
    int ReadPenDef(int nPenIndex, TABPenDef *psDef);
1518
    int ReadBrushDef(int nBrushIndex, TABBrushDef *psDef);
1519
    int ReadFontDef(int nFontIndex, TABFontDef *psDef);
1520
    int ReadSymbolDef(int nSymbolIndex, TABSymbolDef *psDef);
1521
    int WritePenDef(TABPenDef *psDef);
1522
    int WriteBrushDef(TABBrushDef *psDef);
1523
    int WriteFontDef(TABFontDef *psDef);
1524
    int WriteSymbolDef(TABSymbolDef *psDef);
1525
1526
    int GetMinTABFileVersion();
1527
1528
    const CPLString &GetEncoding() const;
1529
    void SetEncoding(const CPLString &);
1530
1531
    static bool IsValidObjType(int nObjType);
1532
1533
#ifdef DEBUG
1534
    void Dump(FILE *fpOut = nullptr);
1535
    void DumpSpatialIndexToMIF(TABMAPIndexBlock *poNode, FILE *fpMIF,
1536
                               FILE *fpMID, int nParentId = -1,
1537
                               int nIndexInNode = -1, int nCurDepth = 0,
1538
                               int nMaxDepth = -1);
1539
#endif
1540
};
1541
1542
/*---------------------------------------------------------------------
1543
 *                      class TABINDNode
1544
 *
1545
 * An index node in a .IND file.
1546
 *
1547
 * This class takes care of reading child nodes as necessary when looking
1548
 * for a given key value in the index tree.
1549
 *--------------------------------------------------------------------*/
1550
1551
class TABINDNode
1552
{
1553
    CPL_DISALLOW_COPY_ASSIGN(TABINDNode)
1554
1555
  private:
1556
    VSILFILE *m_fp;
1557
    TABAccess m_eAccessMode;
1558
    TABINDNode *m_poCurChildNode;
1559
    TABINDNode *m_poParentNodeRef;
1560
1561
    TABBinBlockManager *m_poBlockManagerRef;
1562
1563
    int m_nSubTreeDepth;
1564
    int m_nKeyLength;
1565
    TABFieldType m_eFieldType;
1566
    GBool m_bUnique;
1567
1568
    GInt32 m_nCurDataBlockPtr;
1569
    int m_nCurIndexEntry;
1570
    TABRawBinBlock *m_poDataBlock;
1571
    int m_numEntriesInNode;
1572
    GInt32 m_nPrevNodePtr;
1573
    GInt32 m_nNextNodePtr;
1574
1575
    int GotoNodePtr(GInt32 nNewNodePtr);
1576
    GInt32 ReadIndexEntry(int nEntryNo, GByte *pKeyValue);
1577
    int IndexKeyCmp(const GByte *pKeyValue, int nEntryNo);
1578
1579
    int InsertEntry(GByte *pKeyValue, GInt32 nRecordNo,
1580
                    GBool bInsertAfterCurChild = FALSE,
1581
                    GBool bMakeNewEntryCurChild = FALSE);
1582
    int SetNodeBufferDirectly(int numEntries, GByte *pBuf,
1583
                              int nCurIndexEntry = 0,
1584
                              TABINDNode *poCurChild = nullptr);
1585
    GInt32 FindFirst(const GByte *pKeyValue, std::set<int> &oSetVisitedNodePtr);
1586
1587
  public:
1588
    explicit TABINDNode(TABAccess eAccessMode = TABRead);
1589
    ~TABINDNode();
1590
1591
    int InitNode(VSILFILE *fp, int nBlockPtr, int nKeyLength, int nSubTreeDepth,
1592
                 GBool bUnique, TABBinBlockManager *poBlockMgr = nullptr,
1593
                 TABINDNode *poParentNode = nullptr, int nPrevNodePtr = 0,
1594
                 int nNextNodePtr = 0);
1595
1596
    int SetFieldType(TABFieldType eType);
1597
1598
    TABFieldType GetFieldType()
1599
0
    {
1600
0
        return m_eFieldType;
1601
0
    }
1602
1603
    void SetUnique(GBool bUnique)
1604
0
    {
1605
0
        m_bUnique = bUnique;
1606
0
    }
1607
1608
    GBool IsUnique()
1609
0
    {
1610
0
        return m_bUnique;
1611
0
    }
1612
1613
    int GetKeyLength()
1614
8.24k
    {
1615
8.24k
        return m_nKeyLength;
1616
8.24k
    }
1617
1618
    int GetSubTreeDepth()
1619
0
    {
1620
0
        return m_nSubTreeDepth;
1621
0
    }
1622
1623
    GInt32 GetNodeBlockPtr()
1624
0
    {
1625
0
        return m_nCurDataBlockPtr;
1626
0
    }
1627
1628
    int GetNumEntries()
1629
0
    {
1630
0
        return m_numEntriesInNode;
1631
0
    }
1632
1633
    int GetMaxNumEntries()
1634
0
    {
1635
0
        return (512 - 12) / (m_nKeyLength + 4);
1636
0
    }
1637
1638
    GInt32 FindFirst(const GByte *pKeyValue);
1639
    GInt32 FindNext(GByte *pKeyValue);
1640
1641
    int CommitToFile();
1642
1643
    int AddEntry(GByte *pKeyValue, GInt32 nRecordNo,
1644
                 GBool bAddInThisNodeOnly = FALSE,
1645
                 GBool bInsertAfterCurChild = FALSE,
1646
                 GBool bMakeNewEntryCurChild = FALSE);
1647
    int SplitNode();
1648
    int SplitRootNode();
1649
    GByte *GetNodeKey();
1650
    int UpdateCurChildEntry(GByte *pKeyValue, GInt32 nRecordNo);
1651
    int UpdateSplitChild(GByte *pKeyValue1, GInt32 nRecordNo1,
1652
                         GByte *pKeyValue2, GInt32 nRecordNo2,
1653
                         int nNewCurChildNo /* 1 or 2 */);
1654
1655
    int SetNodeBlockPtr(GInt32 nThisNodePtr);
1656
    int SetPrevNodePtr(GInt32 nPrevNodePtr);
1657
    int SetNextNodePtr(GInt32 nNextNodePtr);
1658
1659
#ifdef DEBUG
1660
    void Dump(FILE *fpOut = nullptr);
1661
#endif
1662
};
1663
1664
/*---------------------------------------------------------------------
1665
 *                      class TABINDFile
1666
 *
1667
 * Class to handle table field index (.IND) files... we use this
1668
 * class as the main entry point to open and search the table field indexes.
1669
 * Note that .IND files are supported for read access only.
1670
 *--------------------------------------------------------------------*/
1671
1672
class TABINDFile
1673
{
1674
    CPL_DISALLOW_COPY_ASSIGN(TABINDFile)
1675
1676
  private:
1677
    char *m_pszFname;
1678
    VSILFILE *m_fp;
1679
    TABAccess m_eAccessMode;
1680
1681
    TABBinBlockManager m_oBlockManager{};
1682
1683
    int m_numIndexes;
1684
    TABINDNode **m_papoIndexRootNodes;
1685
    GByte **m_papbyKeyBuffers;
1686
1687
    int ValidateIndexNo(int nIndexNumber);
1688
    int ReadHeader();
1689
    int WriteHeader();
1690
1691
  public:
1692
    TABINDFile();
1693
    ~TABINDFile();
1694
1695
    int Open(const char *pszFname, const char *pszAccess,
1696
             GBool bTestOpenNoError = FALSE);
1697
    int Close();
1698
1699
    int GetNumIndexes()
1700
0
    {
1701
0
        return m_numIndexes;
1702
0
    }
1703
1704
    int SetIndexFieldType(int nIndexNumber, TABFieldType eType);
1705
    int SetIndexUnique(int nIndexNumber, GBool bUnique = TRUE);
1706
    GByte *BuildKey(int nIndexNumber, GInt32 nValue);
1707
    GByte *BuildKey(int nIndexNumber, GInt64 nValue);
1708
    GByte *BuildKey(int nIndexNumber, const char *pszStr);
1709
    GByte *BuildKey(int nIndexNumber, double dValue);
1710
    GInt32 FindFirst(int nIndexNumber, GByte *pKeyValue);
1711
    GInt32 FindNext(int nIndexNumber, GByte *pKeyValue);
1712
1713
    int CreateIndex(TABFieldType eType, int nFieldSize);
1714
    int AddEntry(int nIndexNumber, GByte *pKeyValue, GInt32 nRecordNo);
1715
1716
#ifdef DEBUG
1717
    void Dump(FILE *fpOut = nullptr);
1718
#endif
1719
};
1720
1721
/*---------------------------------------------------------------------
1722
 *                      class TABDATFile
1723
 *
1724
 * Class to handle Read/Write operation on .DAT files... the .DAT file
1725
 * contains the table of attribute field values.
1726
 *--------------------------------------------------------------------*/
1727
1728
class TABDATFile
1729
{
1730
    CPL_DISALLOW_COPY_ASSIGN(TABDATFile)
1731
1732
  private:
1733
    char *m_pszFname;
1734
    VSILFILE *m_fp;
1735
    TABAccess m_eAccessMode;
1736
    TABTableType m_eTableType;
1737
1738
    TABRawBinBlock *m_poHeaderBlock;
1739
    int m_numFields;
1740
    TABDATFieldDef *m_pasFieldDef;
1741
1742
    TABRawBinBlock *m_poRecordBlock;
1743
    int m_nBlockSize;
1744
    int m_nRecordSize;
1745
    int m_nCurRecordId;
1746
    GBool m_bCurRecordDeletedFlag;
1747
1748
    GInt32 m_numRecords;
1749
    GInt32 m_nFirstRecordPtr;
1750
    GBool m_bWriteHeaderInitialized;
1751
    GBool m_bWriteEOF;
1752
1753
    int m_bUpdated;
1754
    CPLString m_osEncoding;
1755
1756
    int InitWriteHeader();
1757
    int WriteHeader();
1758
1759
    // We know that character strings are limited to 254 chars in MapInfo
1760
    // Using a buffer pr. class instance to avoid threading issues with the
1761
    // library
1762
    char m_szBuffer[256];
1763
1764
  public:
1765
    explicit TABDATFile(const char *pszEncoding);
1766
    ~TABDATFile();
1767
1768
    int Open(const char *pszFname, const char *pszAccess,
1769
             TABTableType eTableType = TABTableNative);
1770
    int Open(const char *pszFname, TABAccess eAccess,
1771
             TABTableType eTableType = TABTableNative);
1772
    int Close();
1773
1774
    int GetNumFields();
1775
    TABFieldType GetFieldType(int nFieldId);
1776
    int GetFieldWidth(int nFieldId);
1777
    int GetFieldPrecision(int nFieldId);
1778
    int ValidateFieldInfoFromTAB(int iField, const char *pszName,
1779
                                 TABFieldType eType, int nWidth,
1780
                                 int nPrecision);
1781
1782
    int AddField(const char *pszName, TABFieldType eType, int nWidth,
1783
                 int nPrecision = 0);
1784
1785
    int DeleteField(int iField);
1786
    int ReorderFields(int *panMap);
1787
    int AlterFieldDefn(int iField, const OGRFieldDefn *poSrcFieldDefn,
1788
                       OGRFieldDefn *poNewFieldDefn, int nFlags);
1789
1790
    int SyncToDisk();
1791
1792
    GInt32 GetNumRecords();
1793
    TABRawBinBlock *GetRecordBlock(int nRecordId);
1794
1795
    GBool IsCurrentRecordDeleted()
1796
901k
    {
1797
901k
        return m_bCurRecordDeletedFlag;
1798
901k
    }
1799
1800
    int CommitRecordToFile();
1801
1802
    int MarkAsDeleted();
1803
    int MarkRecordAsExisting();
1804
1805
    const char *ReadCharField(int nWidth);
1806
    GInt32 ReadIntegerField(int nWidth);
1807
    GInt16 ReadSmallIntField(int nWidth);
1808
    GInt64 ReadLargeIntField(int nWidth);
1809
    double ReadFloatField(int nWidth);
1810
    double ReadDecimalField(int nWidth);
1811
    bool ReadLogicalField(int nWidth);
1812
    const char *ReadDateField(int nWidth);
1813
    int ReadDateField(int nWidth, int *nYear, int *nMonth, int *nDay);
1814
    const char *ReadTimeField(int nWidth);
1815
    int ReadTimeField(int nWidth, int *nHour, int *nMinute, int *nSecond,
1816
                      int *nMS);
1817
    const char *ReadDateTimeField(int nWidth);
1818
    int ReadDateTimeField(int nWidth, int *nYear, int *nMonth, int *nDay,
1819
                          int *nHour, int *nMinute, int *nSecond, int *nMS);
1820
1821
    int WriteCharField(const char *pszValue, int nWidth, TABINDFile *poINDFile,
1822
                       int nIndexNo);
1823
    int WriteIntegerField(GInt32 nValue, TABINDFile *poINDFile, int nIndexNo);
1824
    int WriteSmallIntField(GInt16 nValue, TABINDFile *poINDFile, int nIndexNo);
1825
    int WriteLargeIntField(GInt64 nValue, TABINDFile *poINDFile, int nIndexNo);
1826
    int WriteFloatField(double dValue, TABINDFile *poINDFile, int nIndexNo);
1827
    int WriteDecimalField(double dValue, int nWidth, int nPrecision,
1828
                          TABINDFile *poINDFile, int nIndexNo);
1829
    int WriteLogicalField(bool bValue, TABINDFile *poINDFile, int nIndexNo);
1830
    int WriteDateField(const char *pszValue, TABINDFile *poINDFile,
1831
                       int nIndexNo);
1832
    int WriteDateField(int nYear, int nMonth, int nDay, TABINDFile *poINDFile,
1833
                       int nIndexNo);
1834
    int WriteTimeField(const char *pszValue, TABINDFile *poINDFile,
1835
                       int nIndexNo);
1836
    int WriteTimeField(int nHour, int nMinute, int nSecond, int nMS,
1837
                       TABINDFile *poINDFile, int nIndexNo);
1838
    int WriteDateTimeField(const char *pszValue, TABINDFile *poINDFile,
1839
                           int nIndexNo);
1840
    int WriteDateTimeField(int nYear, int nMonth, int nDay, int nHour,
1841
                           int nMinute, int nSecond, int nMS,
1842
                           TABINDFile *poINDFile, int nIndexNo);
1843
1844
    const CPLString &GetEncoding() const;
1845
    void SetEncoding(const CPLString &);
1846
1847
#ifdef DEBUG
1848
    void Dump(FILE *fpOut = nullptr);
1849
#endif
1850
};
1851
1852
/*---------------------------------------------------------------------
1853
 *                      class TABRelation
1854
 *
1855
 * Class that maintains a relation between 2 tables through a field
1856
 * in each table (the SQL "where table1.field1=table2.field2" found in
1857
 * TABView datasets).
1858
 *
1859
 * An instance of this class is used to read data records from the
1860
 * combined tables as if they were a single one.
1861
 *--------------------------------------------------------------------*/
1862
1863
class TABRelation
1864
{
1865
    CPL_DISALLOW_COPY_ASSIGN(TABRelation)
1866
1867
  private:
1868
    /* Information about the main table.
1869
     */
1870
    TABFile *m_poMainTable;
1871
    char *m_pszMainFieldName;
1872
    int m_nMainFieldNo;
1873
1874
    /* Information about the related table.
1875
     * NOTE: The related field MUST be indexed.
1876
     */
1877
    TABFile *m_poRelTable;
1878
    char *m_pszRelFieldName;
1879
    int m_nRelFieldNo;
1880
1881
    TABINDFile *m_poRelINDFileRef;
1882
    int m_nRelFieldIndexNo;
1883
1884
    int m_nUniqueRecordNo;
1885
1886
    /* Main and Rel table field map:
1887
     * For each field in the source tables, -1 means that the field is not
1888
     * selected, and a value >=0 is the index of this field in the combined
1889
     * FeatureDefn
1890
     */
1891
    int *m_panMainTableFieldMap;
1892
    int *m_panRelTableFieldMap;
1893
1894
    OGRFeatureDefn *m_poDefn;
1895
1896
    void ResetAllMembers();
1897
    GByte *BuildFieldKey(TABFeature *poFeature, int nFieldNo,
1898
                         TABFieldType eType, int nIndexNo);
1899
1900
  public:
1901
    TABRelation();
1902
    ~TABRelation();
1903
1904
    int Init(const char *pszViewName, TABFile *poMainTable, TABFile *poRelTable,
1905
             const char *pszMainFieldName, const char *pszRelFieldName,
1906
             char **papszSelectedFields);
1907
    int CreateRelFields();
1908
1909
    OGRFeatureDefn *GetFeatureDefn()
1910
648
    {
1911
648
        return m_poDefn;
1912
648
    }
1913
1914
    TABFieldType GetNativeFieldType(int nFieldId);
1915
    TABFeature *GetFeature(int nFeatureId);
1916
1917
    int WriteFeature(TABFeature *poFeature, int nFeatureId = -1);
1918
1919
    int SetFeatureDefn(OGRFeatureDefn *poFeatureDefn,
1920
                       TABFieldType *paeMapInfoNativeFieldTypes = nullptr);
1921
    int AddFieldNative(const char *pszName, TABFieldType eMapInfoType,
1922
                       int nWidth = 0, int nPrecision = 0,
1923
                       GBool bIndexed = FALSE, GBool bUnique = FALSE,
1924
                       int bApproxOK = TRUE);
1925
1926
    int SetFieldIndexed(int nFieldId);
1927
    GBool IsFieldIndexed(int nFieldId);
1928
    GBool IsFieldUnique(int nFieldId);
1929
1930
    const char *GetMainFieldName()
1931
0
    {
1932
0
        return m_pszMainFieldName;
1933
0
    }
1934
1935
    const char *GetRelFieldName()
1936
0
    {
1937
0
        return m_pszRelFieldName;
1938
0
    }
1939
};
1940
1941
/*---------------------------------------------------------------------
1942
 *                      class MIDDATAFile
1943
 *
1944
 * Class to handle a file pointer with a copy of the latest read line.
1945
 *
1946
 *--------------------------------------------------------------------*/
1947
1948
class MIDDATAFile
1949
{
1950
    CPL_DISALLOW_COPY_ASSIGN(MIDDATAFile)
1951
1952
  public:
1953
    explicit MIDDATAFile(const char *pszEncoding);
1954
    ~MIDDATAFile();
1955
1956
    int Open(const char *pszFname, const char *pszAccess);
1957
    int Close();
1958
1959
    const char *GetLine();
1960
    const char *GetLastLine();
1961
    char **GetTokenizedNextLine();
1962
    int Rewind();
1963
    void SaveLine(const char *pszLine);
1964
    const char *GetSavedLine();
1965
    void WriteLine(const char *, ...) CPL_PRINT_FUNC_FORMAT(2, 3);
1966
    static GBool IsValidFeature(const char *pszString);
1967
1968
    //  Translation information
1969
    void SetTranslation(double, double, double, double);
1970
    double GetXTrans(double);
1971
    double GetYTrans(double);
1972
1973
    double GetXMultiplier()
1974
30.0k
    {
1975
30.0k
        return m_dfXMultiplier;
1976
30.0k
    }
1977
1978
    const char *GetDelimiter()
1979
2.18k
    {
1980
2.18k
        return m_pszDelimiter;
1981
2.18k
    }
1982
1983
    void SetDelimiter(const char *pszDelimiter)
1984
21.5k
    {
1985
21.5k
        m_pszDelimiter = pszDelimiter;
1986
21.5k
    }
1987
1988
    void SetEof(GBool bEof);
1989
    GBool GetEof();
1990
1991
    const CPLString &GetEncoding() const;
1992
    void SetEncoding(const CPLString &);
1993
1994
  private:
1995
    VSILFILE *m_fp;
1996
    const char *m_pszDelimiter;
1997
1998
    std::string m_osLastRead{};
1999
    std::string m_osSavedLine{};
2000
2001
    char *m_pszFname;
2002
    TABAccess m_eAccessMode;
2003
    double m_dfXMultiplier;
2004
    double m_dfYMultiplier;
2005
    double m_dfXDisplacement;
2006
    double m_dfYDisplacement;
2007
    GBool m_bEof;
2008
    CPLString m_osEncoding;
2009
};
2010
2011
/*=====================================================================
2012
                        Function prototypes
2013
 =====================================================================*/
2014
2015
TABRawBinBlock *TABCreateMAPBlockFromFile(VSILFILE *fpSrc, int nOffset,
2016
                                          int nSize,
2017
                                          GBool bHardBlockSize = TRUE,
2018
                                          TABAccess eAccessMode = TABRead);
2019
2020
#endif /* MITAB_PRIV_H_INCLUDED_ */