Coverage Report

Created: 2025-06-13 06:18

/src/MapServer/src/mapshape.c
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 * $Id$
3
 *
4
 * Project:  MapServer
5
 * Purpose:  Implements support for shapefile access.
6
 * Authors:  Steve Lime and Frank Warmerdam
7
 *
8
 * Note:
9
 * This code is entirely based on the previous work of Frank Warmerdam. It is
10
 * essentially shapelib 1.1.5. However, there were enough changes that it was
11
 * incorporated into the MapServer source to avoid confusion. Relicensed with
12
 * permission of Frank Warmerdam (shapelib author). See the README
13
 * for licence details.
14
 *
15
 ******************************************************************************
16
 * Copyright (c) 1996-2005 Regents of the University of Minnesota.
17
 *
18
 * Permission is hereby granted, free of charge, to any person obtaining a
19
 * copy of this software and associated documentation files (the "Software"),
20
 * to deal in the Software without restriction, including without limitation
21
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
22
 * and/or sell copies of the Software, and to permit persons to whom the
23
 * Software is furnished to do so, subject to the following conditions:
24
 *
25
 * The above copyright notice and this permission notice shall be included in
26
 * all copies of this Software or works derived from this Software.
27
 *
28
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
29
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
31
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
33
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
34
 * DEALINGS IN THE SOFTWARE.
35
 ****************************************************************************/
36
37
#define NEED_IGNORE_RET_VAL
38
39
#include <limits.h>
40
#include <assert.h>
41
#include <stdbool.h>
42
#include "mapserver.h"
43
#include "mapows.h"
44
45
#include <cpl_conv.h>
46
#include <ogr_srs_api.h>
47
48
/* Only use this macro on 32-bit integers! */
49
0
#define SWAP_FOUR_BYTES(data) CPL_SWAP32(data)
50
51
0
#define ByteCopy(a, b, c) memcpy(b, a, c)
52
53
#ifdef __BYTE_ORDER__
54
/* GCC/clang predefined macro */
55
0
#define bBigEndian (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
56
#elif defined(_MSC_VER)
57
/* MSVC doesn't support the C99 trick below, but all Microsoft
58
   platforms are little-endian */
59
#define bBigEndian false
60
#else
61
/* generic check */
62
#define bBigEndian                                                             \
63
  (((union {                                                                   \
64
     int in;                                                                   \
65
     char out;                                                                 \
66
   }){1})                                                                      \
67
       .out)
68
#endif
69
70
/* SHX reading */
71
static int msSHXLoadAll(SHPHandle psSHP);
72
static int msSHXReadOffset(SHPHandle psSHP, int hEntity);
73
static int msSHXReadSize(SHPHandle psSHP, int hEntity);
74
75
/************************************************************************/
76
/*                              SwapWord()                              */
77
/*                                                                      */
78
/*      Swap a 2, 4 or 8 byte word.                                     */
79
/************************************************************************/
80
0
static void SwapWord(int length, void *wordP) {
81
0
  int i;
82
0
  uchar temp;
83
84
0
  for (i = 0; i < length / 2; i++) {
85
0
    temp = ((uchar *)wordP)[i];
86
0
    ((uchar *)wordP)[i] = ((uchar *)wordP)[length - i - 1];
87
0
    ((uchar *)wordP)[length - i - 1] = temp;
88
0
  }
89
0
}
90
91
/************************************************************************/
92
/*                             SfRealloc()                              */
93
/*                                                                      */
94
/*      A realloc cover function that will access a NULL pointer as     */
95
/*      a valid input.                                                  */
96
/************************************************************************/
97
0
static void *SfRealloc(void *pMem, int nNewSize) {
98
0
  return realloc(pMem, nNewSize);
99
0
}
100
101
/************************************************************************/
102
/*                          writeHeader()                               */
103
/*                                                                      */
104
/*      Write out a header for the .shp and .shx files as well as the */
105
/*  contents of the index (.shx) file.        */
106
/************************************************************************/
107
0
static void writeHeader(SHPHandle psSHP) {
108
0
  uchar abyHeader[100];
109
0
  int i;
110
0
  ms_int32 i32;
111
0
  double dValue;
112
0
  ms_int32 *panSHX;
113
114
  /* -------------------------------------------------------------------- */
115
  /*      Prepare header block for .shp file.                             */
116
  /* -------------------------------------------------------------------- */
117
0
  for (i = 0; i < 100; i++)
118
0
    abyHeader[i] = 0;
119
120
0
  abyHeader[2] = 0x27; /* magic cookie */
121
0
  abyHeader[3] = 0x0a;
122
123
0
  i32 = psSHP->nFileSize / 2; /* file size */
124
0
  ByteCopy(&i32, abyHeader + 24, 4);
125
0
  if (!bBigEndian)
126
0
    SwapWord(4, abyHeader + 24);
127
128
0
  i32 = 1000; /* version */
129
0
  ByteCopy(&i32, abyHeader + 28, 4);
130
0
  if (bBigEndian)
131
0
    SwapWord(4, abyHeader + 28);
132
133
0
  i32 = psSHP->nShapeType; /* shape type */
134
0
  ByteCopy(&i32, abyHeader + 32, 4);
135
0
  if (bBigEndian)
136
0
    SwapWord(4, abyHeader + 32);
137
138
0
  dValue = psSHP->adBoundsMin[0]; /* set bounds */
139
0
  ByteCopy(&dValue, abyHeader + 36, 8);
140
0
  if (bBigEndian)
141
0
    SwapWord(8, abyHeader + 36);
142
143
0
  dValue = psSHP->adBoundsMin[1];
144
0
  ByteCopy(&dValue, abyHeader + 44, 8);
145
0
  if (bBigEndian)
146
0
    SwapWord(8, abyHeader + 44);
147
148
0
  dValue = psSHP->adBoundsMax[0];
149
0
  ByteCopy(&dValue, abyHeader + 52, 8);
150
0
  if (bBigEndian)
151
0
    SwapWord(8, abyHeader + 52);
152
153
0
  dValue = psSHP->adBoundsMax[1];
154
0
  ByteCopy(&dValue, abyHeader + 60, 8);
155
0
  if (bBigEndian)
156
0
    SwapWord(8, abyHeader + 60);
157
158
0
  dValue = psSHP->adBoundsMin[2]; /* z */
159
0
  ByteCopy(&dValue, abyHeader + 68, 8);
160
0
  if (bBigEndian)
161
0
    SwapWord(8, abyHeader + 68);
162
163
0
  dValue = psSHP->adBoundsMax[2];
164
0
  ByteCopy(&dValue, abyHeader + 76, 8);
165
0
  if (bBigEndian)
166
0
    SwapWord(8, abyHeader + 76);
167
168
0
  dValue = psSHP->adBoundsMin[3]; /* m */
169
0
  ByteCopy(&dValue, abyHeader + 84, 8);
170
0
  if (bBigEndian)
171
0
    SwapWord(8, abyHeader + 84);
172
173
0
  dValue = psSHP->adBoundsMax[3];
174
0
  ByteCopy(&dValue, abyHeader + 92, 8);
175
0
  if (bBigEndian)
176
0
    SwapWord(8, abyHeader + 92);
177
178
  /* -------------------------------------------------------------------- */
179
  /*      Write .shp file header.                                         */
180
  /* -------------------------------------------------------------------- */
181
0
  VSIFSeekL(psSHP->fpSHP, 0, 0);
182
0
  VSIFWriteL(abyHeader, 100, 1, psSHP->fpSHP);
183
184
  /* -------------------------------------------------------------------- */
185
  /*      Prepare, and write .shx file header.                            */
186
  /* -------------------------------------------------------------------- */
187
0
  i32 = (psSHP->nRecords * 2 * sizeof(ms_int32) + 100) / 2; /* file size */
188
0
  ByteCopy(&i32, abyHeader + 24, 4);
189
0
  if (!bBigEndian)
190
0
    SwapWord(4, abyHeader + 24);
191
192
0
  VSIFSeekL(psSHP->fpSHX, 0, 0);
193
0
  VSIFWriteL(abyHeader, 100, 1, psSHP->fpSHX);
194
195
  /* -------------------------------------------------------------------- */
196
  /*      Write out the .shx contents.                                    */
197
  /* -------------------------------------------------------------------- */
198
0
  panSHX = (ms_int32 *)msSmallMalloc(sizeof(ms_int32) * 2 * psSHP->nRecords);
199
200
0
  for (i = 0; i < psSHP->nRecords; i++) {
201
0
    panSHX[i * 2] = psSHP->panRecOffset[i] / 2;
202
0
    panSHX[i * 2 + 1] = psSHP->panRecSize[i] / 2;
203
0
    if (!bBigEndian) {
204
0
      *(panSHX + i * 2) = SWAP_FOUR_BYTES(*(panSHX + i * 2));
205
0
      *(panSHX + i * 2 + 1) = SWAP_FOUR_BYTES(*(panSHX + i * 2 + 1));
206
0
    }
207
0
  }
208
209
0
  VSIFWriteL(panSHX, sizeof(ms_int32) * 2, psSHP->nRecords, psSHP->fpSHX);
210
211
0
  free(panSHX);
212
0
}
213
214
0
SHPHandle msSHPOpenVirtualFile(VSILFILE *fpSHP, VSILFILE *fpSHX) {
215
  /* -------------------------------------------------------------------- */
216
  /*  Initialize the info structure.              */
217
  /* -------------------------------------------------------------------- */
218
0
  SHPHandle psSHP = (SHPHandle)msSmallMalloc(sizeof(SHPInfo));
219
220
0
  psSHP->bUpdated = MS_FALSE;
221
222
0
  psSHP->pabyRec = NULL;
223
0
  psSHP->panParts = NULL;
224
0
  psSHP->nBufSize = psSHP->nPartMax = 0;
225
226
0
  psSHP->fpSHP = fpSHP;
227
0
  psSHP->fpSHX = fpSHX;
228
229
  /* -------------------------------------------------------------------- */
230
  /*   Read the file size from the SHP file.            */
231
  /* -------------------------------------------------------------------- */
232
0
  uchar *pabyBuf = (uchar *)msSmallMalloc(100);
233
0
  if (1 != VSIFReadL(pabyBuf, 100, 1, psSHP->fpSHP)) {
234
0
    VSIFCloseL(psSHP->fpSHP);
235
0
    VSIFCloseL(psSHP->fpSHX);
236
0
    free(psSHP);
237
0
    free(pabyBuf);
238
0
    return (NULL);
239
0
  }
240
241
0
  if (!bBigEndian)
242
0
    SwapWord(4, pabyBuf + 24);
243
0
  memcpy(&psSHP->nFileSize, pabyBuf + 24, 4);
244
0
  if (psSHP->nFileSize < 0 || psSHP->nFileSize > INT_MAX / 2) {
245
0
    msDebug("Invalid / unsupported nFileSize = %d value. Got it from actual "
246
0
            "file length",
247
0
            psSHP->nFileSize);
248
0
    VSIFSeekL(psSHP->fpSHP, 0, SEEK_END);
249
0
    vsi_l_offset nSize = VSIFTellL(psSHP->fpSHP);
250
0
    if (nSize > (vsi_l_offset)INT_MAX) {
251
0
      msDebug("Actual .shp size is larger than 2 GB. Not supported. "
252
0
              "Invalidating nFileSize");
253
0
      psSHP->nFileSize = 0;
254
0
    } else
255
0
      psSHP->nFileSize = (int)nSize;
256
0
  } else {
257
0
    psSHP->nFileSize *= 2;
258
0
  }
259
260
  /* -------------------------------------------------------------------- */
261
  /*  Read SHX file Header info                                           */
262
  /* -------------------------------------------------------------------- */
263
0
  if (1 != VSIFReadL(pabyBuf, 100, 1, psSHP->fpSHX)) {
264
0
    msSetError(MS_SHPERR, "Corrupted .shx file", "msSHPOpen()");
265
0
    VSIFCloseL(psSHP->fpSHP);
266
0
    VSIFCloseL(psSHP->fpSHX);
267
0
    free(psSHP);
268
0
    free(pabyBuf);
269
0
    return (NULL);
270
0
  }
271
272
0
  if (pabyBuf[0] != 0 || pabyBuf[1] != 0 || pabyBuf[2] != 0x27 ||
273
0
      (pabyBuf[3] != 0x0a && pabyBuf[3] != 0x0d)) {
274
0
    msSetError(MS_SHPERR, "Corrupted .shx file", "msSHPOpen()");
275
0
    VSIFCloseL(psSHP->fpSHP);
276
0
    VSIFCloseL(psSHP->fpSHX);
277
0
    free(psSHP);
278
0
    free(pabyBuf);
279
280
0
    return (NULL);
281
0
  }
282
283
0
  int nSHXHalfFileSize;
284
0
  if (!bBigEndian)
285
0
    SwapWord(4, pabyBuf + 24);
286
0
  memcpy(&nSHXHalfFileSize, pabyBuf + 24, 4);
287
0
  if (nSHXHalfFileSize >= 50)
288
0
    psSHP->nRecords = (nSHXHalfFileSize - 50) / 4; // (nSHXFileSize - 100) / 8
289
0
  else
290
0
    psSHP->nRecords = -1;
291
292
0
  if (psSHP->nRecords < 0 || psSHP->nRecords > 256000000) {
293
0
    msSetError(MS_SHPERR, "Corrupted .shx file : nRecords = %d.", "msSHPOpen()",
294
0
               psSHP->nRecords);
295
0
    VSIFCloseL(psSHP->fpSHP);
296
0
    VSIFCloseL(psSHP->fpSHX);
297
0
    free(psSHP);
298
0
    free(pabyBuf);
299
0
    return (NULL);
300
0
  }
301
302
0
  psSHP->nShapeType = pabyBuf[32];
303
304
0
  if (bBigEndian)
305
0
    SwapWord(8, pabyBuf + 36);
306
0
  double dValue;
307
0
  memcpy(&dValue, pabyBuf + 36, 8);
308
0
  psSHP->adBoundsMin[0] = dValue;
309
310
0
  if (bBigEndian)
311
0
    SwapWord(8, pabyBuf + 44);
312
0
  memcpy(&dValue, pabyBuf + 44, 8);
313
0
  psSHP->adBoundsMin[1] = dValue;
314
315
0
  if (bBigEndian)
316
0
    SwapWord(8, pabyBuf + 52);
317
0
  memcpy(&dValue, pabyBuf + 52, 8);
318
0
  psSHP->adBoundsMax[0] = dValue;
319
320
0
  if (bBigEndian)
321
0
    SwapWord(8, pabyBuf + 60);
322
0
  memcpy(&dValue, pabyBuf + 60, 8);
323
0
  psSHP->adBoundsMax[1] = dValue;
324
325
0
  if (bBigEndian)
326
0
    SwapWord(8, pabyBuf + 68); /* z */
327
0
  memcpy(&dValue, pabyBuf + 68, 8);
328
0
  psSHP->adBoundsMin[2] = dValue;
329
330
0
  if (bBigEndian)
331
0
    SwapWord(8, pabyBuf + 76);
332
0
  memcpy(&dValue, pabyBuf + 76, 8);
333
0
  psSHP->adBoundsMax[2] = dValue;
334
335
0
  if (bBigEndian)
336
0
    SwapWord(8, pabyBuf + 84); /* m */
337
0
  memcpy(&dValue, pabyBuf + 84, 8);
338
0
  psSHP->adBoundsMin[3] = dValue;
339
340
0
  if (bBigEndian)
341
0
    SwapWord(8, pabyBuf + 92);
342
0
  memcpy(&dValue, pabyBuf + 92, 8);
343
0
  psSHP->adBoundsMax[3] = dValue;
344
0
  free(pabyBuf);
345
346
  /* -------------------------------------------------------------------- */
347
  /*  Read the .shx file to get the offsets to each record in       */
348
  /*  the .shp file.                  */
349
  /* -------------------------------------------------------------------- */
350
0
  psSHP->nMaxRecords = psSHP->nRecords;
351
352
  /* Our in-memory cache of offset information */
353
0
  psSHP->panRecOffset = (int *)malloc(sizeof(int) * psSHP->nMaxRecords);
354
  /* Our in-memory cache of size information */
355
0
  psSHP->panRecSize = (int *)malloc(sizeof(int) * psSHP->nMaxRecords);
356
  /* The completeness information for our in-memory cache */
357
0
  psSHP->panRecLoaded =
358
0
      msAllocBitArray(1 + (psSHP->nMaxRecords / SHX_BUFFER_PAGE));
359
  /* Is our in-memory cache completely populated? */
360
0
  psSHP->panRecAllLoaded = 0;
361
362
  /* malloc failed? clean up and shut down */
363
0
  if (psSHP->panRecOffset == NULL || psSHP->panRecSize == NULL ||
364
0
      psSHP->panRecLoaded == NULL) {
365
0
    free(psSHP->panRecOffset);
366
0
    free(psSHP->panRecSize);
367
0
    free(psSHP->panRecLoaded);
368
0
    VSIFCloseL(psSHP->fpSHP);
369
0
    VSIFCloseL(psSHP->fpSHX);
370
0
    free(psSHP);
371
0
    msSetError(MS_MEMERR, "Out of memory", "msSHPOpen()");
372
0
    return (NULL);
373
0
  }
374
375
0
  return (psSHP);
376
0
}
377
378
/************************************************************************/
379
/*                              msSHPOpen()                             */
380
/*                                                                      */
381
/*      Open the .shp and .shx files based on the basename of the       */
382
/*      files or either file name.                                      */
383
/************************************************************************/
384
0
SHPHandle msSHPOpen(const char *pszLayer, const char *pszAccess) {
385
0
  char *pszFullname, *pszBasename;
386
387
0
  int i;
388
389
  /* -------------------------------------------------------------------- */
390
  /*      Ensure the access string is one of the legal ones.  We          */
391
  /*      ensure the result string indicates binary to avoid common       */
392
  /*      problems on Windows.                                            */
393
  /* -------------------------------------------------------------------- */
394
0
  if (strcmp(pszAccess, "rb+") == 0 || strcmp(pszAccess, "r+b") == 0 ||
395
0
      strcmp(pszAccess, "r+") == 0)
396
0
    pszAccess = "r+b";
397
0
  else
398
0
    pszAccess = "rb";
399
400
  /* -------------------------------------------------------------------- */
401
  /*  Compute the base (layer) name.  If there is any extension     */
402
  /*  on the passed in filename we will strip it off.         */
403
  /* -------------------------------------------------------------------- */
404
0
  pszBasename = (char *)msSmallMalloc(strlen(pszLayer) + 5);
405
0
  strcpy(pszBasename, pszLayer);
406
0
  for (i = strlen(pszBasename) - 1;
407
0
       i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/' &&
408
0
       pszBasename[i] != '\\';
409
0
       i--) {
410
0
  }
411
412
0
  if (pszBasename[i] == '.')
413
0
    pszBasename[i] = '\0';
414
415
  /* -------------------------------------------------------------------- */
416
  /*  Open the .shp and .shx files.  Note that files pulled from      */
417
  /*  a PC to Unix with upper case filenames won't work!        */
418
  /* -------------------------------------------------------------------- */
419
0
  pszFullname = (char *)msSmallMalloc(strlen(pszBasename) + 5);
420
0
  sprintf(pszFullname, "%s.shp", pszBasename);
421
0
  VSILFILE *fpSHP = VSIFOpenL(pszFullname, pszAccess);
422
0
  if (fpSHP == NULL) {
423
0
    sprintf(pszFullname, "%s.SHP", pszBasename);
424
0
    fpSHP = VSIFOpenL(pszFullname, pszAccess);
425
0
  }
426
0
  if (fpSHP == NULL) {
427
0
    msFree(pszBasename);
428
0
    msFree(pszFullname);
429
0
    return (NULL);
430
0
  }
431
432
0
  sprintf(pszFullname, "%s.shx", pszBasename);
433
0
  VSILFILE *fpSHX = VSIFOpenL(pszFullname, pszAccess);
434
0
  if (fpSHX == NULL) {
435
0
    sprintf(pszFullname, "%s.SHX", pszBasename);
436
0
    fpSHX = VSIFOpenL(pszFullname, pszAccess);
437
0
  }
438
0
  if (fpSHX == NULL) {
439
0
    VSIFCloseL(fpSHP);
440
0
    msFree(pszBasename);
441
0
    msFree(pszFullname);
442
0
    return (NULL);
443
0
  }
444
445
0
  free(pszFullname);
446
0
  free(pszBasename);
447
448
0
  return msSHPOpenVirtualFile(fpSHP, fpSHX);
449
0
}
450
451
/************************************************************************/
452
/*                              msSHPClose()                            */
453
/*                        */
454
/*  Close the .shp and .shx files.          */
455
/************************************************************************/
456
0
void msSHPClose(SHPHandle psSHP) {
457
  /* -------------------------------------------------------------------- */
458
  /*  Update the header if we have modified anything.           */
459
  /* -------------------------------------------------------------------- */
460
0
  if (psSHP->bUpdated)
461
0
    writeHeader(psSHP);
462
463
  /* -------------------------------------------------------------------- */
464
  /*      Free all resources, and close files.                            */
465
  /* -------------------------------------------------------------------- */
466
0
  free(psSHP->panRecOffset);
467
0
  free(psSHP->panRecSize);
468
0
  free(psSHP->panRecLoaded);
469
470
0
  free(psSHP->pabyRec);
471
0
  free(psSHP->panParts);
472
473
0
  VSIFCloseL(psSHP->fpSHX);
474
0
  VSIFCloseL(psSHP->fpSHP);
475
476
0
  free(psSHP);
477
0
}
478
479
/************************************************************************/
480
/*                             msSHPGetInfo()                           */
481
/*                                                                      */
482
/*      Fetch general information about the shape file.                 */
483
/************************************************************************/
484
0
void msSHPGetInfo(SHPHandle psSHP, int *pnEntities, int *pnShapeType) {
485
0
  if (pnEntities)
486
0
    *pnEntities = psSHP->nRecords;
487
488
0
  if (pnShapeType)
489
0
    *pnShapeType = psSHP->nShapeType;
490
0
}
491
492
/************************************************************************/
493
/*                             msSHPCreate()                            */
494
/*                                                                      */
495
/*      Create a new shape file and return a handle to the open         */
496
/*      shape file with read/write access.                              */
497
/************************************************************************/
498
0
SHPHandle msSHPCreate(const char *pszLayer, int nShapeType) {
499
0
  char *pszBasename, *pszFullname;
500
0
  int i;
501
0
  VSILFILE *fpSHP, *fpSHX;
502
0
  uchar abyHeader[100];
503
0
  ms_int32 i32;
504
0
  double dValue;
505
506
  /* -------------------------------------------------------------------- */
507
  /*  Compute the base (layer) name.  If there is any extension       */
508
  /*  on the passed in filename we will strip it off.         */
509
  /* -------------------------------------------------------------------- */
510
0
  pszBasename = (char *)msSmallMalloc(strlen(pszLayer) + 5);
511
0
  strcpy(pszBasename, pszLayer);
512
0
  for (i = strlen(pszBasename) - 1;
513
0
       i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/' &&
514
0
       pszBasename[i] != '\\';
515
0
       i--) {
516
0
  }
517
518
0
  if (pszBasename[i] == '.')
519
0
    pszBasename[i] = '\0';
520
521
  /* -------------------------------------------------------------------- */
522
  /*      Open the two files so we can write their headers.               */
523
  /* -------------------------------------------------------------------- */
524
0
  pszFullname = (char *)msSmallMalloc(strlen(pszBasename) + 5);
525
0
  sprintf(pszFullname, "%s.shp", pszBasename);
526
0
  fpSHP = VSIFOpenL(pszFullname, "wb");
527
0
  if (fpSHP == NULL) {
528
0
    free(pszFullname);
529
0
    free(pszBasename);
530
0
    return (NULL);
531
0
  }
532
533
0
  sprintf(pszFullname, "%s.shx", pszBasename);
534
0
  fpSHX = VSIFOpenL(pszFullname, "wb");
535
0
  if (fpSHX == NULL) {
536
0
    VSIFCloseL(fpSHP);
537
0
    free(pszFullname);
538
0
    free(pszBasename);
539
0
    return (NULL);
540
0
  }
541
542
0
  free(pszFullname);
543
0
  free(pszBasename);
544
545
  /* -------------------------------------------------------------------- */
546
  /*      Prepare header block for .shp file.                             */
547
  /* -------------------------------------------------------------------- */
548
0
  for (i = 0; i < 100; i++)
549
0
    abyHeader[i] = 0;
550
551
0
  abyHeader[2] = 0x27; /* magic cookie */
552
0
  abyHeader[3] = 0x0a;
553
554
0
  i32 = 50; /* file size */
555
0
  ByteCopy(&i32, abyHeader + 24, 4);
556
0
  if (!bBigEndian)
557
0
    SwapWord(4, abyHeader + 24);
558
559
0
  i32 = 1000; /* version */
560
0
  ByteCopy(&i32, abyHeader + 28, 4);
561
0
  if (bBigEndian)
562
0
    SwapWord(4, abyHeader + 28);
563
564
0
  i32 = nShapeType; /* shape type */
565
0
  ByteCopy(&i32, abyHeader + 32, 4);
566
0
  if (bBigEndian)
567
0
    SwapWord(4, abyHeader + 32);
568
569
0
  dValue = 0.0; /* set bounds */
570
0
  ByteCopy(&dValue, abyHeader + 36, 8);
571
0
  ByteCopy(&dValue, abyHeader + 44, 8);
572
0
  ByteCopy(&dValue, abyHeader + 52, 8);
573
0
  ByteCopy(&dValue, abyHeader + 60, 8);
574
575
  /* -------------------------------------------------------------------- */
576
  /*      Write .shp file header.                                         */
577
  /* -------------------------------------------------------------------- */
578
0
  VSIFWriteL(abyHeader, 100, 1, fpSHP);
579
580
  /* -------------------------------------------------------------------- */
581
  /*      Prepare, and write .shx file header.                            */
582
  /* -------------------------------------------------------------------- */
583
0
  i32 = 50; /* file size */
584
0
  ByteCopy(&i32, abyHeader + 24, 4);
585
0
  if (!bBigEndian)
586
0
    SwapWord(4, abyHeader + 24);
587
588
0
  VSIFWriteL(abyHeader, 100, 1, fpSHX);
589
590
  /* -------------------------------------------------------------------- */
591
  /*      Close the files, and then open them as regular existing files.  */
592
  /* -------------------------------------------------------------------- */
593
0
  VSIFCloseL(fpSHP);
594
0
  VSIFCloseL(fpSHX);
595
596
0
  return (msSHPOpen(pszLayer, "rb+"));
597
0
}
598
599
/************************************************************************/
600
/*                           writeBounds()                              */
601
/*                                                                      */
602
/*      Compute a bounds rectangle for a shape, and set it into the     */
603
/*      indicated location in the record.                               */
604
/************************************************************************/
605
0
static void writeBounds(uchar *pabyRec, shapeObj *shape, int nVCount) {
606
0
  double dXMin, dXMax, dYMin, dYMax;
607
0
  int i, j;
608
609
0
  if (nVCount == 0) {
610
0
    dXMin = dYMin = dXMax = dYMax = 0.0;
611
0
  } else {
612
0
    dXMin = dXMax = shape->line[0].point[0].x;
613
0
    dYMin = dYMax = shape->line[0].point[0].y;
614
615
0
    for (i = 0; i < shape->numlines; i++) {
616
0
      for (j = 0; j < shape->line[i].numpoints; j++) {
617
0
        dXMin = MS_MIN(dXMin, shape->line[i].point[j].x);
618
0
        dXMax = MS_MAX(dXMax, shape->line[i].point[j].x);
619
0
        dYMin = MS_MIN(dYMin, shape->line[i].point[j].y);
620
0
        dYMax = MS_MAX(dYMax, shape->line[i].point[j].y);
621
0
      }
622
0
    }
623
0
  }
624
625
0
  if (bBigEndian) {
626
0
    SwapWord(8, &dXMin);
627
0
    SwapWord(8, &dYMin);
628
0
    SwapWord(8, &dXMax);
629
0
    SwapWord(8, &dYMax);
630
0
  }
631
632
0
  ByteCopy(&dXMin, pabyRec + 0, 8);
633
0
  ByteCopy(&dYMin, pabyRec + 8, 8);
634
0
  ByteCopy(&dXMax, pabyRec + 16, 8);
635
0
  ByteCopy(&dYMax, pabyRec + 24, 8);
636
0
}
637
638
0
int msSHPWritePoint(SHPHandle psSHP, pointObj *point) {
639
0
  int nRecordOffset, nRecordSize = 0;
640
0
  uchar *pabyRec;
641
0
  ms_int32 i32, nPoints, nParts;
642
643
0
  if (psSHP->nShapeType != SHP_POINT)
644
0
    return (-1);
645
0
  if (psSHP->nFileSize == 0)
646
0
    return -1;
647
648
0
  psSHP->bUpdated = MS_TRUE;
649
650
  /* Fill the SHX buffer if it is not already full. */
651
0
  if (!psSHP->panRecAllLoaded)
652
0
    msSHXLoadAll(psSHP);
653
654
  /* -------------------------------------------------------------------- */
655
  /*      Add the new entity to the in memory index.                      */
656
  /* -------------------------------------------------------------------- */
657
0
  psSHP->nRecords++;
658
0
  if (psSHP->nRecords > psSHP->nMaxRecords) {
659
0
    psSHP->nMaxRecords = (int)(psSHP->nMaxRecords * 1.3 + 100);
660
661
0
    psSHP->panRecOffset =
662
0
        (int *)SfRealloc(psSHP->panRecOffset, sizeof(int) * psSHP->nMaxRecords);
663
0
    psSHP->panRecSize =
664
0
        (int *)SfRealloc(psSHP->panRecSize, sizeof(int) * psSHP->nMaxRecords);
665
0
  }
666
667
  /* -------------------------------------------------------------------- */
668
  /*      Compute a few things.                                           */
669
  /* -------------------------------------------------------------------- */
670
0
  nPoints = 1;
671
0
  nParts = 1;
672
673
  /* -------------------------------------------------------------------- */
674
  /*      Initialize record.                                              */
675
  /* -------------------------------------------------------------------- */
676
0
  psSHP->panRecOffset[psSHP->nRecords - 1] = nRecordOffset = psSHP->nFileSize;
677
678
0
  pabyRec =
679
0
      (uchar *)msSmallMalloc(nPoints * 2 * sizeof(double) + nParts * 4 + 128);
680
681
  /* -------------------------------------------------------------------- */
682
  /*      Write vertices for a point.                                     */
683
  /* -------------------------------------------------------------------- */
684
0
  ByteCopy(&(point->x), pabyRec + 12, 8);
685
0
  ByteCopy(&(point->y), pabyRec + 20, 8);
686
687
0
  if (bBigEndian) {
688
0
    SwapWord(8, pabyRec + 12);
689
0
    SwapWord(8, pabyRec + 20);
690
0
  }
691
692
0
  nRecordSize = 20;
693
694
  /* -------------------------------------------------------------------- */
695
  /*      Set the shape type, record number, and record size.             */
696
  /* -------------------------------------------------------------------- */
697
0
  i32 = psSHP->nRecords - 1 + 1; /* record # */
698
0
  if (!bBigEndian)
699
0
    i32 = SWAP_FOUR_BYTES(i32);
700
0
  ByteCopy(&i32, pabyRec, 4);
701
702
0
  i32 = nRecordSize / 2; /* record size */
703
0
  if (!bBigEndian)
704
0
    i32 = SWAP_FOUR_BYTES(i32);
705
0
  ByteCopy(&i32, pabyRec + 4, 4);
706
707
0
  i32 = psSHP->nShapeType; /* shape type */
708
0
  if (bBigEndian)
709
0
    i32 = SWAP_FOUR_BYTES(i32);
710
0
  ByteCopy(&i32, pabyRec + 8, 4);
711
712
  /* -------------------------------------------------------------------- */
713
  /*      Write out record.                                               */
714
  /* -------------------------------------------------------------------- */
715
0
  if (VSIFSeekL(psSHP->fpSHP, nRecordOffset, 0) == 0) {
716
0
    VSIFWriteL(pabyRec, nRecordSize + 8, 1, psSHP->fpSHP);
717
718
0
    psSHP->panRecSize[psSHP->nRecords - 1] = nRecordSize;
719
0
    psSHP->nFileSize += nRecordSize + 8;
720
721
    /* -------------------------------------------------------------------- */
722
    /*  Expand file wide bounds based on this shape.        */
723
    /* -------------------------------------------------------------------- */
724
0
    if (psSHP->nRecords == 1) {
725
0
      psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = point->x;
726
0
      psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = point->y;
727
0
    } else {
728
0
      psSHP->adBoundsMin[0] = MS_MIN(psSHP->adBoundsMin[0], point->x);
729
0
      psSHP->adBoundsMin[1] = MS_MIN(psSHP->adBoundsMin[1], point->y);
730
0
      psSHP->adBoundsMax[0] = MS_MAX(psSHP->adBoundsMax[0], point->x);
731
0
      psSHP->adBoundsMax[1] = MS_MAX(psSHP->adBoundsMax[1], point->y);
732
0
    }
733
0
  } else {
734
0
    psSHP->nRecords--;
735
0
  }
736
0
  free(pabyRec);
737
0
  return (psSHP->nRecords - 1);
738
0
}
739
740
0
int msSHPWriteShape(SHPHandle psSHP, shapeObj *shape) {
741
0
  int nRecordOffset, i, j, k, nRecordSize = 0;
742
0
  uchar *pabyRec;
743
0
  int nShapeType;
744
745
0
  ms_int32 i32, nPoints, nParts;
746
747
0
  if (psSHP->nFileSize == 0)
748
0
    return -1;
749
750
0
  psSHP->bUpdated = MS_TRUE;
751
752
  /* Fill the SHX buffer if it is not already full. */
753
0
  if (!psSHP->panRecAllLoaded)
754
0
    msSHXLoadAll(psSHP);
755
756
  /* -------------------------------------------------------------------- */
757
  /*      Add the new entity to the in memory index.                      */
758
  /* -------------------------------------------------------------------- */
759
0
  psSHP->nRecords++;
760
0
  if (psSHP->nRecords > psSHP->nMaxRecords) {
761
0
    psSHP->nMaxRecords = (int)(psSHP->nMaxRecords * 1.3 + 100);
762
763
0
    psSHP->panRecOffset =
764
0
        (int *)SfRealloc(psSHP->panRecOffset, sizeof(int) * psSHP->nMaxRecords);
765
0
    psSHP->panRecSize =
766
0
        (int *)SfRealloc(psSHP->panRecSize, sizeof(int) * psSHP->nMaxRecords);
767
0
  }
768
769
  /* -------------------------------------------------------------------- */
770
  /*      Compute a few things.                                           */
771
  /* -------------------------------------------------------------------- */
772
0
  nPoints = 0;
773
0
  for (i = 0; i < shape->numlines; i++)
774
0
    nPoints += shape->line[i].numpoints;
775
776
0
  nParts = shape->numlines;
777
778
  /* -------------------------------------------------------------------- */
779
  /*      Initialize record.                                              */
780
  /* -------------------------------------------------------------------- */
781
0
  psSHP->panRecOffset[psSHP->nRecords - 1] = nRecordOffset = psSHP->nFileSize;
782
783
0
  pabyRec =
784
0
      (uchar *)msSmallMalloc(nPoints * 4 * sizeof(double) + nParts * 8 + 128);
785
0
  nShapeType = psSHP->nShapeType;
786
787
0
  if (shape->type == MS_SHAPE_NULL) {
788
0
    nShapeType = 0;
789
0
    nRecordSize = 12;
790
0
  }
791
  /* -------------------------------------------------------------------- */
792
  /*  Write vertices for a Polygon or Arc.            */
793
  /* -------------------------------------------------------------------- */
794
0
  else if (psSHP->nShapeType == SHP_POLYGON || psSHP->nShapeType == SHP_ARC ||
795
0
           psSHP->nShapeType == SHP_POLYGONM || psSHP->nShapeType == SHP_ARCM ||
796
0
           psSHP->nShapeType == SHP_ARCZ || psSHP->nShapeType == SHP_POLYGONZ) {
797
0
    ms_int32 t_nParts, t_nPoints, partSize;
798
799
0
    t_nParts = nParts;
800
0
    t_nPoints = nPoints;
801
802
0
    writeBounds(pabyRec + 12, shape, t_nPoints);
803
804
0
    if (bBigEndian) {
805
0
      nPoints = SWAP_FOUR_BYTES(nPoints);
806
0
      nParts = SWAP_FOUR_BYTES(nParts);
807
0
    }
808
809
0
    ByteCopy(&nPoints, pabyRec + 40 + 8, 4);
810
0
    ByteCopy(&nParts, pabyRec + 36 + 8, 4);
811
812
0
    partSize = 0; /* first part always starts at 0 */
813
0
    ByteCopy(&partSize, pabyRec + 44 + 8 + 4 * 0, 4);
814
0
    if (bBigEndian)
815
0
      SwapWord(4, pabyRec + 44 + 8 + 4 * 0);
816
817
0
    for (i = 1; i < t_nParts; i++) {
818
0
      partSize += shape->line[i - 1].numpoints;
819
0
      ByteCopy(&partSize, pabyRec + 44 + 8 + 4 * i, 4);
820
0
      if (bBigEndian)
821
0
        SwapWord(4, pabyRec + 44 + 8 + 4 * i);
822
0
    }
823
824
0
    k = 0; /* overall point counter */
825
0
    for (i = 0; i < shape->numlines; i++) {
826
0
      for (j = 0; j < shape->line[i].numpoints; j++) {
827
0
        ByteCopy(&(shape->line[i].point[j].x),
828
0
                 pabyRec + 44 + 4 * t_nParts + 8 + k * 16, 8);
829
0
        ByteCopy(&(shape->line[i].point[j].y),
830
0
                 pabyRec + 44 + 4 * t_nParts + 8 + k * 16 + 8, 8);
831
832
0
        if (bBigEndian) {
833
0
          SwapWord(8, pabyRec + 44 + 4 * t_nParts + 8 + k * 16);
834
0
          SwapWord(8, pabyRec + 44 + 4 * t_nParts + 8 + k * 16 + 8);
835
0
        }
836
837
0
        k++;
838
0
      }
839
0
    }
840
841
0
    nRecordSize = 44 + 4 * t_nParts + 16 * t_nPoints;
842
843
    /* -------------------------------------------------------------------- */
844
    /*      measured shape : polygon and arc.                               */
845
    /* -------------------------------------------------------------------- */
846
0
    if (psSHP->nShapeType == SHP_POLYGONM || psSHP->nShapeType == SHP_ARCM) {
847
0
      const double dfMMin = shape->line[0].point[0].m;
848
0
      const double dfMMax =
849
0
          shape->line[shape->numlines - 1]
850
0
              .point[shape->line[shape->numlines - 1].numpoints - 1]
851
0
              .m;
852
853
0
      nRecordSize = 44 + 4 * t_nParts + 8 + (t_nPoints * 16);
854
855
0
      ByteCopy(&(dfMMin), pabyRec + nRecordSize, 8);
856
0
      if (bBigEndian)
857
0
        SwapWord(8, pabyRec + nRecordSize);
858
0
      nRecordSize += 8;
859
860
0
      ByteCopy(&(dfMMax), pabyRec + nRecordSize, 8);
861
0
      if (bBigEndian)
862
0
        SwapWord(8, pabyRec + nRecordSize);
863
0
      nRecordSize += 8;
864
865
0
      for (i = 0; i < shape->numlines; i++) {
866
0
        for (j = 0; j < shape->line[i].numpoints; j++) {
867
0
          ByteCopy(&(shape->line[i].point[j].m), pabyRec + nRecordSize, 8);
868
0
          if (bBigEndian)
869
0
            SwapWord(8, pabyRec + nRecordSize);
870
0
          nRecordSize += 8;
871
0
        }
872
0
      }
873
0
    }
874
875
    /* -------------------------------------------------------------------- */
876
    /*      Polygon. Arc with Z                                             */
877
    /* -------------------------------------------------------------------- */
878
0
    if (psSHP->nShapeType == SHP_POLYGONZ || psSHP->nShapeType == SHP_ARCZ ||
879
0
        psSHP->nShapeType == SHP_POLYGONM || psSHP->nShapeType == SHP_ARCM) {
880
0
      const double dfMMin = shape->line[0].point[0].z;
881
0
      const double dfMMax =
882
0
          shape->line[shape->numlines - 1]
883
0
              .point[shape->line[shape->numlines - 1].numpoints - 1]
884
0
              .z;
885
886
0
      nRecordSize = 44 + 4 * t_nParts + 8 + (t_nPoints * 16);
887
888
0
      ByteCopy(&(dfMMin), pabyRec + nRecordSize, 8);
889
0
      if (bBigEndian)
890
0
        SwapWord(8, pabyRec + nRecordSize);
891
0
      nRecordSize += 8;
892
893
0
      ByteCopy(&(dfMMax), pabyRec + nRecordSize, 8);
894
0
      if (bBigEndian)
895
0
        SwapWord(8, pabyRec + nRecordSize);
896
0
      nRecordSize += 8;
897
898
0
      for (i = 0; i < shape->numlines; i++) {
899
0
        for (j = 0; j < shape->line[i].numpoints; j++) {
900
0
          ByteCopy(&(shape->line[i].point[j].z), pabyRec + nRecordSize, 8);
901
0
          if (bBigEndian)
902
0
            SwapWord(8, pabyRec + nRecordSize);
903
0
          nRecordSize += 8;
904
0
        }
905
0
      }
906
0
    }
907
0
  }
908
909
  /* -------------------------------------------------------------------- */
910
  /*  Write vertices for a MultiPoint.                                    */
911
  /* -------------------------------------------------------------------- */
912
0
  else if (psSHP->nShapeType == SHP_MULTIPOINT ||
913
0
           psSHP->nShapeType == SHP_MULTIPOINTM ||
914
0
           psSHP->nShapeType == SHP_MULTIPOINTZ) {
915
0
    ms_int32 t_nPoints;
916
917
0
    t_nPoints = nPoints;
918
919
0
    writeBounds(pabyRec + 12, shape, nPoints);
920
921
0
    if (bBigEndian)
922
0
      nPoints = SWAP_FOUR_BYTES(nPoints);
923
0
    ByteCopy(&nPoints, pabyRec + 44, 4);
924
925
0
    for (i = 0; i < shape->line[0].numpoints; i++) {
926
0
      ByteCopy(&(shape->line[0].point[i].x), pabyRec + 48 + i * 16, 8);
927
0
      ByteCopy(&(shape->line[0].point[i].y), pabyRec + 48 + i * 16 + 8, 8);
928
929
0
      if (bBigEndian) {
930
0
        SwapWord(8, pabyRec + 48 + i * 16);
931
0
        SwapWord(8, pabyRec + 48 + i * 16 + 8);
932
0
      }
933
0
    }
934
935
0
    nRecordSize = 40 + 16 * t_nPoints;
936
937
0
    if (psSHP->nShapeType == SHP_MULTIPOINTM) {
938
0
      const double dfMMin = shape->line[0].point[0].m;
939
0
      const double dfMMax =
940
0
          shape->line[0].point[shape->line[0].numpoints - 1].m;
941
942
0
      ByteCopy(&(dfMMin), pabyRec + nRecordSize, 8);
943
0
      if (bBigEndian)
944
0
        SwapWord(8, pabyRec + nRecordSize);
945
0
      nRecordSize += 8;
946
947
0
      ByteCopy(&(dfMMax), pabyRec + nRecordSize, 8);
948
0
      if (bBigEndian)
949
0
        SwapWord(8, pabyRec + nRecordSize);
950
0
      nRecordSize += 8;
951
952
0
      for (i = 0; i < shape->line[0].numpoints; i++) {
953
0
        ByteCopy(&(shape->line[0].point[i].m), pabyRec + nRecordSize, 8);
954
0
        if (bBigEndian)
955
0
          SwapWord(8, pabyRec + nRecordSize);
956
0
        nRecordSize += 8;
957
0
      }
958
0
    }
959
960
0
    if (psSHP->nShapeType == SHP_MULTIPOINTZ) {
961
0
      const double dfMMin = shape->line[0].point[0].z;
962
0
      const double dfMMax =
963
0
          shape->line[0].point[shape->line[0].numpoints - 1].z;
964
965
0
      ByteCopy(&(dfMMin), pabyRec + nRecordSize, 8);
966
0
      if (bBigEndian)
967
0
        SwapWord(8, pabyRec + nRecordSize);
968
0
      nRecordSize += 8;
969
970
0
      ByteCopy(&(dfMMax), pabyRec + nRecordSize, 8);
971
0
      if (bBigEndian)
972
0
        SwapWord(8, pabyRec + nRecordSize);
973
0
      nRecordSize += 8;
974
975
0
      for (i = 0; i < shape->line[0].numpoints; i++) {
976
0
        ByteCopy(&(shape->line[0].point[i].z), pabyRec + nRecordSize, 8);
977
0
        if (bBigEndian)
978
0
          SwapWord(8, pabyRec + nRecordSize);
979
0
        nRecordSize += 8;
980
0
      }
981
0
    }
982
0
  }
983
984
  /* -------------------------------------------------------------------- */
985
  /*      Write vertices for a point.                                     */
986
  /* -------------------------------------------------------------------- */
987
0
  else if (psSHP->nShapeType == SHP_POINT || psSHP->nShapeType == SHP_POINTM ||
988
0
           psSHP->nShapeType == SHP_POINTZ) {
989
0
    ByteCopy(&(shape->line[0].point[0].x), pabyRec + 12, 8);
990
0
    ByteCopy(&(shape->line[0].point[0].y), pabyRec + 20, 8);
991
992
0
    if (bBigEndian) {
993
0
      SwapWord(8, pabyRec + 12);
994
0
      SwapWord(8, pabyRec + 20);
995
0
    }
996
997
0
    nRecordSize = 20;
998
999
0
    if (psSHP->nShapeType == SHP_POINTM) {
1000
0
      ByteCopy(&(shape->line[0].point[0].m), pabyRec + nRecordSize, 8);
1001
0
      if (bBigEndian)
1002
0
        SwapWord(8, pabyRec + nRecordSize);
1003
0
      nRecordSize += 8;
1004
0
    }
1005
1006
0
    if (psSHP->nShapeType == SHP_POINTZ) {
1007
0
      ByteCopy(&(shape->line[0].point[0].z), pabyRec + nRecordSize, 8);
1008
0
      if (bBigEndian)
1009
0
        SwapWord(8, pabyRec + nRecordSize);
1010
0
      nRecordSize += 8;
1011
0
    }
1012
0
  }
1013
1014
  /* -------------------------------------------------------------------- */
1015
  /*      Set the shape type, record number, and record size.             */
1016
  /* -------------------------------------------------------------------- */
1017
0
  i32 = psSHP->nRecords - 1 + 1; /* record # */
1018
0
  if (!bBigEndian)
1019
0
    i32 = SWAP_FOUR_BYTES(i32);
1020
0
  ByteCopy(&i32, pabyRec, 4);
1021
1022
0
  i32 = nRecordSize / 2; /* record size */
1023
0
  if (!bBigEndian)
1024
0
    i32 = SWAP_FOUR_BYTES(i32);
1025
0
  ByteCopy(&i32, pabyRec + 4, 4);
1026
1027
0
  i32 = nShapeType; /* shape type */
1028
0
  if (bBigEndian)
1029
0
    i32 = SWAP_FOUR_BYTES(i32);
1030
0
  ByteCopy(&i32, pabyRec + 8, 4);
1031
1032
  /* -------------------------------------------------------------------- */
1033
  /*      Write out record.                                               */
1034
  /* -------------------------------------------------------------------- */
1035
0
  if (VSIFSeekL(psSHP->fpSHP, nRecordOffset, 0) == 0) {
1036
0
    VSIFWriteL(pabyRec, nRecordSize + 8, 1, psSHP->fpSHP);
1037
1038
0
    psSHP->panRecSize[psSHP->nRecords - 1] = nRecordSize;
1039
0
    psSHP->nFileSize += nRecordSize + 8;
1040
1041
    /* -------------------------------------------------------------------- */
1042
    /*  Expand file wide bounds based on this shape.        */
1043
    /* -------------------------------------------------------------------- */
1044
0
    if (psSHP->nRecords == 1) {
1045
0
      psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = shape->line[0].point[0].x;
1046
0
      psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = shape->line[0].point[0].y;
1047
0
      psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = shape->line[0].point[0].z;
1048
0
      psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = shape->line[0].point[0].m;
1049
0
    }
1050
1051
0
    for (i = 0; i < shape->numlines; i++) {
1052
0
      for (j = 0; j < shape->line[i].numpoints; j++) {
1053
0
        psSHP->adBoundsMin[0] =
1054
0
            MS_MIN(psSHP->adBoundsMin[0], shape->line[i].point[j].x);
1055
0
        psSHP->adBoundsMin[1] =
1056
0
            MS_MIN(psSHP->adBoundsMin[1], shape->line[i].point[j].y);
1057
0
        psSHP->adBoundsMin[2] =
1058
0
            MS_MIN(psSHP->adBoundsMin[2], shape->line[i].point[j].z);
1059
0
        psSHP->adBoundsMin[3] =
1060
0
            MS_MIN(psSHP->adBoundsMin[3], shape->line[i].point[j].m);
1061
0
        psSHP->adBoundsMax[0] =
1062
0
            MS_MAX(psSHP->adBoundsMax[0], shape->line[i].point[j].x);
1063
0
        psSHP->adBoundsMax[1] =
1064
0
            MS_MAX(psSHP->adBoundsMax[1], shape->line[i].point[j].y);
1065
0
        psSHP->adBoundsMax[2] =
1066
0
            MS_MAX(psSHP->adBoundsMax[2], shape->line[i].point[j].z);
1067
0
        psSHP->adBoundsMax[3] =
1068
0
            MS_MAX(psSHP->adBoundsMax[3], shape->line[i].point[j].m);
1069
0
      }
1070
0
    }
1071
1072
0
  } else {
1073
0
    psSHP->nRecords--;
1074
    /* there was an error writing the record */
1075
0
  }
1076
0
  free(pabyRec);
1077
0
  return (psSHP->nRecords - 1);
1078
0
}
1079
1080
/*
1081
 ** msSHPReadAllocateBuffer() - Ensure our record buffer is large enough.
1082
 */
1083
static uchar *msSHPReadAllocateBuffer(SHPHandle psSHP, int hEntity,
1084
0
                                      const char *pszCallingFunction) {
1085
1086
0
  int nEntitySize = msSHXReadSize(psSHP, hEntity);
1087
0
  if (nEntitySize <= 0 || nEntitySize > INT_MAX - 8) {
1088
0
    msSetError(MS_MEMERR,
1089
0
               "Out of memory. Cannot allocate %d bytes. Probably broken "
1090
0
               "shapefile at feature %d",
1091
0
               pszCallingFunction, nEntitySize, hEntity);
1092
0
    return NULL;
1093
0
  }
1094
0
  nEntitySize += 8;
1095
  /* -------------------------------------------------------------------- */
1096
  /*      Ensure our record buffer is large enough.                       */
1097
  /* -------------------------------------------------------------------- */
1098
1099
0
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1100
  /* when running with libFuzzer, allocate a new buffer for every
1101
     call, to allow AddressSanitizer to detect memory errors */
1102
0
  free(psSHP->pabyRec);
1103
0
  psSHP->pabyRec = NULL;
1104
0
  psSHP->nBufSize = 0;
1105
0
#endif
1106
1107
0
  if (nEntitySize > psSHP->nBufSize) {
1108
0
    uchar *pabyRec = (uchar *)SfRealloc(psSHP->pabyRec, nEntitySize);
1109
0
    if (pabyRec == NULL) {
1110
0
      msSetError(MS_MEMERR,
1111
0
                 "Out of memory. Cannot allocate %d bytes. Probably broken "
1112
0
                 "shapefile at feature %d",
1113
0
                 pszCallingFunction, nEntitySize, hEntity);
1114
0
      return NULL;
1115
0
    }
1116
0
    psSHP->pabyRec = pabyRec;
1117
0
    psSHP->nBufSize = nEntitySize;
1118
0
  }
1119
0
  return psSHP->pabyRec;
1120
0
}
1121
1122
/*
1123
** msSHPReadPoint() - Reads a single point from a POINT shape file.
1124
*/
1125
0
int msSHPReadPoint(SHPHandle psSHP, int hEntity, pointObj *point) {
1126
0
  int nEntitySize;
1127
1128
  /* -------------------------------------------------------------------- */
1129
  /*      Only valid for point shapefiles                                 */
1130
  /* -------------------------------------------------------------------- */
1131
0
  if (psSHP->nShapeType != SHP_POINT) {
1132
0
    msSetError(MS_SHPERR, "msSHPReadPoint only operates on point shapefiles.",
1133
0
               "msSHPReadPoint()");
1134
0
    return (MS_FAILURE);
1135
0
  }
1136
1137
  /* -------------------------------------------------------------------- */
1138
  /*      Validate the record/entity number.                              */
1139
  /* -------------------------------------------------------------------- */
1140
0
  if (hEntity < 0 || hEntity >= psSHP->nRecords) {
1141
0
    msSetError(MS_SHPERR, "Record index out of bounds.", "msSHPReadPoint()");
1142
0
    return (MS_FAILURE);
1143
0
  }
1144
1145
0
  nEntitySize = msSHXReadSize(psSHP, hEntity) + 8;
1146
1147
0
  if (nEntitySize == 12) {
1148
0
    msSetError(MS_SHPERR, "NULL feature encountered.", "msSHPReadPoint()");
1149
0
    return (MS_FAILURE);
1150
0
  } else if (nEntitySize < 28) {
1151
0
    msSetError(MS_SHPERR,
1152
0
               "Corrupted feature encountered.  hEntity=%d, nEntitySize=%d",
1153
0
               "msSHPReadPoint()", hEntity, nEntitySize);
1154
0
    return (MS_FAILURE);
1155
0
  }
1156
1157
0
  uchar *pabyRec = msSHPReadAllocateBuffer(psSHP, hEntity, "msSHPReadPoint()");
1158
0
  if (pabyRec == NULL) {
1159
0
    return MS_FAILURE;
1160
0
  }
1161
1162
  /* -------------------------------------------------------------------- */
1163
  /*      Read the record.                                                */
1164
  /* -------------------------------------------------------------------- */
1165
0
  const int offset = msSHXReadOffset(psSHP, hEntity);
1166
0
  if (offset <= 0 || 0 != VSIFSeekL(psSHP->fpSHP, offset, 0)) {
1167
0
    msSetError(MS_IOERR, "failed to seek offset", "msSHPReadPoint()");
1168
0
    return (MS_FAILURE);
1169
0
  }
1170
0
  if (1 != VSIFReadL(pabyRec, nEntitySize, 1, psSHP->fpSHP)) {
1171
0
    msSetError(MS_IOERR, "failed to fread record", "msSHPReadPoint()");
1172
0
    return (MS_FAILURE);
1173
0
  }
1174
1175
0
  memcpy(&(point->x), pabyRec + 12, 8);
1176
0
  memcpy(&(point->y), pabyRec + 20, 8);
1177
1178
0
  if (bBigEndian) {
1179
0
    SwapWord(8, &(point->x));
1180
0
    SwapWord(8, &(point->y));
1181
0
  }
1182
1183
0
  return (MS_SUCCESS);
1184
0
}
1185
1186
/*
1187
** msSHXLoadPage()
1188
**
1189
** The SHX tells us what the byte offsets of the shapes in the SHP file are.
1190
** We read the SHX file in ~8K pages and store those pages in memory for
1191
** successive accesses during the reading cycle (first bounds are read,
1192
** then entire shapes). Each time we read a page, we mark it as read.
1193
*/
1194
0
static bool msSHXLoadPage(SHPHandle psSHP, int shxBufferPage) {
1195
0
  int i;
1196
1197
  /* Each SHX record is 8 bytes long (two ints), hence our buffer size. */
1198
0
  char buffer[SHX_BUFFER_PAGE * 8];
1199
1200
  /*  Validate the page number. */
1201
0
  if (shxBufferPage < 0)
1202
0
    return (MS_FAILURE);
1203
1204
0
  const int nShapesToCache =
1205
0
      shxBufferPage < psSHP->nRecords / SHX_BUFFER_PAGE
1206
0
          ? SHX_BUFFER_PAGE
1207
0
          : psSHP->nRecords - shxBufferPage * SHX_BUFFER_PAGE;
1208
1209
0
  if (0 !=
1210
0
      VSIFSeekL(psSHP->fpSHX, 100 + shxBufferPage * SHX_BUFFER_PAGE * 8, 0)) {
1211
0
    memset(psSHP->panRecOffset + shxBufferPage * SHX_BUFFER_PAGE, 0,
1212
0
           nShapesToCache * sizeof(psSHP->panRecOffset[0]));
1213
0
    memset(psSHP->panRecSize + shxBufferPage * SHX_BUFFER_PAGE, 0,
1214
0
           nShapesToCache * sizeof(psSHP->panRecSize[0]));
1215
0
    msSetBit(psSHP->panRecLoaded, shxBufferPage, 1);
1216
0
    msSetError(MS_IOERR, "failed to seek offset", "msSHXLoadPage()");
1217
0
    return false;
1218
0
  }
1219
1220
0
  if ((size_t)nShapesToCache !=
1221
0
      VSIFReadL(buffer, 8, nShapesToCache, psSHP->fpSHX)) {
1222
0
    memset(psSHP->panRecOffset + shxBufferPage * SHX_BUFFER_PAGE, 0,
1223
0
           nShapesToCache * sizeof(psSHP->panRecOffset[0]));
1224
0
    memset(psSHP->panRecSize + shxBufferPage * SHX_BUFFER_PAGE, 0,
1225
0
           nShapesToCache * sizeof(psSHP->panRecSize[0]));
1226
0
    msSetBit(psSHP->panRecLoaded, shxBufferPage, 1);
1227
0
    msSetError(MS_IOERR, "failed to fread SHX record", "msSHXLoadPage()");
1228
0
    return false;
1229
0
  }
1230
1231
  /* Copy the buffer contents out into the working arrays. */
1232
0
  for (i = 0; i < nShapesToCache; i++) {
1233
0
    int tmpOffset, tmpSize;
1234
1235
0
    memcpy(&tmpOffset, (buffer + (8 * i)), 4);
1236
0
    memcpy(&tmpSize, (buffer + (8 * i) + 4), 4);
1237
1238
    /* SHX uses big endian numbers for the offsets, so we have to flip them */
1239
    /* if we are a little endian machine. */
1240
0
    if (!bBigEndian) {
1241
0
      tmpOffset = SWAP_FOUR_BYTES(tmpOffset);
1242
0
      tmpSize = SWAP_FOUR_BYTES(tmpSize);
1243
0
    }
1244
1245
    /* SHX stores the offsets in 2 byte units, so we double them to get */
1246
    /* an offset in bytes. */
1247
0
    if (tmpOffset > 0 && tmpOffset < INT_MAX / 2)
1248
0
      tmpOffset = tmpOffset * 2;
1249
0
    else
1250
0
      tmpOffset = 0;
1251
1252
0
    if (tmpSize > 0 && tmpSize < INT_MAX / 2)
1253
0
      tmpSize = tmpSize * 2;
1254
0
    else
1255
0
      tmpSize = 0;
1256
1257
    /* Write the answer into the working arrays on the SHPHandle */
1258
0
    psSHP->panRecOffset[shxBufferPage * SHX_BUFFER_PAGE + i] = tmpOffset;
1259
0
    psSHP->panRecSize[shxBufferPage * SHX_BUFFER_PAGE + i] = tmpSize;
1260
0
  }
1261
1262
0
  msSetBit(psSHP->panRecLoaded, shxBufferPage, 1);
1263
1264
0
  return (MS_SUCCESS);
1265
0
}
1266
1267
0
static int msSHXLoadAll(SHPHandle psSHP) {
1268
1269
0
  int i;
1270
0
  uchar *pabyBuf;
1271
1272
0
  pabyBuf = (uchar *)malloc(8 * psSHP->nRecords);
1273
0
  if (pabyBuf == NULL) {
1274
0
    msSetError(MS_IOERR, "failed to allocate memory for SHX buffer",
1275
0
               "msSHXLoadAll()");
1276
0
    return MS_FAILURE;
1277
0
  }
1278
0
  if ((size_t)psSHP->nRecords !=
1279
0
      VSIFReadL(pabyBuf, 8, psSHP->nRecords, psSHP->fpSHX)) {
1280
0
    msSetError(MS_IOERR, "failed to read shx records", "msSHXLoadAll()");
1281
0
    free(pabyBuf);
1282
0
    return MS_FAILURE;
1283
0
  }
1284
0
  for (i = 0; i < psSHP->nRecords; i++) {
1285
0
    ms_int32 nOffset, nLength;
1286
1287
0
    memcpy(&nOffset, pabyBuf + i * 8, 4);
1288
0
    memcpy(&nLength, pabyBuf + i * 8 + 4, 4);
1289
1290
0
    if (!bBigEndian) {
1291
0
      nOffset = SWAP_FOUR_BYTES(nOffset);
1292
0
      nLength = SWAP_FOUR_BYTES(nLength);
1293
0
    }
1294
1295
    /* SHX stores the offsets in 2 byte units, so we double them to get */
1296
    /* an offset in bytes. */
1297
0
    if (nOffset > 0 && nOffset < INT_MAX / 2)
1298
0
      nOffset = nOffset * 2;
1299
0
    else
1300
0
      nOffset = 0;
1301
1302
0
    if (nLength > 0 && nLength < INT_MAX / 2)
1303
0
      nLength = nLength * 2;
1304
0
    else
1305
0
      nLength = 0;
1306
1307
0
    psSHP->panRecOffset[i] = nOffset;
1308
0
    psSHP->panRecSize[i] = nLength;
1309
0
  }
1310
0
  free(pabyBuf);
1311
0
  psSHP->panRecAllLoaded = 1;
1312
1313
0
  return (MS_SUCCESS);
1314
0
}
1315
1316
0
static int msSHXReadOffset(SHPHandle psSHP, int hEntity) {
1317
1318
0
  int shxBufferPage = hEntity / SHX_BUFFER_PAGE;
1319
1320
  /*  Validate the record/entity number. */
1321
0
  if (hEntity < 0 || hEntity >= psSHP->nRecords)
1322
0
    return 0;
1323
1324
0
  if (!(psSHP->panRecAllLoaded ||
1325
0
        msGetBit(psSHP->panRecLoaded, shxBufferPage))) {
1326
0
    msSHXLoadPage(psSHP, shxBufferPage);
1327
0
  }
1328
1329
0
  return psSHP->panRecOffset[hEntity];
1330
0
}
1331
1332
0
static int msSHXReadSize(SHPHandle psSHP, int hEntity) {
1333
1334
0
  int shxBufferPage = hEntity / SHX_BUFFER_PAGE;
1335
1336
  /*  Validate the record/entity number. */
1337
0
  if (hEntity < 0 || hEntity >= psSHP->nRecords)
1338
0
    return 0;
1339
1340
0
  if (!(psSHP->panRecAllLoaded ||
1341
0
        msGetBit(psSHP->panRecLoaded, shxBufferPage))) {
1342
0
    msSHXLoadPage(psSHP, shxBufferPage);
1343
0
  }
1344
1345
0
  return psSHP->panRecSize[hEntity];
1346
0
}
1347
1348
0
static void ReadRect(rectObj *r, const uchar *src) {
1349
0
  memcpy(&r->minx, src, 8);
1350
0
  memcpy(&r->miny, src + 8, 8);
1351
0
  memcpy(&r->maxx, src + 16, 8);
1352
0
  memcpy(&r->maxy, src + 24, 8);
1353
1354
0
  if (bBigEndian) {
1355
0
    SwapWord(8, &r->minx);
1356
0
    SwapWord(8, &r->miny);
1357
0
    SwapWord(8, &r->maxx);
1358
0
    SwapWord(8, &r->maxy);
1359
0
  }
1360
0
}
1361
1362
/*
1363
** msSHPReadShape() - Reads the vertices for one shape from a shape file.
1364
*/
1365
0
void msSHPReadShape(SHPHandle psSHP, int hEntity, shapeObj *shape) {
1366
0
  int i, j, k;
1367
0
  int nEntitySize, nRequiredSize;
1368
1369
0
  msInitShape(shape); /* initialize the shape */
1370
1371
  /* -------------------------------------------------------------------- */
1372
  /*      Validate the record/entity number.                              */
1373
  /* -------------------------------------------------------------------- */
1374
0
  if (hEntity < 0 || hEntity >= psSHP->nRecords)
1375
0
    return;
1376
1377
0
  nEntitySize = msSHXReadSize(psSHP, hEntity);
1378
0
  if (nEntitySize < 4 || nEntitySize > INT_MAX - 8) {
1379
0
    shape->type = MS_SHAPE_NULL;
1380
0
    msSetError(MS_SHPERR,
1381
0
               "Corrupted feature encountered.  hEntity = %d, nEntitySize=%d",
1382
0
               "msSHPReadShape()", hEntity, nEntitySize);
1383
0
    return;
1384
0
  }
1385
1386
0
  nEntitySize += 8;
1387
0
  if (nEntitySize == 12) {
1388
0
    shape->type = MS_SHAPE_NULL;
1389
0
    return;
1390
0
  }
1391
1392
0
  uchar *pabyRec = msSHPReadAllocateBuffer(psSHP, hEntity, "msSHPReadShape()");
1393
0
  if (pabyRec == NULL) {
1394
0
    shape->type = MS_SHAPE_NULL;
1395
0
    return;
1396
0
  }
1397
1398
  /* -------------------------------------------------------------------- */
1399
  /*      Read the record.                                                */
1400
  /* -------------------------------------------------------------------- */
1401
0
  const int offset = msSHXReadOffset(psSHP, hEntity);
1402
0
  if (offset <= 0 || 0 != VSIFSeekL(psSHP->fpSHP, offset, 0)) {
1403
0
    msSetError(MS_IOERR, "failed to seek offset", "msSHPReadShape()");
1404
0
    shape->type = MS_SHAPE_NULL;
1405
0
    return;
1406
0
  }
1407
0
  if (1 != VSIFReadL(pabyRec, nEntitySize, 1, psSHP->fpSHP)) {
1408
0
    msSetError(MS_IOERR, "failed to fread record", "msSHPReadPoint()");
1409
0
    shape->type = MS_SHAPE_NULL;
1410
0
    return;
1411
0
  }
1412
1413
  /* -------------------------------------------------------------------- */
1414
  /*  Extract vertices for a Polygon or Arc.            */
1415
  /* -------------------------------------------------------------------- */
1416
0
  if (psSHP->nShapeType == SHP_POLYGON || psSHP->nShapeType == SHP_ARC ||
1417
0
      psSHP->nShapeType == SHP_POLYGONM || psSHP->nShapeType == SHP_ARCM ||
1418
0
      psSHP->nShapeType == SHP_POLYGONZ || psSHP->nShapeType == SHP_ARCZ) {
1419
0
    ms_int32 nPoints, nParts;
1420
1421
0
    if (nEntitySize < 40 + 8 + 4) {
1422
0
      shape->type = MS_SHAPE_NULL;
1423
0
      msSetError(MS_SHPERR,
1424
0
                 "Corrupted feature encountered.  hEntity = %d, nEntitySize=%d",
1425
0
                 "msSHPReadShape()", hEntity, nEntitySize);
1426
0
      return;
1427
0
    }
1428
1429
    /* copy the bounding box */
1430
0
    ReadRect(&shape->bounds, pabyRec + 8 + 4);
1431
1432
0
    memcpy(&nPoints, pabyRec + 40 + 8, 4);
1433
0
    memcpy(&nParts, pabyRec + 36 + 8, 4);
1434
1435
0
    if (bBigEndian) {
1436
0
      nPoints = SWAP_FOUR_BYTES(nPoints);
1437
0
      nParts = SWAP_FOUR_BYTES(nParts);
1438
0
    }
1439
1440
0
    if (nPoints < 0 || nParts < 0 || nPoints > 50 * 1000 * 1000 ||
1441
0
        nParts > 10 * 1000 * 1000) {
1442
0
      shape->type = MS_SHAPE_NULL;
1443
0
      msSetError(MS_SHPERR,
1444
0
                 "Corrupted feature encountered.  hEntity = %d, nPoints =%d, "
1445
0
                 "nParts = %d",
1446
0
                 "msSHPReadShape()", hEntity, nPoints, nParts);
1447
0
      return;
1448
0
    }
1449
1450
    /* -------------------------------------------------------------------- */
1451
    /*      Copy out the part array from the record.                        */
1452
    /* -------------------------------------------------------------------- */
1453
1454
0
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1455
    /* when running with libFuzzer, allocate a new buffer for every
1456
       call, to allow AddressSanitizer to detect memory errors */
1457
0
    free(psSHP->panParts);
1458
0
    psSHP->panParts = NULL;
1459
0
    psSHP->nPartMax = 0;
1460
0
#endif
1461
1462
0
    if (psSHP->nPartMax < nParts) {
1463
0
      psSHP->panParts = (int *)SfRealloc(psSHP->panParts, nParts * sizeof(int));
1464
0
      if (psSHP->panParts == NULL) {
1465
        /* Reallocate previous successful size for following features */
1466
0
        psSHP->panParts = (int *)msSmallMalloc(psSHP->nPartMax * sizeof(int));
1467
1468
0
        shape->type = MS_SHAPE_NULL;
1469
0
        msSetError(MS_MEMERR,
1470
0
                   "Out of memory. Cannot allocate %d bytes. Probably broken "
1471
0
                   "shapefile at feature %d",
1472
0
                   "msSHPReadShape()", (int)(nParts * sizeof(int)), hEntity);
1473
0
        return;
1474
0
      }
1475
0
      psSHP->nPartMax = nParts;
1476
0
    }
1477
0
    if (psSHP->panParts == NULL) {
1478
0
      shape->type = MS_SHAPE_NULL;
1479
0
      msSetError(MS_MEMERR, "Out of memory", "msSHPReadShape()");
1480
0
      return;
1481
0
    }
1482
1483
    /* With the previous checks on nPoints and nParts, */
1484
    /* we should not overflow here and after */
1485
    /* since 50 M * (16 + 8 + 8) = 1 600 MB */
1486
0
    if (44 + 8 + 4 * nParts + 16 * nPoints > nEntitySize) {
1487
0
      shape->type = MS_SHAPE_NULL;
1488
0
      msSetError(MS_SHPERR,
1489
0
                 "Corrupted .shp file : shape %d, nPoints=%d, nParts=%d.",
1490
0
                 "msSHPReadShape()", hEntity, nPoints, nParts);
1491
0
      return;
1492
0
    }
1493
1494
0
    memcpy(psSHP->panParts, pabyRec + 44 + 8, 4 * nParts);
1495
0
    if (bBigEndian) {
1496
0
      for (i = 0; i < nParts; i++) {
1497
0
        *(psSHP->panParts + i) = SWAP_FOUR_BYTES(*(psSHP->panParts + i));
1498
0
      }
1499
0
    }
1500
1501
    /* -------------------------------------------------------------------- */
1502
    /*      Fill the shape structure.                                       */
1503
    /* -------------------------------------------------------------------- */
1504
0
    shape->line = (lineObj *)malloc(sizeof(lineObj) * nParts);
1505
0
    MS_CHECK_ALLOC_NO_RET(shape->line, sizeof(lineObj) * nParts);
1506
1507
0
    shape->numlines = nParts;
1508
1509
0
    k = 0; /* overall point counter */
1510
0
    for (i = 0; i < nParts; i++) {
1511
0
      const ms_int32 end = i == nParts - 1 ? nPoints : psSHP->panParts[i + 1];
1512
0
      if (psSHP->panParts[i] < 0 || end < 0 || end > nPoints ||
1513
0
          psSHP->panParts[i] >= end) {
1514
0
        msSetError(MS_SHPERR,
1515
0
                   "Corrupted .shp file : shape %d, shape->line[%d].start=%d, "
1516
0
                   "shape->line[%d].end=%d",
1517
0
                   "msSHPReadShape()", hEntity, i, psSHP->panParts[i], i, end);
1518
0
        while (--i >= 0)
1519
0
          free(shape->line[i].point);
1520
0
        free(shape->line);
1521
0
        shape->line = NULL;
1522
0
        shape->numlines = 0;
1523
0
        shape->type = MS_SHAPE_NULL;
1524
0
        return;
1525
0
      }
1526
1527
0
      shape->line[i].numpoints = end - psSHP->panParts[i];
1528
0
      if ((shape->line[i].point = (pointObj *)malloc(
1529
0
               sizeof(pointObj) * shape->line[i].numpoints)) == NULL) {
1530
0
        while (--i >= 0)
1531
0
          free(shape->line[i].point);
1532
0
        free(shape->line);
1533
0
        shape->line = NULL;
1534
0
        shape->numlines = 0;
1535
0
        shape->type = MS_SHAPE_NULL;
1536
0
        msSetError(MS_MEMERR, "Out of memory", "msSHPReadShape()");
1537
0
        return;
1538
0
      }
1539
1540
      /* nOffset = 44 + 8 + 4*nParts; */
1541
0
      for (j = 0; j < shape->line[i].numpoints; j++) {
1542
0
        memcpy(&(shape->line[i].point[j].x),
1543
0
               pabyRec + 44 + 4 * nParts + 8 + k * 16, 8);
1544
0
        memcpy(&(shape->line[i].point[j].y),
1545
0
               pabyRec + 44 + 4 * nParts + 8 + k * 16 + 8, 8);
1546
1547
0
        if (bBigEndian) {
1548
0
          SwapWord(8, &(shape->line[i].point[j].x));
1549
0
          SwapWord(8, &(shape->line[i].point[j].y));
1550
0
        }
1551
1552
        /* --------------------------------------------------------------------
1553
         */
1554
        /*      Polygon, Arc with Z values. */
1555
        /* --------------------------------------------------------------------
1556
         */
1557
0
        shape->line[i].point[j].z = 0.0; /* initialize */
1558
0
        if (psSHP->nShapeType == SHP_POLYGONZ ||
1559
0
            psSHP->nShapeType == SHP_ARCZ) {
1560
0
          const int nOffset = 44 + 8 + (4 * nParts) + (16 * nPoints);
1561
0
          if (nEntitySize >= nOffset + 16 + 8 * nPoints) {
1562
0
            memcpy(&(shape->line[i].point[j].z), pabyRec + nOffset + 16 + k * 8,
1563
0
                   8);
1564
0
            if (bBigEndian)
1565
0
              SwapWord(8, &(shape->line[i].point[j].z));
1566
0
          }
1567
0
        }
1568
1569
        /* --------------------------------------------------------------------
1570
         */
1571
        /*      Measured arc and polygon support. */
1572
        /* --------------------------------------------------------------------
1573
         */
1574
0
        shape->line[i].point[j].m = 0; /* initialize */
1575
0
        if (psSHP->nShapeType == SHP_POLYGONM ||
1576
0
            psSHP->nShapeType == SHP_ARCM) {
1577
0
          const int nOffset = 44 + 8 + (4 * nParts) + (16 * nPoints);
1578
0
          if (nEntitySize >= nOffset + 16 + 8 * nPoints) {
1579
0
            memcpy(&(shape->line[i].point[j].m), pabyRec + nOffset + 16 + k * 8,
1580
0
                   8);
1581
0
            if (bBigEndian)
1582
0
              SwapWord(8, &(shape->line[i].point[j].m));
1583
0
          }
1584
0
        }
1585
0
        k++;
1586
0
      }
1587
0
    }
1588
1589
0
    if (psSHP->nShapeType == SHP_POLYGON || psSHP->nShapeType == SHP_POLYGONZ ||
1590
0
        psSHP->nShapeType == SHP_POLYGONM)
1591
0
      shape->type = MS_SHAPE_POLYGON;
1592
0
    else
1593
0
      shape->type = MS_SHAPE_LINE;
1594
1595
0
  }
1596
1597
  /* -------------------------------------------------------------------- */
1598
  /*  Extract a MultiPoint.                                               */
1599
  /* -------------------------------------------------------------------- */
1600
0
  else if (psSHP->nShapeType == SHP_MULTIPOINT ||
1601
0
           psSHP->nShapeType == SHP_MULTIPOINTM ||
1602
0
           psSHP->nShapeType == SHP_MULTIPOINTZ) {
1603
0
    ms_int32 nPoints;
1604
1605
0
    if (nEntitySize < 44 + 4) {
1606
0
      shape->type = MS_SHAPE_NULL;
1607
0
      msSetError(MS_SHPERR,
1608
0
                 "Corrupted feature encountered.  recSize of feature %d=%d",
1609
0
                 "msSHPReadShape()", hEntity, msSHXReadSize(psSHP, hEntity));
1610
0
      return;
1611
0
    }
1612
1613
    /* copy the bounding box */
1614
0
    ReadRect(&shape->bounds, pabyRec + 8 + 4);
1615
1616
0
    memcpy(&nPoints, pabyRec + 44, 4);
1617
0
    if (bBigEndian)
1618
0
      nPoints = SWAP_FOUR_BYTES(nPoints);
1619
1620
    /* -------------------------------------------------------------------- */
1621
    /*      Fill the shape structure.                                       */
1622
    /* -------------------------------------------------------------------- */
1623
0
    if ((shape->line = (lineObj *)malloc(sizeof(lineObj))) == NULL) {
1624
0
      shape->type = MS_SHAPE_NULL;
1625
0
      msSetError(MS_MEMERR, "Out of memory", "msSHPReadShape()");
1626
0
      return;
1627
0
    }
1628
1629
0
    if (nPoints < 0 || nPoints > 50 * 1000 * 1000) {
1630
0
      free(shape->line);
1631
0
      shape->line = NULL;
1632
0
      shape->numlines = 0;
1633
0
      shape->type = MS_SHAPE_NULL;
1634
0
      msSetError(MS_SHPERR, "Corrupted .shp file : shape %d, nPoints=%d.",
1635
0
                 "msSHPReadShape()", hEntity, nPoints);
1636
0
      return;
1637
0
    }
1638
1639
0
    nRequiredSize = 48 + nPoints * 16;
1640
0
    if (psSHP->nShapeType == SHP_MULTIPOINTZ ||
1641
0
        psSHP->nShapeType == SHP_MULTIPOINTM)
1642
0
      nRequiredSize += 16 + nPoints * 8;
1643
0
    if (nRequiredSize > nEntitySize) {
1644
0
      free(shape->line);
1645
0
      shape->line = NULL;
1646
0
      shape->numlines = 0;
1647
0
      shape->type = MS_SHAPE_NULL;
1648
0
      msSetError(
1649
0
          MS_SHPERR,
1650
0
          "Corrupted .shp file : shape %d : nPoints = %d, nEntitySize = %d",
1651
0
          "msSHPReadShape()", hEntity, nPoints, nEntitySize);
1652
0
      return;
1653
0
    }
1654
1655
0
    shape->numlines = 1;
1656
0
    shape->line[0].numpoints = nPoints;
1657
0
    shape->line[0].point = (pointObj *)malloc(nPoints * sizeof(pointObj));
1658
0
    if (shape->line[0].point == NULL) {
1659
0
      free(shape->line);
1660
0
      shape->line = NULL;
1661
0
      shape->numlines = 0;
1662
0
      shape->type = MS_SHAPE_NULL;
1663
0
      msSetError(MS_MEMERR, "Out of memory", "msSHPReadShape()");
1664
0
      return;
1665
0
    }
1666
1667
0
    for (i = 0; i < nPoints; i++) {
1668
0
      memcpy(&(shape->line[0].point[i].x), pabyRec + 48 + 16 * i, 8);
1669
0
      memcpy(&(shape->line[0].point[i].y), pabyRec + 48 + 16 * i + 8, 8);
1670
1671
0
      if (bBigEndian) {
1672
0
        SwapWord(8, &(shape->line[0].point[i].x));
1673
0
        SwapWord(8, &(shape->line[0].point[i].y));
1674
0
      }
1675
1676
      /* -------------------------------------------------------------------- */
1677
      /*      MulipointZ                                                      */
1678
      /* -------------------------------------------------------------------- */
1679
0
      shape->line[0].point[i].z = 0; /* initialize */
1680
0
      if (psSHP->nShapeType == SHP_MULTIPOINTZ) {
1681
0
        const int nOffset = 48 + 16 * nPoints;
1682
0
        memcpy(&(shape->line[0].point[i].z), pabyRec + nOffset + 16 + i * 8, 8);
1683
0
        if (bBigEndian)
1684
0
          SwapWord(8, &(shape->line[0].point[i].z));
1685
0
      }
1686
1687
      /* -------------------------------------------------------------------- */
1688
      /*      Measured shape : multipont.                                     */
1689
      /* -------------------------------------------------------------------- */
1690
0
      shape->line[0].point[i].m = 0; /* initialize */
1691
0
      if (psSHP->nShapeType == SHP_MULTIPOINTM) {
1692
0
        const int nOffset = 48 + 16 * nPoints;
1693
0
        memcpy(&(shape->line[0].point[i].m), pabyRec + nOffset + 16 + i * 8, 8);
1694
0
        if (bBigEndian)
1695
0
          SwapWord(8, &(shape->line[0].point[i].m));
1696
0
      }
1697
0
    }
1698
1699
0
    shape->type = MS_SHAPE_POINT;
1700
0
  }
1701
1702
  /* -------------------------------------------------------------------- */
1703
  /*  Extract a Point.                            */
1704
  /* -------------------------------------------------------------------- */
1705
0
  else if (psSHP->nShapeType == SHP_POINT || psSHP->nShapeType == SHP_POINTM ||
1706
0
           psSHP->nShapeType == SHP_POINTZ) {
1707
1708
0
    if (nEntitySize < 20 + 8) {
1709
0
      shape->type = MS_SHAPE_NULL;
1710
0
      msSetError(MS_SHPERR,
1711
0
                 "Corrupted feature encountered.  recSize of feature %d=%d",
1712
0
                 "msSHPReadShape()", hEntity, msSHXReadSize(psSHP, hEntity));
1713
0
      return;
1714
0
    }
1715
1716
    /* -------------------------------------------------------------------- */
1717
    /*      Fill the shape structure.                                       */
1718
    /* -------------------------------------------------------------------- */
1719
0
    shape->line = (lineObj *)malloc(sizeof(lineObj));
1720
0
    MS_CHECK_ALLOC_NO_RET(shape->line, sizeof(lineObj));
1721
1722
0
    shape->numlines = 1;
1723
0
    shape->line[0].numpoints = 1;
1724
0
    shape->line[0].point = (pointObj *)msSmallMalloc(sizeof(pointObj));
1725
1726
0
    memcpy(&(shape->line[0].point[0].x), pabyRec + 12, 8);
1727
0
    memcpy(&(shape->line[0].point[0].y), pabyRec + 20, 8);
1728
1729
0
    if (bBigEndian) {
1730
0
      SwapWord(8, &(shape->line[0].point[0].x));
1731
0
      SwapWord(8, &(shape->line[0].point[0].y));
1732
0
    }
1733
1734
    /* -------------------------------------------------------------------- */
1735
    /*      PointZ                                                          */
1736
    /* -------------------------------------------------------------------- */
1737
0
    shape->line[0].point[0].z = 0; /* initialize */
1738
0
    if (psSHP->nShapeType == SHP_POINTZ) {
1739
0
      const int nOffset = 20 + 8;
1740
0
      if (nEntitySize >= nOffset + 8) {
1741
0
        memcpy(&(shape->line[0].point[0].z), pabyRec + nOffset, 8);
1742
0
        if (bBigEndian)
1743
0
          SwapWord(8, &(shape->line[0].point[0].z));
1744
0
      }
1745
0
    }
1746
1747
    /* -------------------------------------------------------------------- */
1748
    /*      Measured support : point.                                       */
1749
    /* -------------------------------------------------------------------- */
1750
0
    shape->line[0].point[0].m = 0; /* initialize */
1751
0
    if (psSHP->nShapeType == SHP_POINTM) {
1752
0
      const int nOffset = 20 + 8;
1753
0
      if (nEntitySize >= nOffset + 8) {
1754
0
        memcpy(&(shape->line[0].point[0].m), pabyRec + nOffset, 8);
1755
0
        if (bBigEndian)
1756
0
          SwapWord(8, &(shape->line[0].point[0].m));
1757
0
      }
1758
0
    }
1759
1760
    /* set the bounding box to the point */
1761
0
    shape->bounds.minx = shape->bounds.maxx = shape->line[0].point[0].x;
1762
0
    shape->bounds.miny = shape->bounds.maxy = shape->line[0].point[0].y;
1763
1764
0
    shape->type = MS_SHAPE_POINT;
1765
0
  }
1766
1767
0
  shape->index = hEntity;
1768
1769
0
  return;
1770
0
}
1771
1772
0
int msSHPReadBounds(SHPHandle psSHP, int hEntity, rectObj *padBounds) {
1773
  /* -------------------------------------------------------------------- */
1774
  /*      Validate the record/entity number.                              */
1775
  /* -------------------------------------------------------------------- */
1776
0
  if (psSHP->nRecords <= 0 || hEntity < -1 || hEntity >= psSHP->nRecords) {
1777
0
    padBounds->minx = padBounds->miny = padBounds->maxx = padBounds->maxy = 0.0;
1778
0
    return MS_FAILURE;
1779
0
  }
1780
1781
  /* -------------------------------------------------------------------- */
1782
  /*  If the entity is -1 we fetch the bounds for the whole file.   */
1783
  /* -------------------------------------------------------------------- */
1784
0
  if (hEntity == -1) {
1785
0
    padBounds->minx = psSHP->adBoundsMin[0];
1786
0
    padBounds->miny = psSHP->adBoundsMin[1];
1787
0
    padBounds->maxx = psSHP->adBoundsMax[0];
1788
0
    padBounds->maxy = psSHP->adBoundsMax[1];
1789
0
  } else {
1790
1791
0
    if (msSHXReadSize(psSHP, hEntity) <= 4) { /* NULL shape */
1792
0
      padBounds->minx = padBounds->miny = padBounds->maxx = padBounds->maxy =
1793
0
          0.0;
1794
0
      return MS_FAILURE;
1795
0
    }
1796
1797
0
    const int offset = msSHXReadOffset(psSHP, hEntity);
1798
0
    if (offset <= 0 || offset >= INT_MAX - 12 ||
1799
0
        0 != VSIFSeekL(psSHP->fpSHP, offset + 12, 0)) {
1800
0
      msSetError(MS_IOERR, "failed to seek offset", "msSHPReadBounds()");
1801
0
      return (MS_FAILURE);
1802
0
    }
1803
1804
0
    if (psSHP->nShapeType != SHP_POINT && psSHP->nShapeType != SHP_POINTZ &&
1805
0
        psSHP->nShapeType != SHP_POINTM) {
1806
0
      if (1 != VSIFReadL(padBounds, sizeof(double) * 4, 1, psSHP->fpSHP)) {
1807
0
        msSetError(MS_IOERR, "failed to fread record", "msSHPReadBounds()");
1808
0
        return (MS_FAILURE);
1809
0
      }
1810
1811
0
      if (bBigEndian) {
1812
0
        SwapWord(8, &(padBounds->minx));
1813
0
        SwapWord(8, &(padBounds->miny));
1814
0
        SwapWord(8, &(padBounds->maxx));
1815
0
        SwapWord(8, &(padBounds->maxy));
1816
0
      }
1817
1818
0
      if (msIsNan(padBounds->minx)) { /* empty shape */
1819
0
        padBounds->minx = padBounds->miny = padBounds->maxx = padBounds->maxy =
1820
0
            0.0;
1821
0
        return MS_FAILURE;
1822
0
      }
1823
0
    } else {
1824
      /* -------------------------------------------------------------------- */
1825
      /*      For points we fetch the point, and duplicate it as the          */
1826
      /*      minimum and maximum bound.                                      */
1827
      /* -------------------------------------------------------------------- */
1828
0
      if (1 != VSIFReadL(padBounds, sizeof(double) * 2, 1, psSHP->fpSHP)) {
1829
0
        msSetError(MS_IOERR, "failed to fread record", "msSHPReadBounds()");
1830
0
        return (MS_FAILURE);
1831
0
      }
1832
1833
0
      if (bBigEndian) {
1834
0
        SwapWord(8, &(padBounds->minx));
1835
0
        SwapWord(8, &(padBounds->miny));
1836
0
      }
1837
1838
0
      padBounds->maxx = padBounds->minx;
1839
0
      padBounds->maxy = padBounds->miny;
1840
0
    }
1841
0
  }
1842
1843
0
  return MS_SUCCESS;
1844
0
}
1845
1846
int msShapefileOpenHandle(shapefileObj *shpfile, const char *filename,
1847
0
                          SHPHandle hSHP, DBFHandle hDBF) {
1848
0
  assert(filename != NULL);
1849
0
  assert(hSHP != NULL);
1850
0
  assert(hDBF != NULL);
1851
1852
  /* initialize a few things */
1853
0
  shpfile->status = NULL;
1854
0
  shpfile->lastshape = -1;
1855
0
  shpfile->isopen = MS_FALSE;
1856
1857
0
  shpfile->hSHP = hSHP;
1858
1859
0
  strlcpy(shpfile->source, filename, sizeof(shpfile->source));
1860
1861
  /* load some information about this shapefile */
1862
0
  msSHPGetInfo(shpfile->hSHP, &shpfile->numshapes, &shpfile->type);
1863
1864
0
  if (shpfile->numshapes < 0 || shpfile->numshapes > 256000000) {
1865
0
    msSetError(MS_SHPERR, "Corrupted .shp file : numshapes = %d.",
1866
0
               "msShapefileOpen()", shpfile->numshapes);
1867
0
    msDBFClose(hDBF);
1868
0
    msSHPClose(hSHP);
1869
0
    return -1;
1870
0
  }
1871
1872
0
  msSHPReadBounds(shpfile->hSHP, -1, &(shpfile->bounds));
1873
1874
0
  shpfile->hDBF = hDBF;
1875
1876
0
  shpfile->isopen = MS_TRUE;
1877
0
  return (0); /* all o.k. */
1878
0
}
1879
1880
int msShapefileOpenVirtualFile(shapefileObj *shpfile, const char *filename,
1881
                               VSILFILE *fpSHP, VSILFILE *fpSHX,
1882
0
                               VSILFILE *fpDBF, int log_failures) {
1883
0
  assert(filename != NULL);
1884
0
  assert(fpSHP != NULL);
1885
0
  assert(fpSHX != NULL);
1886
0
  assert(fpDBF != NULL);
1887
1888
  /* open the shapefile file (appending ok) and get basic info */
1889
0
  SHPHandle hSHP = msSHPOpenVirtualFile(fpSHP, fpSHX);
1890
0
  if (!hSHP) {
1891
0
    if (log_failures)
1892
0
      msSetError(MS_IOERR, "(%s)", "msShapefileOpen()", filename);
1893
0
    VSIFCloseL(fpDBF);
1894
0
    return (-1);
1895
0
  }
1896
1897
0
  DBFHandle hDBF = msDBFOpenVirtualFile(fpDBF);
1898
1899
0
  if (!hDBF) {
1900
0
    if (log_failures)
1901
0
      msSetError(MS_IOERR, "(%s)", "msShapefileOpen()", filename);
1902
0
    msSHPClose(hSHP);
1903
0
    return (-1);
1904
0
  }
1905
1906
0
  return msShapefileOpenHandle(shpfile, filename, hSHP, hDBF);
1907
0
}
1908
1909
int msShapefileOpen(shapefileObj *shpfile, const char *mode,
1910
0
                    const char *filename, int log_failures) {
1911
0
  int i;
1912
0
  char *dbfFilename;
1913
0
  size_t bufferSize = 0;
1914
1915
0
  if (!filename) {
1916
0
    if (log_failures)
1917
0
      msSetError(MS_IOERR, "No (NULL) filename provided.", "msShapefileOpen()");
1918
0
    return (-1);
1919
0
  }
1920
1921
  /* open the shapefile file (appending ok) and get basic info */
1922
0
  SHPHandle hSHP;
1923
0
  if (!mode)
1924
0
    hSHP = msSHPOpen(filename, "rb");
1925
0
  else
1926
0
    hSHP = msSHPOpen(filename, mode);
1927
1928
0
  if (!hSHP) {
1929
0
    if (log_failures)
1930
0
      msSetError(MS_IOERR, "(%s)", "msShapefileOpen()", filename);
1931
0
    return (-1);
1932
0
  }
1933
1934
0
  bufferSize = strlen(filename) + 5;
1935
0
  dbfFilename = (char *)msSmallMalloc(bufferSize);
1936
0
  strcpy(dbfFilename, filename);
1937
1938
  /* clean off any extension the filename might have */
1939
0
  for (i = strlen(dbfFilename) - 1;
1940
0
       i > 0 && dbfFilename[i] != '.' && dbfFilename[i] != '/' &&
1941
0
       dbfFilename[i] != '\\';
1942
0
       i--) {
1943
0
  }
1944
1945
0
  if (dbfFilename[i] == '.')
1946
0
    dbfFilename[i] = '\0';
1947
1948
0
  strlcat(dbfFilename, ".dbf", bufferSize);
1949
1950
0
  DBFHandle hDBF = msDBFOpen(dbfFilename, "rb");
1951
1952
0
  if (!hDBF) {
1953
0
    if (log_failures)
1954
0
      msSetError(MS_IOERR, "(%s)", "msShapefileOpen()", dbfFilename);
1955
0
    free(dbfFilename);
1956
0
    msSHPClose(hSHP);
1957
0
    return (-1);
1958
0
  }
1959
0
  free(dbfFilename);
1960
1961
0
  return msShapefileOpenHandle(shpfile, filename, hSHP, hDBF);
1962
0
}
1963
1964
/* Creates a new shapefile */
1965
0
int msShapefileCreate(shapefileObj *shpfile, char *filename, int type) {
1966
0
  if (type != SHP_POINT && type != SHP_MULTIPOINT && type != SHP_ARC &&
1967
0
      type != SHP_POLYGON && type != SHP_POINTM && type != SHP_MULTIPOINTM &&
1968
0
      type != SHP_ARCM && type != SHP_POLYGONM && type != SHP_POINTZ &&
1969
0
      type != SHP_MULTIPOINTZ && type != SHP_ARCZ && type != SHP_POLYGONZ) {
1970
0
    msSetError(MS_SHPERR, "Invalid shape type.", "msNewSHPFile()");
1971
0
    return (-1);
1972
0
  }
1973
1974
  /* create the spatial portion */
1975
0
  shpfile->hSHP = msSHPCreate(filename, type);
1976
0
  if (!shpfile->hSHP) {
1977
0
    msSetError(MS_IOERR, "(%s)", "msNewSHPFile()", filename);
1978
0
    return (-1);
1979
0
  }
1980
1981
  /* retrieve a few things about this shapefile */
1982
0
  msSHPGetInfo(shpfile->hSHP, &shpfile->numshapes, &shpfile->type);
1983
0
  msSHPReadBounds(shpfile->hSHP, -1, &(shpfile->bounds));
1984
1985
  /* initialize a few other things */
1986
0
  shpfile->status = NULL;
1987
0
  shpfile->lastshape = -1;
1988
0
  shpfile->isopen = MS_TRUE;
1989
1990
0
  shpfile->hDBF = NULL; /* XBase file is NOT created here... */
1991
0
  return (0);
1992
0
}
1993
1994
0
void msShapefileClose(shapefileObj *shpfile) {
1995
0
  if (shpfile && shpfile->isopen == MS_TRUE) { /* Silently return if called with
1996
                                                  NULL shpfile by freeLayer() */
1997
0
    if (shpfile->hSHP)
1998
0
      msSHPClose(shpfile->hSHP);
1999
0
    if (shpfile->hDBF)
2000
0
      msDBFClose(shpfile->hDBF);
2001
0
    free(shpfile->status);
2002
0
    shpfile->isopen = MS_FALSE;
2003
0
  }
2004
0
}
2005
2006
/* status array lives in the shpfile, can return MS_SUCCESS/MS_FAILURE/MS_DONE
2007
 */
2008
0
int msShapefileWhichShapes(shapefileObj *shpfile, rectObj rect, int debug) {
2009
0
  int i;
2010
0
  rectObj shaperect;
2011
0
  char *filename;
2012
2013
0
  free(shpfile->status);
2014
0
  shpfile->status = NULL;
2015
2016
  /* rect and shapefile DON'T overlap... */
2017
0
  if (msRectOverlap(&shpfile->bounds, &rect) != MS_TRUE)
2018
0
    return (MS_DONE);
2019
2020
0
  if (msRectContained(&shpfile->bounds, &rect) == MS_TRUE) {
2021
0
    shpfile->status = msAllocBitArray(shpfile->numshapes);
2022
0
    if (!shpfile->status) {
2023
0
      msSetError(MS_MEMERR, NULL, "msShapefileWhichShapes()");
2024
0
      return (MS_FAILURE);
2025
0
    }
2026
0
    msSetAllBits(shpfile->status, shpfile->numshapes, 1);
2027
0
  } else {
2028
2029
    /* deal with case where sourcename is of the form 'file.shp' */
2030
0
    char *sourcename =
2031
0
        msStrdup(shpfile->source); /* shape file source string from map file */
2032
0
    char *s = strstr(sourcename, ".shp");
2033
0
    if (s)
2034
0
      *s = '\0';
2035
0
    else {
2036
0
      s = strstr(sourcename, ".SHP");
2037
0
      if (s)
2038
0
        *s = '\0';
2039
0
    }
2040
2041
0
    filename =
2042
0
        (char *)malloc(strlen(sourcename) + strlen(MS_INDEX_EXTENSION) + 1);
2043
0
    MS_CHECK_ALLOC(filename,
2044
0
                   strlen(sourcename) + strlen(MS_INDEX_EXTENSION) + 1,
2045
0
                   MS_FAILURE);
2046
2047
0
    sprintf(filename, "%s%s", sourcename, MS_INDEX_EXTENSION);
2048
2049
0
    shpfile->status =
2050
0
        msSearchDiskTree(filename, rect, debug, shpfile->numshapes);
2051
0
    free(filename);
2052
0
    free(sourcename);
2053
2054
0
    if (shpfile->status) { /* index  */
2055
0
      msFilterTreeSearch(shpfile, shpfile->status, rect);
2056
0
    } else { /* no index  */
2057
0
      shpfile->status = msAllocBitArray(shpfile->numshapes);
2058
0
      if (!shpfile->status) {
2059
0
        msSetError(MS_MEMERR, NULL, "msShapefileWhichShapes()");
2060
0
        return (MS_FAILURE);
2061
0
      }
2062
2063
0
      for (i = 0; i < shpfile->numshapes; i++) {
2064
0
        if (msSHPReadBounds(shpfile->hSHP, i, &shaperect) != MS_SUCCESS) {
2065
0
          if (msSHXReadSize(shpfile->hSHP, i) == 4) { /* handle NULL shape */
2066
0
            continue;
2067
0
          }
2068
0
          return (MS_FAILURE);
2069
0
        }
2070
2071
0
        if (msRectOverlap(&shaperect, &rect) == MS_TRUE)
2072
0
          msSetBit(shpfile->status, i, 1);
2073
0
      }
2074
0
    }
2075
0
  }
2076
2077
0
  shpfile->lastshape = -1;
2078
2079
0
  return (MS_SUCCESS); /* success */
2080
0
}
2081
2082
/* Return the absolute path to the given layer's tileindex file's directory */
2083
0
void msTileIndexAbsoluteDir(char *tiFileAbsDir, layerObj *layer) {
2084
0
  char tiFileAbsPath[MS_MAXPATHLEN];
2085
0
  char *tiFileAbsDirTmp = NULL;
2086
2087
0
  msBuildPath(tiFileAbsPath, layer->map->mappath,
2088
0
              layer->tileindex); /* absolute path to tileindex file */
2089
0
  tiFileAbsDirTmp = msGetPath(tiFileAbsPath); /* tileindex file's directory */
2090
0
  strlcpy(tiFileAbsDir, tiFileAbsDirTmp, MS_MAXPATHLEN);
2091
0
  free(tiFileAbsDirTmp);
2092
0
}
2093
2094
/*
2095
** Build possible paths we might find the tile file at:
2096
**   map dir + shape path + filename?
2097
**   tile dir + shape path + filename?
2098
**   map dir + filename?
2099
**
2100
** Returns
2101
** MS_SUCCESS - found a file
2102
** MS_FAILURE - no file, and map is configured to fail on missing
2103
** MS_DONE - no file, and map is configured to continue on missing
2104
*/
2105
static int msTiledSHPTryOpen(shapefileObj *shpfile, layerObj *layer,
2106
0
                             char *tiFileAbsDir, const char *filename) {
2107
0
  char szPath[MS_MAXPATHLEN];
2108
0
  int ignore_missing = msMapIgnoreMissingData(layer->map);
2109
0
  int log_failures = MS_TRUE;
2110
2111
0
  if (ignore_missing == MS_MISSING_DATA_IGNORE)
2112
0
    log_failures = MS_FALSE;
2113
2114
0
  if (msShapefileOpen(shpfile, "rb",
2115
0
                      msBuildPath3(szPath, layer->map->mappath,
2116
0
                                   layer->map->shapepath, filename),
2117
0
                      log_failures) == -1) {
2118
0
    if (msShapefileOpen(
2119
0
            shpfile, "rb",
2120
0
            msBuildPath3(szPath, tiFileAbsDir, layer->map->shapepath, filename),
2121
0
            log_failures) == -1) {
2122
0
      if (msShapefileOpen(shpfile, "rb",
2123
0
                          msBuildPath(szPath, layer->map->mappath, filename),
2124
0
                          log_failures) == -1) {
2125
0
        if (ignore_missing == MS_MISSING_DATA_FAIL) {
2126
0
          msSetError(
2127
0
              MS_IOERR,
2128
0
              "Unable to open shapefile '%s' for layer '%s' ... fatal error.",
2129
0
              "msTiledSHPTryOpen()", filename, layer->name);
2130
0
          return (MS_FAILURE);
2131
0
        } else if (ignore_missing == MS_MISSING_DATA_LOG) {
2132
0
          if (layer->debug || layer->map->debug) {
2133
0
            msDebug("Unable to open shapefile '%s' for layer '%s' ... ignoring "
2134
0
                    "this missing data.\n",
2135
0
                    szPath, layer->name);
2136
0
          }
2137
0
          return (MS_DONE);
2138
0
        } else if (ignore_missing == MS_MISSING_DATA_IGNORE) {
2139
0
          return (MS_DONE);
2140
0
        } else {
2141
          /* never get here */
2142
0
          msSetError(MS_IOERR, "msIgnoreMissingData returned unexpected value.",
2143
0
                     "msTiledSHPTryOpen()");
2144
0
          return (MS_FAILURE);
2145
0
        }
2146
0
      }
2147
0
    }
2148
0
  }
2149
0
  return (MS_SUCCESS);
2150
0
}
2151
2152
static const char *msTiledSHPLoadEntry(layerObj *layer, int i, char *tilename,
2153
0
                                       size_t tilenamesize) {
2154
0
  const char *filename;
2155
0
  msTiledSHPLayerInfo *tSHP = layer->layerinfo;
2156
2157
0
  msProjectDestroyReprojector(tSHP->reprojectorFromTileProjToLayerProj);
2158
0
  tSHP->reprojectorFromTileProjToLayerProj = NULL;
2159
2160
0
  msFreeProjection(&(tSHP->sTileProj));
2161
0
  if (layer->tilesrs != NULL) {
2162
0
    int idx = msDBFGetItemIndex(tSHP->tileshpfile->hDBF, layer->tilesrs);
2163
0
    const char *pszWKT =
2164
0
        msDBFReadStringAttribute(tSHP->tileshpfile->hDBF, i, idx);
2165
0
    IGNORE_RET_VAL(
2166
0
        msOGCWKT2ProjectionObj(pszWKT, &(tSHP->sTileProj), layer->debug));
2167
0
  }
2168
2169
0
  if (!layer->data) /* assume whole filename is in attribute field */
2170
0
    filename = msDBFReadStringAttribute(tSHP->tileshpfile->hDBF, i,
2171
0
                                        layer->tileitemindex);
2172
0
  else {
2173
0
    snprintf(tilename, tilenamesize, "%s/%s",
2174
0
             msDBFReadStringAttribute(tSHP->tileshpfile->hDBF, i,
2175
0
                                      layer->tileitemindex),
2176
0
             layer->data);
2177
0
    filename = tilename;
2178
0
  }
2179
2180
0
  return filename;
2181
0
}
2182
2183
0
static int msTiledSHPOpenFile(layerObj *layer) {
2184
0
  int i;
2185
0
  const char *filename;
2186
0
  char tilename[MS_MAXPATHLEN], szPath[MS_MAXPATHLEN];
2187
0
  char tiFileAbsDir[MS_MAXPATHLEN];
2188
2189
0
  msTiledSHPLayerInfo *tSHP = NULL;
2190
2191
0
  if (layer->layerinfo != NULL) {
2192
0
    return MS_SUCCESS; // Nothing to do... layer is already opened
2193
0
  }
2194
2195
0
  if (msCheckParentPointer(layer->map, "map") == MS_FAILURE)
2196
0
    return MS_FAILURE;
2197
2198
  /* allocate space for a shapefileObj using layer->layerinfo  */
2199
0
  tSHP = (msTiledSHPLayerInfo *)calloc(1, sizeof(msTiledSHPLayerInfo));
2200
0
  MS_CHECK_ALLOC(tSHP, sizeof(msTiledSHPLayerInfo), MS_FAILURE);
2201
0
  msInitProjection(&(tSHP->sTileProj));
2202
0
  msProjectionInheritContextFrom(&(tSHP->sTileProj), &layer->projection);
2203
2204
0
  tSHP->shpfile = (shapefileObj *)malloc(sizeof(shapefileObj));
2205
0
  if (tSHP->shpfile == NULL) {
2206
0
    msSetError(MS_MEMERR, "%s: %d: Out of memory allocating %u bytes.\n",
2207
0
               "msTiledSHPOpenFile()", __FILE__, __LINE__,
2208
0
               (unsigned int)sizeof(shapefileObj));
2209
0
    msFreeProjection(&(tSHP->sTileProj));
2210
0
    free(tSHP);
2211
0
    return MS_FAILURE;
2212
0
  }
2213
2214
0
  tSHP->shpfile->isopen =
2215
0
      MS_FALSE; /* in case of error: do not try to close the shpfile */
2216
0
  tSHP->tileshpfile =
2217
0
      NULL; /* may need this if not using a tile layer, look for malloc later */
2218
0
  layer->layerinfo = tSHP;
2219
2220
0
  tSHP->tilelayerindex = msGetLayerIndex(layer->map, layer->tileindex);
2221
0
  if (tSHP->tilelayerindex !=
2222
0
      -1) { /* does the tileindex reference another layer */
2223
0
    int status;
2224
0
    layerObj *tlp;
2225
2226
0
    tlp = (GET_LAYER(layer->map, tSHP->tilelayerindex));
2227
2228
0
    if (tlp->connectiontype != MS_SHAPEFILE) {
2229
0
      msSetError(MS_SHPERR, "Tileindex layer must be a shapefile.",
2230
0
                 "msTiledSHPOpenFile()");
2231
0
      return (MS_FAILURE);
2232
0
    }
2233
2234
0
    status = msLayerOpen(tlp);
2235
0
    if (status != MS_SUCCESS)
2236
0
      return (MS_FAILURE);
2237
2238
    /* build item list */
2239
0
    status = msLayerWhichItems(tlp, MS_FALSE, NULL);
2240
0
    if (status != MS_SUCCESS)
2241
0
      return (MS_FAILURE);
2242
2243
0
    tSHP->tileshpfile =
2244
0
        (shapefileObj *)tlp->layerinfo; /* shapefiles use layerinfo to point to
2245
                                           a shapefileObj */
2246
2247
0
  } else { /* or reference a shapefile directly */
2248
2249
    /* we need tSHP->tileshpfile if we're not working with a layer */
2250
0
    tSHP->tileshpfile = (shapefileObj *)malloc(sizeof(shapefileObj));
2251
0
    if (tSHP->tileshpfile == NULL) {
2252
0
      msSetError(MS_MEMERR, "%s: %d: Out of memory allocating %u bytes.\n",
2253
0
                 "msTiledSHPOpenFile()", __FILE__, __LINE__,
2254
0
                 (unsigned int)sizeof(shapefileObj));
2255
0
      free(tSHP->shpfile);
2256
0
      msFreeProjection(&(tSHP->sTileProj));
2257
0
      free(tSHP);
2258
0
      layer->layerinfo = NULL;
2259
0
      return MS_FAILURE;
2260
0
    }
2261
2262
0
    if (msShapefileOpen(tSHP->tileshpfile, "rb",
2263
0
                        msBuildPath3(szPath, layer->map->mappath,
2264
0
                                     layer->map->shapepath, layer->tileindex),
2265
0
                        MS_TRUE) == -1)
2266
0
      if (msShapefileOpen(
2267
0
              tSHP->tileshpfile, "rb",
2268
0
              msBuildPath(szPath, layer->map->mappath, layer->tileindex),
2269
0
              MS_TRUE) == -1)
2270
0
        return (MS_FAILURE);
2271
0
  }
2272
2273
0
  if ((layer->tileitemindex =
2274
0
           msDBFGetItemIndex(tSHP->tileshpfile->hDBF, layer->tileitem)) == -1)
2275
0
    return (MS_FAILURE);
2276
2277
0
  if (layer->tilesrs != NULL &&
2278
0
      msDBFGetItemIndex(tSHP->tileshpfile->hDBF, layer->tilesrs) < 0) {
2279
0
    msSetError(MS_SHPERR, "Cannot identify TILESRS field.",
2280
0
               "msTiledSHPOpenFile()");
2281
0
    return MS_FAILURE;
2282
0
  }
2283
0
  if (layer->tilesrs != NULL && layer->projection.numargs == 0) {
2284
0
    msSetError(MS_SHPERR,
2285
0
               "A layer with TILESRS set in TILEINDEX `%s' must have a "
2286
0
               "projection set on itself.",
2287
0
               "msOGRLayerOpen()", layer->tileindex);
2288
0
    return MS_FAILURE;
2289
0
  }
2290
2291
0
  msTileIndexAbsoluteDir(tiFileAbsDir, layer);
2292
2293
  /* position the source at the FIRST tile to use as a template, this is so the
2294
   * functions that fill the iteminfo array have something to work from */
2295
0
  for (i = 0; i < tSHP->tileshpfile->numshapes; i++) {
2296
0
    int try_open;
2297
2298
0
    filename = msTiledSHPLoadEntry(layer, i, tilename, sizeof(tilename));
2299
0
    if (strlen(filename) == 0)
2300
0
      continue; /* check again */
2301
2302
0
    try_open = msTiledSHPTryOpen(tSHP->shpfile, layer, tiFileAbsDir, filename);
2303
0
    if (try_open == MS_DONE)
2304
0
      continue;
2305
0
    else if (try_open == MS_FAILURE)
2306
0
      return (MS_FAILURE);
2307
2308
0
    return (MS_SUCCESS); /* found a template, ok to proceed */
2309
0
  }
2310
2311
0
  msSetError(MS_SHPERR,
2312
0
             "Unable to open a single tile to use as a template in layer %s.",
2313
0
             "msTiledSHPOpenFile()", layer->name ? layer->name : "(null)");
2314
0
  return (MS_FAILURE);
2315
0
}
2316
2317
0
static int msTiledSHPWhichShapes(layerObj *layer, rectObj rect, int isQuery) {
2318
0
  int i, status;
2319
0
  const char *filename;
2320
0
  char tilename[MS_MAXPATHLEN];
2321
0
  char tiFileAbsDir[MS_MAXPATHLEN];
2322
2323
0
  msTiledSHPLayerInfo *tSHP = NULL;
2324
2325
0
  if (msCheckParentPointer(layer->map, "map") == MS_FAILURE)
2326
0
    return MS_FAILURE;
2327
2328
0
  tSHP = layer->layerinfo;
2329
0
  if (!tSHP) {
2330
0
    msSetError(MS_SHPERR, "Tiled shapefile layer has not been opened.",
2331
0
               "msTiledSHPWhichShapes()");
2332
0
    return (MS_FAILURE);
2333
0
  }
2334
2335
0
  msShapefileClose(tSHP->shpfile); /* close previously opened files */
2336
2337
0
  tSHP->searchrect = rect; /* save the search extent */
2338
2339
0
  if (tSHP->tilelayerindex !=
2340
0
      -1) { /* does the tileindex reference another layer */
2341
0
    layerObj *tlp;
2342
0
    shapeObj tshape;
2343
2344
0
    tlp = (GET_LAYER(layer->map, tSHP->tilelayerindex));
2345
0
    status = msLayerWhichShapes(tlp, rect, isQuery);
2346
0
    if (status != MS_SUCCESS)
2347
0
      return (status); /* could be MS_DONE or MS_FAILURE */
2348
2349
0
    msTileIndexAbsoluteDir(tiFileAbsDir, layer);
2350
2351
0
    msInitShape(&tshape);
2352
0
    while ((status = msLayerNextShape(tlp, &tshape)) == MS_SUCCESS) {
2353
0
      int try_open;
2354
0
      rectObj rectTile = rect;
2355
2356
0
      filename =
2357
0
          msTiledSHPLoadEntry(layer, tshape.index, tilename, sizeof(tilename));
2358
0
      if (strlen(filename) == 0)
2359
0
        continue; /* check again */
2360
2361
0
      try_open =
2362
0
          msTiledSHPTryOpen(tSHP->shpfile, layer, tiFileAbsDir, filename);
2363
0
      if (try_open == MS_DONE)
2364
0
        continue;
2365
0
      else if (try_open == MS_FAILURE)
2366
0
        return (MS_FAILURE);
2367
2368
0
      if (tSHP->sTileProj.numargs > 0) {
2369
0
        msProjectRect(&(layer->projection), &(tSHP->sTileProj), &rectTile);
2370
0
      }
2371
2372
0
      status = msShapefileWhichShapes(tSHP->shpfile, rectTile, layer->debug);
2373
0
      if (status == MS_DONE) {
2374
        /* Close and continue to next tile */
2375
0
        msShapefileClose(tSHP->shpfile);
2376
0
        continue;
2377
0
      } else if (status != MS_SUCCESS) {
2378
0
        msShapefileClose(tSHP->shpfile);
2379
0
        return (MS_FAILURE);
2380
0
      }
2381
2382
      /* the layer functions keeps track of this */
2383
      /* tSHP->tileshpfile->lastshape = tshape.index; */
2384
0
      break;
2385
0
    }
2386
0
    return (status); /* if we reach here we either 1) ran out of tiles or 2) had
2387
                        an error reading a tile */
2388
2389
0
  } else { /* or reference a shapefile directly */
2390
0
    int try_open;
2391
2392
0
    status = msShapefileWhichShapes(tSHP->tileshpfile, rect, layer->debug);
2393
0
    if (status != MS_SUCCESS)
2394
0
      return (status); /* could be MS_DONE or MS_FAILURE */
2395
2396
0
    msTileIndexAbsoluteDir(tiFileAbsDir, layer);
2397
2398
    /* position the source at the FIRST shapefile */
2399
0
    for (i = 0; i < tSHP->tileshpfile->numshapes; i++) {
2400
0
      rectObj rectTile = rect;
2401
0
      if (msGetBit(tSHP->tileshpfile->status, i)) {
2402
2403
0
        filename = msTiledSHPLoadEntry(layer, i, tilename, sizeof(tilename));
2404
0
        if (strlen(filename) == 0)
2405
0
          continue; /* check again */
2406
2407
0
        try_open =
2408
0
            msTiledSHPTryOpen(tSHP->shpfile, layer, tiFileAbsDir, filename);
2409
0
        if (try_open == MS_DONE)
2410
0
          continue;
2411
0
        else if (try_open == MS_FAILURE)
2412
0
          return (MS_FAILURE);
2413
2414
0
        if (tSHP->sTileProj.numargs > 0) {
2415
0
          msProjectRect(&(layer->projection), &(tSHP->sTileProj), &rectTile);
2416
0
        }
2417
2418
0
        status = msShapefileWhichShapes(tSHP->shpfile, rectTile, layer->debug);
2419
0
        if (status == MS_DONE) {
2420
          /* Close and continue to next tile */
2421
0
          msShapefileClose(tSHP->shpfile);
2422
0
          continue;
2423
0
        } else if (status != MS_SUCCESS) {
2424
0
          msShapefileClose(tSHP->shpfile);
2425
0
          return (MS_FAILURE);
2426
0
        }
2427
2428
0
        tSHP->tileshpfile->lastshape = i;
2429
0
        break;
2430
0
      }
2431
0
    }
2432
2433
0
    if (i == tSHP->tileshpfile->numshapes)
2434
0
      return (MS_DONE); /* no more tiles */
2435
0
    else
2436
0
      return (MS_SUCCESS);
2437
0
  }
2438
2439
0
  return (MS_FAILURE); /* should *never* get here */
2440
0
}
2441
2442
0
static int msTiledSHPNextShape(layerObj *layer, shapeObj *shape) {
2443
0
  int i, status, filter_passed = MS_FALSE;
2444
0
  const char *filename;
2445
0
  char tilename[MS_MAXPATHLEN];
2446
0
  char tiFileAbsDir[MS_MAXPATHLEN];
2447
2448
0
  msTiledSHPLayerInfo *tSHP = NULL;
2449
2450
0
  if (msCheckParentPointer(layer->map, "map") == MS_FAILURE)
2451
0
    return MS_FAILURE;
2452
2453
0
  tSHP = layer->layerinfo;
2454
0
  if (!tSHP) {
2455
0
    msSetError(MS_SHPERR, "Tiled shapefile layer has not been opened.",
2456
0
               "msTiledSHPNextShape()");
2457
0
    return (MS_FAILURE);
2458
0
  }
2459
2460
0
  msTileIndexAbsoluteDir(tiFileAbsDir, layer);
2461
2462
0
  do {
2463
0
    i = tSHP->shpfile->lastshape + 1;
2464
0
    while (i < tSHP->shpfile->numshapes && !msGetBit(tSHP->shpfile->status, i))
2465
0
      i++; /* next "in" shape */
2466
2467
0
    if (i ==
2468
0
        tSHP->shpfile->numshapes) {    /* done with this tile, need a new one */
2469
0
      msShapefileClose(tSHP->shpfile); /* clean up */
2470
2471
      /* position the source to the NEXT shapefile based on the tileindex */
2472
0
      if (tSHP->tilelayerindex !=
2473
0
          -1) { /* does the tileindex reference another layer */
2474
0
        layerObj *tlp;
2475
0
        shapeObj tshape;
2476
0
        int try_open;
2477
2478
0
        tlp = (GET_LAYER(layer->map, tSHP->tilelayerindex));
2479
2480
0
        msInitShape(&tshape);
2481
0
        while ((status = msLayerNextShape(tlp, &tshape)) == MS_SUCCESS) {
2482
0
          rectObj rectTile = tSHP->searchrect;
2483
2484
0
          filename = msTiledSHPLoadEntry(layer, tshape.index, tilename,
2485
0
                                         sizeof(tilename));
2486
0
          if (strlen(filename) == 0)
2487
0
            continue; /* check again */
2488
2489
0
          try_open =
2490
0
              msTiledSHPTryOpen(tSHP->shpfile, layer, tiFileAbsDir, filename);
2491
0
          if (try_open == MS_DONE)
2492
0
            continue;
2493
0
          else if (try_open == MS_FAILURE)
2494
0
            return (MS_FAILURE);
2495
2496
0
          if (tSHP->sTileProj.numargs > 0) {
2497
0
            msProjectRect(&(layer->projection), &(tSHP->sTileProj), &rectTile);
2498
0
          }
2499
2500
0
          status =
2501
0
              msShapefileWhichShapes(tSHP->shpfile, rectTile, layer->debug);
2502
0
          if (status == MS_DONE) {
2503
            /* Close and continue to next tile */
2504
0
            msShapefileClose(tSHP->shpfile);
2505
0
            continue;
2506
0
          } else if (status != MS_SUCCESS) {
2507
0
            msShapefileClose(tSHP->shpfile);
2508
0
            tSHP->tileshpfile->lastshape = -1;
2509
0
            return (MS_FAILURE);
2510
0
          }
2511
2512
          /* the layer functions keeps track of this */
2513
          /* tSHP->tileshpfile->lastshape = tshape.index; */
2514
0
          break;
2515
0
        }
2516
2517
0
        if (status == MS_DONE) {
2518
0
          tSHP->tileshpfile->lastshape = -1;
2519
0
          return (MS_DONE); /* no more tiles */
2520
0
        } else {
2521
0
          msFreeShape(&tshape);
2522
0
          continue; /* we've got shapes */
2523
0
        }
2524
2525
0
      } else { /* or reference a shapefile directly   */
2526
2527
0
        for (i = (tSHP->tileshpfile->lastshape + 1);
2528
0
             i < tSHP->tileshpfile->numshapes; i++) {
2529
0
          if (msGetBit(tSHP->tileshpfile->status, i)) {
2530
0
            rectObj rectTile = tSHP->searchrect;
2531
0
            int try_open;
2532
2533
0
            filename =
2534
0
                msTiledSHPLoadEntry(layer, i, tilename, sizeof(tilename));
2535
0
            if (strlen(filename) == 0)
2536
0
              continue; /* check again */
2537
2538
0
            try_open =
2539
0
                msTiledSHPTryOpen(tSHP->shpfile, layer, tiFileAbsDir, filename);
2540
0
            if (try_open == MS_DONE)
2541
0
              continue;
2542
0
            else if (try_open == MS_FAILURE)
2543
0
              return (MS_FAILURE);
2544
2545
0
            if (tSHP->sTileProj.numargs > 0) {
2546
0
              msProjectRect(&(layer->projection), &(tSHP->sTileProj),
2547
0
                            &rectTile);
2548
0
            }
2549
2550
0
            status =
2551
0
                msShapefileWhichShapes(tSHP->shpfile, rectTile, layer->debug);
2552
0
            if (status == MS_DONE) {
2553
              /* Close and continue to next tile */
2554
0
              msShapefileClose(tSHP->shpfile);
2555
0
              continue;
2556
0
            } else if (status != MS_SUCCESS) {
2557
0
              msShapefileClose(tSHP->shpfile);
2558
0
              tSHP->tileshpfile->lastshape = -1;
2559
0
              return (MS_FAILURE);
2560
0
            }
2561
2562
0
            tSHP->tileshpfile->lastshape = i;
2563
0
            break;
2564
0
          }
2565
0
        } /* end for loop */
2566
2567
0
        if (i == tSHP->tileshpfile->numshapes) {
2568
0
          tSHP->tileshpfile->lastshape = -1;
2569
0
          return (MS_DONE); /* no more tiles */
2570
0
        } else
2571
0
          continue; /* we've got shapes */
2572
0
      }
2573
0
    }
2574
2575
0
    tSHP->shpfile->lastshape = i;
2576
2577
0
    msSHPReadShape(tSHP->shpfile->hSHP, i, shape);
2578
0
    if (shape->type == MS_SHAPE_NULL) {
2579
0
      msFreeShape(shape);
2580
0
      continue; /* skip NULL shapes */
2581
0
    }
2582
2583
0
    if (tSHP->sTileProj.numargs > 0) {
2584
0
      if (tSHP->reprojectorFromTileProjToLayerProj == NULL) {
2585
0
        tSHP->reprojectorFromTileProjToLayerProj = msProjectCreateReprojector(
2586
0
            &(tSHP->sTileProj), &(layer->projection));
2587
0
      }
2588
0
      if (tSHP->reprojectorFromTileProjToLayerProj) {
2589
0
        msProjectShapeEx(tSHP->reprojectorFromTileProjToLayerProj, shape);
2590
0
      }
2591
0
    }
2592
2593
0
    shape->tileindex = tSHP->tileshpfile->lastshape;
2594
0
    shape->numvalues = layer->numitems;
2595
0
    shape->values = msDBFGetValueList(tSHP->shpfile->hDBF, i, layer->iteminfo,
2596
0
                                      layer->numitems);
2597
0
    if (!shape->values)
2598
0
      shape->numvalues = 0;
2599
2600
0
    filter_passed = MS_TRUE; /* By default accept ANY shape */
2601
0
    if (layer->numitems > 0 && layer->iteminfo) {
2602
0
      filter_passed = msEvalExpression(layer, shape, &(layer->filter),
2603
0
                                       layer->filteritemindex);
2604
0
    }
2605
2606
0
    if (!filter_passed)
2607
0
      msFreeShape(shape); /* free's values as well */
2608
2609
0
  } while (
2610
0
      !filter_passed); /* Loop until both spatial and attribute filters match */
2611
2612
0
  return (MS_SUCCESS);
2613
0
}
2614
2615
static int msTiledSHPGetShape(layerObj *layer, shapeObj *shape,
2616
0
                              resultObj *record) {
2617
0
  const char *filename;
2618
0
  char tilename[MS_MAXPATHLEN], szPath[MS_MAXPATHLEN];
2619
2620
0
  msTiledSHPLayerInfo *tSHP = NULL;
2621
0
  char tiFileAbsDir[MS_MAXPATHLEN];
2622
2623
0
  long shapeindex = record->shapeindex;
2624
0
  int tileindex = record->tileindex;
2625
2626
0
  if (msCheckParentPointer(layer->map, "map") == MS_FAILURE)
2627
0
    return MS_FAILURE;
2628
2629
0
  tSHP = layer->layerinfo;
2630
0
  if (!tSHP) {
2631
0
    msSetError(MS_SHPERR, "Tiled shapefile layer has not been opened.",
2632
0
               "msTiledSHPGetShape()");
2633
0
    return (MS_FAILURE);
2634
0
  }
2635
2636
0
  msTileIndexAbsoluteDir(tiFileAbsDir, layer);
2637
2638
0
  if ((tileindex < 0) || (tileindex >= tSHP->tileshpfile->numshapes))
2639
0
    return (MS_FAILURE); /* invalid tile id */
2640
2641
0
  if (tileindex !=
2642
0
      tSHP->tileshpfile->lastshape) { /* correct tile is not currently open so
2643
                                         open the correct tile */
2644
0
    msShapefileClose(tSHP->shpfile);  /* close current tile */
2645
2646
0
    filename =
2647
0
        msTiledSHPLoadEntry(layer, tileindex, tilename, sizeof(tilename));
2648
2649
    /* open the shapefile, since a specific tile was request an error should be
2650
     * generated if that tile does not exist */
2651
0
    if (strlen(filename) == 0)
2652
0
      return (MS_FAILURE);
2653
0
    if (msShapefileOpen(
2654
0
            tSHP->shpfile, "rb",
2655
0
            msBuildPath3(szPath, tiFileAbsDir, layer->map->shapepath, filename),
2656
0
            MS_TRUE) == -1) {
2657
0
      if (msShapefileOpen(tSHP->shpfile, "rb",
2658
0
                          msBuildPath3(szPath, layer->map->mappath,
2659
0
                                       layer->map->shapepath, filename),
2660
0
                          MS_TRUE) == -1) {
2661
0
        if (msShapefileOpen(tSHP->shpfile, "rb",
2662
0
                            msBuildPath(szPath, layer->map->mappath, filename),
2663
0
                            MS_TRUE) == -1) {
2664
0
          return (MS_FAILURE);
2665
0
        }
2666
0
      }
2667
0
    }
2668
0
  }
2669
2670
0
  if ((shapeindex < 0) || (shapeindex >= tSHP->shpfile->numshapes))
2671
0
    return (MS_FAILURE);
2672
2673
0
  msSHPReadShape(tSHP->shpfile->hSHP, shapeindex, shape);
2674
0
  tSHP->shpfile->lastshape = shapeindex;
2675
0
  tSHP->tileshpfile->lastshape = tileindex;
2676
2677
0
  if (tSHP->sTileProj.numargs > 0) {
2678
0
    if (tSHP->reprojectorFromTileProjToLayerProj == NULL) {
2679
0
      tSHP->reprojectorFromTileProjToLayerProj =
2680
0
          msProjectCreateReprojector(&(tSHP->sTileProj), &(layer->projection));
2681
0
    }
2682
0
    if (tSHP->reprojectorFromTileProjToLayerProj) {
2683
0
      msProjectShapeEx(tSHP->reprojectorFromTileProjToLayerProj, shape);
2684
0
    }
2685
0
  }
2686
2687
0
  if (layer->numitems > 0 && layer->iteminfo) {
2688
0
    shape->numvalues = layer->numitems;
2689
0
    shape->values = msDBFGetValueList(tSHP->shpfile->hDBF, shapeindex,
2690
0
                                      layer->iteminfo, layer->numitems);
2691
0
    if (!shape->values)
2692
0
      return (MS_FAILURE);
2693
0
  }
2694
2695
0
  shape->tileindex = tileindex;
2696
2697
0
  return (MS_SUCCESS);
2698
0
}
2699
2700
0
static void msTiledSHPClose(layerObj *layer) {
2701
0
  msTiledSHPLayerInfo *tSHP = NULL;
2702
2703
0
  tSHP = layer->layerinfo;
2704
0
  if (tSHP) {
2705
0
    msShapefileClose(tSHP->shpfile);
2706
0
    free(tSHP->shpfile);
2707
2708
0
    if (tSHP->tilelayerindex != -1) {
2709
0
      layerObj *tlp;
2710
0
      if (msCheckParentPointer(layer->map, "map") == MS_FAILURE)
2711
0
        return;
2712
0
      tlp = (GET_LAYER(layer->map, tSHP->tilelayerindex));
2713
0
      msLayerClose(tlp);
2714
0
    } else {
2715
0
      msShapefileClose(tSHP->tileshpfile);
2716
0
      free(tSHP->tileshpfile);
2717
0
    }
2718
2719
0
    msProjectDestroyReprojector(tSHP->reprojectorFromTileProjToLayerProj);
2720
2721
0
    msFreeProjection(&(tSHP->sTileProj));
2722
2723
0
    free(tSHP);
2724
0
  }
2725
0
  layer->layerinfo = NULL;
2726
0
}
2727
/************************************************************************/
2728
/*                              msTiledSHPClose()                       */
2729
/* Overloaded version of msTiledSHPClose for virtual table architecture */
2730
/************************************************************************/
2731
0
int msTiledSHPCloseVT(layerObj *layer) {
2732
0
  msTiledSHPClose(layer);
2733
0
  return MS_SUCCESS;
2734
0
}
2735
2736
0
void msTiledSHPLayerFreeItemInfo(layerObj *layer) {
2737
0
  if (layer->iteminfo) {
2738
0
    free(layer->iteminfo);
2739
0
    layer->iteminfo = NULL;
2740
0
  }
2741
0
}
2742
2743
0
int msTiledSHPLayerInitItemInfo(layerObj *layer) {
2744
0
  msTiledSHPLayerInfo *tSHP = NULL;
2745
2746
0
  tSHP = layer->layerinfo;
2747
0
  if (!tSHP) {
2748
0
    msSetError(MS_SHPERR, "Tiled shapefile layer has not been opened.",
2749
0
               "msTiledSHPLayerInitItemInfo()");
2750
0
    return MS_FAILURE;
2751
0
  }
2752
2753
0
  msTiledSHPLayerFreeItemInfo(layer);
2754
0
  layer->iteminfo = (int *)msDBFGetItemIndexes(tSHP->shpfile->hDBF,
2755
0
                                               layer->items, layer->numitems);
2756
0
  if (!layer->iteminfo)
2757
0
    return (MS_FAILURE);
2758
2759
0
  return MS_SUCCESS;
2760
0
}
2761
2762
0
static void msSHPPassThroughFieldDefinitions(layerObj *layer, DBFHandle hDBF) {
2763
0
  int numitems, i;
2764
2765
0
  numitems = msDBFGetFieldCount(hDBF);
2766
2767
0
  for (i = 0; i < numitems; i++) {
2768
0
    char item[16];
2769
0
    int nWidth = 0, nPrecision = 0;
2770
0
    char gml_width[32], gml_precision[32];
2771
0
    DBFFieldType eType;
2772
0
    const char *gml_type = NULL;
2773
2774
0
    eType = msDBFGetFieldInfo(hDBF, i, item, &nWidth, &nPrecision);
2775
2776
0
    gml_width[0] = '\0';
2777
0
    gml_precision[0] = '\0';
2778
2779
0
    switch (eType) {
2780
0
    case FTInteger:
2781
0
      gml_type = "Integer";
2782
0
      sprintf(gml_width, "%d", nWidth);
2783
0
      break;
2784
2785
0
    case FTDouble:
2786
0
      gml_type = "Real";
2787
0
      sprintf(gml_width, "%d", nWidth);
2788
0
      sprintf(gml_precision, "%d", nPrecision);
2789
0
      break;
2790
2791
0
    case FTString:
2792
0
    default:
2793
0
      gml_type = "Character";
2794
0
      sprintf(gml_width, "%d", nWidth);
2795
0
      break;
2796
0
    }
2797
2798
0
    msUpdateGMLFieldMetadata(layer, item, gml_type, gml_width, gml_precision,
2799
0
                             0);
2800
0
  }
2801
0
}
2802
2803
0
int msTiledSHPLayerGetItems(layerObj *layer) {
2804
0
  msTiledSHPLayerInfo *tSHP = NULL;
2805
0
  const char *value;
2806
2807
0
  tSHP = layer->layerinfo;
2808
0
  if (!tSHP) {
2809
0
    msSetError(MS_SHPERR, "Tiled shapefile layer has not been opened.",
2810
0
               "msTiledSHPLayerGetItems()");
2811
0
    return MS_FAILURE;
2812
0
  }
2813
2814
0
  layer->numitems = msDBFGetFieldCount(tSHP->shpfile->hDBF);
2815
0
  layer->items = msDBFGetItems(tSHP->shpfile->hDBF);
2816
0
  if (!layer->items)
2817
0
    return MS_FAILURE;
2818
2819
  /* -------------------------------------------------------------------- */
2820
  /*      consider populating the field definitions in metadata.          */
2821
  /* -------------------------------------------------------------------- */
2822
0
  if ((value = msOWSLookupMetadata(&(layer->metadata), "G", "types")) != NULL &&
2823
0
      strcasecmp(value, "auto") == 0)
2824
0
    msSHPPassThroughFieldDefinitions(layer, tSHP->shpfile->hDBF);
2825
2826
0
  return msTiledSHPLayerInitItemInfo(layer);
2827
0
}
2828
2829
0
int msTiledSHPLayerGetExtent(layerObj *layer, rectObj *extent) {
2830
0
  msTiledSHPLayerInfo *tSHP = NULL;
2831
2832
0
  tSHP = layer->layerinfo;
2833
0
  if (!tSHP) {
2834
0
    msSetError(MS_SHPERR, "Tiled shapefile layer has not been opened.",
2835
0
               "msTiledSHPLayerGetExtent()");
2836
0
    return MS_FAILURE;
2837
0
  }
2838
2839
0
  *extent = tSHP->tileshpfile->bounds;
2840
0
  return MS_SUCCESS;
2841
0
}
2842
2843
0
int msTiledSHPLayerIsOpen(layerObj *layer) {
2844
0
  if (layer->layerinfo)
2845
0
    return MS_TRUE;
2846
0
  else
2847
0
    return MS_FALSE;
2848
0
}
2849
2850
0
int msTiledSHPLayerSupportsCommonFilters(layerObj *layer) {
2851
0
  (void)layer;
2852
0
  return MS_TRUE;
2853
0
}
2854
2855
0
int msTiledSHPLayerInitializeVirtualTable(layerObj *layer) {
2856
0
  assert(layer != NULL);
2857
0
  assert(layer->vtable != NULL);
2858
2859
0
  layer->vtable->LayerSupportsCommonFilters =
2860
0
      msTiledSHPLayerSupportsCommonFilters;
2861
0
  layer->vtable->LayerInitItemInfo = msTiledSHPLayerInitItemInfo;
2862
0
  layer->vtable->LayerFreeItemInfo = msTiledSHPLayerFreeItemInfo;
2863
0
  layer->vtable->LayerOpen = msTiledSHPOpenFile;
2864
0
  layer->vtable->LayerIsOpen = msTiledSHPLayerIsOpen;
2865
0
  layer->vtable->LayerWhichShapes = msTiledSHPWhichShapes;
2866
0
  layer->vtable->LayerNextShape = msTiledSHPNextShape;
2867
  /* no special version, use ...GetShape() */
2868
  /* layer->vtable->LayerResultsGetShape = msTiledSHPGetShape; */
2869
0
  layer->vtable->LayerGetShape = msTiledSHPGetShape;
2870
0
  layer->vtable->LayerClose = msTiledSHPCloseVT;
2871
0
  layer->vtable->LayerGetItems = msTiledSHPLayerGetItems;
2872
0
  layer->vtable->LayerGetExtent = msTiledSHPLayerGetExtent;
2873
  /* layer->vtable->LayerApplyFilterToLayer, use default */
2874
  /* layer->vtable->LayerGetAutoStyle, use default */
2875
0
  /* layer->vtable->LayerCloseConnection, use default */;
2876
0
  layer->vtable->LayerSetTimeFilter = msLayerMakeBackticsTimeFilter;
2877
  /* layer->vtable->LayerCreateItems, use default */
2878
  /* layer->vtable->LayerGetNumFeatures, use default */
2879
  /* layer->vtable->LayerGetAutoProjection, use default*/
2880
2881
0
  return MS_SUCCESS;
2882
0
}
2883
2884
/* SHAPEFILE Layer virtual table functions */
2885
2886
0
void msSHPLayerFreeItemInfo(layerObj *layer) {
2887
0
  if (layer->iteminfo) {
2888
0
    free(layer->iteminfo);
2889
0
    layer->iteminfo = NULL;
2890
0
  }
2891
0
}
2892
2893
0
int msSHPLayerInitItemInfo(layerObj *layer) {
2894
0
  shapefileObj *shpfile = layer->layerinfo;
2895
0
  if (!shpfile) {
2896
0
    msSetError(MS_SHPERR, "Shapefile layer has not been opened.",
2897
0
               "msSHPLayerInitItemInfo()");
2898
0
    return MS_FAILURE;
2899
0
  }
2900
2901
  /* iteminfo needs to be a bit more complex, a list of indexes plus the length
2902
   * of the list */
2903
0
  msSHPLayerFreeItemInfo(layer);
2904
0
  layer->iteminfo =
2905
0
      (int *)msDBFGetItemIndexes(shpfile->hDBF, layer->items, layer->numitems);
2906
0
  if (!layer->iteminfo) {
2907
0
    return MS_FAILURE;
2908
0
  }
2909
2910
0
  return MS_SUCCESS;
2911
0
}
2912
2913
0
int msSHPLayerOpen(layerObj *layer) {
2914
0
  char szPath[MS_MAXPATHLEN];
2915
0
  shapefileObj *shpfile;
2916
2917
0
  if (layer->layerinfo)
2918
0
    return MS_SUCCESS; /* layer already open */
2919
2920
0
  if (msCheckParentPointer(layer->map, "map") == MS_FAILURE)
2921
0
    return MS_FAILURE;
2922
2923
  /* allocate space for a shapefileObj using layer->layerinfo  */
2924
0
  shpfile = (shapefileObj *)malloc(sizeof(shapefileObj));
2925
0
  MS_CHECK_ALLOC(shpfile, sizeof(shapefileObj), MS_FAILURE);
2926
2927
0
  layer->layerinfo = shpfile;
2928
2929
0
  if (msShapefileOpen(shpfile, "rb",
2930
0
                      msBuildPath3(szPath, layer->map->mappath,
2931
0
                                   layer->map->shapepath, layer->data),
2932
0
                      MS_TRUE) == -1) {
2933
0
    if (msShapefileOpen(shpfile, "rb",
2934
0
                        msBuildPath(szPath, layer->map->mappath, layer->data),
2935
0
                        MS_TRUE) == -1) {
2936
0
      layer->layerinfo = NULL;
2937
0
      free(shpfile);
2938
0
      return MS_FAILURE;
2939
0
    }
2940
0
  }
2941
2942
  /* Update layer encoding if encoding is defined in CPG file */
2943
0
  if (!layer->encoding && shpfile->hDBF->pszEncoding) {
2944
0
    layer->encoding = msStrdup(shpfile->hDBF->pszEncoding);
2945
0
  }
2946
2947
0
  if (layer->projection.numargs > 0 &&
2948
0
      EQUAL(layer->projection.args[0], "auto")) {
2949
0
    const char *pszPRJFilename = CPLResetExtension(szPath, "prj");
2950
0
    int bOK = MS_FALSE;
2951
0
    VSILFILE *fp = VSIFOpenL(pszPRJFilename, "rb");
2952
0
    if (fp != NULL) {
2953
0
      char szPRJ[2048];
2954
0
      OGRSpatialReferenceH hSRS;
2955
0
      int nRead;
2956
2957
0
      nRead = (int)VSIFReadL(szPRJ, 1, sizeof(szPRJ) - 1, fp);
2958
0
      szPRJ[nRead] = '\0';
2959
0
      hSRS = OSRNewSpatialReference(szPRJ);
2960
0
      if (hSRS != NULL) {
2961
0
        if (OSRMorphFromESRI(hSRS) == OGRERR_NONE) {
2962
0
          char *pszWKT = NULL;
2963
0
          if (OSRExportToWkt(hSRS, &pszWKT) == OGRERR_NONE) {
2964
0
            if (msOGCWKT2ProjectionObj(pszWKT, &(layer->projection),
2965
0
                                       layer->debug) == MS_SUCCESS) {
2966
0
              bOK = MS_TRUE;
2967
0
            }
2968
0
          }
2969
0
          CPLFree(pszWKT);
2970
0
        }
2971
0
        OSRDestroySpatialReference(hSRS);
2972
0
      }
2973
0
      VSIFCloseL(fp);
2974
0
    }
2975
2976
0
    if (bOK != MS_TRUE) {
2977
0
      if (layer->debug || layer->map->debug) {
2978
0
        msDebug("Unable to get SRS from shapefile '%s' for layer '%s'.\n",
2979
0
                szPath, layer->name);
2980
0
      }
2981
0
    }
2982
0
  }
2983
2984
0
  return MS_SUCCESS;
2985
0
}
2986
2987
0
int msSHPLayerIsOpen(layerObj *layer) {
2988
0
  if (layer->layerinfo)
2989
0
    return MS_TRUE;
2990
0
  else
2991
0
    return MS_FALSE;
2992
0
}
2993
2994
0
int msSHPLayerWhichShapes(layerObj *layer, rectObj rect, int isQuery) {
2995
0
  (void)isQuery;
2996
0
  int status;
2997
0
  shapefileObj *shpfile;
2998
2999
0
  shpfile = layer->layerinfo;
3000
3001
0
  if (!shpfile) {
3002
0
    msSetError(MS_SHPERR, "Shapefile layer has not been opened.",
3003
0
               "msSHPLayerWhichShapes()");
3004
0
    return MS_FAILURE;
3005
0
  }
3006
3007
0
  status = msShapefileWhichShapes(shpfile, rect, layer->debug);
3008
0
  if (status != MS_SUCCESS) {
3009
0
    return status;
3010
0
  }
3011
3012
0
  return MS_SUCCESS;
3013
0
}
3014
3015
0
int msSHPLayerNextShape(layerObj *layer, shapeObj *shape) {
3016
0
  int i;
3017
0
  shapefileObj *shpfile;
3018
3019
0
  shpfile = layer->layerinfo;
3020
3021
0
  if (!shpfile) {
3022
0
    msSetError(MS_SHPERR, "Shapefile layer has not been opened.",
3023
0
               "msSHPLayerNextShape()");
3024
0
    return MS_FAILURE;
3025
0
  }
3026
3027
0
  if (!shpfile->status) {
3028
    /* probably whichShapes didn't overlap */
3029
0
    return MS_DONE;
3030
0
  }
3031
3032
0
  i = msGetNextBit(shpfile->status, shpfile->lastshape + 1, shpfile->numshapes);
3033
0
  shpfile->lastshape = i;
3034
0
  if (i == -1)
3035
0
    return (MS_DONE); /* nothing else to read */
3036
3037
0
  msSHPReadShape(shpfile->hSHP, i, shape);
3038
0
  if (shape->type == MS_SHAPE_NULL) {
3039
0
    msFreeShape(shape);
3040
0
    return msSHPLayerNextShape(layer, shape); /* skip NULL shapes */
3041
0
  }
3042
0
  shape->numvalues = layer->numitems;
3043
0
  shape->values =
3044
0
      msDBFGetValueList(shpfile->hDBF, i, layer->iteminfo, layer->numitems);
3045
0
  if (!shape->values)
3046
0
    shape->numvalues = 0;
3047
3048
0
  return MS_SUCCESS;
3049
0
}
3050
3051
0
int msSHPLayerGetShape(layerObj *layer, shapeObj *shape, resultObj *record) {
3052
0
  shapefileObj *shpfile;
3053
0
  long shapeindex;
3054
3055
0
  shpfile = layer->layerinfo;
3056
3057
0
  shapeindex = record->shapeindex;
3058
3059
0
  if (!shpfile) {
3060
0
    msSetError(MS_SHPERR, "Shapefile layer has not been opened.",
3061
0
               "msSHPLayerGetShape()");
3062
0
    return MS_FAILURE;
3063
0
  }
3064
3065
  /* msSHPReadShape *should* return success or failure so we don't have to test
3066
   * here */
3067
0
  if (shapeindex < 0 || shapeindex >= shpfile->numshapes) {
3068
0
    msSetError(MS_MISCERR, "Invalid feature id.", "msSHPLayerGetShape()");
3069
0
    return MS_FAILURE;
3070
0
  }
3071
3072
0
  msSHPReadShape(shpfile->hSHP, shapeindex, shape);
3073
0
  if (layer->numitems > 0 && layer->iteminfo) {
3074
0
    shape->numvalues = layer->numitems;
3075
0
    shape->values = msDBFGetValueList(shpfile->hDBF, shapeindex,
3076
0
                                      layer->iteminfo, layer->numitems);
3077
0
    if (!shape->values)
3078
0
      return MS_FAILURE;
3079
0
  }
3080
3081
0
  shpfile->lastshape = shapeindex;
3082
3083
0
  return MS_SUCCESS;
3084
0
}
3085
3086
0
int msSHPLayerClose(layerObj *layer) {
3087
0
  shapefileObj *shpfile;
3088
0
  shpfile = layer->layerinfo;
3089
0
  if (!shpfile)
3090
0
    return MS_SUCCESS; /* nothing to do */
3091
3092
0
  msShapefileClose(shpfile);
3093
0
  free(layer->layerinfo);
3094
0
  layer->layerinfo = NULL;
3095
3096
0
  return MS_SUCCESS;
3097
0
}
3098
3099
0
int msSHPLayerGetItems(layerObj *layer) {
3100
0
  shapefileObj *shpfile;
3101
0
  const char *value;
3102
3103
0
  shpfile = layer->layerinfo;
3104
3105
0
  if (!shpfile) {
3106
0
    msSetError(MS_SHPERR, "Shapefile layer has not been opened.",
3107
0
               "msSHPLayerGetItems()");
3108
0
    return MS_FAILURE;
3109
0
  }
3110
3111
0
  layer->numitems = msDBFGetFieldCount(shpfile->hDBF);
3112
0
  layer->items = msDBFGetItems(shpfile->hDBF);
3113
0
  if (layer->numitems == 0)
3114
0
    return MS_SUCCESS; /* No items is a valid case (#3147) */
3115
0
  if (!layer->items)
3116
0
    return MS_FAILURE;
3117
3118
  /* -------------------------------------------------------------------- */
3119
  /*      consider populating the field definitions in metadata.          */
3120
  /* -------------------------------------------------------------------- */
3121
0
  if ((value = msOWSLookupMetadata(&(layer->metadata), "G", "types")) != NULL &&
3122
0
      strcasecmp(value, "auto") == 0)
3123
0
    msSHPPassThroughFieldDefinitions(layer, shpfile->hDBF);
3124
3125
0
  return msLayerInitItemInfo(layer);
3126
0
}
3127
3128
0
int msSHPLayerGetExtent(layerObj *layer, rectObj *extent) {
3129
0
  *extent = ((shapefileObj *)layer->layerinfo)->bounds;
3130
0
  return MS_SUCCESS;
3131
0
}
3132
3133
0
int msSHPLayerSupportsCommonFilters(layerObj *layer) {
3134
0
  (void)layer;
3135
0
  return MS_TRUE;
3136
0
}
3137
3138
0
int msSHPLayerInitializeVirtualTable(layerObj *layer) {
3139
0
  assert(layer != NULL);
3140
0
  assert(layer->vtable != NULL);
3141
3142
0
  layer->vtable->LayerSupportsCommonFilters = msSHPLayerSupportsCommonFilters;
3143
0
  layer->vtable->LayerInitItemInfo = msSHPLayerInitItemInfo;
3144
0
  layer->vtable->LayerFreeItemInfo = msSHPLayerFreeItemInfo;
3145
0
  layer->vtable->LayerOpen = msSHPLayerOpen;
3146
0
  layer->vtable->LayerIsOpen = msSHPLayerIsOpen;
3147
0
  layer->vtable->LayerWhichShapes = msSHPLayerWhichShapes;
3148
0
  layer->vtable->LayerNextShape = msSHPLayerNextShape;
3149
0
  layer->vtable->LayerGetShape = msSHPLayerGetShape;
3150
  /* layer->vtable->LayerGetShapeCount, use default */
3151
0
  layer->vtable->LayerClose = msSHPLayerClose;
3152
0
  layer->vtable->LayerGetItems = msSHPLayerGetItems;
3153
0
  layer->vtable->LayerGetExtent = msSHPLayerGetExtent;
3154
  /* layer->vtable->LayerGetAutoStyle, use default */
3155
  /* layer->vtable->LayerCloseConnection, use default */
3156
0
  layer->vtable->LayerSetTimeFilter = msLayerMakeBackticsTimeFilter;
3157
  /* layer->vtable->LayerTranslateFilter, use default */
3158
  /* layer->vtable->LayerApplyFilterToLayer, use default */
3159
  /* layer->vtable->LayerCreateItems, use default */
3160
  /* layer->vtable->LayerGetNumFeatures, use default */
3161
3162
0
  return MS_SUCCESS;
3163
0
}