From e86e793fc643c6c1b53035862c9aa9caaebe1d68 Mon Sep 17 00:00:00 2001 From: Colin Clark Date: Tue, 11 Jan 2022 10:21:47 +0000 Subject: [PATCH] Revise timezone function - Download database file from the web, instead of compiling locally - Update zonedetect.c --- CHECKLIST.md | 8 - geeqie-install-debian.sh | 2 +- scripts/zonedetect/builder.cpp | 566 ------------------ .../zonedetect/create_timezone_database.sh | 97 --- scripts/zonedetect/zoneToAlpha.h | 425 ------------- src/exif-common.c | 14 +- src/main.h | 5 +- src/preferences.c | 55 +- src/zonedetect.c | 117 +++- 9 files changed, 142 insertions(+), 1147 deletions(-) delete mode 100644 scripts/zonedetect/builder.cpp delete mode 100755 scripts/zonedetect/create_timezone_database.sh delete mode 100644 scripts/zonedetect/zoneToAlpha.h diff --git a/CHECKLIST.md b/CHECKLIST.md index ab7cb4c2..cb76f478 100644 --- a/CHECKLIST.md +++ b/CHECKLIST.md @@ -24,14 +24,6 @@ make update-po ./scripts/template-desktop.sh ``` -* Update the the timezone database if the underlying database has changed significantly - -```sh -./scripts/zonedetect/create_timezone_database -``` - -* Upload the timezone database to TBD - ## After compiling the sources, carry out the following actions when necessary * Update the man page and Command Line Options section in Help if the command line options have changed diff --git a/geeqie-install-debian.sh b/geeqie-install-debian.sh index 900929cb..0499c56d 100755 --- a/geeqie-install-debian.sh +++ b/geeqie-install-debian.sh @@ -81,7 +81,7 @@ optional_array=( "libraw-dev" "libomp (required by libraw)" "libomp-dev" -"libarchive (for compressed files e.g. zip)" +"libarchive (for compressed files e.g. zip, including timezone)" "libarchive-dev" ) diff --git a/scripts/zonedetect/builder.cpp b/scripts/zonedetect/builder.cpp deleted file mode 100644 index af6e65e1..00000000 --- a/scripts/zonedetect/builder.cpp +++ /dev/null @@ -1,566 +0,0 @@ -/* - * Copyright (c) 2018, Bertold Van den Bergh (vandenbergh@bertold.org) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the author nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTOR BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -const double Inf = std::numeric_limits::infinity(); - -std::unordered_map alpha2ToName; -std::unordered_map tzidToAlpha2; - -void errorFatal(std::string what) -{ - std::cerr<& output, int64_t valueIn, bool handleNeg = true) -{ - uint64_t value = valueIn * 2; - if(valueIn < 0) { - value = -valueIn * 2 + 1; - } - - if(!handleNeg) { - value = valueIn; - } - - int bytesUsed = 0; - do { - uint8_t byteOut = value & 0x7F; - if(value >= 128) { - byteOut |= 0x80; - } - output.push_back(byteOut); - bytesUsed ++; - value >>= 7; - } while(value); - - return bytesUsed; -} - -int64_t doubleToFixedPoint(double input, double scale, unsigned int precision = 32) -{ - double inputScaled = input / scale; - return inputScaled * pow(2, precision-1); - -} - -struct Point { - Point(double lat = 0, double lon = 0) - { - lat_ = lat; - lon_ = lon; - } - - Point operator-(const Point& p) - { - Point result(lat_ - p.lat_, lon_ - p.lon_); - return result; - } - - std::tuple toFixedPoint(unsigned int precision = 32) - { - int64_t latFixedPoint = doubleToFixedPoint(lat_, 90, precision); - int64_t lonFixedPoint = doubleToFixedPoint(lon_, 180, precision); - - return std::make_tuple(latFixedPoint, lonFixedPoint); - } - - int encodePointBinary(std::vector& output, unsigned int precision = 32) - { - int64_t latFixedPoint, lonFixedPoint; - std::tie(latFixedPoint, lonFixedPoint) = toFixedPoint(precision); - - int bytesUsed = encodeVariableLength(output, latFixedPoint); - bytesUsed += encodeVariableLength(output, lonFixedPoint); - - return bytesUsed; - } - - double lat_; - double lon_; -}; - -struct PolygonData { - Point boundingMin; - Point boundingMax; - std::vector points_; - unsigned long fileIndex_ = 0; - unsigned long metadataId_; - - void processPoint(const Point& p) - { - if(p.lat_ < boundingMin.lat_) { - boundingMin.lat_ = p.lat_; - } - if(p.lon_ < boundingMin.lon_) { - boundingMin.lon_ = p.lon_; - } - if(p.lat_ > boundingMax.lat_) { - boundingMax.lat_ = p.lat_; - } - if(p.lon_ > boundingMax.lon_) { - boundingMax.lon_ = p.lon_; - } - - points_.push_back(p); - } - - PolygonData(unsigned long id): - boundingMin(Inf, Inf), - boundingMax(-Inf, -Inf), - metadataId_(id) - { - } - - long encodeBinaryData(std::vector& output, unsigned int precision = 20) - { - long bytesEncoded = 0; - bool first = true; - int64_t latFixedPoint = 0, lonFixedPoint = 0; - int64_t latFixedPointPrev, lonFixedPointPrev; - uint64_t vertices = 0; - - std::vector tmp; - - int64_t diffLatAcc = 0, diffLonAcc = 0, diffLatPrev = 0, diffLonPrev = 0; - - for(Point& point: points_) { - /* The points should first be rounded, and then the integer value is differentiated */ - latFixedPointPrev = latFixedPoint; - lonFixedPointPrev = lonFixedPoint; - std::tie(latFixedPoint, lonFixedPoint) = point.toFixedPoint(precision); - - int64_t diffLat = latFixedPoint - latFixedPointPrev; - int64_t diffLon = lonFixedPoint - lonFixedPointPrev; - - if(first) { - /* First point is always encoded */ - vertices++; - encodeVariableLength(tmp, latFixedPoint); - encodeVariableLength(tmp, lonFixedPoint); - first = false; - } else { - /* Ignore points that are not different */ - if(!diffLon && !diffLat) { - continue; - } - - if(diffLat != diffLatPrev || diffLon != diffLonPrev) { - /* Encode accumulator */ - vertices++; - encodeVariableLength(tmp, diffLatAcc); - encodeVariableLength(tmp, diffLonAcc); - - diffLatAcc = 0; - diffLonAcc = 0; - } - - diffLatAcc += diffLat; - diffLonAcc += diffLon; - } - - diffLatPrev = diffLat; - diffLonPrev = diffLon; - } - - /* Encode final point */ - vertices++; - encodeVariableLength(tmp, diffLatAcc); - encodeVariableLength(tmp, diffLonAcc); - - encodeVariableLength(output, vertices, false); - std::copy(tmp.begin(), tmp.end(), std::back_inserter(output)); - - return bytesEncoded; - } -}; - -void encodeStringToBinary(std::vector& output, std::string& input) -{ - encodeVariableLength(output, input.size(), false); - for(unsigned int i=0; i usedStrings_; - -struct MetaData { - void encodeBinaryData(std::vector& output) - { - for(std::string& str: data_) { - if(str.length() >= 256) { - std::cout << "Metadata string is too long\n"; - exit(1); - } - - if(!usedStrings_.count(str)) { - usedStrings_[str] = output.size(); - encodeStringToBinary(output, str); - } else { - encodeVariableLength(output, usedStrings_[str] + 256, false); - } - } - } - - std::vector data_; - - unsigned long fileIndex_; -}; - - -std::vector polygons_; -std::vector metadata_; -std::vector fieldNames_; - - -unsigned int decodeVariableLength(uint8_t* buffer, int64_t* result, bool handleNeg = true) -{ - int64_t value = 0; - unsigned int i=0, shift = 0; - - do { - value |= (buffer[i] & 0x7F) << shift; - shift += 7; - } while(buffer[i++] & 0x80); - - if(!handleNeg) { - *result = value; - } else { - *result = (value & 1)?-(value/2):(value/2); - } - return i; -} - -void readMetaDataTimezone(DBFHandle dataHandle) -{ - /* Specify field names */ - fieldNames_.push_back("TimezoneIdPrefix"); - fieldNames_.push_back("TimezoneId"); - fieldNames_.push_back("CountryAlpha2"); - fieldNames_.push_back("CountryName"); - - /* Parse attribute names */ - for(int i = 0; i < DBFGetRecordCount(dataHandle); i++) { - metadata_[i].data_.resize(4); - for(int j = 0; j < DBFGetFieldCount(dataHandle); j++) { - char fieldTitle[12]; - int fieldWidth, fieldDecimals; - DBFFieldType eType = DBFGetFieldInfo(dataHandle, j, fieldTitle, &fieldWidth, &fieldDecimals); - - fieldTitle[11] = 0; - std::string fieldTitleStr(fieldTitle); - - if( eType == FTString ) { - if(fieldTitleStr == "tzid") { - std::string data = DBFReadStringAttribute(dataHandle, i, j); - size_t pos = data.find('/'); - if (pos == std::string::npos) { - metadata_[i].data_.at(0) = data; - } else { - metadata_[i].data_.at(0) = data.substr(0, pos) + "/"; - metadata_[i].data_.at(1) = data.substr(pos + 1, std::string::npos); - } - if(tzidToAlpha2.count(data)) { - metadata_[i].data_.at(2) = tzidToAlpha2[data]; - if(alpha2ToName.count(metadata_[i].data_.at(2))) { - metadata_[i].data_.at(3) = alpha2ToName[metadata_[i].data_.at(2)]; - } else { - std::cout< parseAlpha2ToName(DBFHandle dataHandle) -{ - std::unordered_map result; - - for(int i = 0; i < DBFGetRecordCount(dataHandle); i++) { - std::string alpha2, name; - for(int j = 0; j < DBFGetFieldCount(dataHandle); j++) { - char fieldTitle[12]; - int fieldWidth, fieldDecimals; - DBFFieldType eType = DBFGetFieldInfo(dataHandle, j, fieldTitle, &fieldWidth, &fieldDecimals); - - fieldTitle[11] = 0; - std::string fieldTitleStr(fieldTitle); - - if( eType == FTString ) { - if(fieldTitleStr == "ISO_A2" || fieldTitleStr == "WB_A2") { - std::string tmp = DBFReadStringAttribute(dataHandle, i, j); - if(tmp != "-99" && alpha2 == "") { - alpha2 = tmp; - } - } else if(fieldTitleStr == "NAME_LONG") { - name = DBFReadStringAttribute(dataHandle, i, j); - } - } - } - if(alpha2 != "") { - result[alpha2]=name; - } - } - - result["GF"]="French Guiana"; - result["GP"]="Guadeloupe"; - result["BQ"]="Bonaire"; - result["MQ"]="Martinique"; - result["SJ"]="Svalbard and Jan Mayen Islands"; - result["NO"]="Norway"; - result["CX"]="Christmas Island"; - result["CC"]="Cocos Islands"; - result["YT"]="Mayotte"; - result["RE"]="Réunion"; - result["TK"]="Tokelau"; - - return result; -} - -std::unordered_map parseTimezoneToAlpha2(std::string path) -{ - std::unordered_map result; - //TODO: Clean solution... -#include "zoneToAlpha.h" - - return result; -} - -int main(int argc, char ** argv ) -{ - if(argc != 6) { - std::cout << "Wrong number of parameters\n"; - return 1; - } - - tzidToAlpha2 = parseTimezoneToAlpha2("TODO"); - - char tableType = argv[1][0]; - std::string path = argv[2]; - std::string outPath = argv[3]; - unsigned int precision = strtol(argv[4], NULL, 10); - std::string notice = argv[5]; - - DBFHandle dataHandle = DBFOpen("naturalearth/ne_10m_admin_0_countries_lakes", "rb" ); - alpha2ToName = parseAlpha2ToName(dataHandle); - DBFClose(dataHandle); - - dataHandle = DBFOpen(path.c_str(), "rb" ); - if( dataHandle == NULL ) { - errorFatal("Could not open attribute file\n"); - } - - metadata_.resize(DBFGetRecordCount(dataHandle)); - std::cout << "Reading "<nSHPType != 3 && shapeObject->nSHPType != 5 && - shapeObject->nSHPType != 13 && shapeObject->nSHPType != 15) { - std::cout<<"Unsupported shape object ("<< SHPTypeName(shapeObject->nSHPType) <<")\n"; - continue; - } - - int partIndex = 0; - - PolygonData* polygonData = nullptr; - - for(int j = 0; j < shapeObject->nVertices; j++ ) { - if(j == 0 || j == shapeObject->panPartStart[partIndex]) { - totalPolygons++; - - if(polygonData) { - /* Commit it */ - polygons_.push_back(polygonData); - } - polygonData = new PolygonData(i); - - if(partIndex + 1 < shapeObject->nParts) { - partIndex++; - } - } - - Point p(shapeObject->padfY[j], shapeObject->padfX[j]); - polygonData->processPoint(p); - - } - - if(polygonData) { - /* Commit it */ - polygons_.push_back(polygonData); - } - - SHPDestroyObject(shapeObject); - } - } - - SHPClose(shapeHandle); - - std::cout<<"Parsed "<boundingMin.lat_ < b->boundingMin.lat_; - }); - - /* Encode data section and store pointers */ - std::vector outputData; - for(PolygonData* polygon: polygons_) { - polygon->fileIndex_ = outputData.size(); - polygon->encodeBinaryData(outputData, precision); - } - std::cout << "Encoded data section into "< outputMeta; - for(MetaData& metadata: metadata_) { - metadata.fileIndex_ = outputMeta.size(); - metadata.encodeBinaryData(outputMeta); - } - std::cout << "Encoded metadata into "< outputBBox; - int64_t prevFileIndex = 0; - int64_t prevMetaIndex = 0; - for(PolygonData* polygon: polygons_) { - polygon->boundingMin.encodePointBinary(outputBBox, precision); - polygon->boundingMax.encodePointBinary(outputBBox, precision); - - encodeVariableLength(outputBBox, metadata_.at(polygon->metadataId_).fileIndex_ - prevMetaIndex); - prevMetaIndex = metadata_[polygon->metadataId_].fileIndex_; - - encodeVariableLength(outputBBox, polygon->fileIndex_ - prevFileIndex, false); - prevFileIndex = polygon->fileIndex_; - } - std::cout << "Encoded bounding box section into "< outputHeader; - outputHeader.push_back('P'); - outputHeader.push_back('L'); - outputHeader.push_back('B'); - outputHeader.push_back(tableType); - outputHeader.push_back(0); - outputHeader.push_back(precision); - outputHeader.push_back(fieldNames_.size()); - for(unsigned int i=0; i "timezone_boundary_builder_release.txt" -else - exit -fi - -rm -rf naturalearth -rm -rf timezone -rm -rf geeqie_org -rm -f timezone21.bin - -g++ builder.cpp -o builder -lshp - -mkdir naturalearth -cd naturalearth -wget https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_admin_0_countries_lakes.zip -if [ "$?" -ne 0 ] -then - zenity --error --text="Download of naturalearthdata failed" --title="Generate Geeqie timezone database" --width=300 --window-icon="$current_dir/../../geeqie.png" - exit -fi - -unzip ne_10m_admin_0_countries_lakes.zip -cd .. - -mkdir timezone -cd timezone -wget "https://github.com/evansiroky/timezone-boundary-builder/releases/download/$timezone_boundary_builder_release/timezones.shapefile.zip" -if [ "$?" -ne 0 ] -then - zenity --error --text="Download of timezone-boundary-builder failed" --title="Generate Geeqie timezone database" --width=300 --window-icon="$current_dir/../../geeqie.png" - exit -fi - -unzip timezones.shapefile.zip -cd .. - - -./builder T timezone/dist/combined-shapefile timezone21.bin 21 "Contains data from Natural Earth, placed in the Public Domain. Contains information from https://github.com/evansiroky/timezone-boundary-builder, which is made available here under the Open Database License (ODbL)." - -mkdir geeqie_org -cd geeqie_org -wget http://www.geeqie.org/downloads/timezone21.bin -if [ "$?" -ne 0 ] -then - zenity --error --text="Download of timezone database from geeqie.org failed" --title="Generate Geeqie timezone database" --width=300 --window-icon="$current_dir/../../geeqie.png" - exit -fi -cd .. - -diff ./geeqie_org/timezone21.bin timezone21.bin - -if [ "$?" -ne 0 ] -then - zenity --info --title="Generate Geeqie timezone database" --text="Generated file differs from that on geeqie.org\n\nUpload timezone21.bin to:\ngeeqie.org/downloads/" --width=300 --window-icon="$current_dir/../../geeqie.png" -else - zenity --info --title="Generate Geeqie timezone database" --text="Generated file is the same as on geeqie.org" --width=300 --window-icon="$current_dir/../../geeqie.png" - rm timezone21.bin -fi - -rm -f builder -rm -rf naturalearth -rm -rf timezone -rm -rf geeqie_org diff --git a/scripts/zonedetect/zoneToAlpha.h b/scripts/zonedetect/zoneToAlpha.h deleted file mode 100644 index aba55aa2..00000000 --- a/scripts/zonedetect/zoneToAlpha.h +++ /dev/null @@ -1,425 +0,0 @@ -result["Europe/Andorra"] = "AD"; -result["Asia/Dubai"] = "AE"; -result["Asia/Kabul"] = "AF"; -result["America/Antigua"] = "AG"; -result["America/Anguilla"] = "AI"; -result["Europe/Tirane"] = "AL"; -result["Asia/Yerevan"] = "AM"; -result["Africa/Luanda"] = "AO"; -result["Antarctica/McMurdo"] = "AQ"; -result["Antarctica/Casey"] = "AQ"; -result["Antarctica/Davis"] = "AQ"; -result["Antarctica/DumontDUrville"] = "AQ"; -result["Antarctica/Mawson"] = "AQ"; -result["Antarctica/Palmer"] = "AQ"; -result["Antarctica/Rothera"] = "AQ"; -result["Antarctica/Syowa"] = "AQ"; -result["Antarctica/Troll"] = "AQ"; -result["Antarctica/Vostok"] = "AQ"; -result["America/Argentina/Buenos_Aires"] = "AR"; -result["America/Argentina/Cordoba"] = "AR"; -result["America/Argentina/Salta"] = "AR"; -result["America/Argentina/Jujuy"] = "AR"; -result["America/Argentina/Tucuman"] = "AR"; -result["America/Argentina/Catamarca"] = "AR"; -result["America/Argentina/La_Rioja"] = "AR"; -result["America/Argentina/San_Juan"] = "AR"; -result["America/Argentina/Mendoza"] = "AR"; -result["America/Argentina/San_Luis"] = "AR"; -result["America/Argentina/Rio_Gallegos"] = "AR"; -result["America/Argentina/Ushuaia"] = "AR"; -result["Pacific/Pago_Pago"] = "AS"; -result["Europe/Vienna"] = "AT"; -result["Australia/Lord_Howe"] = "AU"; -result["Antarctica/Macquarie"] = "AU"; -result["Australia/Hobart"] = "AU"; -result["Australia/Currie"] = "AU"; -result["Australia/Melbourne"] = "AU"; -result["Australia/Sydney"] = "AU"; -result["Australia/Broken_Hill"] = "AU"; -result["Australia/Brisbane"] = "AU"; -result["Australia/Lindeman"] = "AU"; -result["Australia/Adelaide"] = "AU"; -result["Australia/Darwin"] = "AU"; -result["Australia/Perth"] = "AU"; -result["Australia/Eucla"] = "AU"; -result["America/Aruba"] = "AW"; -result["Europe/Mariehamn"] = "AX"; -result["Asia/Baku"] = "AZ"; -result["Europe/Sarajevo"] = "BA"; -result["America/Barbados"] = "BB"; -result["Asia/Dhaka"] = "BD"; -result["Europe/Brussels"] = "BE"; -result["Africa/Ouagadougou"] = "BF"; -result["Europe/Sofia"] = "BG"; -result["Asia/Bahrain"] = "BH"; -result["Africa/Bujumbura"] = "BI"; -result["Africa/Porto-Novo"] = "BJ"; -result["America/St_Barthelemy"] = "BL"; -result["Atlantic/Bermuda"] = "BM"; -result["Asia/Brunei"] = "BN"; -result["America/La_Paz"] = "BO"; -result["America/Kralendijk"] = "BQ"; -result["America/Noronha"] = "BR"; -result["America/Belem"] = "BR"; -result["America/Fortaleza"] = "BR"; -result["America/Recife"] = "BR"; -result["America/Araguaina"] = "BR"; -result["America/Maceio"] = "BR"; -result["America/Bahia"] = "BR"; -result["America/Sao_Paulo"] = "BR"; -result["America/Campo_Grande"] = "BR"; -result["America/Cuiaba"] = "BR"; -result["America/Santarem"] = "BR"; -result["America/Porto_Velho"] = "BR"; -result["America/Boa_Vista"] = "BR"; -result["America/Manaus"] = "BR"; -result["America/Eirunepe"] = "BR"; -result["America/Rio_Branco"] = "BR"; -result["America/Nassau"] = "BS"; -result["Asia/Thimphu"] = "BT"; -result["Africa/Gaborone"] = "BW"; -result["Europe/Minsk"] = "BY"; -result["America/Belize"] = "BZ"; -result["America/St_Johns"] = "CA"; -result["America/Halifax"] = "CA"; -result["America/Glace_Bay"] = "CA"; -result["America/Moncton"] = "CA"; -result["America/Goose_Bay"] = "CA"; -result["America/Blanc-Sablon"] = "CA"; -result["America/Toronto"] = "CA"; -result["America/Nipigon"] = "CA"; -result["America/Thunder_Bay"] = "CA"; -result["America/Iqaluit"] = "CA"; -result["America/Pangnirtung"] = "CA"; -result["America/Atikokan"] = "CA"; -result["America/Winnipeg"] = "CA"; -result["America/Rainy_River"] = "CA"; -result["America/Resolute"] = "CA"; -result["America/Rankin_Inlet"] = "CA"; -result["America/Regina"] = "CA"; -result["America/Swift_Current"] = "CA"; -result["America/Edmonton"] = "CA"; -result["America/Cambridge_Bay"] = "CA"; -result["America/Yellowknife"] = "CA"; -result["America/Inuvik"] = "CA"; -result["America/Creston"] = "CA"; -result["America/Dawson_Creek"] = "CA"; -result["America/Fort_Nelson"] = "CA"; -result["America/Vancouver"] = "CA"; -result["America/Whitehorse"] = "CA"; -result["America/Dawson"] = "CA"; -result["Indian/Cocos"] = "CC"; -result["Africa/Kinshasa"] = "CD"; -result["Africa/Lubumbashi"] = "CD"; -result["Africa/Bangui"] = "CF"; -result["Africa/Brazzaville"] = "CG"; -result["Europe/Zurich"] = "CH"; -result["Africa/Abidjan"] = "CI"; -result["Pacific/Rarotonga"] = "CK"; -result["America/Santiago"] = "CL"; -result["America/Punta_Arenas"] = "CL"; -result["Pacific/Easter"] = "CL"; -result["Africa/Douala"] = "CM"; -result["Asia/Shanghai"] = "CN"; -result["Asia/Urumqi"] = "CN"; -result["America/Bogota"] = "CO"; -result["America/Costa_Rica"] = "CR"; -result["America/Havana"] = "CU"; -result["Atlantic/Cape_Verde"] = "CV"; -result["America/Curacao"] = "CW"; -result["Indian/Christmas"] = "CX"; -result["Asia/Nicosia"] = "CY"; -result["Asia/Famagusta"] = "CY"; -result["Europe/Prague"] = "CZ"; -result["Europe/Berlin"] = "DE"; -result["Europe/Busingen"] = "DE"; -result["Africa/Djibouti"] = "DJ"; -result["Europe/Copenhagen"] = "DK"; -result["America/Dominica"] = "DM"; -result["America/Santo_Domingo"] = "DO"; -result["Africa/Algiers"] = "DZ"; -result["America/Guayaquil"] = "EC"; -result["Pacific/Galapagos"] = "EC"; -result["Europe/Tallinn"] = "EE"; -result["Africa/Cairo"] = "EG"; -result["Africa/El_Aaiun"] = "EH"; -result["Africa/Asmara"] = "ER"; -result["Europe/Madrid"] = "ES"; -result["Africa/Ceuta"] = "ES"; -result["Atlantic/Canary"] = "ES"; -result["Africa/Addis_Ababa"] = "ET"; -result["Europe/Helsinki"] = "FI"; -result["Pacific/Fiji"] = "FJ"; -result["Atlantic/Stanley"] = "FK"; -result["Pacific/Chuuk"] = "FM"; -result["Pacific/Pohnpei"] = "FM"; -result["Pacific/Kosrae"] = "FM"; -result["Atlantic/Faroe"] = "FO"; -result["Europe/Paris"] = "FR"; -result["Africa/Libreville"] = "GA"; -result["Europe/London"] = "GB"; -result["America/Grenada"] = "GD"; -result["Asia/Tbilisi"] = "GE"; -result["America/Cayenne"] = "GF"; -result["Europe/Guernsey"] = "GG"; -result["Africa/Accra"] = "GH"; -result["Europe/Gibraltar"] = "GI"; -result["America/Godthab"] = "GL"; -result["America/Danmarkshavn"] = "GL"; -result["America/Scoresbysund"] = "GL"; -result["America/Thule"] = "GL"; -result["Africa/Banjul"] = "GM"; -result["Africa/Conakry"] = "GN"; -result["America/Guadeloupe"] = "GP"; -result["Africa/Malabo"] = "GQ"; -result["Europe/Athens"] = "GR"; -result["Atlantic/South_Georgia"] = "GS"; -result["America/Guatemala"] = "GT"; -result["Pacific/Guam"] = "GU"; -result["Africa/Bissau"] = "GW"; -result["America/Guyana"] = "GY"; -result["Asia/Hong_Kong"] = "HK"; -result["America/Tegucigalpa"] = "HN"; -result["Europe/Zagreb"] = "HR"; -result["America/Port-au-Prince"] = "HT"; -result["Europe/Budapest"] = "HU"; -result["Asia/Jakarta"] = "ID"; -result["Asia/Pontianak"] = "ID"; -result["Asia/Makassar"] = "ID"; -result["Asia/Jayapura"] = "ID"; -result["Europe/Dublin"] = "IE"; -result["Asia/Jerusalem"] = "IL"; -result["Europe/Isle_of_Man"] = "IM"; -result["Asia/Kolkata"] = "IN"; -result["Indian/Chagos"] = "IO"; -result["Asia/Baghdad"] = "IQ"; -result["Asia/Tehran"] = "IR"; -result["Atlantic/Reykjavik"] = "IS"; -result["Europe/Rome"] = "IT"; -result["Europe/Jersey"] = "JE"; -result["America/Jamaica"] = "JM"; -result["Asia/Amman"] = "JO"; -result["Asia/Tokyo"] = "JP"; -result["Africa/Nairobi"] = "KE"; -result["Asia/Bishkek"] = "KG"; -result["Asia/Phnom_Penh"] = "KH"; -result["Pacific/Tarawa"] = "KI"; -result["Pacific/Enderbury"] = "KI"; -result["Pacific/Kiritimati"] = "KI"; -result["Indian/Comoro"] = "KM"; -result["America/St_Kitts"] = "KN"; -result["Asia/Pyongyang"] = "KP"; -result["Asia/Seoul"] = "KR"; -result["Asia/Kuwait"] = "KW"; -result["America/Cayman"] = "KY"; -result["Asia/Almaty"] = "KZ"; -result["Asia/Qyzylorda"] = "KZ"; -result["Asia/Aqtobe"] = "KZ"; -result["Asia/Aqtau"] = "KZ"; -result["Asia/Atyrau"] = "KZ"; -result["Asia/Oral"] = "KZ"; -result["Asia/Vientiane"] = "LA"; -result["Asia/Beirut"] = "LB"; -result["America/St_Lucia"] = "LC"; -result["Europe/Vaduz"] = "LI"; -result["Asia/Colombo"] = "LK"; -result["Africa/Monrovia"] = "LR"; -result["Africa/Maseru"] = "LS"; -result["Europe/Vilnius"] = "LT"; -result["Europe/Luxembourg"] = "LU"; -result["Europe/Riga"] = "LV"; -result["Africa/Tripoli"] = "LY"; -result["Africa/Casablanca"] = "MA"; -result["Europe/Monaco"] = "MC"; -result["Europe/Chisinau"] = "MD"; -result["Europe/Podgorica"] = "ME"; -result["America/Marigot"] = "MF"; -result["Indian/Antananarivo"] = "MG"; -result["Pacific/Majuro"] = "MH"; -result["Pacific/Kwajalein"] = "MH"; -result["Europe/Skopje"] = "MK"; -result["Africa/Bamako"] = "ML"; -result["Asia/Yangon"] = "MM"; -result["Asia/Ulaanbaatar"] = "MN"; -result["Asia/Hovd"] = "MN"; -result["Asia/Choibalsan"] = "MN"; -result["Asia/Macau"] = "MO"; -result["Pacific/Saipan"] = "MP"; -result["America/Martinique"] = "MQ"; -result["Africa/Nouakchott"] = "MR"; -result["America/Montserrat"] = "MS"; -result["Europe/Malta"] = "MT"; -result["Indian/Mauritius"] = "MU"; -result["Indian/Maldives"] = "MV"; -result["Africa/Blantyre"] = "MW"; -result["America/Mexico_City"] = "MX"; -result["America/Cancun"] = "MX"; -result["America/Merida"] = "MX"; -result["America/Monterrey"] = "MX"; -result["America/Matamoros"] = "MX"; -result["America/Mazatlan"] = "MX"; -result["America/Chihuahua"] = "MX"; -result["America/Ojinaga"] = "MX"; -result["America/Hermosillo"] = "MX"; -result["America/Tijuana"] = "MX"; -result["America/Bahia_Banderas"] = "MX"; -result["Asia/Kuala_Lumpur"] = "MY"; -result["Asia/Qostanay"] = "KZ"; -result["Asia/Kuching"] = "MY"; -result["Africa/Maputo"] = "MZ"; -result["Africa/Windhoek"] = "NA"; -result["Pacific/Noumea"] = "NC"; -result["Africa/Niamey"] = "NE"; -result["Pacific/Norfolk"] = "NF"; -result["Africa/Lagos"] = "NG"; -result["America/Managua"] = "NI"; -result["Europe/Amsterdam"] = "NL"; -result["Europe/Oslo"] = "NO"; -result["Asia/Kathmandu"] = "NP"; -result["Pacific/Nauru"] = "NR"; -result["Pacific/Niue"] = "NU"; -result["Pacific/Auckland"] = "NZ"; -result["Pacific/Chatham"] = "NZ"; -result["Asia/Muscat"] = "OM"; -result["America/Panama"] = "PA"; -result["America/Lima"] = "PE"; -result["Pacific/Tahiti"] = "PF"; -result["Pacific/Marquesas"] = "PF"; -result["Pacific/Gambier"] = "PF"; -result["Pacific/Port_Moresby"] = "PG"; -result["Pacific/Bougainville"] = "PG"; -result["Asia/Manila"] = "PH"; -result["Asia/Karachi"] = "PK"; -result["Europe/Warsaw"] = "PL"; -result["America/Miquelon"] = "PM"; -result["Pacific/Pitcairn"] = "PN"; -result["America/Puerto_Rico"] = "PR"; -result["Asia/Gaza"] = "PS"; -result["Asia/Hebron"] = "PS"; -result["Europe/Lisbon"] = "PT"; -result["Atlantic/Madeira"] = "PT"; -result["Atlantic/Azores"] = "PT"; -result["Pacific/Palau"] = "PW"; -result["America/Asuncion"] = "PY"; -result["Asia/Qatar"] = "QA"; -result["Indian/Reunion"] = "RE"; -result["Europe/Bucharest"] = "RO"; -result["Europe/Belgrade"] = "RS"; -result["Europe/Kaliningrad"] = "RU"; -result["Europe/Moscow"] = "RU"; -result["Europe/Simferopol"] = "RU"; -result["Europe/Volgograd"] = "RU"; -result["Europe/Kirov"] = "RU"; -result["Europe/Astrakhan"] = "RU"; -result["Europe/Saratov"] = "RU"; -result["Europe/Ulyanovsk"] = "RU"; -result["Europe/Samara"] = "RU"; -result["Asia/Yekaterinburg"] = "RU"; -result["Asia/Omsk"] = "RU"; -result["Asia/Novosibirsk"] = "RU"; -result["Asia/Barnaul"] = "RU"; -result["Asia/Tomsk"] = "RU"; -result["Asia/Novokuznetsk"] = "RU"; -result["Asia/Krasnoyarsk"] = "RU"; -result["Asia/Irkutsk"] = "RU"; -result["Asia/Chita"] = "RU"; -result["Asia/Yakutsk"] = "RU"; -result["Asia/Khandyga"] = "RU"; -result["Asia/Vladivostok"] = "RU"; -result["Asia/Ust-Nera"] = "RU"; -result["Asia/Magadan"] = "RU"; -result["Asia/Sakhalin"] = "RU"; -result["Asia/Srednekolymsk"] = "RU"; -result["Asia/Kamchatka"] = "RU"; -result["Asia/Anadyr"] = "RU"; -result["Africa/Kigali"] = "RW"; -result["Asia/Riyadh"] = "SA"; -result["Pacific/Guadalcanal"] = "SB"; -result["Indian/Mahe"] = "SC"; -result["Africa/Khartoum"] = "SD"; -result["Europe/Stockholm"] = "SE"; -result["Asia/Singapore"] = "SG"; -result["Atlantic/St_Helena"] = "SH"; -result["Europe/Ljubljana"] = "SI"; -result["Arctic/Longyearbyen"] = "SJ"; -result["Europe/Bratislava"] = "SK"; -result["Africa/Freetown"] = "SL"; -result["Europe/San_Marino"] = "SM"; -result["Africa/Dakar"] = "SN"; -result["Africa/Mogadishu"] = "SO"; -result["America/Paramaribo"] = "SR"; -result["Africa/Juba"] = "SS"; -result["Africa/Sao_Tome"] = "ST"; -result["America/El_Salvador"] = "SV"; -result["America/Lower_Princes"] = "SX"; -result["Asia/Damascus"] = "SY"; -result["Africa/Mbabane"] = "SZ"; -result["America/Grand_Turk"] = "TC"; -result["Africa/Ndjamena"] = "TD"; -result["Indian/Kerguelen"] = "TF"; -result["Africa/Lome"] = "TG"; -result["Asia/Bangkok"] = "TH"; -result["Asia/Dushanbe"] = "TJ"; -result["Pacific/Fakaofo"] = "TK"; -result["Asia/Dili"] = "TL"; -result["Asia/Ashgabat"] = "TM"; -result["Africa/Tunis"] = "TN"; -result["Pacific/Tongatapu"] = "TO"; -result["Europe/Istanbul"] = "TR"; -result["America/Port_of_Spain"] = "TT"; -result["Pacific/Funafuti"] = "TV"; -result["Asia/Taipei"] = "TW"; -result["Africa/Dar_es_Salaam"] = "TZ"; -result["Europe/Kiev"] = "UA"; -result["Europe/Uzhgorod"] = "UA"; -result["Europe/Zaporozhye"] = "UA"; -result["Africa/Kampala"] = "UG"; -result["Pacific/Midway"] = "UM"; -result["Pacific/Wake"] = "UM"; -result["America/New_York"] = "US"; -result["America/Detroit"] = "US"; -result["America/Kentucky/Louisville"] = "US"; -result["America/Kentucky/Monticello"] = "US"; -result["America/Indiana/Indianapolis"] = "US"; -result["America/Indiana/Vincennes"] = "US"; -result["America/Indiana/Winamac"] = "US"; -result["America/Indiana/Marengo"] = "US"; -result["America/Indiana/Petersburg"] = "US"; -result["America/Indiana/Vevay"] = "US"; -result["America/Chicago"] = "US"; -result["America/Indiana/Tell_City"] = "US"; -result["America/Indiana/Knox"] = "US"; -result["America/Menominee"] = "US"; -result["America/North_Dakota/Center"] = "US"; -result["America/North_Dakota/New_Salem"] = "US"; -result["America/North_Dakota/Beulah"] = "US"; -result["America/Denver"] = "US"; -result["America/Boise"] = "US"; -result["America/Phoenix"] = "US"; -result["America/Los_Angeles"] = "US"; -result["America/Anchorage"] = "US"; -result["America/Juneau"] = "US"; -result["America/Sitka"] = "US"; -result["America/Metlakatla"] = "US"; -result["America/Yakutat"] = "US"; -result["America/Nome"] = "US"; -result["America/Adak"] = "US"; -result["Pacific/Honolulu"] = "US"; -result["America/Montevideo"] = "UY"; -result["Asia/Samarkand"] = "UZ"; -result["Asia/Tashkent"] = "UZ"; -result["Europe/Vatican"] = "VA"; -result["America/St_Vincent"] = "VC"; -result["America/Caracas"] = "VE"; -result["America/Tortola"] = "VG"; -result["America/St_Thomas"] = "VI"; -result["Asia/Ho_Chi_Minh"] = "VN"; -result["Pacific/Efate"] = "VU"; -result["Pacific/Wallis"] = "WF"; -result["Pacific/Apia"] = "WS"; -result["Asia/Aden"] = "YE"; -result["Indian/Mayotte"] = "YT"; -result["Africa/Johannesburg"] = "ZA"; -result["Africa/Lusaka"] = "ZM"; -result["Africa/Harare"] = "ZW"; diff --git a/src/exif-common.c b/src/exif-common.c index 833a86cf..ecd64f6d 100644 --- a/src/exif-common.c +++ b/src/exif-common.c @@ -660,6 +660,11 @@ static void zd_tz(ZoneDetectResult *results, gchar **timezone, gchar **countryna g_free(timezone_id); } +void ZoneDetect_onError(int errZD, int errNative) +{ + log_printf("Error: ZoneDetect %s (0x%08X)\n", ZDGetErrorString(errZD), (unsigned)errNative); +} + /** * @brief Gets timezone data from an exif structure * @param[in] exif @@ -689,8 +694,6 @@ static gboolean exif_build_tz_data(ExifData *exif, gchar **exif_date_time, gchar ZoneDetect *cd; ZoneDetectResult *results; gboolean ret = FALSE; - gchar *basename; - gchar *path; text_latitude = exif_get_data_as_text(exif, "Exif.GPSInfo.GPSLatitude"); text_longitude = exif_get_data_as_text(exif, "Exif.GPSInfo.GPSLongitude"); @@ -724,11 +727,10 @@ static gboolean exif_build_tz_data(ExifData *exif, gchar **exif_date_time, gchar longitude = -longitude; } - path = path_from_utf8(TIMEZONE_DATABASE); - basename = g_path_get_basename(path); - timezone_path = g_build_filename(get_rc_dir(), basename, NULL); + timezone_path = g_build_filename(get_rc_dir(), TIMEZONE_DATABASE_FILE, NULL); if (g_file_test(timezone_path, G_FILE_TEST_EXISTS)) { + ZDSetErrorHandler(ZoneDetect_onError); cd = ZDOpenDatabase(timezone_path); if (cd) { @@ -745,9 +747,7 @@ static gboolean exif_build_tz_data(ExifData *exif, gchar **exif_date_time, gchar } ZDCloseDatabase(cd); } - g_free(path); g_free(timezone_path); - g_free(basename); } if (ret && text_date && text_time) diff --git a/src/main.h b/src/main.h index 426017c9..25729c67 100644 --- a/src/main.h +++ b/src/main.h @@ -126,8 +126,9 @@ #include "debug.h" #include "options.h" -#define TIMEZONE_DATABASE GQ_WEBSITE"downloads/timezone21.bin" - +#define TIMEZONE_DATABASE_WEB "https://cdn.bertold.org/zonedetect/db/db.zip" +#define TIMEZONE_DATABASE_FILE "timezone21.bin" +#define TIMEZONE_DATABASE_VERSION "out_v1" #define HELP_SEARCH_ENGINE "https://duckduckgo.com/?q=site:geeqie.org/help " #define STAR_RATING_NOT_READ -12345 diff --git a/src/preferences.c b/src/preferences.c index dc26b82a..7b135fe0 100644 --- a/src/preferences.c +++ b/src/preferences.c @@ -1992,6 +1992,7 @@ static void config_tab_general(GtkWidget *notebook) gchar *rating_symbol; gchar *path; gchar *basename; + gchar *download_locn; GNetworkMonitor *net_mon; GSocketConnectable *geeqie_org; gboolean internet_available; @@ -2198,9 +2199,9 @@ static void config_tab_general(GtkWidget *notebook) tz = g_new0(TZData, 1); - path = path_from_utf8(TIMEZONE_DATABASE); + path = path_from_utf8(TIMEZONE_DATABASE_WEB); basename = g_path_get_basename(path); - tz->timezone_database_user = g_build_filename(get_rc_dir(), basename, NULL); + tz->timezone_database_user = g_build_filename(get_rc_dir(), TIMEZONE_DATABASE_FILE, NULL); g_free(path); g_free(basename); @@ -2213,6 +2214,10 @@ static void config_tab_general(GtkWidget *notebook) button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Install"), FALSE, G_CALLBACK(timezone_database_install_cb), tz); } + download_locn = g_strconcat(_("Download database from: "), TIMEZONE_DATABASE_WEB, NULL); + pref_label_new(GTK_WIDGET(hbox), download_locn); + g_free(download_locn); + if (!internet_available) { gtk_widget_set_tooltip_text(button, _("No Internet connection!\nThe timezone database is used to display exif time and date\ncorrected for UTC offset and Daylight Saving Time")); @@ -4068,7 +4073,6 @@ void show_about_window(LayoutWindow *lw) gchar *path; GString *copyright; gchar *timezone_path; - gchar *basename; ZoneDetect *cd; FILE *fp = NULL; #define LINE_LENGTH 1000 @@ -4077,21 +4081,21 @@ void show_about_window(LayoutWindow *lw) copyright = g_string_new(NULL); copyright = g_string_append(copyright, "This program comes with absolutely no warranty.\nGNU General Public License, version 2 or later.\nSee https://www.gnu.org/licenses/old-licenses/gpl-2.0.html\n\n"); - path = path_from_utf8(TIMEZONE_DATABASE); - basename = g_path_get_basename(path); - timezone_path = g_build_filename(get_rc_dir(), basename, NULL); + timezone_path = g_build_filename(get_rc_dir(), TIMEZONE_DATABASE_FILE, NULL); if (g_file_test(timezone_path, G_FILE_TEST_EXISTS)) { cd = ZDOpenDatabase(timezone_path); if (cd) { copyright = g_string_append(copyright, ZDGetNotice(cd)); - ZDCloseDatabase(cd); } + else + { + log_printf("Error: Init of timezone database %s failed\n", timezone_path); + } + ZDCloseDatabase(cd); } - g_free(path); g_free(timezone_path); - g_free(basename); authors[0] = NULL; path = g_build_filename(gq_helpdir, "AUTHORS", NULL); @@ -4167,6 +4171,9 @@ static void timezone_async_ready_cb(GObject *source_object, GAsyncResult *res, g GError *error = NULL; TZData *tz = data; gchar *tmp_filename; + gchar *timezone_bin; + gchar *tmp_dir = NULL; + FileData *fd; if (!g_cancellable_is_cancelled(tz->cancellable)) { @@ -4176,13 +4183,35 @@ static void timezone_async_ready_cb(GObject *source_object, GAsyncResult *res, g if (g_file_copy_finish(G_FILE(source_object), res, &error)) { - tmp_filename = g_file_get_parse_name(tz->tmp_g_file); - move_file(tmp_filename, tz->timezone_database_user); + tmp_filename = g_file_get_path(tz->tmp_g_file); + fd = file_data_new_simple(tmp_filename); + tmp_dir = open_archive(fd); + + if (tmp_dir) + { + timezone_bin = g_build_filename(tmp_dir, TIMEZONE_DATABASE_VERSION, TIMEZONE_DATABASE_FILE, NULL); + if (isfile(timezone_bin)) + { + move_file(timezone_bin, tz->timezone_database_user); + } + else + { + warning_dialog(_("Warning: Cannot open timezone database file"), _("See the Log Window"), GTK_STOCK_DIALOG_WARNING, NULL); + } + + g_free(timezone_bin); + g_free(tmp_dir); // The folder in /tmp is deleted in exit_program_final() + } + else + { + warning_dialog(_("Warning: Cannot open timezone database file"), _("See the Log Window"), GTK_STOCK_DIALOG_WARNING, NULL); + } g_free(tmp_filename); + file_data_unref(fd); } else { - file_util_warning_dialog(_("Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL); + file_util_warning_dialog(_("Error: Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL); } g_file_delete(tz->tmp_g_file, NULL, &error); @@ -4231,7 +4260,7 @@ static void timezone_database_install_cb(GtkWidget *widget, gpointer data) } else { - tz->timezone_database_gq = g_file_new_for_uri(TIMEZONE_DATABASE); + tz->timezone_database_gq = g_file_new_for_uri(TIMEZONE_DATABASE_WEB); tz->gd = generic_dialog_new(_("Timezone database"), "download_timezone_database", NULL, TRUE, timezone_cancel_button_cb, tz); diff --git a/src/zonedetect.c b/src/zonedetect.c index 47fe37bd..9265c62e 100644 --- a/src/zonedetect.c +++ b/src/zonedetect.c @@ -34,7 +34,7 @@ #include #if defined(_MSC_VER) || defined(__MINGW32__) #include -#else +#elif defined(__APPLE__) || defined(__linux__) || defined(__unix__) || defined(_POSIX_VERSION) #include #include #include @@ -64,9 +64,11 @@ struct ZoneDetectOpaque { HANDLE fdMap; int32_t length; int32_t padding; -#else +#elif defined(__APPLE__) || defined(__linux__) || defined(__unix__) || defined(_POSIX_VERSION) int fd; off_t length; +#else + int length; #endif uint8_t closeType; @@ -232,7 +234,8 @@ static char *ZDParseString(const ZoneDetect *library, uint32_t *index) #if defined(_MSC_VER) __try { #endif - for(size_t i = 0; i < strLength; i++) { + size_t i; + for(i = 0; i < strLength; i++) { str[i] = (char)(library->mapping[strOffset + i] ^ UINT8_C(0x80)); } #if defined(_MSC_VER) @@ -286,7 +289,12 @@ static int ZDParseHeader(ZoneDetect *library) uint32_t index = UINT32_C(7); library->fieldNames = malloc(library->numFields * sizeof *library->fieldNames); - for(size_t i = 0; i < library->numFields; i++) { + if (!library->fieldNames) { + return -1; + } + + size_t i; + for(i = 0; i < library->numFields; i++) { library->fieldNames[i] = ZDParseString(library, &index); } @@ -333,12 +341,12 @@ static int ZDPointInBox(int32_t xl, int32_t x, int32_t xr, int32_t yl, int32_t y static uint32_t ZDUnshuffle(uint64_t w) { - 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; + w &= 0x5555555555555555llu; + w = (w | (w >> 1)) & 0x3333333333333333llu; + w = (w | (w >> 2)) & 0x0F0F0F0F0F0F0F0Fllu; + w = (w | (w >> 4)) & 0x00FF00FF00FF00FFllu; + w = (w | (w >> 8)) & 0x0000FFFF0000FFFFllu; + w = (w | (w >> 16)) & 0x00000000FFFFFFFFllu; return (uint32_t)w; } @@ -602,7 +610,8 @@ float* ZDPolygonToList(const ZoneDetect *library, uint32_t polygonId, size_t* le goto fail; } - for(size_t i = 0; ifieldNames) { - for(size_t i = 0; i < (size_t)library->numFields; i++) { + size_t i; + for(i = 0; i < (size_t)library->numFields; i++) { if(library->fieldNames[i]) { free(library->fieldNames[i]); } @@ -793,9 +803,9 @@ void ZDCloseDatabase(ZoneDetect *library) 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); +#elif defined(__APPLE__) || defined(__linux__) || defined(__unix__) || defined(_POSIX_VERSION) + if(library->mapping && munmap(library->mapping, (size_t)(library->length))) zdError(ZD_E_DB_MUNMAP, 0); + if(library->fd >= 0 && close(library->fd)) zdError(ZD_E_DB_CLOSE, 0); #endif } @@ -813,7 +823,11 @@ ZoneDetect *ZDOpenDatabaseFromMemory(void* buffer, size_t length) library->length = (long int)length; if(library->length <= 0) { +#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__APPLE__) || defined(__linux__) || defined(__unix__) || defined(_POSIX_VERSION) zdError(ZD_E_DB_SEEK, errno); +#else + zdError(ZD_E_DB_SEEK, 0); +#endif goto fail; } @@ -865,7 +879,7 @@ ZoneDetect *ZDOpenDatabase(const char *path) zdError(ZD_E_DB_MMAP_MSVIEW, (int)GetLastError()); goto fail; } -#else +#elif defined(__APPLE__) || defined(__linux__) || defined(__unix__) || defined(_POSIX_VERSION) library->fd = open(path, O_RDONLY | O_CLOEXEC); if(library->fd < 0) { zdError(ZD_E_DB_OPEN, errno); @@ -966,10 +980,12 @@ ZoneDetectResult *ZDLookup(const ZoneDetect *library, float lat, float lon, floa } /* Clean up results */ - for(size_t i = 0; i < numResults; i++) { + size_t i; + for(i = 0; i < numResults; i++) { int insideSum = 0; ZDLookupResult overrideResult = ZD_LOOKUP_IGNORE; - for(size_t j = i; j < numResults; j++) { + size_t j; + for(j = i; j < numResults; j++) { if(results[i].metaId == results[j].metaId) { ZDLookupResult tmpResult = results[j].lookupResult; results[j].lookupResult = ZD_LOOKUP_IGNORE; @@ -998,7 +1014,7 @@ ZoneDetectResult *ZDLookup(const ZoneDetect *library, float lat, float lon, floa /* Remove zones to ignore */ size_t newNumResults = 0; - for(size_t i = 0; i < numResults; i++) { + for(i = 0; i < numResults; i++) { if(results[i].lookupResult != ZD_LOOKUP_IGNORE) { results[newNumResults] = results[i]; newNumResults++; @@ -1007,13 +1023,54 @@ ZoneDetectResult *ZDLookup(const ZoneDetect *library, float lat, float lon, floa numResults = newNumResults; /* Lookup metadata */ - for(size_t i = 0; i < numResults; i++) { + for(i = 0; i < numResults; i++) { uint32_t tmpIndex = library->metadataOffset + results[i].metaId; results[i].data = malloc(library->numFields * sizeof *results[i].data); if(results[i].data) { - for(size_t j = 0; j < library->numFields; j++) { + size_t j; + for(j = 0; j < library->numFields; j++) { results[i].data[j] = ZDParseString(library, &tmpIndex); + if (!results[i].data[j]) { + /* free all allocated memory */ + size_t m; + for(m = 0; m < j; m++) { + if(results[i].data[m]) { + free(results[i].data[m]); + } + } + size_t k; + for(k = 0; k < i; k++) { + size_t l; + for(l = 0; l < (size_t)results[k].numFields; l++) { + if(results[k].data[l]) { + free(results[k].data[l]); + } + } + if (results[k].data) { + free(results[k].data); + } + } + free(results); + return NULL; + } + } + } + else { + /* free all allocated memory */ + size_t k; + for(k = 0; k < i; k++) { + size_t l; + for(l = 0; l < (size_t)results[k].numFields; l++) { + if(results[k].data[l]) { + free(results[k].data[l]); + } + } + if (results[k].data) { + free(results[k].data); + } } + free(results); + return NULL; } } @@ -1040,7 +1097,8 @@ void ZDFreeResults(ZoneDetectResult *results) while(results[index].lookupResult != ZD_LOOKUP_END) { if(results[index].data) { - for(size_t i = 0; i < (size_t)results[index].numFields; i++) { + size_t i; + for(i = 0; i < (size_t)results[index].numFields; i++) { if(results[index].data[i]) { free(results[index].data[i]); } @@ -1141,7 +1199,8 @@ char* ZDHelperSimpleLookupString(const ZoneDetect* library, float lat, float lon char* strings[2] = {NULL}; - for(unsigned int i = 0; i < result[0].numFields; i++) { + unsigned int i; + for(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")) { @@ -1160,7 +1219,7 @@ char* ZDHelperSimpleLookupString(const ZoneDetect* library, float lat, float lon } size_t length = 0; - for(unsigned int i=0; i 512) { @@ -1177,10 +1236,12 @@ char* ZDHelperSimpleLookupString(const ZoneDetect* library, float lat, float lon length += 1; output = (char*)malloc(length); - output[0] = 0; - for(unsigned int i=0; i