52 typedef unsigned long int32;
62 #define ByteCopy(a, b, c) memcpy(b, a, c)
64 #define MIN(a, b) ((a < b) ? a : b)
65 #define MAX(a, b) ((a > b) ? a : b)
71 #define snprintf _snprintf
73 #elif defined(WIN32) || defined(_WIN32)
75 #define snprintf _snprintf
81 #if defined(__GNUC__) && __GNUC__ >= 4
82 #define CPL_UNUSED __attribute((__unused__))
89 #define bBigEndian false
90 #elif defined(CPL_MSB)
91 #define bBigEndian true
93 static bool bBigEndian;
97 #define STATIC_CAST(type, x) static_cast<type>(x)
98 #define SHPLIB_NULLPTR nullptr
100 #define STATIC_CAST(type, x) ((type)(x))
101 #define SHPLIB_NULLPTR NULL
110 static void SwapWord(
int length,
void *wordP)
112 for (
int i = 0; i < length / 2; i++) {
127 static void *SfRealloc(
void *pMem,
int nNewSize)
132 return realloc(pMem, nNewSize);
145 psSHP->
sHooks.
Error(
"SHPWriteHeader failed : SHX file is closed");
153 uchar abyHeader[100] = {0};
160 SwapWord(4, abyHeader + 24);
165 SwapWord(4, abyHeader + 28);
170 SwapWord(4, abyHeader + 32);
173 ByteCopy(&dValue, abyHeader + 36, 8);
175 SwapWord(8, abyHeader + 36);
178 ByteCopy(&dValue, abyHeader + 44, 8);
180 SwapWord(8, abyHeader + 44);
183 ByteCopy(&dValue, abyHeader + 52, 8);
185 SwapWord(8, abyHeader + 52);
188 ByteCopy(&dValue, abyHeader + 60, 8);
190 SwapWord(8, abyHeader + 60);
193 ByteCopy(&dValue, abyHeader + 68, 8);
195 SwapWord(8, abyHeader + 68);
198 ByteCopy(&dValue, abyHeader + 76, 8);
200 SwapWord(8, abyHeader + 76);
203 ByteCopy(&dValue, abyHeader + 84, 8);
205 SwapWord(8, abyHeader + 84);
208 ByteCopy(&dValue, abyHeader + 92, 8);
210 SwapWord(8, abyHeader + 92);
217 char szErrorMsg[200];
219 snprintf(szErrorMsg,
sizeof(szErrorMsg),
220 "Failure writing .shp header: %s", strerror(errno));
221 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
232 SwapWord(4, abyHeader + 24);
236 char szErrorMsg[200];
238 snprintf(szErrorMsg,
sizeof(szErrorMsg),
239 "Failure writing .shx header: %s", strerror(errno));
240 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
256 for (
int i = 0; i < psSHP->
nRecords; i++) {
260 SwapWord(4, panSHX + i * 2);
262 SwapWord(4, panSHX + i * 2 + 1);
268 char szErrorMsg[200];
270 snprintf(szErrorMsg,
sizeof(szErrorMsg),
271 "Failure writing .shx contents: %s", strerror(errno));
272 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
295 return SHPOpenLL(pszLayer, pszAccess, &sHooks);
302 static int SHPGetLenWithoutExtension(
const char *pszBasename)
304 const int nLen =
STATIC_CAST(
int, strlen(pszBasename));
305 for (
int i = nLen - 1;
306 i > 0 && pszBasename[i] !=
'/' && pszBasename[i] !=
'\\'; i--) {
307 if (pszBasename[i] ==
'.') {
329 bool bLazySHXLoading =
false;
330 if (strcmp(pszAccess,
"rb+") == 0 || strcmp(pszAccess,
"r+b") == 0 ||
331 strcmp(pszAccess,
"r+") == 0) {
342 #if !defined(bBigEndian)
345 if (*((
uchar *)&i) == 1)
364 const int nLenWithoutExtension = SHPGetLenWithoutExtension(pszLayer);
366 memcpy(pszFullname, pszLayer, nLenWithoutExtension);
367 memcpy(pszFullname + nLenWithoutExtension,
".shp", 5);
370 memcpy(pszFullname + nLenWithoutExtension,
".SHP", 5);
375 const size_t nMessageLen = strlen(pszFullname) * 2 + 256;
377 pszFullname[nLenWithoutExtension] = 0;
378 snprintf(pszMessage, nMessageLen,
"Unable to open %s.shp or %s.SHP.",
379 pszFullname, pszFullname);
380 psHooks->
Error(pszMessage);
389 memcpy(pszFullname + nLenWithoutExtension,
".shx", 5);
392 memcpy(pszFullname + nLenWithoutExtension,
".SHX", 5);
397 const size_t nMessageLen = strlen(pszFullname) * 2 + 256;
399 pszFullname[nLenWithoutExtension] = 0;
400 snprintf(pszMessage, nMessageLen,
401 "Unable to open %s.shx or %s.SHX. "
402 "Set SHAPE_RESTORE_SHX config option to YES to restore or "
404 pszFullname, pszFullname);
405 psHooks->
Error(pszMessage);
421 psSHP->
sHooks.
Error(
".shp file is unreadable, or corrupt.");
431 (pabyBuf[25] << 16) | (pabyBuf[26] << 8) | pabyBuf[27];
441 pabyBuf[0] != 0 || pabyBuf[1] != 0 || pabyBuf[2] != 0x27 ||
442 (pabyBuf[3] != 0x0a && pabyBuf[3] != 0x0d)) {
443 psSHP->
sHooks.
Error(
".shx file is unreadable, or corrupt.");
452 psSHP->
nRecords = pabyBuf[27] | (pabyBuf[26] << 8) | (pabyBuf[25] << 16) |
453 ((pabyBuf[24] & 0x7F) << 24);
459 char szErrorMsg[200];
461 snprintf(szErrorMsg,
sizeof(szErrorMsg),
462 "Record count in .shx header is %d, which seems\n"
463 "unreasonable. Assuming header is corrupt.",
465 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
477 if (psSHP->
nRecords >= 1024 * 1024) {
480 if (nFileSize > 100 &&
493 SwapWord(8, pabyBuf + 36);
494 memcpy(&dValue, pabyBuf + 36, 8);
498 SwapWord(8, pabyBuf + 44);
499 memcpy(&dValue, pabyBuf + 44, 8);
503 SwapWord(8, pabyBuf + 52);
504 memcpy(&dValue, pabyBuf + 52, 8);
508 SwapWord(8, pabyBuf + 60);
509 memcpy(&dValue, pabyBuf + 60, 8);
513 SwapWord(8, pabyBuf + 68);
514 memcpy(&dValue, pabyBuf + 68, 8);
518 SwapWord(8, pabyBuf + 76);
519 memcpy(&dValue, pabyBuf + 76, 8);
523 SwapWord(8, pabyBuf + 84);
524 memcpy(&dValue, pabyBuf + 84, 8);
528 SwapWord(8, pabyBuf + 92);
529 memcpy(&dValue, pabyBuf + 92, 8);
554 char szErrorMsg[200];
557 szErrorMsg,
sizeof(szErrorMsg),
558 "Not enough memory to allocate requested memory (nRecords=%d).\n"
559 "Probably broken SHP file",
561 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
575 if (bLazySHXLoading) {
587 char szErrorMsg[200];
589 snprintf(szErrorMsg,
sizeof(szErrorMsg),
590 "Failed to read all values for %d records in .shx file: %s.",
592 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
607 if (strcmp(pszAccess,
"rb") == 0) {
612 for (
int i = 0; i < psSHP->
nRecords; i++) {
613 unsigned int nOffset;
614 memcpy(&nOffset, pabyBuf + i * 8, 4);
616 SwapWord(4, &nOffset);
618 unsigned int nLength;
619 memcpy(&nLength, pabyBuf + i * 8 + 4, 4);
621 SwapWord(4, &nLength);
623 if (nOffset >
STATIC_CAST(
unsigned int, INT_MAX)) {
625 snprintf(str,
sizeof(str),
"Invalid offset for entity %d", i);
626 str[
sizeof(str) - 1] =
'\0';
633 if (nLength >
STATIC_CAST(
unsigned int, INT_MAX / 2 - 4)) {
635 snprintf(str,
sizeof(str),
"Invalid length for entity %d", i);
636 str[
sizeof(str) - 1] =
'\0';
660 SAHooks *psHooks,
int bRestoreSHX)
663 return SHPOpenLL(pszLayer, pszAccess, psHooks);
666 return SHPOpenLL(pszLayer, pszAccess, psHooks);
688 if (strcmp(pszAccess,
"rb+") == 0 || strcmp(pszAccess,
"r+b") == 0 ||
689 strcmp(pszAccess,
"r+") == 0) {
699 #if !defined(bBigEndian)
702 if (*((
uchar *)&i) == 1)
713 const int nLenWithoutExtension = SHPGetLenWithoutExtension(pszLayer);
715 memcpy(pszFullname, pszLayer, nLenWithoutExtension);
716 memcpy(pszFullname + nLenWithoutExtension,
".shp", 5);
717 SAFile fpSHP = psHooks->
FOpen(pszFullname, pszAccess);
719 memcpy(pszFullname + nLenWithoutExtension,
".SHP", 5);
720 fpSHP = psHooks->
FOpen(pszFullname, pszAccess);
724 const size_t nMessageLen = strlen(pszFullname) * 2 + 256;
727 pszFullname[nLenWithoutExtension] = 0;
728 snprintf(pszMessage, nMessageLen,
"Unable to open %s.shp or %s.SHP.",
729 pszFullname, pszFullname);
730 psHooks->
Error(pszMessage);
742 if (psHooks->
FRead(pabyBuf, 100, 1, fpSHP) != 1) {
743 psHooks->
Error(
".shp file is unreadable, or corrupt.");
752 unsigned int nSHPFilesize = (
STATIC_CAST(
unsigned int, pabyBuf[24]) << 24) |
753 (pabyBuf[25] << 16) | (pabyBuf[26] << 8) |
755 if (nSHPFilesize < UINT_MAX / 2)
758 nSHPFilesize = (UINT_MAX / 2) * 2;
760 memcpy(pszFullname + nLenWithoutExtension,
".shx", 5);
761 const char pszSHXAccess[] =
"w+b";
762 SAFile fpSHX = psHooks->
FOpen(pszFullname, pszSHXAccess);
764 size_t nMessageLen = strlen(pszFullname) * 2 + 256;
766 pszFullname[nLenWithoutExtension] = 0;
767 snprintf(pszMessage, nMessageLen,
768 "Error opening file %s.shx for writing", pszFullname);
769 psHooks->
Error(pszMessage);
783 psHooks->
FSeek(fpSHP, 100, 0);
785 memcpy(pabySHXHeader, pabyBuf, 100);
786 psHooks->
FWrite(pabySHXHeader, 100, 1, fpSHX);
790 unsigned int nCurrentSHPOffset = 100;
791 unsigned int nRealSHXContentSize = 100;
792 unsigned int niRecord = 0;
793 unsigned int nRecordLength = 0;
794 unsigned int nRecordOffset = 50;
795 char abyReadRecord[8];
797 while (nCurrentSHPOffset < nSHPFilesize) {
798 if (psHooks->
FRead(&niRecord, 4, 1, fpSHP) == 1 &&
799 psHooks->
FRead(&nRecordLength, 4, 1, fpSHP) == 1) {
801 SwapWord(4, &nRecordOffset);
802 memcpy(abyReadRecord, &nRecordOffset, 4);
803 memcpy(abyReadRecord + 4, &nRecordLength, 4);
805 psHooks->
FWrite(abyReadRecord, 8, 1, fpSHX);
808 SwapWord(4, &nRecordOffset);
810 SwapWord(4, &nRecordLength);
811 nRecordOffset += nRecordLength + 4;
813 nCurrentSHPOffset += 8 + nRecordLength * 2;
815 psHooks->
FSeek(fpSHP, nCurrentSHPOffset, 0);
816 nRealSHXContentSize += 8;
819 psHooks->
Error(
"Error parsing .shp to restore .shx");
831 nRealSHXContentSize /= 2;
833 SwapWord(4, &nRealSHXContentSize);
834 psHooks->
FSeek(fpSHX, 24, 0);
835 psHooks->
FWrite(&nRealSHXContentSize, 4, 1, fpSHX);
918 double *padfMinBound,
double *padfMaxBound)
929 for (
int i = 0; i < 4; i++) {
966 #if !defined(bBigEndian)
969 if (*((
uchar *)&i) == 1)
979 const int nLenWithoutExtension = SHPGetLenWithoutExtension(pszLayer);
981 memcpy(pszFullname, pszLayer, nLenWithoutExtension);
982 memcpy(pszFullname + nLenWithoutExtension,
".shp", 5);
985 char szErrorMsg[200];
986 snprintf(szErrorMsg,
sizeof(szErrorMsg),
"Failed to create file %s: %s",
987 pszFullname, strerror(errno));
988 psHooks->
Error(szErrorMsg);
994 memcpy(pszFullname + nLenWithoutExtension,
".shx", 5);
997 char szErrorMsg[200];
998 snprintf(szErrorMsg,
sizeof(szErrorMsg),
"Failed to create file %s: %s",
999 pszFullname, strerror(errno));
1000 psHooks->
Error(szErrorMsg);
1013 uchar abyHeader[100];
1014 memset(abyHeader, 0,
sizeof(abyHeader));
1016 abyHeader[2] = 0x27;
1017 abyHeader[3] = 0x0a;
1022 SwapWord(4, abyHeader + 24);
1027 SwapWord(4, abyHeader + 28);
1032 SwapWord(4, abyHeader + 32);
1034 double dValue = 0.0;
1035 ByteCopy(&dValue, abyHeader + 36, 8);
1036 ByteCopy(&dValue, abyHeader + 44, 8);
1037 ByteCopy(&dValue, abyHeader + 52, 8);
1038 ByteCopy(&dValue, abyHeader + 60, 8);
1043 if (psHooks->
FWrite(abyHeader, 100, 1, fpSHP) != 1) {
1044 char szErrorMsg[200];
1046 snprintf(szErrorMsg,
sizeof(szErrorMsg),
1047 "Failed to write .shp header: %s", strerror(errno));
1048 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
1049 psHooks->
Error(szErrorMsg);
1063 SwapWord(4, abyHeader + 24);
1065 if (psHooks->
FWrite(abyHeader, 100, 1, fpSHX) != 1) {
1066 char szErrorMsg[200];
1068 snprintf(szErrorMsg,
sizeof(szErrorMsg),
1069 "Failure writing .shx header: %s", strerror(errno));
1070 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
1071 psHooks->
Error(szErrorMsg);
1085 return (
SHPOpenLL(pszLayer,
"r+b", psHooks));
1103 SwapWord(8, pabyRec + 0);
1104 SwapWord(8, pabyRec + 8);
1105 SwapWord(8, pabyRec + 16);
1106 SwapWord(8, pabyRec + 24);
1129 for (
int i = 0; i < psObject->
nVertices; i++) {
1151 const
int *panPartStart, const
int *panPartType,
1152 int nVertices, const
double *padfX, const
double *padfY,
1153 const
double *padfZ, const
double *padfM)
1201 for (
int i = 0; i < nParts; i++) {
1219 const size_t nSize =
sizeof(double) *
nVertices;
1233 memcpy(psObject->
padfX, padfX, nSize);
1235 memcpy(psObject->
padfY, padfY, nSize);
1237 memcpy(psObject->
padfZ, padfZ, nSize);
1239 memcpy(psObject->
padfM, padfM, nSize);
1262 const
double *padfY, const
double *padfZ)
1302 unsigned int *panRecOffsetNew;
1303 unsigned int *panRecSizeNew;
1307 sizeof(
unsigned int) * nNewMaxRecords));
1314 sizeof(
unsigned int) * nNewMaxRecords));
1327 psObject->
nParts * 8 + 128));
1334 unsigned int nRecordSize = 0;
1335 const bool bFirstFeature = psSHP->
nRecords == 0;
1345 _SHPSetBounds(pabyRec + 12, psObject);
1348 SwapWord(4, &nPoints);
1350 SwapWord(4, &nParts);
1352 ByteCopy(&nPoints, pabyRec + 40 + 8, 4);
1353 ByteCopy(&nParts, pabyRec + 36 + 8, 4);
1362 for (
int i = 0; i < psObject->
nParts; i++) {
1364 SwapWord(4, pabyRec + 44 + 8 + 4 * i);
1372 memcpy(pabyRec + nRecordSize, psObject->
panPartType,
1374 for (
int i = 0; i < psObject->
nParts; i++) {
1376 SwapWord(4, pabyRec + nRecordSize);
1384 for (
int i = 0; i < psObject->
nVertices; i++) {
1386 ByteCopy(psObject->
padfY + i, pabyRec + nRecordSize + 8, 8);
1389 SwapWord(8, pabyRec + nRecordSize);
1392 SwapWord(8, pabyRec + nRecordSize + 8);
1394 nRecordSize += 2 * 8;
1405 SwapWord(8, pabyRec + nRecordSize);
1410 SwapWord(8, pabyRec + nRecordSize);
1413 for (
int i = 0; i < psObject->
nVertices; i++) {
1416 SwapWord(8, pabyRec + nRecordSize);
1434 SwapWord(8, pabyRec + nRecordSize);
1439 SwapWord(8, pabyRec + nRecordSize);
1442 for (
int i = 0; i < psObject->
nVertices; i++) {
1445 SwapWord(8, pabyRec + nRecordSize);
1459 _SHPSetBounds(pabyRec + 12, psObject);
1462 SwapWord(4, &nPoints);
1463 ByteCopy(&nPoints, pabyRec + 44, 4);
1465 for (
int i = 0; i < psObject->
nVertices; i++) {
1467 ByteCopy(psObject->
padfY + i, pabyRec + 48 + i * 16 + 8, 8);
1470 SwapWord(8, pabyRec + 48 + i * 16);
1472 SwapWord(8, pabyRec + 48 + i * 16 + 8);
1475 nRecordSize = 48 + 16 * psObject->
nVertices;
1480 SwapWord(8, pabyRec + nRecordSize);
1485 SwapWord(8, pabyRec + nRecordSize);
1488 for (
int i = 0; i < psObject->
nVertices; i++) {
1491 SwapWord(8, pabyRec + nRecordSize);
1501 SwapWord(8, pabyRec + nRecordSize);
1506 SwapWord(8, pabyRec + nRecordSize);
1509 for (
int i = 0; i < psObject->
nVertices; i++) {
1512 SwapWord(8, pabyRec + nRecordSize);
1528 SwapWord(8, pabyRec + 12);
1530 SwapWord(8, pabyRec + 20);
1537 SwapWord(8, pabyRec + nRecordSize);
1545 SwapWord(8, pabyRec + nRecordSize);
1569 bool bAppendToLastRecord =
false;
1570 bool bAppendToFile =
false;
1575 bAppendToLastRecord =
true;
1578 if (psSHP->
nFileSize > UINT_MAX - nRecordSize) {
1580 snprintf(str,
sizeof(str),
1581 "Failed to write shape object. "
1582 "The maximum file size of %u has been reached. "
1583 "The current record of size %u cannot be added.",
1585 str[
sizeof(str) - 1] =
'\0';
1591 bAppendToFile =
true;
1607 i32 = (nRecordSize - 8) / 2;
1627 char szErrorMsg[200];
1629 snprintf(szErrorMsg,
sizeof(szErrorMsg),
1630 "Error in psSHP->sHooks.FSeek() while writing object to "
1633 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
1641 char szErrorMsg[200];
1643 snprintf(szErrorMsg,
sizeof(szErrorMsg),
1644 "Error in psSHP->sHooks.FWrite() while writing object of %u "
1645 "bytes to .shp file: %s",
1646 nRecordSize, strerror(errno));
1647 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
1656 if (bAppendToLastRecord) {
1659 else if (bAppendToFile) {
1671 if (bFirstFeature) {
1688 for (
int i = 0; i < psObject->
nVertices; i++) {
1693 if (psObject->
padfZ) {
1699 if (psObject->
padfM) {
1714 static void *SHPAllocBuffer(
unsigned char **pBuffer,
int nSize)
1717 return calloc(1, nSize);
1719 unsigned char *pRet = *pBuffer;
1723 (*pBuffer) += nSize;
1731 static unsigned char *SHPReallocObjectBufIfNecessary(
SHPHandle psSHP,
1734 if (nObjectBufSize == 0) {
1735 nObjectBufSize = 4 *
sizeof(double);
1738 unsigned char *pBuffer;
1766 if (hEntity < 0 || hEntity >= psSHP->nRecords)
1772 if (psSHP->panRecOffset[hEntity] == 0 && psSHP->fpSHX !=
SHPLIB_NULLPTR) {
1773 unsigned int nOffset;
1774 unsigned int nLength;
1776 if (psSHP->sHooks.FSeek(psSHP->fpSHX, 100 + 8 * hEntity, 0) != 0 ||
1777 psSHP->sHooks.FRead(&nOffset, 1, 4, psSHP->fpSHX) != 4 ||
1778 psSHP->sHooks.FRead(&nLength, 1, 4, psSHP->fpSHX) != 4) {
1780 snprintf(str,
sizeof(str),
1781 "Error in fseek()/fread() reading object from .shx file "
1784 str[
sizeof(str) - 1] =
'\0';
1786 psSHP->sHooks.Error(str);
1790 SwapWord(4, &nOffset);
1792 SwapWord(4, &nLength);
1794 if (nOffset >
STATIC_CAST(
unsigned int, INT_MAX)) {
1796 snprintf(str,
sizeof(str),
"Invalid offset for entity %d", hEntity);
1797 str[
sizeof(str) - 1] =
'\0';
1799 psSHP->sHooks.Error(str);
1802 if (nLength >
STATIC_CAST(
unsigned int, INT_MAX / 2 - 4)) {
1804 snprintf(str,
sizeof(str),
"Invalid length for entity %d", hEntity);
1805 str[
sizeof(str) - 1] =
'\0';
1807 psSHP->sHooks.Error(str);
1811 psSHP->panRecOffset[hEntity] = nOffset * 2;
1812 psSHP->panRecSize[hEntity] = nLength * 2;
1821 if (nNewBufSize < INT_MAX - nNewBufSize / 3)
1822 nNewBufSize += nNewBufSize / 3;
1824 nNewBufSize = INT_MAX;
1830 if (nNewBufSize >= 10 * 1024 * 1024) {
1831 if (psSHP->nBufSize < 10 * 1024 * 1024) {
1833 psSHP->sHooks.FSeek(psSHP->fpSHP, 0, 2);
1834 nFileSize = psSHP->sHooks.FTell(psSHP->fpSHP);
1835 if (nFileSize >= UINT_MAX)
1836 psSHP->nFileSize = UINT_MAX;
1838 psSHP->nFileSize =
STATIC_CAST(
unsigned int, nFileSize);
1841 if (psSHP->panRecOffset[hEntity] >= psSHP->nFileSize ||
1848 psSHP->panRecSize[hEntity] >
1849 psSHP->nFileSize - psSHP->panRecOffset[hEntity]) {
1851 snprintf(str,
sizeof(str),
1852 "Error in fread() reading object of size %d at offset "
1853 "%u from .shp file",
1855 str[
sizeof(str) - 1] =
'\0';
1857 psSHP->sHooks.Error(str);
1865 char szErrorMsg[160];
1866 snprintf(szErrorMsg,
sizeof(szErrorMsg),
1867 "Not enough memory to allocate requested memory "
1868 "(nNewBufSize=%d). "
1869 "Probably broken SHP file",
1871 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
1872 psSHP->sHooks.Error(szErrorMsg);
1877 psSHP->pabyRec = pabyRecNew;
1878 psSHP->nBufSize = nNewBufSize;
1889 if (psSHP->sHooks.FSeek(psSHP->fpSHP, psSHP->panRecOffset[hEntity], 0) !=
1896 snprintf(str,
sizeof(str),
1897 "Error in fseek() reading object from .shp file at offset %u",
1898 psSHP->panRecOffset[hEntity]);
1899 str[
sizeof(str) - 1] =
'\0';
1901 psSHP->sHooks.Error(str);
1906 int, psSHP->sHooks.FRead(psSHP->pabyRec, 1,
nEntitySize, psSHP->fpSHP));
1920 int nSHPContentLength;
1921 memcpy(&nSHPContentLength, psSHP->pabyRec + 4, 4);
1923 SwapWord(4, &(nSHPContentLength));
1924 if (nSHPContentLength < 0 || nSHPContentLength > INT_MAX / 2 - 4 ||
1927 snprintf(str,
sizeof(str),
1928 "Sanity check failed when trying to recover from "
1929 "inconsistent .shx/.shp with shape %d",
1931 str[
sizeof(str) - 1] =
'\0';
1933 psSHP->sHooks.Error(str);
1943 snprintf(str,
sizeof(str),
1944 "Error in fread() reading object of size %d at offset %u from "
1947 str[
sizeof(str) - 1] =
'\0';
1949 psSHP->sHooks.Error(str);
1954 char szErrorMsg[160];
1955 snprintf(szErrorMsg,
sizeof(szErrorMsg),
1956 "Corrupted .shp file : shape %d : nEntitySize = %d", hEntity,
1958 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
1959 psSHP->sHooks.Error(szErrorMsg);
1963 memcpy(&
nSHPType, psSHP->pabyRec + 8, 4);
1972 if (psSHP->bFastModeReadObject) {
1973 if (psSHP->psCachedObject->bFastModeReadObject) {
1974 psSHP->sHooks.Error(
"Invalid read pattern in fast read mode. "
1975 "SHPDestroyObject() should be called.");
1979 psShape = psSHP->psCachedObject;
1999 char szErrorMsg[160];
2000 snprintf(szErrorMsg,
sizeof(szErrorMsg),
2001 "Corrupted .shp file : shape %d : nEntitySize = %d",
2003 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
2004 psSHP->sHooks.Error(szErrorMsg);
2013 memcpy(&(psShape->
dfXMin), psSHP->pabyRec + 8 + 4, 8);
2014 memcpy(&(psShape->
dfYMin), psSHP->pabyRec + 8 + 12, 8);
2015 memcpy(&(psShape->
dfXMax), psSHP->pabyRec + 8 + 20, 8);
2016 memcpy(&(psShape->
dfYMax), psSHP->pabyRec + 8 + 28, 8);
2019 SwapWord(8, &(psShape->
dfXMin));
2021 SwapWord(8, &(psShape->
dfYMin));
2023 SwapWord(8, &(psShape->
dfXMax));
2025 SwapWord(8, &(psShape->
dfYMax));
2034 memcpy(&nPoints, psSHP->pabyRec + 40 + 8, 4);
2036 memcpy(&nParts, psSHP->pabyRec + 36 + 8, 4);
2039 SwapWord(4, &nPoints);
2041 SwapWord(4, &nParts);
2045 nPoints > 50 * 1000 * 1000 || nParts > 10 * 1000 * 1000) {
2046 char szErrorMsg[160];
2047 snprintf(szErrorMsg,
sizeof(szErrorMsg),
2048 "Corrupted .shp file : shape %d, nPoints=%u, nParts=%u.",
2049 hEntity, nPoints, nParts);
2050 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
2051 psSHP->sHooks.Error(szErrorMsg);
2059 int nRequiredSize = 44 + 8 + 4 * nParts + 16 * nPoints;
2063 nRequiredSize += 16 + 8 * nPoints;
2066 nRequiredSize += 4 * nParts;
2069 char szErrorMsg[160];
2070 snprintf(szErrorMsg,
sizeof(szErrorMsg),
2071 "Corrupted .shp file : shape %d, nPoints=%u, nParts=%u, "
2074 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
2075 psSHP->sHooks.Error(szErrorMsg);
2084 const int nObjectBufSize =
2085 4 *
sizeof(double) * nPoints + 2 *
sizeof(
int) * nParts;
2086 pBuffer = SHPReallocObjectBufIfNecessary(psSHP, nObjectBufSize);
2087 ppBuffer = &pBuffer;
2092 double *, SHPAllocBuffer(ppBuffer,
sizeof(
double) * nPoints));
2094 double *, SHPAllocBuffer(ppBuffer,
sizeof(
double) * nPoints));
2096 double *, SHPAllocBuffer(ppBuffer,
sizeof(
double) * nPoints));
2098 double *, SHPAllocBuffer(ppBuffer,
sizeof(
double) * nPoints));
2100 psShape->
nParts = nParts;
2102 STATIC_CAST(
int *, SHPAllocBuffer(ppBuffer, nParts *
sizeof(
int)));
2104 STATIC_CAST(
int *, SHPAllocBuffer(ppBuffer, nParts *
sizeof(
int)));
2112 char szErrorMsg[160];
2113 snprintf(szErrorMsg,
sizeof(szErrorMsg),
2114 "Not enough memory to allocate requested memory "
2115 "(nPoints=%u, nParts=%u) for shape %d. "
2116 "Probably broken SHP file",
2117 nPoints, nParts, hEntity);
2118 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
2119 psSHP->sHooks.Error(szErrorMsg);
2132 memcpy(psShape->
panPartStart, psSHP->pabyRec + 44 + 8, 4 * nParts);
2142 char szErrorMsg[160];
2143 snprintf(szErrorMsg,
sizeof(szErrorMsg),
2144 "Corrupted .shp file : shape %d : panPartStart[%d] = "
2145 "%d, nVertices = %d",
2148 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
2149 psSHP->sHooks.Error(szErrorMsg);
2155 char szErrorMsg[160];
2156 snprintf(szErrorMsg,
sizeof(szErrorMsg),
2157 "Corrupted .shp file : shape %d : panPartStart[%d] = "
2158 "%d, panPartStart[%d] = %d",
2161 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
2162 psSHP->sHooks.Error(szErrorMsg);
2168 int nOffset = 44 + 8 + 4 * nParts;
2176 memcpy(psShape->
panPartType, psSHP->pabyRec + nOffset, 4 * nParts);
2182 nOffset += 4 * nParts;
2191 memcpy(psShape->
padfX + i, psSHP->pabyRec + nOffset + i * 16, 8);
2193 memcpy(psShape->
padfY + i, psSHP->pabyRec + nOffset + i * 16 + 8,
2197 SwapWord(8, psShape->
padfX + i);
2199 SwapWord(8, psShape->
padfY + i);
2202 nOffset += 16 * nPoints;
2212 memcpy(&(psShape->
dfZMin), psSHP->pabyRec + nOffset, 8);
2213 memcpy(&(psShape->
dfZMax), psSHP->pabyRec + nOffset + 8, 8);
2216 SwapWord(8, &(psShape->
dfZMin));
2218 SwapWord(8, &(psShape->
dfZMax));
2221 memcpy(psShape->
padfZ + i,
2222 psSHP->pabyRec + nOffset + 16 + i * 8, 8);
2224 SwapWord(8, psShape->
padfZ + i);
2227 nOffset += 16 + 8 * nPoints;
2242 memcpy(&(psShape->
dfMMin), psSHP->pabyRec + nOffset, 8);
2243 memcpy(&(psShape->
dfMMax), psSHP->pabyRec + nOffset + 8, 8);
2246 SwapWord(8, &(psShape->
dfMMin));
2248 SwapWord(8, &(psShape->
dfMMax));
2251 memcpy(psShape->
padfM + i,
2252 psSHP->pabyRec + nOffset + 16 + i * 8, 8);
2254 SwapWord(8, psShape->
padfM + i);
2270 char szErrorMsg[160];
2271 snprintf(szErrorMsg,
sizeof(szErrorMsg),
2272 "Corrupted .shp file : shape %d : nEntitySize = %d",
2274 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
2275 psSHP->sHooks.Error(szErrorMsg);
2280 memcpy(&nPoints, psSHP->pabyRec + 44, 4);
2283 SwapWord(4, &nPoints);
2286 if ( nPoints > 50 * 1000 * 1000) {
2287 char szErrorMsg[160];
2288 snprintf(szErrorMsg,
sizeof(szErrorMsg),
2289 "Corrupted .shp file : shape %d : nPoints = %u", hEntity,
2291 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
2292 psSHP->sHooks.Error(szErrorMsg);
2297 int nRequiredSize = 48 + nPoints * 16;
2299 nRequiredSize += 16 + nPoints * 8;
2302 char szErrorMsg[160];
2303 snprintf(szErrorMsg,
sizeof(szErrorMsg),
2304 "Corrupted .shp file : shape %d : nPoints = %u, "
2307 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
2308 psSHP->sHooks.Error(szErrorMsg);
2317 const int nObjectBufSize = 4 *
sizeof(double) * nPoints;
2318 pBuffer = SHPReallocObjectBufIfNecessary(psSHP, nObjectBufSize);
2319 ppBuffer = &pBuffer;
2325 double *, SHPAllocBuffer(ppBuffer,
sizeof(
double) * nPoints));
2327 double *, SHPAllocBuffer(ppBuffer,
sizeof(
double) * nPoints));
2329 double *, SHPAllocBuffer(ppBuffer,
sizeof(
double) * nPoints));
2331 double *, SHPAllocBuffer(ppBuffer,
sizeof(
double) * nPoints));
2337 char szErrorMsg[160];
2338 snprintf(szErrorMsg,
sizeof(szErrorMsg),
2339 "Not enough memory to allocate requested memory "
2340 "(nPoints=%u) for shape %d. "
2341 "Probably broken SHP file",
2343 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
2344 psSHP->sHooks.Error(szErrorMsg);
2350 memcpy(psShape->
padfX + i, psSHP->pabyRec + 48 + 16 * i, 8);
2351 memcpy(psShape->
padfY + i, psSHP->pabyRec + 48 + 16 * i + 8, 8);
2354 SwapWord(8, psShape->
padfX + i);
2356 SwapWord(8, psShape->
padfY + i);
2359 int nOffset = 48 + 16 * nPoints;
2366 memcpy(&(psShape->
dfXMin), psSHP->pabyRec + 8 + 4, 8);
2367 memcpy(&(psShape->
dfYMin), psSHP->pabyRec + 8 + 12, 8);
2368 memcpy(&(psShape->
dfXMax), psSHP->pabyRec + 8 + 20, 8);
2369 memcpy(&(psShape->
dfYMax), psSHP->pabyRec + 8 + 28, 8);
2372 SwapWord(8, &(psShape->
dfXMin));
2374 SwapWord(8, &(psShape->
dfYMin));
2376 SwapWord(8, &(psShape->
dfXMax));
2378 SwapWord(8, &(psShape->
dfYMax));
2386 memcpy(&(psShape->
dfZMin), psSHP->pabyRec + nOffset, 8);
2387 memcpy(&(psShape->
dfZMax), psSHP->pabyRec + nOffset + 8, 8);
2390 SwapWord(8, &(psShape->
dfZMin));
2392 SwapWord(8, &(psShape->
dfZMax));
2395 memcpy(psShape->
padfZ + i,
2396 psSHP->pabyRec + nOffset + 16 + i * 8, 8);
2398 SwapWord(8, psShape->
padfZ + i);
2401 nOffset += 16 + 8 * nPoints;
2415 memcpy(&(psShape->
dfMMin), psSHP->pabyRec + nOffset, 8);
2416 memcpy(&(psShape->
dfMMax), psSHP->pabyRec + nOffset + 8, 8);
2419 SwapWord(8, &(psShape->
dfMMin));
2421 SwapWord(8, &(psShape->
dfMMax));
2424 memcpy(psShape->
padfM + i,
2425 psSHP->pabyRec + nOffset + 16 + i * 8, 8);
2427 SwapWord(8, psShape->
padfM + i);
2447 psShape->
padfZ[0] = 0.0;
2448 psShape->
padfM[0] = 0.0;
2459 char szErrorMsg[160];
2460 snprintf(szErrorMsg,
sizeof(szErrorMsg),
2461 "Corrupted .shp file : shape %d : nEntitySize = %d",
2463 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
2464 psSHP->sHooks.Error(szErrorMsg);
2468 memcpy(psShape->
padfX, psSHP->pabyRec + 12, 8);
2469 memcpy(psShape->
padfY, psSHP->pabyRec + 20, 8);
2472 SwapWord(8, psShape->
padfX);
2474 SwapWord(8, psShape->
padfY);
2476 int nOffset = 20 + 8;
2484 memcpy(psShape->
padfZ, psSHP->pabyRec + nOffset, 8);
2487 SwapWord(8, psShape->
padfZ);
2501 memcpy(psShape->
padfM, psSHP->pabyRec + nOffset, 8);
2504 SwapWord(8, psShape->
padfM);
2543 return "MultiPoint";
2555 return "MultiPointZ";
2567 return "MultiPointM";
2570 return "MultiPatch";
2573 return "UnknownShapeType";
2583 switch (nPartType) {
2585 return "TriangleStrip";
2588 return "TriangleFan";
2603 return "UnknownPartType";
2642 static int SHPGetPartVertexCount(
const SHPObject *psObject,
int iPart)
2644 if (iPart == psObject->
nParts - 1)
2656 static int SHPRewindIsInnerRing(
const SHPObject *psObject,
int iOpRing,
2657 double dfTestX,
double dfTestY,
2658 double dfRelativeTolerance,
int bSameZ,
2670 bool bInner =
false;
2671 for (
int iCheckRing = 0; iCheckRing < psObject->
nParts; iCheckRing++) {
2672 if (iCheckRing == iOpRing)
2675 const int nVertStartCheck = psObject->
panPartStart[iCheckRing];
2676 const int nVertCountCheck = SHPGetPartVertexCount(psObject, iCheckRing);
2683 int bZTestOK =
TRUE;
2684 for (
int iVert = nVertStartCheck + 1;
2685 iVert < nVertStartCheck + nVertCountCheck; ++iVert) {
2686 if (psObject->
padfZ[iVert] != dfTestZ) {
2695 for (
int iEdge = 0; iEdge < nVertCountCheck; iEdge++) {
2697 if (iEdge < nVertCountCheck - 1)
2702 const double y0 = psObject->
padfY[iEdge + nVertStartCheck];
2703 const double y1 = psObject->
padfY[iNext + nVertStartCheck];
2709 if ((y0 < dfTestY && dfTestY <= y1) ||
2710 (y1 < dfTestY && dfTestY <= y0)) {
2715 const double x0 = psObject->
padfX[iEdge + nVertStartCheck];
2716 const double x1 = psObject->
padfX[iNext + nVertStartCheck];
2717 const double intersect_minus_testX =
2718 (x0 - dfTestX) + (dfTestY - y0) / (y1 - y0) * (x1 - x0);
2720 if (fabs(intersect_minus_testX) <=
2721 dfRelativeTolerance * fabs(dfTestX)) {
2726 else if (intersect_minus_testX < 0) {
2761 for (
int iVert = 1; iVert < psObject->
nVertices; ++iVert) {
2762 if (psObject->
padfZ[iVert] != psObject->
padfZ[0]) {
2773 for (
int iOpRing = 0; iOpRing < psObject->
nParts; iOpRing++) {
2774 const int nVertStart = psObject->
panPartStart[iOpRing];
2775 const int nVertCount = SHPGetPartVertexCount(psObject, iOpRing);
2786 int bDoIsInnerRingTest =
TRUE;
2788 int bPartSameZ =
TRUE;
2789 for (
int iVert = nVertStart + 1; iVert < nVertStart + nVertCount;
2791 if (psObject->
padfZ[iVert] != psObject->
padfZ[nVertStart]) {
2797 bDoIsInnerRingTest =
FALSE;
2801 if (bDoIsInnerRingTest) {
2802 for (
int iTolerance = 0; iTolerance < 2; iTolerance++) {
2810 const double dfRelativeTolerance = (iTolerance == 0) ? 1e-9 : 0;
2811 for (
int iVert = nVertStart;
2812 iVert + 1 < nVertStart + nVertCount; ++iVert) {
2816 const double dfTestX =
2817 (psObject->
padfX[iVert] + psObject->
padfX[iVert + 1]) /
2819 const double dfTestY =
2820 (psObject->
padfY[iVert] + psObject->
padfY[iVert + 1]) /
2822 const double dfTestZ =
2823 !bSameZ ? psObject->
padfZ[nVertStart] : 0;
2825 bInner = SHPRewindIsInnerRing(psObject, iOpRing, dfTestX,
2826 dfTestY, dfRelativeTolerance,
2847 double dfSum = psObject->
padfX[nVertStart] *
2848 (psObject->
padfY[nVertStart + 1] -
2849 psObject->
padfY[nVertStart + nVertCount - 1]);
2850 int iVert = nVertStart + 1;
2851 for (; iVert < nVertStart + nVertCount - 1; iVert++) {
2852 dfSum += psObject->
padfX[iVert] *
2853 (psObject->
padfY[iVert + 1] - psObject->
padfY[iVert - 1]);
2856 dfSum += psObject->
padfX[iVert] *
2857 (psObject->
padfY[nVertStart] - psObject->
padfY[iVert - 1]);
2864 if ((dfSum < 0.0 && bInner) || (dfSum > 0.0 && !bInner)) {
2866 for (
int i = 0; i < nVertCount / 2; i++) {
2868 double dfSaved = psObject->
padfX[nVertStart + i];
2869 psObject->
padfX[nVertStart + i] =
2870 psObject->
padfX[nVertStart + nVertCount - i - 1];
2871 psObject->
padfX[nVertStart + nVertCount - i - 1] = dfSaved;
2874 dfSaved = psObject->
padfY[nVertStart + i];
2875 psObject->
padfY[nVertStart + i] =
2876 psObject->
padfY[nVertStart + nVertCount - i - 1];
2877 psObject->
padfY[nVertStart + nVertCount - i - 1] = dfSaved;
2880 if (psObject->
padfZ) {
2881 dfSaved = psObject->
padfZ[nVertStart + i];
2882 psObject->
padfZ[nVertStart + i] =
2883 psObject->
padfZ[nVertStart + nVertCount - i - 1];
2884 psObject->
padfZ[nVertStart + nVertCount - i - 1] = dfSaved;
2888 if (psObject->
padfM) {
2889 dfSaved = psObject->
padfM[nVertStart + i];
2890 psObject->
padfM[nVertStart + i] =
2891 psObject->
padfM[nVertStart + nVertCount - i - 1];
2892 psObject->
padfM[nVertStart + nVertCount - i - 1] = dfSaved;
#define assert(condition)
void SASetupDefaultHooks(SAHooks *psHooks)
#define SHP_CVSID(string)
#define DISABLE_MULTIPATCH_MEASURE
SHPHandle SHPAPI_CALL SHPOpen(const char *pszLayer, const char *pszAccess)
SHPHandle SHPAPI_CALL SHPOpenLL(const char *pszLayer, const char *pszAccess, SAHooks *psHooks)
SHPHandle SHPAPI_CALL SHPCreate(const char *pszLayer, int nShapeType)
void SHPAPI_CALL SHPSetFastModeReadObject(SHPHandle hSHP, int bFastMode)
SHPObject SHPAPI_CALL1 * SHPCreateObject(int nSHPType, int nShapeId, int nParts, const int *panPartStart, const int *panPartType, int nVertices, const double *padfX, const double *padfY, const double *padfZ, const double *padfM){ SHPObject *psObject=STATIC_CAST(SHPObject *, calloc(1, sizeof(SHPObject))
SHPHandle SHPAPI_CALL SHPCreateLL(const char *pszLayer, int nShapeType, SAHooks *psHooks)
void SHPAPI_CALL SHPComputeExtents(SHPObject *psObject)
SHPObject SHPAPI_CALL1 * SHPCreateSimpleObject(int nSHPType, int nVertices, const double *padfX, const double *padfY, const double *padfZ){ return(SHPCreateObject(nSHPType, -1, 0, SHPLIB_NULLPTR, SHPLIB_NULLPTR, nVertices, padfX, padfY, padfZ, SHPLIB_NULLPTR)
if(nSHPType==SHPT_ARCM||nSHPType==SHPT_POINTM||nSHPType==SHPT_POLYGONM||nSHPType==SHPT_MULTIPOINTM)
void SHPAPI_CALL SHPWriteHeader(SHPHandle psSHP)
void SHPAPI_CALL SHPClose(SHPHandle psSHP)
void SHPAPI_CALL SHPGetInfo(SHPHandle psSHP, int *pnEntities, int *pnShapeType, double *padfMinBound, double *padfMaxBound)
#define STATIC_CAST(type, x)
int SHPAPI_CALL SHPRestoreSHX(const char *pszLayer, const char *pszAccess, SAHooks *psHooks)
int SHPAPI_CALL SHPRewindObject(CPL_UNUSED SHPHandle hSHP, SHPObject *psObject)
SHPObject SHPAPI_CALL1 * SHPReadObject(SHPHandle psSHP, int hEntity){ if(hEntity< 0||hEntity >=psSHP->nRecords) return SHPLIB_NULLPTR;if(psSHP->panRecOffset[hEntity]==0 &&psSHP->fpSHX !=SHPLIB_NULLPTR
void SHPAPI_CALL SHPDestroyObject(SHPObject *psShape)
int SHPAPI_CALL SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject *psObject)
#define ByteCopy(a, b, c)
SHPHandle SHPAPI_CALL SHPOpenLLEx(const char *pszLayer, const char *pszAccess, SAHooks *psHooks, int bRestoreSHX)
const char SHPAPI_CALL1 * SHPPartTypeName(int nPartType){ switch(nPartType
const char SHPAPI_CALL1 * SHPTypeName(int nSHPType){ switch(nSHPType
void(* Error)(const char *message)
SAFile(* FOpen)(const char *filename, const char *access)
SAOffset(* FTell)(SAFile file)
int(* FFlush)(SAFile file)
SAOffset(* FWrite)(void *p, SAOffset size, SAOffset nmemb, SAFile file)
int(* FClose)(SAFile file)
SAOffset(* FRead)(void *p, SAOffset size, SAOffset nmemb, SAFile file)
SAOffset(* FSeek)(SAFile file, SAOffset offset, int whence)
SHPObject * psCachedObject
unsigned int * panRecSize
unsigned char * pabyObjectBuf
unsigned int * panRecOffset