Coverage Report

Created: 2025-06-09 08:44

/src/gdal/ogr/ogrsf_frmts/mitab/mitab_priv.h
Line
Count
Source (jump to first uncovered line)
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
2.78k
#define TABMAP_HEADER_BLOCK 0
46
66
#define TABMAP_INDEX_BLOCK 1
47
332
#define TABMAP_OBJECT_BLOCK 2
48
172
#define TABMAP_COORD_BLOCK 3
49
0
#define TABMAP_GARB_BLOCK 4
50
107
#define TABMAP_TOOL_BLOCK 5
51
0
#define TABMAP_LAST_VALID_BLOCK_TYPE 5
52
53
/*---------------------------------------------------------------------
54
 * Drawing Tool types
55
 *--------------------------------------------------------------------*/
56
88
#define TABMAP_TOOL_PEN 1
57
59
#define TABMAP_TOOL_BRUSH 2
58
26
#define TABMAP_TOOL_FONT 3
59
88
#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
666
#define TAB_REGION_PLINE_300_MAX_VERTICES 32767
66
67
1.33k
#define TAB_REGION_PLINE_450_MAX_SEGMENTS 32767
68
666
#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
666
    ((numSegments) > TAB_REGION_PLINE_450_MAX_SEGMENTS ||                      \
77
666
     ((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
1.29k
    (((nGeomType) < TAB_GEOM_V450_REGION_C)  ? 300                             \
137
1.29k
     : ((nGeomType) < TAB_GEOM_MULTIPOINT_C) ? 450                             \
138
14
     : ((nGeomType) < TAB_GEOM_UNKNOWN1_C)   ? 650                             \
139
8
                                             : 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
2.28k
#define TAB_MIN_BLOCK_SIZE 512
157
56
#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
140
    (type == TABFChar       ? "Char"                                           \
200
140
     : type == TABFInteger  ? "Integer"                                        \
201
140
     : 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
253
    {                                                                          \
258
253
        0, 1, 2, 0, 0x000000                                                   \
259
253
    }
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
120
    {                                                                          \
276
120
        0, 1, 0, 0, 0xffffff                                                   \
277
120
    }
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
93
    {                                                                          \
291
93
        0, "Arial"                                                             \
292
93
    }
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
78
    {                                                                          \
309
78
        0, 35, 12, 0, 0x000000                                                 \
310
78
    }
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
283k
        : m_nType(TAB_GEOM_NONE), m_nId(0), m_nMinX(0), m_nMinY(0), m_nMaxX(0),
384
283k
          m_nMaxY(0)
385
283k
    {
386
283k
    }
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
282k
    TABMAPObjNone() = default;
427
428
    virtual int WriteObj(TABMAPObjectBlock *) override
429
0
    {
430
0
        return 0;
431
0
    }
432
433
    //  protected:
434
    virtual int ReadObj(TABMAPObjectBlock *) override;
435
};
436
437
class TABMAPObjPoint : public TABMAPObjHdr
438
{
439
  public:
440
    GInt32 m_nX;
441
    GInt32 m_nY;
442
    GByte m_nSymbolId;
443
444
474
    TABMAPObjPoint() : m_nX(0), m_nY(0), m_nSymbolId(0)
445
474
    {
446
474
    }
447
448
    virtual ~TABMAPObjPoint()
449
0
    {
450
0
    }
451
452
    virtual int WriteObj(TABMAPObjectBlock *) override;
453
454
    //  protected:
455
    virtual int ReadObj(TABMAPObjectBlock *) override;
456
};
457
458
class TABMAPObjFontPoint : public TABMAPObjPoint
459
{
460
  public:
461
    GByte m_nPointSize;
462
    GInt16 m_nFontStyle;
463
    GByte m_nR;
464
    GByte m_nG;
465
    GByte m_nB;
466
    GInt16 m_nAngle; /* In tenths of degree */
467
    GByte m_nFontId;
468
469
    TABMAPObjFontPoint()
470
39
        : m_nPointSize(0), m_nFontStyle(0), m_nR(0), m_nG(0), m_nB(0),
471
39
          m_nAngle(0), m_nFontId(0)
472
39
    {
473
39
    }
474
475
    virtual ~TABMAPObjFontPoint()
476
0
    {
477
0
    }
478
479
    virtual int WriteObj(TABMAPObjectBlock *) override;
480
481
    //  protected:
482
    virtual int ReadObj(TABMAPObjectBlock *) override;
483
};
484
485
class TABMAPObjCustomPoint final : public TABMAPObjPoint
486
{
487
  public:
488
    GByte m_nUnknown_;
489
    GByte m_nCustomStyle;
490
    GByte m_nFontId;
491
492
62
    TABMAPObjCustomPoint() : m_nUnknown_(0), m_nCustomStyle(0), m_nFontId(0)
493
62
    {
494
62
    }
495
496
    virtual ~TABMAPObjCustomPoint()
497
0
    {
498
0
    }
499
500
    virtual int WriteObj(TABMAPObjectBlock *) override;
501
502
    //  protected:
503
    virtual int ReadObj(TABMAPObjectBlock *) override;
504
};
505
506
class TABMAPObjLine final : public TABMAPObjHdr
507
{
508
  public:
509
    GInt32 m_nX1;
510
    GInt32 m_nY1;
511
    GInt32 m_nX2;
512
    GInt32 m_nY2;
513
    GByte m_nPenId;
514
515
176
    TABMAPObjLine() : m_nX1(0), m_nY1(0), m_nX2(0), m_nY2(0), m_nPenId(0)
516
176
    {
517
176
    }
518
519
    virtual ~TABMAPObjLine()
520
0
    {
521
0
    }
522
523
    virtual int WriteObj(TABMAPObjectBlock *) override;
524
525
    //  protected:
526
    virtual int ReadObj(TABMAPObjectBlock *) override;
527
};
528
529
class TABMAPObjPLine final : public TABMAPObjHdrWithCoord
530
{
531
  public:
532
    GInt32 m_numLineSections; /* MULTIPLINE/REGION only. Not in PLINE */
533
    GInt32 m_nLabelX;         /* Centroid/label location */
534
    GInt32 m_nLabelY;
535
    GInt32 m_nComprOrgX; /* Present only in compressed coord. case */
536
    GInt32 m_nComprOrgY;
537
    GByte m_nPenId;
538
    GByte m_nBrushId;
539
    GBool m_bSmooth; /* TRUE if (m_nCoordDataSize & 0x80000000) */
540
541
    TABMAPObjPLine()
542
526
        : m_numLineSections(0), m_nLabelX(0), m_nLabelY(0), m_nComprOrgX(0),
543
526
          m_nComprOrgY(0), m_nPenId(0), m_nBrushId(0), m_bSmooth(0)
544
526
    {
545
526
    }
546
547
    virtual ~TABMAPObjPLine()
548
0
    {
549
0
    }
550
551
    virtual int WriteObj(TABMAPObjectBlock *) override;
552
553
    //  protected:
554
    virtual int ReadObj(TABMAPObjectBlock *) override;
555
};
556
557
class TABMAPObjRectEllipse final : public TABMAPObjHdr
558
{
559
  public:
560
    GInt32 m_nCornerWidth; /* For rounded rect only */
561
    GInt32 m_nCornerHeight;
562
    GByte m_nPenId;
563
    GByte m_nBrushId;
564
565
    TABMAPObjRectEllipse()
566
109
        : m_nCornerWidth(0), m_nCornerHeight(0), m_nPenId(0), m_nBrushId(0)
567
109
    {
568
109
    }
569
570
    virtual ~TABMAPObjRectEllipse()
571
0
    {
572
0
    }
573
574
    virtual int WriteObj(TABMAPObjectBlock *) override;
575
576
    //  protected:
577
    virtual int ReadObj(TABMAPObjectBlock *) override;
578
};
579
580
class TABMAPObjArc final : public TABMAPObjHdr
581
{
582
  public:
583
    GInt32 m_nStartAngle;
584
    GInt32 m_nEndAngle;
585
    GInt32 m_nArcEllipseMinX; /* MBR of the arc defining ellipse */
586
    GInt32 m_nArcEllipseMinY; /* Only present in arcs            */
587
    GInt32 m_nArcEllipseMaxX;
588
    GInt32 m_nArcEllipseMaxY;
589
    GByte m_nPenId;
590
591
    TABMAPObjArc()
592
44
        : m_nStartAngle(0), m_nEndAngle(0), m_nArcEllipseMinX(0),
593
44
          m_nArcEllipseMinY(0), m_nArcEllipseMaxX(0), m_nArcEllipseMaxY(0),
594
44
          m_nPenId(0)
595
44
    {
596
44
    }
597
598
    virtual ~TABMAPObjArc()
599
0
    {
600
0
    }
601
602
    virtual int WriteObj(TABMAPObjectBlock *) override;
603
604
    //  protected:
605
    virtual int ReadObj(TABMAPObjectBlock *) override;
606
};
607
608
class TABMAPObjText final : public TABMAPObjHdrWithCoord
609
{
610
  public:
611
    /* String and its len stored in the nCoordPtr and nCoordSize */
612
613
    GInt16 m_nTextAlignment;
614
    GInt32 m_nAngle;
615
    GInt16 m_nFontStyle;
616
617
    GByte m_nFGColorR;
618
    GByte m_nFGColorG;
619
    GByte m_nFGColorB;
620
    GByte m_nBGColorR;
621
    GByte m_nBGColorG;
622
    GByte m_nBGColorB;
623
624
    GInt32 m_nLineEndX;
625
    GInt32 m_nLineEndY;
626
627
    GInt32 m_nHeight;
628
    GByte m_nFontId;
629
630
    GByte m_nPenId;
631
632
    TABMAPObjText()
633
16
        : m_nTextAlignment(0), m_nAngle(0), m_nFontStyle(0), m_nFGColorR(0),
634
16
          m_nFGColorG(0), m_nFGColorB(0), m_nBGColorR(0), m_nBGColorG(0),
635
16
          m_nBGColorB(0), m_nLineEndX(0), m_nLineEndY(0), m_nHeight(0),
636
16
          m_nFontId(0), m_nPenId(0)
637
16
    {
638
16
    }
639
640
    virtual ~TABMAPObjText()
641
0
    {
642
0
    }
643
644
    virtual int WriteObj(TABMAPObjectBlock *) override;
645
646
    //  protected:
647
    virtual int ReadObj(TABMAPObjectBlock *) override;
648
};
649
650
class TABMAPObjMultiPoint final : public TABMAPObjHdrWithCoord
651
{
652
  public:
653
    GInt32 m_nNumPoints;
654
    GInt32 m_nComprOrgX; /* Present only in compressed coord. case */
655
    GInt32 m_nComprOrgY;
656
    GByte m_nSymbolId;
657
    GInt32 m_nLabelX; /* Not sure if it is a label point, but */
658
    GInt32 m_nLabelY; /* it is similar to what we find in PLINE */
659
660
    TABMAPObjMultiPoint()
661
19
        : m_nNumPoints(0), m_nComprOrgX(0), m_nComprOrgY(0), m_nSymbolId(0),
662
19
          m_nLabelX(0), m_nLabelY(0)
663
19
    {
664
19
    }
665
666
    virtual ~TABMAPObjMultiPoint()
667
0
    {
668
0
    }
669
670
    virtual int WriteObj(TABMAPObjectBlock *) override;
671
672
    //  protected:
673
    virtual int ReadObj(TABMAPObjectBlock *) override;
674
};
675
676
class TABMAPObjCollection final : public TABMAPObjHdrWithCoord
677
{
678
  public:
679
    GInt32 m_nRegionDataSize;
680
    GInt32 m_nPolylineDataSize;
681
    GInt32 m_nMPointDataSize;
682
    GInt32 m_nComprOrgX; /* Present only in compressed coord. case */
683
    GInt32 m_nComprOrgY;
684
    GInt32 m_nNumMultiPoints;
685
    GInt32 m_nNumRegSections;
686
    GInt32 m_nNumPLineSections;
687
688
    GByte m_nMultiPointSymbolId;
689
    GByte m_nRegionPenId;
690
    GByte m_nRegionBrushId;
691
    GByte m_nPolylinePenId;
692
693
    TABMAPObjCollection()
694
4
        : m_nRegionDataSize(0), m_nPolylineDataSize(0), m_nMPointDataSize(0),
695
4
          m_nComprOrgX(0), m_nComprOrgY(0), m_nNumMultiPoints(0),
696
4
          m_nNumRegSections(0), m_nNumPLineSections(0),
697
4
          m_nMultiPointSymbolId(0), m_nRegionPenId(0), m_nRegionBrushId(0),
698
4
          m_nPolylinePenId(0)
699
4
    {
700
4
    }
701
702
    virtual ~TABMAPObjCollection()
703
0
    {
704
0
    }
705
706
    virtual int WriteObj(TABMAPObjectBlock *) override;
707
708
    //  protected:
709
    virtual int ReadObj(TABMAPObjectBlock *) override;
710
711
  private:
712
    // private copy ctor and assignment operator to prevent shallow copying
713
    TABMAPObjCollection &operator=(const TABMAPObjCollection &rhs);
714
    TABMAPObjCollection(const TABMAPObjCollection &rhs);
715
};
716
717
/*=====================================================================
718
          Classes to handle .MAP files low-level blocks
719
 =====================================================================*/
720
721
typedef struct TABBlockRef_t
722
{
723
    GInt32 nBlockPtr;
724
    struct TABBlockRef_t *psPrev;
725
    struct TABBlockRef_t *psNext;
726
} TABBlockRef;
727
728
/*---------------------------------------------------------------------
729
 *                      class TABBinBlockManager
730
 *
731
 * This class is used to keep track of allocated blocks and is used
732
 * by various classes that need to allocate a new block in a .MAP file.
733
 *--------------------------------------------------------------------*/
734
class TABBinBlockManager
735
{
736
    CPL_DISALLOW_COPY_ASSIGN(TABBinBlockManager)
737
738
  protected:
739
    int m_nBlockSize;
740
    GInt32 m_nLastAllocatedBlock;
741
    TABBlockRef *m_psGarbageBlocksFirst;
742
    TABBlockRef *m_psGarbageBlocksLast;
743
    char m_szName[32]; /* for debug purposes */
744
745
  public:
746
    TABBinBlockManager();
747
    ~TABBinBlockManager();
748
749
    void SetBlockSize(int nBlockSize);
750
751
    int GetBlockSize() const
752
0
    {
753
0
        return m_nBlockSize;
754
0
    }
755
756
    GInt32 AllocNewBlock(const char *pszReason = "");
757
    void Reset();
758
759
    void SetLastPtr(int nBlockPtr)
760
28
    {
761
28
        m_nLastAllocatedBlock = nBlockPtr;
762
28
    }
763
764
    void PushGarbageBlockAsFirst(GInt32 nBlockPtr);
765
    void PushGarbageBlockAsLast(GInt32 nBlockPtr);
766
    GInt32 GetFirstGarbageBlock();
767
    GInt32 PopGarbageBlock();
768
769
    void SetName(const char *pszName);
770
};
771
772
/*---------------------------------------------------------------------
773
 *                      class TABRawBinBlock
774
 *
775
 * This is the base class used for all other data block types... it
776
 * contains all the base functions to handle binary data.
777
 *--------------------------------------------------------------------*/
778
779
class TABRawBinBlock
780
{
781
    CPL_DISALLOW_COPY_ASSIGN(TABRawBinBlock)
782
783
  protected:
784
    VSILFILE *m_fp;      /* Associated file handle               */
785
    TABAccess m_eAccess; /* Read/Write access mode               */
786
787
    int m_nBlockType;
788
789
    GByte *m_pabyBuf;       /* Buffer to contain the block's data    */
790
    int m_nBlockSize;       /* Size of current block (and buffer)    */
791
    int m_nSizeUsed;        /* Number of bytes used in buffer        */
792
    GBool m_bHardBlockSize; /* TRUE=Blocks MUST always be nSize bytes  */
793
                            /* FALSE=last block may be less than nSize */
794
    int m_nFileOffset;      /* Location of current block in the file */
795
    int m_nCurPos;          /* Next byte to read from m_pabyBuf[]    */
796
    int m_nFirstBlockPtr;   /* Size of file header when different from */
797
                            /* block size (used by GotoByteInFile())   */
798
    int m_nFileSize;
799
800
    int m_bModified; /* Used only to detect changes        */
801
802
  public:
803
    explicit TABRawBinBlock(TABAccess eAccessMode = TABRead,
804
                            GBool bHardBlockSize = TRUE);
805
    virtual ~TABRawBinBlock();
806
807
    virtual int ReadFromFile(VSILFILE *fpSrc, int nOffset, int nSize);
808
    virtual int CommitToFile();
809
    int CommitAsDeleted(GInt32 nNextBlockPtr);
810
811
    virtual int InitBlockFromData(GByte *pabyBuf, int nBlockSize, int nSizeUsed,
812
                                  GBool bMakeCopy = TRUE,
813
                                  VSILFILE *fpSrc = nullptr, int nOffset = 0);
814
    virtual int InitNewBlock(VSILFILE *fpSrc, int nBlockSize,
815
                             int nFileOffset = 0);
816
817
    int GetBlockType();
818
819
    virtual int GetBlockClass()
820
0
    {
821
0
        return TAB_RAWBIN_BLOCK;
822
0
    }
823
824
    GInt32 GetStartAddress()
825
1.92k
    {
826
1.92k
        return m_nFileOffset;
827
1.92k
    }
828
#ifdef DEBUG
829
    virtual void Dump(FILE *fpOut = nullptr);
830
#endif
831
    static void DumpBytes(GInt32 nValue, int nOffset = 0,
832
                          FILE *fpOut = nullptr);
833
834
    int GotoByteRel(int nOffset);
835
    int GotoByteInBlock(int nOffset);
836
    int GotoByteInFile(int nOffset, GBool bForceReadFromFile = FALSE,
837
                       GBool bOffsetIsEndOfData = FALSE);
838
    void SetFirstBlockPtr(int nOffset);
839
840
    int GetNumUnusedBytes();
841
    int GetFirstUnusedByteOffset();
842
    int GetCurAddress();
843
844
    virtual int ReadBytes(int numBytes, GByte *pabyDstBuf);
845
    GByte ReadByte();
846
    // cppcheck-suppress functionStatic
847
    GInt16 ReadInt16();
848
    // cppcheck-suppress functionStatic
849
    GInt32 ReadInt32();
850
    // cppcheck-suppress functionStatic
851
    GInt64 ReadInt64();
852
    // cppcheck-suppress functionStatic
853
    float ReadFloat();
854
    // cppcheck-suppress functionStatic
855
    double ReadDouble();
856
857
    virtual int WriteBytes(int nBytesToWrite, const GByte *pBuf);
858
    int WriteByte(GByte byValue);
859
    // cppcheck-suppress functionStatic
860
    int WriteInt16(GInt16 n16Value);
861
    // cppcheck-suppress functionStatic
862
    int WriteInt32(GInt32 n32Value);
863
    // cppcheck-suppress functionStatic
864
    int WriteInt64(GInt64 n64Value);
865
    // cppcheck-suppress functionStatic
866
    int WriteFloat(float fValue);
867
    // cppcheck-suppress functionStatic
868
    int WriteDouble(double dValue);
869
    int WriteZeros(int nBytesToWrite);
870
    int WritePaddedString(int nFieldSize, const char *pszString);
871
872
    void SetModifiedFlag(GBool bModified)
873
0
    {
874
0
        m_bModified = bModified;
875
0
    }
876
877
    // This semi-private method gives a direct access to the internal
878
    // buffer... to be used with extreme care!!!!!!!!!
879
    GByte *GetCurDataPtr()
880
0
    {
881
0
        return (m_pabyBuf + m_nCurPos);
882
0
    }
883
};
884
885
/*---------------------------------------------------------------------
886
 *                      class TABMAPHeaderBlock
887
 *
888
 * Class to handle Read/Write operation on .MAP Header Blocks
889
 *--------------------------------------------------------------------*/
890
891
class TABMAPHeaderBlock final : public TABRawBinBlock
892
{
893
    void InitMembersWithDefaultValues();
894
    void UpdatePrecision();
895
896
  protected:
897
#if defined(__GNUC__)
898
#pragma GCC diagnostic push
899
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
900
#endif
901
    TABProjInfo m_sProj{};
902
#if defined(__GNUC__)
903
#pragma GCC diagnostic pop
904
#endif
905
906
  public:
907
    explicit TABMAPHeaderBlock(TABAccess eAccessMode = TABRead);
908
    virtual ~TABMAPHeaderBlock();
909
910
    virtual int CommitToFile() override;
911
912
    virtual int InitBlockFromData(GByte *pabyBuf, int nBlockSize, int nSizeUsed,
913
                                  GBool bMakeCopy = TRUE,
914
                                  VSILFILE *fpSrc = nullptr,
915
                                  int nOffset = 0) override;
916
    virtual int InitNewBlock(VSILFILE *fpSrc, int nBlockSize,
917
                             int nFileOffset = 0) override;
918
919
    virtual int GetBlockClass() override
920
420
    {
921
420
        return TABMAP_HEADER_BLOCK;
922
420
    }
923
924
    int Int2Coordsys(GInt32 nX, GInt32 nY, double &dX, double &dY);
925
    int Coordsys2Int(double dX, double dY, GInt32 &nX, GInt32 &nY,
926
                     GBool bIgnoreOverflow = FALSE);
927
    int ComprInt2Coordsys(GInt32 nCenterX, GInt32 nCenterY, int nDeltaX,
928
                          int nDeltaY, double &dX, double &dY);
929
    int Int2CoordsysDist(GInt32 nX, GInt32 nY, double &dX, double &dY);
930
    int Coordsys2IntDist(double dX, double dY, GInt32 &nX, GInt32 &nY);
931
    int SetCoordsysBounds(double dXMin, double dYMin, double dXMax,
932
                          double dYMax);
933
934
    int GetMapObjectSize(int nObjType);
935
    GBool MapObjectUsesCoordBlock(int nObjType);
936
937
    int GetProjInfo(TABProjInfo *psProjInfo);
938
    int SetProjInfo(TABProjInfo *psProjInfo);
939
940
#ifdef DEBUG
941
    virtual void Dump(FILE *fpOut = nullptr) override;
942
#endif
943
944
    // Instead of having over 30 get/set methods, we'll make all data
945
    // members public and we will initialize them in the overloaded
946
    // LoadFromFile().  For this reason, this class should be used with care.
947
948
    GInt16 m_nMAPVersionNumber{};
949
    GInt16 m_nRegularBlockSize{};
950
951
    double m_dCoordsys2DistUnits{};
952
    GInt32 m_nXMin{};
953
    GInt32 m_nYMin{};
954
    GInt32 m_nXMax{};
955
    GInt32 m_nYMax{};
956
    GBool m_bIntBoundsOverflow{};  // Set to TRUE if coordinates
957
                                   // outside of bounds were written
958
959
    GInt32 m_nFirstIndexBlock{};
960
    GInt32 m_nFirstGarbageBlock{};
961
    GInt32 m_nFirstToolBlock{};
962
    GInt32 m_numPointObjects{};
963
    GInt32 m_numLineObjects{};
964
    GInt32 m_numRegionObjects{};
965
    GInt32 m_numTextObjects{};
966
    GInt32 m_nMaxCoordBufSize{};
967
968
    GByte m_nDistUnitsCode{};  // See Appendix F
969
    GByte m_nMaxSpIndexDepth{};
970
    GByte m_nCoordPrecision{};  // Num. decimal places on coord.
971
    GByte m_nCoordOriginQuadrant{};
972
    GByte m_nReflectXAxisCoord{};
973
    GByte m_nMaxObjLenArrayId{};  // See gabyObjLenArray[]
974
    GByte m_numPenDefs{};
975
    GByte m_numBrushDefs{};
976
    GByte m_numSymbolDefs{};
977
    GByte m_numFontDefs{};
978
    GInt16 m_numMapToolBlocks{};
979
980
    double m_XScale{};
981
    double m_YScale{};
982
    double m_XDispl{};
983
    double m_YDispl{};
984
    double m_XPrecision{};  // maximum achievable precision along X axis
985
                            // depending on bounds extent
986
    double m_YPrecision{};  // maximum achievable precision along Y axis
987
                            // depending on bounds extent
988
};
989
990
/*---------------------------------------------------------------------
991
 *                      class TABMAPIndexBlock
992
 *
993
 * Class to handle Read/Write operation on .MAP Index Blocks (Type 01)
994
 *--------------------------------------------------------------------*/
995
996
class TABMAPIndexBlock final : public TABRawBinBlock
997
{
998
    CPL_DISALLOW_COPY_ASSIGN(TABMAPIndexBlock)
999
1000
  protected:
1001
    int m_numEntries;
1002
    TABMAPIndexEntry m_asEntries[TAB_MAX_ENTRIES_INDEX_BLOCK];
1003
1004
    int ReadNextEntry(TABMAPIndexEntry *psEntry);
1005
    int WriteNextEntry(TABMAPIndexEntry *psEntry);
1006
1007
    // Use these to keep track of current block's MBR
1008
    GInt32 m_nMinX;
1009
    GInt32 m_nMinY;
1010
    GInt32 m_nMaxX;
1011
    GInt32 m_nMaxY;
1012
1013
    TABBinBlockManager *m_poBlockManagerRef;
1014
1015
    // Info about child currently loaded
1016
    std::unique_ptr<TABMAPIndexBlock> m_poCurChild{};
1017
    int m_nCurChildIndex;
1018
    // Also need to know about its parent
1019
    TABMAPIndexBlock *m_poParentRef;
1020
1021
    int ReadAllEntries();
1022
1023
    int GetMaxEntries() const
1024
0
    {
1025
0
        return ((m_nBlockSize - 4) / 20);
1026
0
    }
1027
1028
  public:
1029
    explicit TABMAPIndexBlock(TABAccess eAccessMode = TABRead);
1030
    virtual ~TABMAPIndexBlock();
1031
1032
    virtual int InitBlockFromData(GByte *pabyBuf, int nBlockSize, int nSizeUsed,
1033
                                  GBool bMakeCopy = TRUE,
1034
                                  VSILFILE *fpSrc = nullptr,
1035
                                  int nOffset = 0) override;
1036
    virtual int InitNewBlock(VSILFILE *fpSrc, int nBlockSize,
1037
                             int nFileOffset = 0) override;
1038
    virtual int CommitToFile() override;
1039
1040
    virtual int GetBlockClass() override
1041
0
    {
1042
0
        return TABMAP_INDEX_BLOCK;
1043
0
    }
1044
1045
    void UnsetCurChild();
1046
1047
    int GetNumFreeEntries();
1048
1049
    int GetNumEntries()
1050
0
    {
1051
0
        return m_numEntries;
1052
0
    }
1053
1054
    TABMAPIndexEntry *GetEntry(int iIndex);
1055
    int AddEntry(GInt32 XMin, GInt32 YMin, GInt32 XMax, GInt32 YMax,
1056
                 GInt32 nBlockPtr, GBool bAddInThisNodeOnly = FALSE);
1057
    int GetCurMaxDepth();
1058
    void GetMBR(GInt32 &nXMin, GInt32 &nYMin, GInt32 &nXMax, GInt32 &nYMax);
1059
    void SetMBR(GInt32 nXMin, GInt32 nYMin, GInt32 nXMax, GInt32 nYMax);
1060
1061
    GInt32 GetNodeBlockPtr()
1062
19
    {
1063
19
        return GetStartAddress();
1064
19
    }
1065
1066
    void SetMAPBlockManagerRef(TABBinBlockManager *poBlockMgr);
1067
    void SetParentRef(TABMAPIndexBlock *poParent);
1068
    void SetCurChild(std::unique_ptr<TABMAPIndexBlock> &&poChild,
1069
                     int nChildIndex);
1070
1071
    int GetCurChildIndex()
1072
0
    {
1073
0
        return m_nCurChildIndex;
1074
0
    }
1075
1076
    TABMAPIndexBlock *GetCurChild()
1077
0
    {
1078
0
        return m_poCurChild.get();
1079
0
    }
1080
1081
    TABMAPIndexBlock *GetParentRef()
1082
0
    {
1083
0
        return m_poParentRef;
1084
0
    }
1085
1086
    int SplitNode(GInt32 nNewEntryXMin, GInt32 nNewEntryYMin,
1087
                  GInt32 nNewEntryXMax, GInt32 nNewEntryYMax);
1088
    int SplitRootNode(GInt32 nNewEntryXMin, GInt32 nNewEntryYMin,
1089
                      GInt32 nNewEntryXMax, GInt32 nNewEntryYMax);
1090
    void UpdateCurChildMBR(GInt32 nXMin, GInt32 nYMin, GInt32 nXMax,
1091
                           GInt32 nYMax, GInt32 nBlockPtr);
1092
    void RecomputeMBR();
1093
    int InsertEntry(GInt32 XMin, GInt32 YMin, GInt32 XMax, GInt32 YMax,
1094
                    GInt32 nBlockPtr);
1095
    int ChooseSubEntryForInsert(GInt32 nXMin, GInt32 nYMin, GInt32 nXMax,
1096
                                GInt32 nYMax);
1097
    GInt32 ChooseLeafForInsert(GInt32 nXMin, GInt32 nYMin, GInt32 nXMax,
1098
                               GInt32 nYMax);
1099
    int UpdateLeafEntry(GInt32 nBlockPtr, GInt32 nXMin, GInt32 nYMin,
1100
                        GInt32 nXMax, GInt32 nYMax);
1101
    int GetCurLeafEntryMBR(GInt32 nBlockPtr, GInt32 &nXMin, GInt32 &nYMin,
1102
                           GInt32 &nXMax, GInt32 &nYMax);
1103
1104
    // Static utility functions for node splitting, also used by
1105
    // the TABMAPObjectBlock class.
1106
    static double ComputeAreaDiff(GInt32 nNodeXMin, GInt32 nNodeYMin,
1107
                                  GInt32 nNodeXMax, GInt32 nNodeYMax,
1108
                                  GInt32 nEntryXMin, GInt32 nEntryYMin,
1109
                                  GInt32 nEntryXMax, GInt32 nEntryYMax);
1110
    static int PickSeedsForSplit(TABMAPIndexEntry *pasEntries, int numEntries,
1111
                                 int nSrcCurChildIndex, GInt32 nNewEntryXMin,
1112
                                 GInt32 nNewEntryYMin, GInt32 nNewEntryXMax,
1113
                                 GInt32 nNewEntryYMax, int &nSeed1,
1114
                                 int &nSeed2);
1115
#ifdef DEBUG
1116
    virtual void Dump(FILE *fpOut = nullptr) override;
1117
#endif
1118
};
1119
1120
/*---------------------------------------------------------------------
1121
 *                      class TABMAPObjectBlock
1122
 *
1123
 * Class to handle Read/Write operation on .MAP Object data Blocks (Type 02)
1124
 *--------------------------------------------------------------------*/
1125
1126
class TABMAPObjectBlock final : public TABRawBinBlock
1127
{
1128
    CPL_DISALLOW_COPY_ASSIGN(TABMAPObjectBlock)
1129
1130
  protected:
1131
    int m_numDataBytes; /* Excluding first 4 bytes header */
1132
    GInt32 m_nFirstCoordBlock;
1133
    GInt32 m_nLastCoordBlock;
1134
    GInt32 m_nCenterX;
1135
    GInt32 m_nCenterY;
1136
1137
    // In order to compute block center, we need to keep track of MBR
1138
    GInt32 m_nMinX;
1139
    GInt32 m_nMinY;
1140
    GInt32 m_nMaxX;
1141
    GInt32 m_nMaxY;
1142
1143
    // Keep track of current object either in read or read/write mode
1144
    int m_nCurObjectOffset;  // -1 if there is no current object.
1145
    int m_nCurObjectId;      // -1 if there is no current object.
1146
    TABGeomType
1147
        m_nCurObjectType;  // TAB_GEOM_UNSET if there is no current object.
1148
1149
    int m_bLockCenter;
1150
1151
  public:
1152
    explicit TABMAPObjectBlock(TABAccess eAccessMode = TABRead);
1153
    virtual ~TABMAPObjectBlock();
1154
1155
    virtual int CommitToFile() override;
1156
    virtual int InitBlockFromData(GByte *pabyBuf, int nBlockSize, int nSizeUsed,
1157
                                  GBool bMakeCopy = TRUE,
1158
                                  VSILFILE *fpSrc = nullptr,
1159
                                  int nOffset = 0) override;
1160
    virtual int InitNewBlock(VSILFILE *fpSrc, int nBlockSize,
1161
                             int nFileOffset = 0) override;
1162
1163
    virtual int GetBlockClass() override
1164
28
    {
1165
28
        return TABMAP_OBJECT_BLOCK;
1166
28
    }
1167
1168
    virtual int ReadIntCoord(GBool bCompressed, GInt32 &nX, GInt32 &nY);
1169
    int WriteIntCoord(GInt32 nX, GInt32 nY, GBool bCompressed);
1170
    int WriteIntMBRCoord(GInt32 nXMin, GInt32 nYMin, GInt32 nXMax, GInt32 nYMax,
1171
                         GBool bCompressed);
1172
    int UpdateMBR(GInt32 nX, GInt32 nY);
1173
1174
    int PrepareNewObject(TABMAPObjHdr *poObjHdr);
1175
    int CommitNewObject(TABMAPObjHdr *poObjHdr);
1176
1177
    void AddCoordBlockRef(GInt32 nCoordBlockAddress);
1178
1179
    GInt32 GetFirstCoordBlockAddress()
1180
0
    {
1181
0
        return m_nFirstCoordBlock;
1182
0
    }
1183
1184
    GInt32 GetLastCoordBlockAddress()
1185
391
    {
1186
391
        return m_nLastCoordBlock;
1187
391
    }
1188
1189
    void GetMBR(GInt32 &nXMin, GInt32 &nYMin, GInt32 &nXMax, GInt32 &nYMax);
1190
    void SetMBR(GInt32 nXMin, GInt32 nYMin, GInt32 nXMax, GInt32 nYMax);
1191
1192
    void Rewind();
1193
    void ClearObjects();
1194
    void LockCenter();
1195
    void SetCenterFromOtherBlock(TABMAPObjectBlock *poOtherObjBlock);
1196
    int AdvanceToNextObject(TABMAPHeaderBlock *);
1197
1198
    int GetCurObjectOffset()
1199
0
    {
1200
0
        return m_nCurObjectOffset;
1201
0
    }
1202
1203
    int GetCurObjectId()
1204
0
    {
1205
0
        return m_nCurObjectId;
1206
0
    }
1207
1208
    TABGeomType GetCurObjectType()
1209
0
    {
1210
0
        return m_nCurObjectType;
1211
0
    }
1212
1213
#ifdef DEBUG
1214
    virtual void Dump(FILE *fpOut = nullptr) override
1215
    {
1216
        Dump(fpOut, FALSE);
1217
    }
1218
1219
    void Dump(FILE *fpOut, GBool bDetails);
1220
#endif
1221
};
1222
1223
/*---------------------------------------------------------------------
1224
 *                      class TABMAPCoordBlock
1225
 *
1226
 * Class to handle Read/Write operation on .MAP Coordinate Blocks (Type 03)
1227
 *--------------------------------------------------------------------*/
1228
1229
class TABMAPCoordBlock final : public TABRawBinBlock
1230
{
1231
    CPL_DISALLOW_COPY_ASSIGN(TABMAPCoordBlock)
1232
1233
  protected:
1234
    int m_numDataBytes; /* Excluding first 8 bytes header */
1235
    GInt32 m_nNextCoordBlock;
1236
    int m_numBlocksInChain;
1237
1238
    GInt32 m_nComprOrgX;
1239
    GInt32 m_nComprOrgY;
1240
1241
    // In order to compute block center, we need to keep track of MBR
1242
    GInt32 m_nMinX;
1243
    GInt32 m_nMinY;
1244
    GInt32 m_nMaxX;
1245
    GInt32 m_nMaxY;
1246
1247
    TABBinBlockManager *m_poBlockManagerRef;
1248
1249
    int m_nTotalDataSize;    // Num bytes in whole chain of blocks
1250
    int m_nFeatureDataSize;  // Num bytes for current feature coords
1251
1252
    GInt32 m_nFeatureXMin;  // Used to keep track of current
1253
    GInt32 m_nFeatureYMin;  // feature MBR.
1254
    GInt32 m_nFeatureXMax;
1255
    GInt32 m_nFeatureYMax;
1256
1257
  public:
1258
    explicit TABMAPCoordBlock(TABAccess eAccessMode = TABRead);
1259
    virtual ~TABMAPCoordBlock();
1260
1261
    virtual int InitBlockFromData(GByte *pabyBuf, int nBlockSize, int nSizeUsed,
1262
                                  GBool bMakeCopy = TRUE,
1263
                                  VSILFILE *fpSrc = nullptr,
1264
                                  int nOffset = 0) override;
1265
    virtual int InitNewBlock(VSILFILE *fpSrc, int nBlockSize,
1266
                             int nFileOffset = 0) override;
1267
    virtual int CommitToFile() override;
1268
1269
    virtual int GetBlockClass() override
1270
0
    {
1271
0
        return TABMAP_COORD_BLOCK;
1272
0
    }
1273
1274
    void SetMAPBlockManagerRef(TABBinBlockManager *poBlockManager);
1275
    virtual int ReadBytes(int numBytes, GByte *pabyDstBuf) override;
1276
    virtual int WriteBytes(int nBytesToWrite, const GByte *pBuf) override;
1277
    void SetComprCoordOrigin(GInt32 nX, GInt32 nY);
1278
    int ReadIntCoord(GBool bCompressed, GInt32 &nX, GInt32 &nY);
1279
    int ReadIntCoords(GBool bCompressed, int numCoords, GInt32 *panXY);
1280
    int ReadCoordSecHdrs(GBool bCompressed, int nVersion, int numSections,
1281
                         TABMAPCoordSecHdr *pasHdrs, GInt32 &numVerticesTotal);
1282
    int WriteCoordSecHdrs(int nVersion, int numSections,
1283
                          TABMAPCoordSecHdr *pasHdrs, GBool bCompressed);
1284
1285
    void SetNextCoordBlock(GInt32 nNextCoordBlockAddress);
1286
1287
    GInt32 GetNextCoordBlock()
1288
0
    {
1289
0
        return m_nNextCoordBlock;
1290
0
    }
1291
1292
    int WriteIntCoord(GInt32 nX, GInt32 nY, GBool bCompressed);
1293
1294
    int GetNumBlocksInChain()
1295
43
    {
1296
43
        return m_numBlocksInChain;
1297
43
    }
1298
1299
    void ResetTotalDataSize()
1300
0
    {
1301
0
        m_nTotalDataSize = 0;
1302
0
    }
1303
1304
    int GetTotalDataSize()
1305
0
    {
1306
0
        return m_nTotalDataSize;
1307
0
    }
1308
1309
    void SeekEnd();
1310
    void StartNewFeature();
1311
1312
    int GetFeatureDataSize()
1313
333
    {
1314
333
        return m_nFeatureDataSize;
1315
333
    }
1316
1317
    //__TODO__ Can we flush GetFeatureMBR() and all MBR tracking in this
1318
    // class???
1319
    void GetFeatureMBR(GInt32 &nXMin, GInt32 &nYMin, GInt32 &nXMax,
1320
                       GInt32 &nYMax);
1321
1322
#ifdef DEBUG
1323
    virtual void Dump(FILE *fpOut = nullptr) override;
1324
#endif
1325
};
1326
1327
/*---------------------------------------------------------------------
1328
 *                      class TABMAPToolBlock
1329
 *
1330
 * Class to handle Read/Write operation on .MAP Drawing Tool Blocks (Type 05)
1331
 *
1332
 * In addition to handling the I/O, this class also maintains the list
1333
 * of Tool definitions in memory.
1334
 *--------------------------------------------------------------------*/
1335
1336
class TABMAPToolBlock final : public TABRawBinBlock
1337
{
1338
    CPL_DISALLOW_COPY_ASSIGN(TABMAPToolBlock)
1339
1340
  protected:
1341
    int m_numDataBytes; /* Excluding first 8 bytes header */
1342
    GInt32 m_nNextToolBlock;
1343
    int m_numBlocksInChain;
1344
1345
    TABBinBlockManager *m_poBlockManagerRef;
1346
1347
  public:
1348
    explicit TABMAPToolBlock(TABAccess eAccessMode = TABRead);
1349
    virtual ~TABMAPToolBlock();
1350
1351
    virtual int InitBlockFromData(GByte *pabyBuf, int nBlockSize, int nSizeUsed,
1352
                                  GBool bMakeCopy = TRUE,
1353
                                  VSILFILE *fpSrc = nullptr,
1354
                                  int nOffset = 0) override;
1355
    virtual int InitNewBlock(VSILFILE *fpSrc, int nBlockSize,
1356
                             int nFileOffset = 0) override;
1357
    virtual int CommitToFile() override;
1358
1359
    virtual int GetBlockClass() override
1360
0
    {
1361
0
        return TABMAP_TOOL_BLOCK;
1362
0
    }
1363
1364
    void SetMAPBlockManagerRef(TABBinBlockManager *poBlockManager);
1365
    virtual int ReadBytes(int numBytes, GByte *pabyDstBuf) override;
1366
    virtual int WriteBytes(int nBytesToWrite, const GByte *pBuf) override;
1367
1368
    void SetNextToolBlock(GInt32 nNextCoordBlockAddress);
1369
1370
    GBool EndOfChain();
1371
1372
    int GetNumBlocksInChain()
1373
19
    {
1374
19
        return m_numBlocksInChain;
1375
19
    }
1376
1377
    int CheckAvailableSpace(int nToolType);
1378
1379
#ifdef DEBUG
1380
    virtual void Dump(FILE *fpOut = nullptr) override;
1381
#endif
1382
};
1383
1384
/*=====================================================================
1385
       Classes to deal with .MAP files at the MapInfo object level
1386
 =====================================================================*/
1387
1388
/*---------------------------------------------------------------------
1389
 *                      class TABIDFile
1390
 *
1391
 * Class to handle Read/Write operation on .ID files... the .ID file
1392
 * contains an index to the objects in the .MAP file by object id.
1393
 *--------------------------------------------------------------------*/
1394
1395
class TABIDFile
1396
{
1397
    CPL_DISALLOW_COPY_ASSIGN(TABIDFile)
1398
1399
  private:
1400
    char *m_pszFname;
1401
    VSILFILE *m_fp;
1402
    TABAccess m_eAccessMode;
1403
1404
    TABRawBinBlock *m_poIDBlock;
1405
    int m_nBlockSize;
1406
    GInt32 m_nMaxId;
1407
1408
  public:
1409
    TABIDFile();
1410
    ~TABIDFile();
1411
1412
    int Open(const char *pszFname, const char *pszAccess);
1413
    int Open(const char *pszFname, TABAccess eAccess);
1414
    int Close();
1415
1416
    int SyncToDisk();
1417
1418
    GInt32 GetObjPtr(GInt32 nObjId);
1419
    int SetObjPtr(GInt32 nObjId, GInt32 nObjPtr);
1420
    GInt32 GetMaxObjId();
1421
1422
#ifdef DEBUG
1423
    void Dump(FILE *fpOut = nullptr);
1424
#endif
1425
};
1426
1427
/*---------------------------------------------------------------------
1428
 *                      class TABMAPFile
1429
 *
1430
 * Class to handle Read/Write operation on .MAP files... this class hides
1431
 * all the dealings with blocks, indexes, etc.
1432
 * Use this class to deal with MapInfo objects directly.
1433
 *--------------------------------------------------------------------*/
1434
1435
class TABMAPFile
1436
{
1437
    CPL_DISALLOW_COPY_ASSIGN(TABMAPFile)
1438
1439
  private:
1440
    int m_nMinTABVersion;
1441
    char *m_pszFname;
1442
    VSILFILE *m_fp;
1443
    TABAccess m_eAccessMode;
1444
1445
    TABBinBlockManager m_oBlockManager{};
1446
1447
    TABMAPHeaderBlock *m_poHeader;
1448
1449
    // Members used to access objects using the spatial index
1450
    TABMAPIndexBlock *m_poSpIndex;
1451
1452
    // Defaults to FALSE, i.e. optimized spatial index
1453
    GBool m_bQuickSpatialIndexMode;
1454
1455
    // Member used to access objects using the object ids (.ID file)
1456
    TABIDFile *m_poIdIndex;
1457
1458
    // Current object data block.
1459
    TABMAPObjectBlock *m_poCurObjBlock;
1460
    int m_nCurObjPtr;
1461
    TABGeomType m_nCurObjType;
1462
    int m_nCurObjId;
1463
    TABMAPCoordBlock *m_poCurCoordBlock;
1464
1465
    // Drawing Tool Def. table (takes care of all drawing tools in memory)
1466
    TABToolDefTable *m_poToolDefTable;
1467
1468
    // Coordinates filter... default is MBR of the whole file
1469
    TABVertex m_sMinFilter{};
1470
    TABVertex m_sMaxFilter{};
1471
    GInt32 m_XMinFilter;
1472
    GInt32 m_YMinFilter;
1473
    GInt32 m_XMaxFilter;
1474
    GInt32 m_YMaxFilter;
1475
1476
    int m_bUpdated;
1477
    int m_bLastOpWasRead;
1478
    int m_bLastOpWasWrite;
1479
1480
    int CommitObjAndCoordBlocks(GBool bDeleteObjects = FALSE);
1481
    int LoadObjAndCoordBlocks(GInt32 nBlockPtr);
1482
    TABMAPObjectBlock *SplitObjBlock(TABMAPObjHdr *poObjHdrToAdd,
1483
                                     int nSizeOfObjToAdd);
1484
    int MoveObjToBlock(TABMAPObjHdr *poObjHdr,
1485
                       TABMAPCoordBlock *poSrcCoordBlock,
1486
                       TABMAPObjectBlock *poDstObjBlock,
1487
                       TABMAPCoordBlock **ppoDstCoordBlock);
1488
    int PrepareCoordBlock(int nObjType, TABMAPObjectBlock *poObjBlock,
1489
                          TABMAPCoordBlock **ppoCoordBlock);
1490
1491
    int InitDrawingTools();
1492
    int CommitDrawingTools();
1493
1494
    int CommitSpatialIndex();
1495
1496
    // Stuff related to traversing spatial index.
1497
    TABMAPIndexBlock *m_poSpIndexLeaf;
1498
1499
    // Strings encoding
1500
    CPLString m_osEncoding;
1501
1502
    int LoadNextMatchingObjectBlock(int bFirstObject);
1503
    TABRawBinBlock *PushBlock(int nFileOffset);
1504
1505
    int ReOpenReadWrite();
1506
1507
  public:
1508
    explicit TABMAPFile(const char *pszEncoding);
1509
    ~TABMAPFile();
1510
1511
    int Open(const char *pszFname, const char *pszAccess,
1512
             GBool bNoErrorMsg = FALSE, int nBlockSizeForCreate = 512);
1513
    int Open(const char *pszFname, TABAccess eAccess, GBool bNoErrorMsg = FALSE,
1514
             int nBlockSizeForCreate = 512);
1515
    int Close();
1516
1517
    GUInt32 GetFileSize();
1518
1519
    int SyncToDisk();
1520
1521
    int SetQuickSpatialIndexMode(GBool bQuickSpatialIndexMode = TRUE);
1522
1523
    int Int2Coordsys(GInt32 nX, GInt32 nY, double &dX, double &dY);
1524
    int Coordsys2Int(double dX, double dY, GInt32 &nX, GInt32 &nY,
1525
                     GBool bIgnoreOverflow = FALSE);
1526
    int Int2CoordsysDist(GInt32 nX, GInt32 nY, double &dX, double &dY);
1527
    int Coordsys2IntDist(double dX, double dY, GInt32 &nX, GInt32 &nY);
1528
    void SetCoordFilter(TABVertex sMin, TABVertex sMax);
1529
    // cppcheck-suppress functionStatic
1530
    void GetCoordFilter(TABVertex &sMin, TABVertex &sMax) const;
1531
    void ResetCoordFilter();
1532
    int SetCoordsysBounds(double dXMin, double dYMin, double dXMax,
1533
                          double dYMax);
1534
1535
    GInt32 GetMaxObjId();
1536
    int MoveToObjId(int nObjId);
1537
    void UpdateMapHeaderInfo(TABGeomType nObjType);
1538
    int PrepareNewObj(TABMAPObjHdr *poObjHdr);
1539
    int PrepareNewObjViaSpatialIndex(TABMAPObjHdr *poObjHdr);
1540
    int PrepareNewObjViaObjBlock(TABMAPObjHdr *poObjHdr);
1541
    int CommitNewObj(TABMAPObjHdr *poObjHdr);
1542
1543
    void ResetReading();
1544
    int GetNextFeatureId(int nPrevId);
1545
1546
    int MarkAsDeleted();
1547
1548
    TABGeomType GetCurObjType();
1549
    int GetCurObjId();
1550
    TABMAPObjectBlock *GetCurObjBlock();
1551
    TABMAPCoordBlock *GetCurCoordBlock();
1552
    TABMAPCoordBlock *GetCoordBlock(int nFileOffset);
1553
    TABMAPHeaderBlock *GetHeaderBlock();
1554
    TABIDFile *GetIDFileRef();
1555
    TABRawBinBlock *GetIndexObjectBlock(int nFileOffset);
1556
1557
    int ReadPenDef(int nPenIndex, TABPenDef *psDef);
1558
    int ReadBrushDef(int nBrushIndex, TABBrushDef *psDef);
1559
    int ReadFontDef(int nFontIndex, TABFontDef *psDef);
1560
    int ReadSymbolDef(int nSymbolIndex, TABSymbolDef *psDef);
1561
    int WritePenDef(TABPenDef *psDef);
1562
    int WriteBrushDef(TABBrushDef *psDef);
1563
    int WriteFontDef(TABFontDef *psDef);
1564
    int WriteSymbolDef(TABSymbolDef *psDef);
1565
1566
    int GetMinTABFileVersion();
1567
1568
    const CPLString &GetEncoding() const;
1569
    void SetEncoding(const CPLString &);
1570
1571
    static bool IsValidObjType(int nObjType);
1572
1573
#ifdef DEBUG
1574
    void Dump(FILE *fpOut = nullptr);
1575
    void DumpSpatialIndexToMIF(TABMAPIndexBlock *poNode, FILE *fpMIF,
1576
                               FILE *fpMID, int nParentId = -1,
1577
                               int nIndexInNode = -1, int nCurDepth = 0,
1578
                               int nMaxDepth = -1);
1579
#endif
1580
};
1581
1582
/*---------------------------------------------------------------------
1583
 *                      class TABINDNode
1584
 *
1585
 * An index node in a .IND file.
1586
 *
1587
 * This class takes care of reading child nodes as necessary when looking
1588
 * for a given key value in the index tree.
1589
 *--------------------------------------------------------------------*/
1590
1591
class TABINDNode
1592
{
1593
    CPL_DISALLOW_COPY_ASSIGN(TABINDNode)
1594
1595
  private:
1596
    VSILFILE *m_fp;
1597
    TABAccess m_eAccessMode;
1598
    TABINDNode *m_poCurChildNode;
1599
    TABINDNode *m_poParentNodeRef;
1600
1601
    TABBinBlockManager *m_poBlockManagerRef;
1602
1603
    int m_nSubTreeDepth;
1604
    int m_nKeyLength;
1605
    TABFieldType m_eFieldType;
1606
    GBool m_bUnique;
1607
1608
    GInt32 m_nCurDataBlockPtr;
1609
    int m_nCurIndexEntry;
1610
    TABRawBinBlock *m_poDataBlock;
1611
    int m_numEntriesInNode;
1612
    GInt32 m_nPrevNodePtr;
1613
    GInt32 m_nNextNodePtr;
1614
1615
    int GotoNodePtr(GInt32 nNewNodePtr);
1616
    GInt32 ReadIndexEntry(int nEntryNo, GByte *pKeyValue);
1617
    int IndexKeyCmp(const GByte *pKeyValue, int nEntryNo);
1618
1619
    int InsertEntry(GByte *pKeyValue, GInt32 nRecordNo,
1620
                    GBool bInsertAfterCurChild = FALSE,
1621
                    GBool bMakeNewEntryCurChild = FALSE);
1622
    int SetNodeBufferDirectly(int numEntries, GByte *pBuf,
1623
                              int nCurIndexEntry = 0,
1624
                              TABINDNode *poCurChild = nullptr);
1625
    GInt32 FindFirst(const GByte *pKeyValue, std::set<int> &oSetVisitedNodePtr);
1626
1627
  public:
1628
    explicit TABINDNode(TABAccess eAccessMode = TABRead);
1629
    ~TABINDNode();
1630
1631
    int InitNode(VSILFILE *fp, int nBlockPtr, int nKeyLength, int nSubTreeDepth,
1632
                 GBool bUnique, TABBinBlockManager *poBlockMgr = nullptr,
1633
                 TABINDNode *poParentNode = nullptr, int nPrevNodePtr = 0,
1634
                 int nNextNodePtr = 0);
1635
1636
    int SetFieldType(TABFieldType eType);
1637
1638
    TABFieldType GetFieldType()
1639
0
    {
1640
0
        return m_eFieldType;
1641
0
    }
1642
1643
    void SetUnique(GBool bUnique)
1644
0
    {
1645
0
        m_bUnique = bUnique;
1646
0
    }
1647
1648
    GBool IsUnique()
1649
0
    {
1650
0
        return m_bUnique;
1651
0
    }
1652
1653
    int GetKeyLength()
1654
9.77k
    {
1655
9.77k
        return m_nKeyLength;
1656
9.77k
    }
1657
1658
    int GetSubTreeDepth()
1659
0
    {
1660
0
        return m_nSubTreeDepth;
1661
0
    }
1662
1663
    GInt32 GetNodeBlockPtr()
1664
0
    {
1665
0
        return m_nCurDataBlockPtr;
1666
0
    }
1667
1668
    int GetNumEntries()
1669
0
    {
1670
0
        return m_numEntriesInNode;
1671
0
    }
1672
1673
    int GetMaxNumEntries()
1674
0
    {
1675
0
        return (512 - 12) / (m_nKeyLength + 4);
1676
0
    }
1677
1678
    GInt32 FindFirst(const GByte *pKeyValue);
1679
    GInt32 FindNext(GByte *pKeyValue);
1680
1681
    int CommitToFile();
1682
1683
    int AddEntry(GByte *pKeyValue, GInt32 nRecordNo,
1684
                 GBool bAddInThisNodeOnly = FALSE,
1685
                 GBool bInsertAfterCurChild = FALSE,
1686
                 GBool bMakeNewEntryCurChild = FALSE);
1687
    int SplitNode();
1688
    int SplitRootNode();
1689
    GByte *GetNodeKey();
1690
    int UpdateCurChildEntry(GByte *pKeyValue, GInt32 nRecordNo);
1691
    int UpdateSplitChild(GByte *pKeyValue1, GInt32 nRecordNo1,
1692
                         GByte *pKeyValue2, GInt32 nRecordNo2,
1693
                         int nNewCurChildNo /* 1 or 2 */);
1694
1695
    int SetNodeBlockPtr(GInt32 nThisNodePtr);
1696
    int SetPrevNodePtr(GInt32 nPrevNodePtr);
1697
    int SetNextNodePtr(GInt32 nNextNodePtr);
1698
1699
#ifdef DEBUG
1700
    void Dump(FILE *fpOut = nullptr);
1701
#endif
1702
};
1703
1704
/*---------------------------------------------------------------------
1705
 *                      class TABINDFile
1706
 *
1707
 * Class to handle table field index (.IND) files... we use this
1708
 * class as the main entry point to open and search the table field indexes.
1709
 * Note that .IND files are supported for read access only.
1710
 *--------------------------------------------------------------------*/
1711
1712
class TABINDFile
1713
{
1714
    CPL_DISALLOW_COPY_ASSIGN(TABINDFile)
1715
1716
  private:
1717
    char *m_pszFname;
1718
    VSILFILE *m_fp;
1719
    TABAccess m_eAccessMode;
1720
1721
    TABBinBlockManager m_oBlockManager{};
1722
1723
    int m_numIndexes;
1724
    TABINDNode **m_papoIndexRootNodes;
1725
    GByte **m_papbyKeyBuffers;
1726
1727
    int ValidateIndexNo(int nIndexNumber);
1728
    int ReadHeader();
1729
    int WriteHeader();
1730
1731
  public:
1732
    TABINDFile();
1733
    ~TABINDFile();
1734
1735
    int Open(const char *pszFname, const char *pszAccess,
1736
             GBool bTestOpenNoError = FALSE);
1737
    int Close();
1738
1739
    int GetNumIndexes()
1740
0
    {
1741
0
        return m_numIndexes;
1742
0
    }
1743
1744
    int SetIndexFieldType(int nIndexNumber, TABFieldType eType);
1745
    int SetIndexUnique(int nIndexNumber, GBool bUnique = TRUE);
1746
    GByte *BuildKey(int nIndexNumber, GInt32 nValue);
1747
    GByte *BuildKey(int nIndexNumber, GInt64 nValue);
1748
    GByte *BuildKey(int nIndexNumber, const char *pszStr);
1749
    GByte *BuildKey(int nIndexNumber, double dValue);
1750
    GInt32 FindFirst(int nIndexNumber, GByte *pKeyValue);
1751
    GInt32 FindNext(int nIndexNumber, GByte *pKeyValue);
1752
1753
    int CreateIndex(TABFieldType eType, int nFieldSize);
1754
    int AddEntry(int nIndexNumber, GByte *pKeyValue, GInt32 nRecordNo);
1755
1756
#ifdef DEBUG
1757
    void Dump(FILE *fpOut = nullptr);
1758
#endif
1759
};
1760
1761
/*---------------------------------------------------------------------
1762
 *                      class TABDATFile
1763
 *
1764
 * Class to handle Read/Write operation on .DAT files... the .DAT file
1765
 * contains the table of attribute field values.
1766
 *--------------------------------------------------------------------*/
1767
1768
class TABDATFile
1769
{
1770
    CPL_DISALLOW_COPY_ASSIGN(TABDATFile)
1771
1772
  private:
1773
    char *m_pszFname;
1774
    VSILFILE *m_fp;
1775
    TABAccess m_eAccessMode;
1776
    TABTableType m_eTableType;
1777
1778
    TABRawBinBlock *m_poHeaderBlock;
1779
    int m_numFields;
1780
    TABDATFieldDef *m_pasFieldDef;
1781
1782
    TABRawBinBlock *m_poRecordBlock;
1783
    int m_nBlockSize;
1784
    int m_nRecordSize;
1785
    int m_nCurRecordId;
1786
    GBool m_bCurRecordDeletedFlag;
1787
1788
    GInt32 m_numRecords;
1789
    GInt32 m_nFirstRecordPtr;
1790
    GBool m_bWriteHeaderInitialized;
1791
    GBool m_bWriteEOF;
1792
1793
    int m_bUpdated;
1794
    CPLString m_osEncoding;
1795
1796
    int InitWriteHeader();
1797
    int WriteHeader();
1798
1799
    // We know that character strings are limited to 254 chars in MapInfo
1800
    // Using a buffer pr. class instance to avoid threading issues with the
1801
    // library
1802
    char m_szBuffer[256];
1803
1804
  public:
1805
    explicit TABDATFile(const char *pszEncoding);
1806
    ~TABDATFile();
1807
1808
    int Open(const char *pszFname, const char *pszAccess,
1809
             TABTableType eTableType = TABTableNative);
1810
    int Open(const char *pszFname, TABAccess eAccess,
1811
             TABTableType eTableType = TABTableNative);
1812
    int Close();
1813
1814
    int GetNumFields();
1815
    TABFieldType GetFieldType(int nFieldId);
1816
    int GetFieldWidth(int nFieldId);
1817
    int GetFieldPrecision(int nFieldId);
1818
    int ValidateFieldInfoFromTAB(int iField, const char *pszName,
1819
                                 TABFieldType eType, int nWidth,
1820
                                 int nPrecision);
1821
1822
    int AddField(const char *pszName, TABFieldType eType, int nWidth,
1823
                 int nPrecision = 0);
1824
1825
    int DeleteField(int iField);
1826
    int ReorderFields(int *panMap);
1827
    int AlterFieldDefn(int iField, const OGRFieldDefn *poSrcFieldDefn,
1828
                       OGRFieldDefn *poNewFieldDefn, int nFlags);
1829
1830
    int SyncToDisk();
1831
1832
    GInt32 GetNumRecords();
1833
    TABRawBinBlock *GetRecordBlock(int nRecordId);
1834
1835
    GBool IsCurrentRecordDeleted()
1836
1.11M
    {
1837
1.11M
        return m_bCurRecordDeletedFlag;
1838
1.11M
    }
1839
1840
    int CommitRecordToFile();
1841
1842
    int MarkAsDeleted();
1843
    int MarkRecordAsExisting();
1844
1845
    const char *ReadCharField(int nWidth);
1846
    GInt32 ReadIntegerField(int nWidth);
1847
    GInt16 ReadSmallIntField(int nWidth);
1848
    GInt64 ReadLargeIntField(int nWidth);
1849
    double ReadFloatField(int nWidth);
1850
    double ReadDecimalField(int nWidth);
1851
    bool ReadLogicalField(int nWidth);
1852
    const char *ReadDateField(int nWidth);
1853
    int ReadDateField(int nWidth, int *nYear, int *nMonth, int *nDay);
1854
    const char *ReadTimeField(int nWidth);
1855
    int ReadTimeField(int nWidth, int *nHour, int *nMinute, int *nSecond,
1856
                      int *nMS);
1857
    const char *ReadDateTimeField(int nWidth);
1858
    int ReadDateTimeField(int nWidth, int *nYear, int *nMonth, int *nDay,
1859
                          int *nHour, int *nMinute, int *nSecond, int *nMS);
1860
1861
    int WriteCharField(const char *pszValue, int nWidth, TABINDFile *poINDFile,
1862
                       int nIndexNo);
1863
    int WriteIntegerField(GInt32 nValue, TABINDFile *poINDFile, int nIndexNo);
1864
    int WriteSmallIntField(GInt16 nValue, TABINDFile *poINDFile, int nIndexNo);
1865
    int WriteLargeIntField(GInt64 nValue, TABINDFile *poINDFile, int nIndexNo);
1866
    int WriteFloatField(double dValue, TABINDFile *poINDFile, int nIndexNo);
1867
    int WriteDecimalField(double dValue, int nWidth, int nPrecision,
1868
                          TABINDFile *poINDFile, int nIndexNo);
1869
    int WriteLogicalField(bool bValue, TABINDFile *poINDFile, int nIndexNo);
1870
    int WriteDateField(const char *pszValue, TABINDFile *poINDFile,
1871
                       int nIndexNo);
1872
    int WriteDateField(int nYear, int nMonth, int nDay, TABINDFile *poINDFile,
1873
                       int nIndexNo);
1874
    int WriteTimeField(const char *pszValue, TABINDFile *poINDFile,
1875
                       int nIndexNo);
1876
    int WriteTimeField(int nHour, int nMinute, int nSecond, int nMS,
1877
                       TABINDFile *poINDFile, int nIndexNo);
1878
    int WriteDateTimeField(const char *pszValue, TABINDFile *poINDFile,
1879
                           int nIndexNo);
1880
    int WriteDateTimeField(int nYear, int nMonth, int nDay, int nHour,
1881
                           int nMinute, int nSecond, int nMS,
1882
                           TABINDFile *poINDFile, int nIndexNo);
1883
1884
    const CPLString &GetEncoding() const;
1885
    void SetEncoding(const CPLString &);
1886
1887
#ifdef DEBUG
1888
    void Dump(FILE *fpOut = nullptr);
1889
#endif
1890
};
1891
1892
/*---------------------------------------------------------------------
1893
 *                      class TABRelation
1894
 *
1895
 * Class that maintains a relation between 2 tables through a field
1896
 * in each table (the SQL "where table1.field1=table2.field2" found in
1897
 * TABView datasets).
1898
 *
1899
 * An instance of this class is used to read data records from the
1900
 * combined tables as if they were a single one.
1901
 *--------------------------------------------------------------------*/
1902
1903
class TABRelation
1904
{
1905
    CPL_DISALLOW_COPY_ASSIGN(TABRelation)
1906
1907
  private:
1908
    /* Information about the main table.
1909
     */
1910
    TABFile *m_poMainTable;
1911
    char *m_pszMainFieldName;
1912
    int m_nMainFieldNo;
1913
1914
    /* Information about the related table.
1915
     * NOTE: The related field MUST be indexed.
1916
     */
1917
    TABFile *m_poRelTable;
1918
    char *m_pszRelFieldName;
1919
    int m_nRelFieldNo;
1920
1921
    TABINDFile *m_poRelINDFileRef;
1922
    int m_nRelFieldIndexNo;
1923
1924
    int m_nUniqueRecordNo;
1925
1926
    /* Main and Rel table field map:
1927
     * For each field in the source tables, -1 means that the field is not
1928
     * selected, and a value >=0 is the index of this field in the combined
1929
     * FeatureDefn
1930
     */
1931
    int *m_panMainTableFieldMap;
1932
    int *m_panRelTableFieldMap;
1933
1934
    OGRFeatureDefn *m_poDefn;
1935
1936
    void ResetAllMembers();
1937
    GByte *BuildFieldKey(TABFeature *poFeature, int nFieldNo,
1938
                         TABFieldType eType, int nIndexNo);
1939
1940
  public:
1941
    TABRelation();
1942
    ~TABRelation();
1943
1944
    int Init(const char *pszViewName, TABFile *poMainTable, TABFile *poRelTable,
1945
             const char *pszMainFieldName, const char *pszRelFieldName,
1946
             char **papszSelectedFields);
1947
    int CreateRelFields();
1948
1949
    OGRFeatureDefn *GetFeatureDefn()
1950
736
    {
1951
736
        return m_poDefn;
1952
736
    }
1953
1954
    TABFieldType GetNativeFieldType(int nFieldId);
1955
    TABFeature *GetFeature(int nFeatureId);
1956
1957
    int WriteFeature(TABFeature *poFeature, int nFeatureId = -1);
1958
1959
    int SetFeatureDefn(OGRFeatureDefn *poFeatureDefn,
1960
                       TABFieldType *paeMapInfoNativeFieldTypes = nullptr);
1961
    int AddFieldNative(const char *pszName, TABFieldType eMapInfoType,
1962
                       int nWidth = 0, int nPrecision = 0,
1963
                       GBool bIndexed = FALSE, GBool bUnique = FALSE,
1964
                       int bApproxOK = TRUE);
1965
1966
    int SetFieldIndexed(int nFieldId);
1967
    GBool IsFieldIndexed(int nFieldId);
1968
    GBool IsFieldUnique(int nFieldId);
1969
1970
    const char *GetMainFieldName()
1971
0
    {
1972
0
        return m_pszMainFieldName;
1973
0
    }
1974
1975
    const char *GetRelFieldName()
1976
0
    {
1977
0
        return m_pszRelFieldName;
1978
0
    }
1979
};
1980
1981
/*---------------------------------------------------------------------
1982
 *                      class MIDDATAFile
1983
 *
1984
 * Class to handle a file pointer with a copy of the latest read line.
1985
 *
1986
 *--------------------------------------------------------------------*/
1987
1988
class MIDDATAFile
1989
{
1990
    CPL_DISALLOW_COPY_ASSIGN(MIDDATAFile)
1991
1992
  public:
1993
    explicit MIDDATAFile(const char *pszEncoding);
1994
    ~MIDDATAFile();
1995
1996
    int Open(const char *pszFname, const char *pszAccess);
1997
    int Close();
1998
1999
    const char *GetLine();
2000
    const char *GetLastLine();
2001
    char **GetTokenizedNextLine();
2002
    int Rewind();
2003
    void SaveLine(const char *pszLine);
2004
    const char *GetSavedLine();
2005
    void WriteLine(const char *, ...) CPL_PRINT_FUNC_FORMAT(2, 3);
2006
    static GBool IsValidFeature(const char *pszString);
2007
2008
    //  Translation information
2009
    void SetTranslation(double, double, double, double);
2010
    double GetXTrans(double);
2011
    double GetYTrans(double);
2012
2013
    double GetXMultiplier()
2014
25.6k
    {
2015
25.6k
        return m_dfXMultiplier;
2016
25.6k
    }
2017
2018
    const char *GetDelimiter()
2019
3.85k
    {
2020
3.85k
        return m_pszDelimiter;
2021
3.85k
    }
2022
2023
    void SetDelimiter(const char *pszDelimiter)
2024
24.3k
    {
2025
24.3k
        m_pszDelimiter = pszDelimiter;
2026
24.3k
    }
2027
2028
    void SetEof(GBool bEof);
2029
    GBool GetEof();
2030
2031
    const CPLString &GetEncoding() const;
2032
    void SetEncoding(const CPLString &);
2033
2034
  private:
2035
    VSILFILE *m_fp;
2036
    const char *m_pszDelimiter;
2037
2038
    std::string m_osLastRead{};
2039
    std::string m_osSavedLine{};
2040
2041
    char *m_pszFname;
2042
    TABAccess m_eAccessMode;
2043
    double m_dfXMultiplier;
2044
    double m_dfYMultiplier;
2045
    double m_dfXDisplacement;
2046
    double m_dfYDisplacement;
2047
    GBool m_bEof;
2048
    CPLString m_osEncoding;
2049
};
2050
2051
/*=====================================================================
2052
                        Function prototypes
2053
 =====================================================================*/
2054
2055
TABRawBinBlock *TABCreateMAPBlockFromFile(VSILFILE *fpSrc, int nOffset,
2056
                                          int nSize,
2057
                                          GBool bHardBlockSize = TRUE,
2058
                                          TABAccess eAccessMode = TABRead);
2059
2060
#endif /* MITAB_PRIV_H_INCLUDED_ */