From d9ecec6e4cf3f8121aac7efb4aeda0fa2cb5e4c2 Mon Sep 17 00:00:00 2001 From: Colin Clark Date: Tue, 2 Jun 2020 15:37:12 +0100 Subject: [PATCH] Fix #771: properly check return value of mmap https://github.com/BestImageViewer/geeqie/pull/771 Updates from ZoneDetect project: https://github.com/BertoldVdb/ZoneDetect --- src/zonedetect.c | 658 +++++++++++++++++++++++++++++++++++++++-------- src/zonedetect.h | 16 +- 2 files changed, 566 insertions(+), 108 deletions(-) diff --git a/src/zonedetect.c b/src/zonedetect.c index 8a7b0eae..47fe37bd 100644 --- a/src/zonedetect.c +++ b/src/zonedetect.c @@ -26,18 +26,19 @@ */ #include +#include #include #include #include #include #include #if defined(_MSC_VER) || defined(__MINGW32__) - #include +#include #else - #include - #include - #include - #include +#include +#include +#include +#include #endif #include "zonedetect.h" @@ -68,6 +69,7 @@ struct ZoneDetectOpaque { off_t length; #endif + uint8_t closeType; uint8_t *mapping; uint8_t tableType; @@ -95,38 +97,44 @@ static int32_t ZDFloatToFixedPoint(float input, float scale, unsigned int precis return (int32_t)(inputScaled * (float)(1 << (precision - 1))); } -static unsigned int ZDDecodeVariableLengthUnsigned(const ZoneDetect *library, uint32_t *index, uint32_t *result) +static float ZDFixedPointToFloat(int32_t input, float scale, unsigned int precision) +{ + const float value = (float)input / (float)(1 << (precision - 1)); + return value * scale; +} + +static unsigned int ZDDecodeVariableLengthUnsigned(const ZoneDetect *library, uint32_t *index, uint64_t *result) { if(*index >= (uint32_t)library->length) { return 0; } - uint32_t value = 0; + uint64_t value = 0; unsigned int i = 0; #if defined(_MSC_VER) __try { #endif - uint8_t *const buffer = library->mapping + *index; - uint8_t *const bufferEnd = library->mapping + library->length - 1; + uint8_t *const buffer = library->mapping + *index; + uint8_t *const bufferEnd = library->mapping + library->length - 1; - unsigned int shift = 0; - while(1) { - value |= (uint32_t)((buffer[i] & UINT8_C(0x7F)) << shift); - shift += 7u; + unsigned int shift = 0; + while(1) { + value |= ((((uint64_t)buffer[i]) & UINT8_C(0x7F)) << shift); + shift += 7u; - if(!(buffer[i] & UINT8_C(0x80))) { - break; - } + if(!(buffer[i] & UINT8_C(0x80))) { + break; + } - i++; - if(buffer + i > bufferEnd) { - return 0; + i++; + if(buffer + i > bufferEnd) { + return 0; + } } - } #if defined(_MSC_VER) } __except(GetExceptionCode() == EXCEPTION_IN_PAGE_ERROR - ? EXCEPTION_EXECUTE_HANDLER - : EXCEPTION_CONTINUE_SEARCH) { /* file mapping SEH exception occurred */ + ? EXCEPTION_EXECUTE_HANDLER + : EXCEPTION_CONTINUE_SEARCH) { /* file mapping SEH exception occurred */ zdError(ZD_E_DB_MAP_EXCEPTION, (int)GetLastError()); return 0; } @@ -138,17 +146,67 @@ static unsigned int ZDDecodeVariableLengthUnsigned(const ZoneDetect *library, ui return i; } +static unsigned int ZDDecodeVariableLengthUnsignedReverse(const ZoneDetect *library, uint32_t *index, uint64_t *result) +{ + uint32_t i = *index; + + if(*index >= (uint32_t)library->length) { + return 0; + } + +#if defined(_MSC_VER) + __try { +#endif + + if(library->mapping[i] & UINT8_C(0x80)) { + return 0; + } + + if(!i) { + return 0; + } + i--; + + while(library->mapping[i] & UINT8_C(0x80)) { + if(!i) { + return 0; + } + i--; + } + +#if defined(_MSC_VER) + } __except(GetExceptionCode() == EXCEPTION_IN_PAGE_ERROR + ? EXCEPTION_EXECUTE_HANDLER + : EXCEPTION_CONTINUE_SEARCH) { /* file mapping SEH exception occurred */ + zdError(ZD_E_DB_MAP_EXCEPTION, (int)GetLastError()); + return 0; + } +#endif + + *index = i; + + i++; + + uint32_t i2 = i; + return ZDDecodeVariableLengthUnsigned(library, &i2, result); +} + +static int64_t ZDDecodeUnsignedToSigned(uint64_t value) +{ + return (value & 1) ? -(int64_t)(value / 2) : (int64_t)(value / 2); +} + static unsigned int ZDDecodeVariableLengthSigned(const ZoneDetect *library, uint32_t *index, int32_t *result) { - uint32_t value = 0; + uint64_t value = 0; const unsigned int retVal = ZDDecodeVariableLengthUnsigned(library, index, &value); - *result = (value & 1) ? -(int32_t)(value / 2) : (int32_t)(value / 2); + *result = (int32_t)ZDDecodeUnsignedToSigned(value); return retVal; } static char *ZDParseString(const ZoneDetect *library, uint32_t *index) { - uint32_t strLength; + uint64_t strLength; if(!ZDDecodeVariableLengthUnsigned(library, index, &strLength)) { return NULL; } @@ -156,7 +214,7 @@ static char *ZDParseString(const ZoneDetect *library, uint32_t *index) uint32_t strOffset = *index; unsigned int remoteStr = 0; if(strLength >= 256) { - strOffset = library->metadataOffset + strLength - 256; + strOffset = library->metadataOffset + (uint32_t)strLength - 256; remoteStr = 1; if(!ZDDecodeVariableLengthUnsigned(library, &strOffset, &strLength)) { @@ -168,28 +226,28 @@ static char *ZDParseString(const ZoneDetect *library, uint32_t *index) } } - char *const str = malloc(strLength + 1); + char *const str = malloc((size_t)(strLength + 1)); if(str) { #if defined(_MSC_VER) - __try { + __try { #endif - for(size_t i = 0; i < strLength; i++) { - str[i] = (char)(library->mapping[strOffset + i] ^ UINT8_C(0x80)); - } + for(size_t i = 0; i < strLength; i++) { + str[i] = (char)(library->mapping[strOffset + i] ^ UINT8_C(0x80)); + } #if defined(_MSC_VER) - } __except(GetExceptionCode() == EXCEPTION_IN_PAGE_ERROR - ? EXCEPTION_EXECUTE_HANDLER - : EXCEPTION_CONTINUE_SEARCH) { /* file mapping SEH exception occurred */ - zdError(ZD_E_DB_MAP_EXCEPTION, (int)GetLastError()); - return 0; - } + } __except(GetExceptionCode() == EXCEPTION_IN_PAGE_ERROR + ? EXCEPTION_EXECUTE_HANDLER + : EXCEPTION_CONTINUE_SEARCH) { /* file mapping SEH exception occurred */ + zdError(ZD_E_DB_MAP_EXCEPTION, (int)GetLastError()); + return 0; + } #endif str[strLength] = 0; } if(!remoteStr) { - *index += strLength; + *index += (uint32_t)strLength; } return str; @@ -204,24 +262,24 @@ static int ZDParseHeader(ZoneDetect *library) #if defined(_MSC_VER) __try { #endif - if(memcmp(library->mapping, "PLB", 3)) { - return -1; - } + if(memcmp(library->mapping, "PLB", 3)) { + return -1; + } - library->tableType = library->mapping[3]; - library->version = library->mapping[4]; - library->precision = library->mapping[5]; - library->numFields = library->mapping[6]; + library->tableType = library->mapping[3]; + library->version = library->mapping[4]; + library->precision = library->mapping[5]; + library->numFields = library->mapping[6]; #if defined(_MSC_VER) } __except(GetExceptionCode() == EXCEPTION_IN_PAGE_ERROR - ? EXCEPTION_EXECUTE_HANDLER - : EXCEPTION_CONTINUE_SEARCH) { /* file mapping SEH exception occurred */ + ? EXCEPTION_EXECUTE_HANDLER + : EXCEPTION_CONTINUE_SEARCH) { /* file mapping SEH exception occurred */ zdError(ZD_E_DB_MAP_EXCEPTION, (int)GetLastError()); return 0; } #endif - if(library->version != 0) { + if(library->version >= 2) { return -1; } @@ -237,15 +295,15 @@ static int ZDParseHeader(ZoneDetect *library) return -1; } - uint32_t tmp; + uint64_t tmp; /* Read section sizes */ /* By memset: library->bboxOffset = 0 */ if(!ZDDecodeVariableLengthUnsigned(library, &index, &tmp)) return -1; - library->metadataOffset = tmp + library->bboxOffset; + library->metadataOffset = (uint32_t)tmp + library->bboxOffset; if(!ZDDecodeVariableLengthUnsigned(library, &index, &tmp))return -1; - library->dataOffset = tmp + library->metadataOffset; + library->dataOffset = (uint32_t)tmp + library->metadataOffset; if(!ZDDecodeVariableLengthUnsigned(library, &index, &tmp)) return -1; @@ -273,32 +331,317 @@ static int ZDPointInBox(int32_t xl, int32_t x, int32_t xr, int32_t yl, int32_t y return 0; } -static ZDLookupResult ZDPointInPolygon(const ZoneDetect *library, uint32_t polygonIndex, int32_t latFixedPoint, int32_t lonFixedPoint, uint64_t *distanceSqrMin) +static uint32_t ZDUnshuffle(uint64_t w) { - uint32_t numVertices; - int32_t pointLat = 0, pointLon = 0, diffLat = 0, diffLon = 0, firstLat = 0, firstLon = 0, prevLat = 0, prevLon = 0; - lonFixedPoint -= 3; + w &= 0x5555555555555555; + w = (w | (w >> 1)) & 0x3333333333333333; + w = (w | (w >> 2)) & 0x0F0F0F0F0F0F0F0F; + w = (w | (w >> 4)) & 0x00FF00FF00FF00FF; + w = (w | (w >> 8)) & 0x0000FFFF0000FFFF; + w = (w | (w >> 16)) & 0x00000000FFFFFFFF; + return (uint32_t)w; +} - /* Read number of vertices */ - if(!ZDDecodeVariableLengthUnsigned(library, &polygonIndex, &numVertices)) return ZD_LOOKUP_PARSE_ERROR; - if(numVertices > 1000000) return ZD_LOOKUP_PARSE_ERROR; +static void ZDDecodePoint(uint64_t point, int32_t* lat, int32_t* lon) +{ + *lat = (int32_t)ZDDecodeUnsignedToSigned(ZDUnshuffle(point)); + *lon = (int32_t)ZDDecodeUnsignedToSigned(ZDUnshuffle(point >> 1)); +} - int prevQuadrant = 0, winding = 0; +struct Reader { + const ZoneDetect *library; + uint32_t polygonIndex; + + uint64_t numVertices; + + uint8_t done, first; + uint32_t referenceStart, referenceEnd; + int32_t referenceDirection; - for(size_t i = 0; i <= (size_t)numVertices; i++) { - if(i < (size_t)numVertices) { - if(!ZDDecodeVariableLengthSigned(library, &polygonIndex, &diffLat)) return ZD_LOOKUP_PARSE_ERROR; - if(!ZDDecodeVariableLengthSigned(library, &polygonIndex, &diffLon)) return ZD_LOOKUP_PARSE_ERROR; - pointLat += diffLat; - pointLon += diffLon; - if(i == 0) { - firstLat = pointLat; - firstLon = pointLon; + int32_t pointLat, pointLon; + int32_t firstLat, firstLon; +}; + +static void ZDReaderInit(struct Reader *reader, const ZoneDetect *library, uint32_t polygonIndex) +{ + memset(reader, 0, sizeof(*reader)); + + reader->library = library; + reader->polygonIndex = polygonIndex; + + reader->first = 1; +} + +static int ZDReaderGetPoint(struct Reader *reader, int32_t *pointLat, int32_t *pointLon) +{ + int32_t diffLat = 0, diffLon = 0; + +readNewPoint: + if(reader->done > 1) { + return 0; + } + + if(reader->first && reader->library->version == 0) { + if(!ZDDecodeVariableLengthUnsigned(reader->library, &reader->polygonIndex, &reader->numVertices)) return -1; + if(!reader->numVertices) return -1; + } + + uint8_t referenceDone = 0; + + if(reader->library->version == 1) { + uint64_t point = 0; + + if(!reader->referenceDirection) { + if(!ZDDecodeVariableLengthUnsigned(reader->library, &reader->polygonIndex, &point)) return -1; + } else { + if(reader->referenceDirection > 0) { + /* Read reference forward */ + if(!ZDDecodeVariableLengthUnsigned(reader->library, &reader->referenceStart, &point)) return -1; + if(reader->referenceStart >= reader->referenceEnd) { + referenceDone = 1; + } + } else if(reader->referenceDirection < 0) { + /* Read reference backwards */ + if(!ZDDecodeVariableLengthUnsignedReverse(reader->library, &reader->referenceStart, &point)) return -1; + if(reader->referenceStart <= reader->referenceEnd) { + referenceDone = 1; + } + } + } + + if(!point) { + /* This is a special marker, it is not allowed in reference mode */ + if(reader->referenceDirection) { + return -1; + } + + uint64_t value; + if(!ZDDecodeVariableLengthUnsigned(reader->library, &reader->polygonIndex, &value)) return -1; + + if(value == 0) { + reader->done = 2; + } else if(value == 1) { + int32_t diff; + int64_t start; + if(!ZDDecodeVariableLengthUnsigned(reader->library, &reader->polygonIndex, (uint64_t*)&start)) return -1; + if(!ZDDecodeVariableLengthSigned(reader->library, &reader->polygonIndex, &diff)) return -1; + + reader->referenceStart = reader->library->dataOffset+(uint32_t)start; + reader->referenceEnd = reader->library->dataOffset+(uint32_t)(start + diff); + reader->referenceDirection = diff; + if(diff < 0) { + reader->referenceStart--; + reader->referenceEnd--; + } + goto readNewPoint; } } else { - /* The polygons should be closed, but just in case */ - pointLat = firstLat; - pointLon = firstLon; + ZDDecodePoint(point, &diffLat, &diffLon); + if(reader->referenceDirection < 0) { + diffLat = -diffLat; + diffLon = -diffLon; + } + } + } + + if(reader->library->version == 0) { + if(!ZDDecodeVariableLengthSigned(reader->library, &reader->polygonIndex, &diffLat)) return -1; + if(!ZDDecodeVariableLengthSigned(reader->library, &reader->polygonIndex, &diffLon)) return -1; + } + + if(!reader->done) { + reader->pointLat += diffLat; + reader->pointLon += diffLon; + if(reader->first) { + reader->firstLat = reader->pointLat; + reader->firstLon = reader->pointLon; + } + } else { + /* Close the polygon (the closing point is not encoded) */ + reader->pointLat = reader->firstLat; + reader->pointLon = reader->firstLon; + reader->done = 2; + } + + reader->first = 0; + + if(reader->library->version == 0) { + reader->numVertices--; + if(!reader->numVertices) { + reader->done = 1; + } + if(!diffLat && !diffLon) { + goto readNewPoint; + } + } + + if(referenceDone) { + reader->referenceDirection = 0; + } + + if(pointLat) { + *pointLat = reader->pointLat; + } + + if(pointLon) { + *pointLon = reader->pointLon; + } + + return 1; +} + +static int ZDFindPolygon(const ZoneDetect *library, uint32_t wantedId, uint32_t* metadataIndexPtr, uint32_t* polygonIndexPtr) +{ + uint32_t polygonId = 0; + uint32_t bboxIndex = library->bboxOffset; + + uint32_t metadataIndex = 0, polygonIndex = 0; + + while(bboxIndex < library->metadataOffset) { + uint64_t polygonIndexDelta; + int32_t metadataIndexDelta; + int32_t tmp; + if(!ZDDecodeVariableLengthSigned(library, &bboxIndex, &tmp)) break; + if(!ZDDecodeVariableLengthSigned(library, &bboxIndex, &tmp)) break; + if(!ZDDecodeVariableLengthSigned(library, &bboxIndex, &tmp)) break; + if(!ZDDecodeVariableLengthSigned(library, &bboxIndex, &tmp)) break; + if(!ZDDecodeVariableLengthSigned(library, &bboxIndex, &metadataIndexDelta)) break; + if(!ZDDecodeVariableLengthUnsigned(library, &bboxIndex, &polygonIndexDelta)) break; + + metadataIndex += (uint32_t)metadataIndexDelta; + polygonIndex += (uint32_t)polygonIndexDelta; + + if(polygonId == wantedId) { + if(metadataIndexPtr) { + metadataIndex += library->metadataOffset; + *metadataIndexPtr = metadataIndex; + } + if(polygonIndexPtr) { + polygonIndex += library->dataOffset; + *polygonIndexPtr = polygonIndex; + } + return 1; + } + + polygonId ++; + } + + return 0; +} + +static int32_t* ZDPolygonToListInternal(const ZoneDetect *library, uint32_t polygonIndex, size_t* length) +{ + struct Reader reader; + ZDReaderInit(&reader, library, polygonIndex); + + size_t listLength = 2 * 100; + size_t listIndex = 0; + + int32_t* list = malloc(sizeof(int32_t) * listLength); + if(!list) { + goto fail; + } + + while(1) { + int32_t pointLat, pointLon; + int result = ZDReaderGetPoint(&reader, &pointLat, &pointLon); + if(result < 0) { + goto fail; + } else if(result == 0) { + break; + } + + if(listIndex >= listLength) { + listLength *= 2; + if(listLength >= 1048576) { + goto fail; + } + + list = realloc(list, sizeof(int32_t) * listLength); + if(!list) { + goto fail; + } + } + + list[listIndex++] = pointLat; + list[listIndex++] = pointLon; + } + + if(length) { + *length = listIndex; + } + + return list; + +fail: + if(list) { + free(list); + } + return NULL; +} + +float* ZDPolygonToList(const ZoneDetect *library, uint32_t polygonId, size_t* lengthPtr) +{ + uint32_t polygonIndex; + int32_t* data = NULL; + float* flData = NULL; + + if(!ZDFindPolygon(library, polygonId, NULL, &polygonIndex)) { + goto fail; + } + + size_t length = 0; + data = ZDPolygonToListInternal(library, polygonIndex, &length); + + if(!data) { + goto fail; + } + + flData = malloc(sizeof(float) * length); + if(!flData) { + goto fail; + } + + for(size_t i = 0; iprecision); + flData[i+1] = ZDFixedPointToFloat(lon, 180, library->precision); + } + + if(lengthPtr) { + *lengthPtr = length; + } + + return flData; + +fail: + if(data) { + free(data); + } + if(flData) { + free(flData); + } + return NULL; +} + +static ZDLookupResult ZDPointInPolygon(const ZoneDetect *library, uint32_t polygonIndex, int32_t latFixedPoint, int32_t lonFixedPoint, uint64_t *distanceSqrMin) +{ + int32_t pointLat, pointLon, prevLat = 0, prevLon = 0; + int prevQuadrant = 0, winding = 0; + + uint8_t first = 1; + + struct Reader reader; + ZDReaderInit(&reader, library, polygonIndex); + + while(1) { + int result = ZDReaderGetPoint(&reader, &pointLat, &pointLon); + if(result < 0) { + return ZD_LOOKUP_PARSE_ERROR; + } else if(result == 0) { + break; } /* Check if point is ON the border */ @@ -323,7 +666,7 @@ static ZDLookupResult ZDPointInPolygon(const ZoneDetect *library, uint32_t polyg } } - if(i > 0) { + if(!first) { int windingNeedCompare = 0, lineIsStraight = 0; float a = 0, b = 0; @@ -349,16 +692,17 @@ static ZDLookupResult ZDPointInPolygon(const ZoneDetect *library, uint32_t polyg b = (float)pointLat - a * (float)pointLon; } + int onStraight = ZDPointInBox(pointLat, latFixedPoint, prevLat, pointLon, lonFixedPoint, prevLon); + if(lineIsStraight && (onStraight || windingNeedCompare)) { + if(distanceSqrMin) *distanceSqrMin = 0; + return ZD_LOOKUP_ON_BORDER_SEGMENT; + } + /* Jumped two quadrants. */ if(windingNeedCompare) { - if(lineIsStraight) { - if(distanceSqrMin) *distanceSqrMin = 0; - return ZD_LOOKUP_ON_BORDER_SEGMENT; - } - /* Check if the target is on the border */ const int32_t intersectLon = (int32_t)(((float)latFixedPoint - b) / a); - if(intersectLon == lonFixedPoint) { + if(intersectLon >= lonFixedPoint-1 && intersectLon <= lonFixedPoint+1) { if(distanceSqrMin) *distanceSqrMin = 0; return ZD_LOOKUP_ON_BORDER_SEGMENT; } @@ -413,7 +757,8 @@ static ZDLookupResult ZDPointInPolygon(const ZoneDetect *library, uint32_t polyg prevQuadrant = quadrant; prevLat = pointLat; prevLon = pointLon; - } + first = 0; + }; if(winding == -4) { return ZD_LOOKUP_IN_ZONE; @@ -443,19 +788,51 @@ void ZDCloseDatabase(ZoneDetect *library) free(library->notice); } + if(library->closeType == 0) { #if defined(_MSC_VER) || defined(__MINGW32__) - if(!UnmapViewOfFile(library->mapping)) zdError(ZD_E_DB_MUNMAP_MSVIEW, (int)GetLastError()); - if(!CloseHandle(library->fdMap)) zdError(ZD_E_DB_MUNMAP , (int)GetLastError()); - if(!CloseHandle(library->fd)) zdError(ZD_E_DB_CLOSE , (int)GetLastError()); + if(library->mapping && !UnmapViewOfFile(library->mapping)) zdError(ZD_E_DB_MUNMAP_MSVIEW, (int)GetLastError()); + if(library->fdMap && !CloseHandle(library->fdMap)) zdError(ZD_E_DB_MUNMAP, (int)GetLastError()); + if(library->fd && !CloseHandle(library->fd)) zdError(ZD_E_DB_CLOSE, (int)GetLastError()); #else - if(library->mapping && munmap(library->mapping, (size_t)(library->length))) zdError(ZD_E_DB_MUNMAP, errno); - if(library->fd >= 0 && close(library->fd)) zdError(ZD_E_DB_CLOSE , errno); + if(library->mapping && munmap(library->mapping, (size_t)(library->length))) zdError(ZD_E_DB_MUNMAP, errno); + if(library->fd >= 0 && close(library->fd)) zdError(ZD_E_DB_CLOSE, errno); #endif + } free(library); } } +ZoneDetect *ZDOpenDatabaseFromMemory(void* buffer, size_t length) +{ + ZoneDetect *const library = malloc(sizeof *library); + + if(library) { + memset(library, 0, sizeof(*library)); + library->closeType = 1; + library->length = (long int)length; + + if(library->length <= 0) { + zdError(ZD_E_DB_SEEK, errno); + goto fail; + } + + library->mapping = buffer; + + /* Parse the header */ + if(ZDParseHeader(library)) { + zdError(ZD_E_PARSE_HEADER, 0); + goto fail; + } + } + + return library; + +fail: + ZDCloseDatabase(library); + return NULL; +} + ZoneDetect *ZDOpenDatabase(const char *path) { ZoneDetect *const library = malloc(sizeof *library); @@ -496,14 +873,14 @@ ZoneDetect *ZDOpenDatabase(const char *path) } library->length = lseek(library->fd, 0, SEEK_END); - if(library->length <= 0) { + if(library->length <= 0 || library->length > 50331648) { zdError(ZD_E_DB_SEEK, errno); goto fail; } lseek(library->fd, 0, SEEK_SET); library->mapping = mmap(NULL, (size_t)library->length, PROT_READ, MAP_PRIVATE | MAP_FILE, library->fd, 0); - if(!library->mapping) { + if(library->mapping == MAP_FAILED) { zdError(ZD_E_DB_MMAP, errno); goto fail; } @@ -540,9 +917,11 @@ ZoneDetectResult *ZDLookup(const ZoneDetect *library, float lat, float lon, floa return NULL; } + uint32_t polygonId = 0; + while(bboxIndex < library->metadataOffset) { int32_t minLat, minLon, maxLat, maxLon, metadataIndexDelta; - uint32_t polygonIndexDelta; + uint64_t polygonIndexDelta; if(!ZDDecodeVariableLengthSigned(library, &bboxIndex, &minLat)) break; if(!ZDDecodeVariableLengthSigned(library, &bboxIndex, &minLon)) break; if(!ZDDecodeVariableLengthSigned(library, &bboxIndex, &maxLat)) break; @@ -551,17 +930,13 @@ ZoneDetectResult *ZDLookup(const ZoneDetect *library, float lat, float lon, floa if(!ZDDecodeVariableLengthUnsigned(library, &bboxIndex, &polygonIndexDelta)) break; metadataIndex += (uint32_t)metadataIndexDelta; - polygonIndex += polygonIndexDelta; + polygonIndex += (uint32_t)polygonIndexDelta; if(latFixedPoint >= minLat) { if(latFixedPoint <= maxLat && lonFixedPoint >= minLon && lonFixedPoint <= maxLon) { - /* Indices valid? */ - if(library->metadataOffset + metadataIndex >= library->dataOffset) continue; - if(library->dataOffset + polygonIndex >= (uint32_t)library->length) continue; - const ZDLookupResult lookupResult = ZDPointInPolygon(library, library->dataOffset + polygonIndex, latFixedPoint, lonFixedPoint, (safezone) ? &distanceSqrMin : NULL); if(lookupResult == ZD_LOOKUP_PARSE_ERROR) { break; @@ -570,6 +945,7 @@ ZoneDetectResult *ZDLookup(const ZoneDetect *library, float lat, float lon, floa if(newResults) { results = newResults; + results[numResults].polygonId = polygonId; results[numResults].metaId = metadataIndex; results[numResults].numFields = library->numFields; results[numResults].fieldNames = library->fieldNames; @@ -585,6 +961,8 @@ ZoneDetectResult *ZDLookup(const ZoneDetect *library, float lat, float lon, floa /* The data is sorted along minLat */ break; } + + polygonId++; } /* Clean up results */ @@ -713,19 +1091,30 @@ const char *ZDLookupResultToString(ZDLookupResult result) const char *ZDGetErrorString(int errZD) { switch ((enum ZDInternalError)errZD) { - default: assert(0); - case ZD_OK : return ""; - case ZD_E_DB_OPEN : return ZD_E_COULD_NOT("open database file"); - case ZD_E_DB_SEEK : return ZD_E_COULD_NOT("retrieve database file size"); - case ZD_E_DB_MMAP : return ZD_E_COULD_NOT("map database file to system memory"); + default: + assert(0); + case ZD_OK : + return ""; + case ZD_E_DB_OPEN : + return ZD_E_COULD_NOT("open database file"); + case ZD_E_DB_SEEK : + return ZD_E_COULD_NOT("retrieve database file size"); + case ZD_E_DB_MMAP : + return ZD_E_COULD_NOT("map database file to system memory"); #if defined(_MSC_VER) || defined(__MINGW32__) - case ZD_E_DB_MMAP_MSVIEW : return ZD_E_COULD_NOT("open database file view"); - case ZD_E_DB_MAP_EXCEPTION: return "I/O exception occurred while accessing database file view"; - case ZD_E_DB_MUNMAP_MSVIEW: return ZD_E_COULD_NOT("close database file view"); + case ZD_E_DB_MMAP_MSVIEW : + return ZD_E_COULD_NOT("open database file view"); + case ZD_E_DB_MAP_EXCEPTION: + return "I/O exception occurred while accessing database file view"; + case ZD_E_DB_MUNMAP_MSVIEW: + return ZD_E_COULD_NOT("close database file view"); #endif - case ZD_E_DB_MUNMAP : return ZD_E_COULD_NOT("unmap database"); - case ZD_E_DB_CLOSE : return ZD_E_COULD_NOT("close database file"); - case ZD_E_PARSE_HEADER : return ZD_E_COULD_NOT("parse database header"); + case ZD_E_DB_MUNMAP : + return ZD_E_COULD_NOT("unmap database"); + case ZD_E_DB_CLOSE : + return ZD_E_COULD_NOT("close database file"); + case ZD_E_PARSE_HEADER : + return ZD_E_COULD_NOT("parse database header"); } } @@ -736,3 +1125,66 @@ int ZDSetErrorHandler(void (*handler)(int, int)) zdErrorHandler = handler; return 0; } + +char* ZDHelperSimpleLookupString(const ZoneDetect* library, float lat, float lon) +{ + ZoneDetectResult *result = ZDLookup(library, lat, lon, NULL); + if(!result) { + return NULL; + } + + char* output = NULL; + + if(result[0].lookupResult == ZD_LOOKUP_END) { + goto done; + } + + char* strings[2] = {NULL}; + + for(unsigned int i = 0; i < result[0].numFields; i++) { + if(result[0].fieldNames[i] && result[0].data[i]) { + if(library->tableType == 'T') { + if(!strcmp(result[0].fieldNames[i], "TimezoneIdPrefix")) { + strings[0] = result[0].data[i]; + } + if(!strcmp(result[0].fieldNames[i], "TimezoneId")) { + strings[1] = result[0].data[i]; + } + } + if(library->tableType == 'C') { + if(!strcmp(result[0].fieldNames[i], "Name")) { + strings[0] = result[0].data[i]; + } + } + } + } + + size_t length = 0; + for(unsigned int i=0; i 512) { + goto done; + } + length += partLength; + } + } + + if(length == 0) { + goto done; + } + + length += 1; + + output = (char*)malloc(length); + output[0] = 0; + for(unsigned int i=0; i