From ee2da0c682cfe5be93d41050971fd148b64976da Mon Sep 17 00:00:00 2001 From: "S. Kozyr" Date: Sat, 16 Sep 2023 14:23:42 +0300 Subject: [PATCH] Extended kml_to_kmb tool to export KMB version 8 Signed-off-by: S. Kozyr --- kml/CMakeLists.txt | 1 + kml/kml_to_kmb/kml_to_kmb.cpp | 55 +++++++++++---------- kml/serdes_binary.hpp | 2 +- kml/serdes_binary_v8.hpp | 93 +++++++++++++++++++++++++++++++++++ kml/types_v8.hpp | 27 ++++++++++ 5 files changed, 151 insertions(+), 27 deletions(-) create mode 100644 kml/serdes_binary_v8.hpp diff --git a/kml/CMakeLists.txt b/kml/CMakeLists.txt index 0454c418df..51eb25eab9 100644 --- a/kml/CMakeLists.txt +++ b/kml/CMakeLists.txt @@ -9,6 +9,7 @@ set(SRC serdes.hpp serdes_binary.cpp serdes_binary.hpp + serdes_binary_v8.hpp serdes_gpx.cpp serdes_gpx.hpp type_utils.cpp diff --git a/kml/kml_to_kmb/kml_to_kmb.cpp b/kml/kml_to_kmb/kml_to_kmb.cpp index e370737929..25aae5984b 100644 --- a/kml/kml_to_kmb/kml_to_kmb.cpp +++ b/kml/kml_to_kmb/kml_to_kmb.cpp @@ -1,5 +1,6 @@ #include "kml/serdes.hpp" #include "kml/serdes_binary.hpp" +#include "kml/serdes_binary_v8.hpp" #include "indexer/classificator_loader.hpp" @@ -11,36 +12,29 @@ int main(int argc, char** argv) { - if (argc < 2) { + if (argc < 2) + { std::cout << "Converts kml file to kmb\n"; - std::cout << "Usage: " << argv[0] << " path_to_kml_file [KMB_VERSION]\n"; - std::cout << " KMB_VERSION could be: "; - for(int i=0; i <= static_cast(kml::binary::Version::Latest); i++) - { - if (i != 0) - std::cout << ", "; - std::cout << VersionToName(static_cast(i)); - } + std::cout << "Usage: " << argv[0] << " path_to_kml_file [KBM_FORMAT_VERSION]\n"; + std::cout << "KBM_FORMAT_VERSION could be V8, V9, or Latest (default)\n"; return 1; } - - // + kml::binary::Version outVersion = kml::binary::Version::Latest; + if (argc >= 3) + { + std::string versionStr = argv[2]; + if (versionStr == "V8") + outVersion = kml::binary::Version::V8; + else if (versionStr != "V9" && versionStr != "Latest") + { + std::cout << "Invalid format version: " << versionStr << '\n'; + return 2; + } + } // TODO: Why bookmarks serialization requires classifier? classificator::Load(); std::string filePath = argv[1]; - kml::binary::Version ver = kml::binary::Version::Latest; - if (argc == 3) - { - std::optional maybeVer = kml::binary::NameToVersion(argv[2]); - if (!maybeVer.has_value()) - { - std::cout << "Invalid KMB_VERSION: " << argv[2] << '\n'; - return 2; - } - ver = maybeVer.value(); - } - kml::FileData kmlData; try { @@ -58,9 +52,18 @@ int main(int argc, char** argv) { // Change extension to kmb. filePath[filePath.size() - 1] = 'b'; - kml::binary::SerializerKml ser(kmlData); - FileWriter kmlFile(filePath); - ser.Serialize(kmlFile, ver); + if (outVersion == kml::binary::Version::V9) + { + kml::binary::SerializerKml ser(kmlData); + FileWriter kmlFile(filePath); + ser.Serialize(kmlFile); + } + else if (outVersion == kml::binary::Version::V8) + { + kml::binary::SerializerKmlV8 ser(kmlData); + FileWriter kmlFile(filePath); + ser.Serialize(kmlFile); + } } catch (kml::SerializerKml::SerializeException const & ex) { diff --git a/kml/serdes_binary.hpp b/kml/serdes_binary.hpp index c5568793db..0b33bb6acc 100644 --- a/kml/serdes_binary.hpp +++ b/kml/serdes_binary.hpp @@ -122,7 +122,7 @@ public: writer.Append(str); } -private: +protected: FileData & m_data; std::vector m_strings; }; diff --git a/kml/serdes_binary_v8.hpp b/kml/serdes_binary_v8.hpp new file mode 100644 index 0000000000..3d35b29fc1 --- /dev/null +++ b/kml/serdes_binary_v8.hpp @@ -0,0 +1,93 @@ +#pragma once + +#include "kml/serdes_binary.hpp" +#include "kml/types_v8.hpp" +#include "kml/types.hpp" +#include "kml/visitors.hpp" + + +#include +#include + + +namespace kml +{ +namespace binary +{ +// This class generates KMB files in format V8. +// The only difference between V8 and V9 (Latest) is bookmarks structure. +class SerializerKmlV8 : public SerializerKml +{ +public: + explicit SerializerKmlV8(FileData & data) : SerializerKml(data) {}; + + template + void Serialize(Sink & sink) + { + // Write format version. + WriteToSink(sink, Version::V8); + + // Write device id. + { + auto const sz = static_cast(m_data.m_deviceId.size()); + WriteVarUint(sink, sz); + sink.Write(m_data.m_deviceId.data(), sz); + } + + // Write server id. + { + auto const sz = static_cast(m_data.m_serverId.size()); + WriteVarUint(sink, sz); + sink.Write(m_data.m_serverId.data(), sz); + } + + // Write bits count in double number. + WriteToSink(sink, kDoubleBits); + + auto const startPos = sink.Pos(); + + // Reserve place for the header. + Header header; + WriteZeroesToSink(sink, header.Size()); + + // Serialize category. + header.m_categoryOffset = sink.Pos() - startPos; + SerializeCategory(sink); + + // Serialize bookmarks. + header.m_bookmarksOffset = sink.Pos() - startPos; + SerializeBookmarks(sink); + + // Serialize tracks. + header.m_tracksOffset = sink.Pos() - startPos; + SerializeTracks(sink); + + // Serialize compilations. + header.m_compilationsOffset = sink.Pos() - startPos; + SerializeCompilations(sink); + + // Serialize strings. + header.m_stringsOffset = sink.Pos() - startPos; + SerializeStrings(sink); + + // Fill header. + header.m_eosOffset = sink.Pos() - startPos; + sink.Seek(startPos); + header.Serialize(sink); + sink.Seek(startPos + header.m_eosOffset); + } + + template + void SerializeBookmarks(Sink & sink) + { + BookmarkSerializerVisitor visitor(sink, kDoubleBits); + // Downgrade bookmark format from Latest to V8 + std::vector bookmarksDataV8; + bookmarksDataV8.reserve(m_data.m_bookmarksData.size()); + for (BookmarkData &bm : m_data.m_bookmarksData) + bookmarksDataV8.push_back(BookmarkDataV8(bm)); + visitor(bookmarksDataV8); + } +}; +} // namespace binary +} // namespace kml diff --git a/kml/types_v8.hpp b/kml/types_v8.hpp index 0c2e7f61a5..bd58d04819 100644 --- a/kml/types_v8.hpp +++ b/kml/types_v8.hpp @@ -46,6 +46,33 @@ struct BookmarkDataV8 bool operator!=(BookmarkDataV8 const & data) const { return !operator==(data); } + BookmarkDataV8() + { + + } + + // Initialize using latest version of BookmarkData + BookmarkDataV8(BookmarkData src) + { + // Copy all fields from `src` except `m_minZoom` + m_id = src.m_id; + m_name = src.m_name; + m_description = src.m_description; + m_featureTypes = src.m_featureTypes; + m_customName = src.m_customName; + m_color = src.m_color; + m_icon = src.m_icon; + m_viewportScale = src.m_viewportScale; + m_timestamp = src.m_timestamp; + m_point = src.m_point; + m_boundTracks = src.m_boundTracks; + m_visible = src.m_visible; + m_nearestToponym = src.m_nearestToponym; + m_properties = src.m_properties; + m_compilations = src.m_compilations; + m_collectionIndex = src.m_collectionIndex; + } + BookmarkData ConvertToLatestVersion() { BookmarkData data;