Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/kml
diff options
context:
space:
mode:
authorAnatoliy Tomilov <tomilovanatoliy@gmail.com>2020-09-22 18:35:46 +0300
committerArsentiy Milchakov <milcars@mapswithme.com>2020-09-24 15:56:15 +0300
commitf7aa1ae5f9d8cccbd2c3b8f2678d13b043274425 (patch)
tree24128209149d8aa045356583b822b87c28ef0efc /kml
parente4a01201467333c29caff9de11d0b271612a22f1 (diff)
[kml] [kmb] Support 10.3 kml types (V8) in text kml and kmb serdes. MAPSME-14910
Diffstat (limited to 'kml')
-rw-r--r--kml/header_binary.hpp28
-rw-r--r--kml/kml_tests/serdes_tests.cpp591
-rw-r--r--kml/kml_tests/tests_data.hpp81
-rw-r--r--kml/serdes.cpp239
-rw-r--r--kml/serdes.hpp2
-rw-r--r--kml/serdes_binary.hpp77
-rw-r--r--kml/types.hpp16
-rw-r--r--kml/visitors.hpp22
8 files changed, 677 insertions, 379 deletions
diff --git a/kml/header_binary.hpp b/kml/header_binary.hpp
index d34daa3cc9..12e0503592 100644
--- a/kml/header_binary.hpp
+++ b/kml/header_binary.hpp
@@ -10,6 +10,23 @@ namespace kml
{
namespace binary
{
+enum class Version : uint8_t
+{
+ V0 = 0,
+ V1 = 1, // 11th April 2018: new Point2D storage, added deviceId, feature name -> custom name.
+ V2 = 2, // 25th April 2018: added serverId.
+ V3 = 3, // 7th May 2018: persistent feature types. V3 is binary compatible with lower versions.
+ V4 = 4, // 26th August 2019: key-value properties and nearestToponym for bookmarks and tracks,
+ // cities -> toponyms.
+ V5 = 5, // 21st November 2019: extended color palette.
+ V6 = 6, // 3rd December 2019: extended bookmark icons. V6 is binary compatible with V4 and V5
+ // versions.
+ V7 = 7, // 13th February 2020: track points are replaced by points with altitude.
+ V8 = 8, // 24 September 2020: add compilations to types and corresponding section to kmb and
+ // tags to kml
+ Latest = V8
+};
+
struct Header
{
template <typename Visitor>
@@ -18,7 +35,11 @@ struct Header
visitor(m_categoryOffset, "categoryOffset");
visitor(m_bookmarksOffset, "bookmarksOffset");
visitor(m_tracksOffset, "tracksOffset");
+ if (HasCompilationsSection())
+ visitor(m_compilationsOffset, "compilationsOffset");
visitor(m_stringsOffset, "stringsOffset");
+ if (!HasCompilationsSection())
+ m_compilationsOffset = m_stringsOffset;
visitor(m_eosOffset, "eosOffset");
}
@@ -44,9 +65,16 @@ struct Header
return visitor.m_size;
}
+ bool HasCompilationsSection() const
+ {
+ return static_cast<uint8_t>(m_version) > static_cast<uint8_t>(Version::V7);
+ }
+
+ Version m_version = Version::Latest;
uint64_t m_categoryOffset = 0;
uint64_t m_bookmarksOffset = 0;
uint64_t m_tracksOffset = 0;
+ uint64_t m_compilationsOffset = 0;
uint64_t m_stringsOffset = 0;
uint64_t m_eosOffset = 0;
};
diff --git a/kml/kml_tests/serdes_tests.cpp b/kml/kml_tests/serdes_tests.cpp
index 4c286c1f32..f6f5aff8c8 100644
--- a/kml/kml_tests/serdes_tests.cpp
+++ b/kml/kml_tests/serdes_tests.cpp
@@ -84,7 +84,10 @@ kml::FileData GenerateKmlFileData()
bookmarkData.m_boundTracks = {0};
bookmarkData.m_visible = false;
bookmarkData.m_nearestToponym = "12345";
- bookmarkData.m_properties = {{"bm_property1", "value1"}, {"bm_property2", "value2"}};
+ bookmarkData.m_properties = {{"bm_property1", "value1"},
+ {"bm_property2", "value2"},
+ {"score", "5"},
+ {"compilations", {"1, 4"}}};
result.m_bookmarksData.emplace_back(std::move(bookmarkData));
kml::TrackData trackData;
@@ -104,241 +107,365 @@ kml::FileData GenerateKmlFileData()
trackData.m_properties = {{"tr_property1", "value1"}, {"tr_property2", "value2"}};
result.m_tracksData.emplace_back(std::move(trackData));
+ kml::CategoryData compilationData1;
+ compilationData1.m_compilationId = 1;
+ compilationData1.m_type = kml::CompilationType::Collection;
+ compilationData1.m_name[kDefaultLang] = "Test collection";
+ compilationData1.m_name[kRuLang] = "Тестовая коллекция";
+ compilationData1.m_description[kDefaultLang] = "Test collection description";
+ compilationData1.m_description[kRuLang] = "Тестовое описание коллекции";
+ compilationData1.m_annotation[kDefaultLang] = "Test collection annotation";
+ compilationData1.m_annotation[kEnLang] = "Test collection annotation";
+ compilationData1.m_imageUrl = "https://localhost/1234.png";
+ compilationData1.m_visible = true;
+ compilationData1.m_authorName = "Maps.Me";
+ compilationData1.m_authorId = "54321";
+ compilationData1.m_rating = 5.9;
+ compilationData1.m_reviewsNumber = 333;
+ compilationData1.m_lastModified = std::chrono::system_clock::from_time_t(999);
+ compilationData1.m_accessRules = kml::AccessRules::Public;
+ compilationData1.m_tags = {"mountains", "ski"};
+ compilationData1.m_toponyms = {"8", "9"};
+ compilationData1.m_languageCodes = {1, 2, 8};
+ compilationData1.m_properties = {{"property1", "value1"}, {"property2", "value2"}};
+ result.m_compilationData.push_back(std::move(compilationData1));
+
+ kml::CategoryData compilationData2;
+ compilationData2.m_compilationId = 4;
+ compilationData2.m_type = kml::CompilationType::Category;
+ compilationData2.m_name[kDefaultLang] = "Test category";
+ compilationData2.m_name[kRuLang] = "Тестовая категория";
+ compilationData2.m_description[kDefaultLang] = "Test category description";
+ compilationData2.m_description[kRuLang] = "Тестовое описание категории";
+ compilationData2.m_annotation[kDefaultLang] = "Test category annotation";
+ compilationData2.m_annotation[kEnLang] = "Test category annotation";
+ compilationData2.m_imageUrl = "https://localhost/134.png";
+ compilationData2.m_visible = false;
+ compilationData2.m_authorName = "Maps.Me";
+ compilationData2.m_authorId = "11111";
+ compilationData2.m_rating = 3.3;
+ compilationData2.m_reviewsNumber = 222;
+ compilationData2.m_lastModified = std::chrono::system_clock::from_time_t(323);
+ compilationData2.m_accessRules = kml::AccessRules::Public;
+ compilationData2.m_tags = {"mountains", "bike"};
+ compilationData2.m_toponyms = {"10", "11"};
+ compilationData2.m_languageCodes = {1, 2, 8};
+ compilationData2.m_properties = {{"property1", "value1"}, {"property2", "value2"}};
+ result.m_compilationData.push_back(std::move(compilationData2));
+
return result;
}
char const * kGeneratedKml =
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
- "<kml xmlns=\"http://earth.google.com/kml/2.2\">\n"
- "<Document>\n"
- " <Style id=\"placemark-red\">\n"
- " <IconStyle>\n"
- " <Icon>\n"
- " <href>http://maps.me/placemarks/placemark-red.png</href>\n"
- " </Icon>\n"
- " </IconStyle>\n"
- " </Style>\n"
- " <Style id=\"placemark-blue\">\n"
- " <IconStyle>\n"
- " <Icon>\n"
- " <href>http://maps.me/placemarks/placemark-blue.png</href>\n"
- " </Icon>\n"
- " </IconStyle>\n"
- " </Style>\n"
- " <Style id=\"placemark-purple\">\n"
- " <IconStyle>\n"
- " <Icon>\n"
- " <href>http://maps.me/placemarks/placemark-purple.png</href>\n"
- " </Icon>\n"
- " </IconStyle>\n"
- " </Style>\n"
- " <Style id=\"placemark-yellow\">\n"
- " <IconStyle>\n"
- " <Icon>\n"
- " <href>http://maps.me/placemarks/placemark-yellow.png</href>\n"
- " </Icon>\n"
- " </IconStyle>\n"
- " </Style>\n"
- " <Style id=\"placemark-pink\">\n"
- " <IconStyle>\n"
- " <Icon>\n"
- " <href>http://maps.me/placemarks/placemark-pink.png</href>\n"
- " </Icon>\n"
- " </IconStyle>\n"
- " </Style>\n"
- " <Style id=\"placemark-brown\">\n"
- " <IconStyle>\n"
- " <Icon>\n"
- " <href>http://maps.me/placemarks/placemark-brown.png</href>\n"
- " </Icon>\n"
- " </IconStyle>\n"
- " </Style>\n"
- " <Style id=\"placemark-green\">\n"
- " <IconStyle>\n"
- " <Icon>\n"
- " <href>http://maps.me/placemarks/placemark-green.png</href>\n"
- " </Icon>\n"
- " </IconStyle>\n"
- " </Style>\n"
- " <Style id=\"placemark-orange\">\n"
- " <IconStyle>\n"
- " <Icon>\n"
- " <href>http://maps.me/placemarks/placemark-orange.png</href>\n"
- " </Icon>\n"
- " </IconStyle>\n"
- " </Style>\n"
- " <Style id=\"placemark-deeppurple\">\n"
- " <IconStyle>\n"
- " <Icon>\n"
- " <href>http://maps.me/placemarks/placemark-deeppurple.png</href>\n"
- " </Icon>\n"
- " </IconStyle>\n"
- " </Style>\n"
- " <Style id=\"placemark-lightblue\">\n"
- " <IconStyle>\n"
- " <Icon>\n"
- " <href>http://maps.me/placemarks/placemark-lightblue.png</href>\n"
- " </Icon>\n"
- " </IconStyle>\n"
- " </Style>\n"
- " <Style id=\"placemark-cyan\">\n"
- " <IconStyle>\n"
- " <Icon>\n"
- " <href>http://maps.me/placemarks/placemark-cyan.png</href>\n"
- " </Icon>\n"
- " </IconStyle>\n"
- " </Style>\n"
- " <Style id=\"placemark-teal\">\n"
- " <IconStyle>\n"
- " <Icon>\n"
- " <href>http://maps.me/placemarks/placemark-teal.png</href>\n"
- " </Icon>\n"
- " </IconStyle>\n"
- " </Style>\n"
- " <Style id=\"placemark-lime\">\n"
- " <IconStyle>\n"
- " <Icon>\n"
- " <href>http://maps.me/placemarks/placemark-lime.png</href>\n"
- " </Icon>\n"
- " </IconStyle>\n"
- " </Style>\n"
- " <Style id=\"placemark-deeporange\">\n"
- " <IconStyle>\n"
- " <Icon>\n"
- " <href>http://maps.me/placemarks/placemark-deeporange.png</href>\n"
- " </Icon>\n"
- " </IconStyle>\n"
- " </Style>\n"
- " <Style id=\"placemark-gray\">\n"
- " <IconStyle>\n"
- " <Icon>\n"
- " <href>http://maps.me/placemarks/placemark-gray.png</href>\n"
- " </Icon>\n"
- " </IconStyle>\n"
- " </Style>\n"
- " <Style id=\"placemark-bluegray\">\n"
- " <IconStyle>\n"
- " <Icon>\n"
- " <href>http://maps.me/placemarks/placemark-bluegray.png</href>\n"
- " </Icon>\n"
- " </IconStyle>\n"
- " </Style>\n"
- " <name>Test category</name>\n"
- " <description>Test description</description>\n"
- " <visibility>1</visibility>\n"
- " <ExtendedData xmlns:mwm=\"https://maps.me\">\n"
- " <mwm:serverId>AAAA-BBBB-CCCC-DDDD</mwm:serverId>\n"
- " <mwm:name>\n"
- " <mwm:lang code=\"ru\">Тестовая категория</mwm:lang>\n"
- " <mwm:lang code=\"default\">Test category</mwm:lang>\n"
- " </mwm:name>\n"
- " <mwm:annotation>\n"
- " <mwm:lang code=\"en\">Test annotation</mwm:lang>\n"
- " <mwm:lang code=\"default\">Test annotation</mwm:lang>\n"
- " </mwm:annotation>\n"
- " <mwm:description>\n"
- " <mwm:lang code=\"ru\">Тестовое описание</mwm:lang>\n"
- " <mwm:lang code=\"default\">Test description</mwm:lang>\n"
- " </mwm:description>\n"
- " <mwm:imageUrl>https://localhost/123.png</mwm:imageUrl>\n"
- " <mwm:author id=\"12345\">Maps.Me</mwm:author>\n"
- " <mwm:lastModified>1970-01-01T00:16:40Z</mwm:lastModified>\n"
- " <mwm:rating>8.9</mwm:rating>\n"
- " <mwm:reviewsNumber>567</mwm:reviewsNumber>\n"
- " <mwm:accessRules>Public</mwm:accessRules>\n"
- " <mwm:tags>\n"
- " <mwm:value>mountains</mwm:value>\n"
- " <mwm:value>ski</mwm:value>\n"
- " <mwm:value>snowboard</mwm:value>\n"
- " </mwm:tags>\n"
- " <mwm:toponyms>\n"
- " <mwm:value>12345</mwm:value>\n"
- " <mwm:value>54321</mwm:value>\n"
- " </mwm:toponyms>\n"
- " <mwm:languageCodes>\n"
- " <mwm:value>en</mwm:value>\n"
- " <mwm:value>ja</mwm:value>\n"
- " <mwm:value>ru</mwm:value>\n"
- " </mwm:languageCodes>\n"
- " <mwm:properties>\n"
- " <mwm:value key=\"property1\">value1</mwm:value>\n"
- " <mwm:value key=\"property2\">value2</mwm:value>\n"
- " </mwm:properties>\n"
- " </ExtendedData>\n"
- " <Placemark>\n"
- " <name>Мое любимое место</name>\n"
- " <description>Test bookmark description</description>\n"
- " <TimeStamp><when>1970-01-01T00:13:20Z</when></TimeStamp>\n"
- " <styleUrl>#placemark-blue</styleUrl>\n"
- " <Point><coordinates>45.9242,49.326859</coordinates></Point>\n"
- " <ExtendedData xmlns:mwm=\"https://maps.me\">\n"
- " <mwm:name>\n"
- " <mwm:lang code=\"ru\">Тестовая метка</mwm:lang>\n"
- " <mwm:lang code=\"default\">Test bookmark</mwm:lang>\n"
- " </mwm:name>\n"
- " <mwm:description>\n"
- " <mwm:lang code=\"ru\">Тестовое описание метки</mwm:lang>\n"
- " <mwm:lang code=\"default\">Test bookmark description</mwm:lang>\n"
- " </mwm:description>\n"
- " <mwm:featureTypes>\n"
- " <mwm:value>historic-castle</mwm:value>\n"
- " <mwm:value>historic-memorial</mwm:value>\n"
- " </mwm:featureTypes>\n"
- " <mwm:customName>\n"
- " <mwm:lang code=\"en\">My favorite place</mwm:lang>\n"
- " <mwm:lang code=\"default\">Мое любимое место</mwm:lang>\n"
- " </mwm:customName>\n"
- " <mwm:scale>15</mwm:scale>\n"
- " <mwm:boundTracks>\n"
- " <mwm:value>0</mwm:value>\n"
- " </mwm:boundTracks>\n"
- " <mwm:visibility>0</mwm:visibility>\n"
- " <mwm:nearestToponym>12345</mwm:nearestToponym>\n"
- " <mwm:properties>\n"
- " <mwm:value key=\"bm_property1\">value1</mwm:value>\n"
- " <mwm:value key=\"bm_property2\">value2</mwm:value>\n"
- " </mwm:properties>\n"
- " </ExtendedData>\n"
- " </Placemark>\n"
- " <Placemark>\n"
- " <name>Test track</name>\n"
- " <description>Test track description</description>\n"
- " <Style><LineStyle>\n"
- " <color>FF0000FF</color>\n"
- " <width>6</width>\n"
- " </LineStyle></Style>\n"
- " <TimeStamp><when>1970-01-01T00:15:00Z</when></TimeStamp>\n"
- " <LineString><coordinates>45.9242,49.326859,1 45.2244,48.941288,2 45.1964,49.401948,3</coordinates></LineString>\n"
- " <ExtendedData xmlns:mwm=\"https://maps.me\">\n"
- " <mwm:name>\n"
- " <mwm:lang code=\"ru\">Тестовый трек</mwm:lang>\n"
- " <mwm:lang code=\"default\">Test track</mwm:lang>\n"
- " </mwm:name>\n"
- " <mwm:description>\n"
- " <mwm:lang code=\"ru\">Тестовое описание трека</mwm:lang>\n"
- " <mwm:lang code=\"default\">Test track description</mwm:lang>\n"
- " </mwm:description>\n"
- " <mwm:localId>0</mwm:localId>\n"
- " <mwm:additionalStyle>\n"
- " <mwm:additionalLineStyle>\n"
- " <color>FF00FF00</color>\n"
- " <width>7</width>\n"
- " </mwm:additionalLineStyle>\n"
- " </mwm:additionalStyle>\n"
- " <mwm:visibility>0</mwm:visibility>\n"
- " <mwm:nearestToponyms>\n"
- " <mwm:value>12345</mwm:value>\n"
- " <mwm:value>54321</mwm:value>\n"
- " <mwm:value>98765</mwm:value>\n"
- " </mwm:nearestToponyms>\n"
- " <mwm:properties>\n"
- " <mwm:value key=\"tr_property1\">value1</mwm:value>\n"
- " <mwm:value key=\"tr_property2\">value2</mwm:value>\n"
- " </mwm:properties>\n"
- " </ExtendedData>\n"
- " </Placemark>\n"
- "</Document>\n"
- "</kml>";
+R"(<?xml version="1.0" encoding="UTF-8"?>
+<kml xmlns="http://earth.google.com/kml/2.2">
+<Document>
+ <Style id="placemark-red">
+ <IconStyle>
+ <Icon>
+ <href>http://maps.me/placemarks/placemark-red.png</href>
+ </Icon>
+ </IconStyle>
+ </Style>
+ <Style id="placemark-blue">
+ <IconStyle>
+ <Icon>
+ <href>http://maps.me/placemarks/placemark-blue.png</href>
+ </Icon>
+ </IconStyle>
+ </Style>
+ <Style id="placemark-purple">
+ <IconStyle>
+ <Icon>
+ <href>http://maps.me/placemarks/placemark-purple.png</href>
+ </Icon>
+ </IconStyle>
+ </Style>
+ <Style id="placemark-yellow">
+ <IconStyle>
+ <Icon>
+ <href>http://maps.me/placemarks/placemark-yellow.png</href>
+ </Icon>
+ </IconStyle>
+ </Style>
+ <Style id="placemark-pink">
+ <IconStyle>
+ <Icon>
+ <href>http://maps.me/placemarks/placemark-pink.png</href>
+ </Icon>
+ </IconStyle>
+ </Style>
+ <Style id="placemark-brown">
+ <IconStyle>
+ <Icon>
+ <href>http://maps.me/placemarks/placemark-brown.png</href>
+ </Icon>
+ </IconStyle>
+ </Style>
+ <Style id="placemark-green">
+ <IconStyle>
+ <Icon>
+ <href>http://maps.me/placemarks/placemark-green.png</href>
+ </Icon>
+ </IconStyle>
+ </Style>
+ <Style id="placemark-orange">
+ <IconStyle>
+ <Icon>
+ <href>http://maps.me/placemarks/placemark-orange.png</href>
+ </Icon>
+ </IconStyle>
+ </Style>
+ <Style id="placemark-deeppurple">
+ <IconStyle>
+ <Icon>
+ <href>http://maps.me/placemarks/placemark-deeppurple.png</href>
+ </Icon>
+ </IconStyle>
+ </Style>
+ <Style id="placemark-lightblue">
+ <IconStyle>
+ <Icon>
+ <href>http://maps.me/placemarks/placemark-lightblue.png</href>
+ </Icon>
+ </IconStyle>
+ </Style>
+ <Style id="placemark-cyan">
+ <IconStyle>
+ <Icon>
+ <href>http://maps.me/placemarks/placemark-cyan.png</href>
+ </Icon>
+ </IconStyle>
+ </Style>
+ <Style id="placemark-teal">
+ <IconStyle>
+ <Icon>
+ <href>http://maps.me/placemarks/placemark-teal.png</href>
+ </Icon>
+ </IconStyle>
+ </Style>
+ <Style id="placemark-lime">
+ <IconStyle>
+ <Icon>
+ <href>http://maps.me/placemarks/placemark-lime.png</href>
+ </Icon>
+ </IconStyle>
+ </Style>
+ <Style id="placemark-deeporange">
+ <IconStyle>
+ <Icon>
+ <href>http://maps.me/placemarks/placemark-deeporange.png</href>
+ </Icon>
+ </IconStyle>
+ </Style>
+ <Style id="placemark-gray">
+ <IconStyle>
+ <Icon>
+ <href>http://maps.me/placemarks/placemark-gray.png</href>
+ </Icon>
+ </IconStyle>
+ </Style>
+ <Style id="placemark-bluegray">
+ <IconStyle>
+ <Icon>
+ <href>http://maps.me/placemarks/placemark-bluegray.png</href>
+ </Icon>
+ </IconStyle>
+ </Style>
+ <name>Test category</name>
+ <description>Test description</description>
+ <visibility>1</visibility>
+ <ExtendedData xmlns:mwm="https://maps.me">
+ <mwm:serverId>AAAA-BBBB-CCCC-DDDD</mwm:serverId>
+ <mwm:name>
+ <mwm:lang code="ru">Тестовая категория</mwm:lang>
+ <mwm:lang code="default">Test category</mwm:lang>
+ </mwm:name>
+ <mwm:annotation>
+ <mwm:lang code="en">Test annotation</mwm:lang>
+ <mwm:lang code="default">Test annotation</mwm:lang>
+ </mwm:annotation>
+ <mwm:description>
+ <mwm:lang code="ru">Тестовое описание</mwm:lang>
+ <mwm:lang code="default">Test description</mwm:lang>
+ </mwm:description>
+ <mwm:imageUrl>https://localhost/123.png</mwm:imageUrl>
+ <mwm:author id="12345">Maps.Me</mwm:author>
+ <mwm:lastModified>1970-01-01T00:16:40Z</mwm:lastModified>
+ <mwm:rating>8.9</mwm:rating>
+ <mwm:reviewsNumber>567</mwm:reviewsNumber>
+ <mwm:accessRules>Public</mwm:accessRules>
+ <mwm:tags>
+ <mwm:value>mountains</mwm:value>
+ <mwm:value>ski</mwm:value>
+ <mwm:value>snowboard</mwm:value>
+ </mwm:tags>
+ <mwm:toponyms>
+ <mwm:value>12345</mwm:value>
+ <mwm:value>54321</mwm:value>
+ </mwm:toponyms>
+ <mwm:languageCodes>
+ <mwm:value>en</mwm:value>
+ <mwm:value>ja</mwm:value>
+ <mwm:value>ru</mwm:value>
+ </mwm:languageCodes>
+ <mwm:properties>
+ <mwm:value key="property1">value1</mwm:value>
+ <mwm:value key="property2">value2</mwm:value>
+ </mwm:properties>
+ <mwm:compilation id="1" type="Collection">
+ <mwm:name>
+ <mwm:lang code="ru">Тестовая коллекция</mwm:lang>
+ <mwm:lang code="default">Test collection</mwm:lang>
+ </mwm:name>
+ <mwm:annotation>
+ <mwm:lang code="en">Test collection annotation</mwm:lang>
+ <mwm:lang code="default">Test collection annotation</mwm:lang>
+ </mwm:annotation>
+ <mwm:description>
+ <mwm:lang code="ru">Тестовое описание коллекции</mwm:lang>
+ <mwm:lang code="default">Test collection description</mwm:lang>
+ </mwm:description>
+ <mwm:visibility>1</mwm:visibility>
+ <mwm:imageUrl>https://localhost/1234.png</mwm:imageUrl>
+ <mwm:author id="54321">Maps.Me</mwm:author>
+ <mwm:lastModified>1970-01-01T00:16:39Z</mwm:lastModified>
+ <mwm:rating>5.9</mwm:rating>
+ <mwm:reviewsNumber>333</mwm:reviewsNumber>
+ <mwm:accessRules>Public</mwm:accessRules>
+ <mwm:tags>
+ <mwm:value>mountains</mwm:value>
+ <mwm:value>ski</mwm:value>
+ </mwm:tags>
+ <mwm:toponyms>
+ <mwm:value>8</mwm:value>
+ <mwm:value>9</mwm:value>
+ </mwm:toponyms>
+ <mwm:languageCodes>
+ <mwm:value>en</mwm:value>
+ <mwm:value>ja</mwm:value>
+ <mwm:value>ru</mwm:value>
+ </mwm:languageCodes>
+ <mwm:properties>
+ <mwm:value key="property1">value1</mwm:value>
+ <mwm:value key="property2">value2</mwm:value>
+ </mwm:properties>
+ </mwm:compilation>
+ <mwm:compilation id="4" type="Category">
+ <mwm:name>
+ <mwm:lang code="ru">Тестовая категория</mwm:lang>
+ <mwm:lang code="default">Test category</mwm:lang>
+ </mwm:name>
+ <mwm:annotation>
+ <mwm:lang code="en">Test category annotation</mwm:lang>
+ <mwm:lang code="default">Test category annotation</mwm:lang>
+ </mwm:annotation>
+ <mwm:description>
+ <mwm:lang code="ru">Тестовое описание категории</mwm:lang>
+ <mwm:lang code="default">Test category description</mwm:lang>
+ </mwm:description>
+ <mwm:visibility>0</mwm:visibility>
+ <mwm:imageUrl>https://localhost/134.png</mwm:imageUrl>
+ <mwm:author id="11111">Maps.Me</mwm:author>
+ <mwm:lastModified>1970-01-01T00:05:23Z</mwm:lastModified>
+ <mwm:rating>3.3</mwm:rating>
+ <mwm:reviewsNumber>222</mwm:reviewsNumber>
+ <mwm:accessRules>Public</mwm:accessRules>
+ <mwm:tags>
+ <mwm:value>mountains</mwm:value>
+ <mwm:value>bike</mwm:value>
+ </mwm:tags>
+ <mwm:toponyms>
+ <mwm:value>10</mwm:value>
+ <mwm:value>11</mwm:value>
+ </mwm:toponyms>
+ <mwm:languageCodes>
+ <mwm:value>en</mwm:value>
+ <mwm:value>ja</mwm:value>
+ <mwm:value>ru</mwm:value>
+ </mwm:languageCodes>
+ <mwm:properties>
+ <mwm:value key="property1">value1</mwm:value>
+ <mwm:value key="property2">value2</mwm:value>
+ </mwm:properties>
+ </mwm:compilation>
+ </ExtendedData>
+ <Placemark>
+ <name>Мое любимое место</name>
+ <description>Test bookmark description</description>
+ <TimeStamp><when>1970-01-01T00:13:20Z</when></TimeStamp>
+ <styleUrl>#placemark-blue</styleUrl>
+ <Point><coordinates>45.9242,49.326859</coordinates></Point>
+ <ExtendedData xmlns:mwm="https://maps.me">
+ <mwm:name>
+ <mwm:lang code="ru">Тестовая метка</mwm:lang>
+ <mwm:lang code="default">Test bookmark</mwm:lang>
+ </mwm:name>
+ <mwm:description>
+ <mwm:lang code="ru">Тестовое описание метки</mwm:lang>
+ <mwm:lang code="default">Test bookmark description</mwm:lang>
+ </mwm:description>
+ <mwm:featureTypes>
+ <mwm:value>historic-castle</mwm:value>
+ <mwm:value>historic-memorial</mwm:value>
+ </mwm:featureTypes>
+ <mwm:customName>
+ <mwm:lang code="en">My favorite place</mwm:lang>
+ <mwm:lang code="default">Мое любимое место</mwm:lang>
+ </mwm:customName>
+ <mwm:scale>15</mwm:scale>
+ <mwm:boundTracks>
+ <mwm:value>0</mwm:value>
+ </mwm:boundTracks>
+ <mwm:visibility>0</mwm:visibility>
+ <mwm:nearestToponym>12345</mwm:nearestToponym>
+ <mwm:properties>
+ <mwm:value key="bm_property1">value1</mwm:value>
+ <mwm:value key="bm_property2">value2</mwm:value>
+ <mwm:value key="compilations">1, 4</mwm:value>
+ <mwm:value key="score">5</mwm:value>
+ </mwm:properties>
+ </ExtendedData>
+ </Placemark>
+ <Placemark>
+ <name>Test track</name>
+ <description>Test track description</description>
+ <Style><LineStyle>
+ <color>FF0000FF</color>
+ <width>6</width>
+ </LineStyle></Style>
+ <TimeStamp><when>1970-01-01T00:15:00Z</when></TimeStamp>
+ <LineString><coordinates>45.9242,49.326859,1 45.2244,48.941288,2 45.1964,49.401948,3</coordinates></LineString>
+ <ExtendedData xmlns:mwm="https://maps.me">
+ <mwm:name>
+ <mwm:lang code="ru">Тестовый трек</mwm:lang>
+ <mwm:lang code="default">Test track</mwm:lang>
+ </mwm:name>
+ <mwm:description>
+ <mwm:lang code="ru">Тестовое описание трека</mwm:lang>
+ <mwm:lang code="default">Test track description</mwm:lang>
+ </mwm:description>
+ <mwm:localId>0</mwm:localId>
+ <mwm:additionalStyle>
+ <mwm:additionalLineStyle>
+ <color>FF00FF00</color>
+ <width>7</width>
+ </mwm:additionalLineStyle>
+ </mwm:additionalStyle>
+ <mwm:visibility>0</mwm:visibility>
+ <mwm:nearestToponyms>
+ <mwm:value>12345</mwm:value>
+ <mwm:value>54321</mwm:value>
+ <mwm:value>98765</mwm:value>
+ </mwm:nearestToponyms>
+ <mwm:properties>
+ <mwm:value key="tr_property1">value1</mwm:value>
+ <mwm:value key="tr_property2">value2</mwm:value>
+ </mwm:properties>
+ </ExtendedData>
+ </Placemark>
+</Document>
+</kml>)";
} // namespace
// 1. Check text and binary deserialization from the prepared sources in memory.
diff --git a/kml/kml_tests/tests_data.hpp b/kml/kml_tests/tests_data.hpp
index c2ba606f2f..3cb8761e8d 100644
--- a/kml/kml_tests/tests_data.hpp
+++ b/kml/kml_tests/tests_data.hpp
@@ -1364,46 +1364,47 @@ std::vector<uint8_t> const kBinKmlV4 = {
};
std::vector<uint8_t> const kBinKml = {
- 0x08, 0x00, 0x00, 0x1E, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x74, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x01, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x8D, 0xB7, 0xF5, 0x71, 0xFC, 0x8C, 0xFC, 0xC0, 0x02, 0x00, 0x01, 0x05,
- 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF3, 0xC2, 0xFB, 0xF9,
- 0x01, 0xE3, 0xB9, 0xBB, 0x8E, 0x01, 0xC3, 0xC5, 0xD2, 0xBB, 0x02, 0x00, 0x01, 0x05, 0x01, 0x00,
- 0x05, 0x01, 0x00, 0x06, 0x01, 0x00, 0x07, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB8, 0xBC, 0xED, 0xA7,
- 0x03, 0x97, 0xB0, 0x9A, 0xA7, 0x02, 0xA4, 0xD6, 0xAE, 0xDB, 0x02, 0x00, 0x01, 0x05, 0x01, 0x00,
- 0x08, 0x00, 0x01, 0x00, 0x09, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9C, 0xCD, 0x97, 0xA7, 0x02,
- 0xFD, 0xC1, 0xAC, 0xDB, 0x02, 0x00, 0x01, 0x05, 0x01, 0x00, 0x0A, 0x01, 0x00, 0x0B, 0x01, 0x00,
- 0x0C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
- 0x0E, 0x08, 0x08, 0x1B, 0x1A, 0x1B, 0x41, 0x41, 0x0C, 0x11, 0x0C, 0x37, 0x3E, 0x00, 0x01, 0x00,
- 0x01, 0x06, 0x01, 0x03, 0x09, 0x03, 0x05, 0x05, 0x07, 0x07, 0x07, 0x41, 0x09, 0x06, 0x0A, 0x0B,
- 0x08, 0x8D, 0x01, 0x0D, 0x07, 0x10, 0x0F, 0x08, 0x71, 0x11, 0x05, 0x02, 0x13, 0x06, 0x04, 0x15,
- 0x06, 0x0B, 0x17, 0x07, 0x5E, 0x19, 0x05, 0x0D, 0x1B, 0x07, 0xBA, 0x01, 0x1D, 0x08, 0x1C, 0x1F,
- 0x06, 0x75, 0x21, 0x06, 0x06, 0x23, 0x06, 0x09, 0x27, 0x08, 0x4E, 0x29, 0x06, 0x12, 0x2B, 0x07,
- 0x91, 0x01, 0x2D, 0x08, 0x14, 0x2F, 0x07, 0x73, 0x33, 0x06, 0x05, 0x35, 0x07, 0x0C, 0x37, 0x08,
- 0x63, 0x3B, 0x07, 0xC0, 0x01, 0x3D, 0x08, 0x31, 0x3F, 0x07, 0x77, 0x43, 0x07, 0x08, 0x47, 0x08,
- 0x48, 0x4B, 0x08, 0x90, 0x01, 0x4D, 0x07, 0x13, 0x4F, 0x07, 0x72, 0x57, 0x07, 0x62, 0x5B, 0x07,
- 0xBD, 0x01, 0x5D, 0x07, 0x29, 0x67, 0x07, 0x57, 0x6B, 0x08, 0xA1, 0x01, 0x6D, 0x08, 0x18, 0x6F,
- 0x08, 0x76, 0x75, 0x07, 0x0F, 0x77, 0x07, 0x68, 0x7B, 0x07, 0xD1, 0x01, 0x7D, 0x08, 0x3F, 0x7F,
- 0x07, 0x79, 0x83, 0x01, 0x08, 0xB8, 0x01, 0x8B, 0x01, 0x08, 0x8F, 0x01, 0x8F, 0x01, 0x08, 0x74,
- 0x9D, 0x01, 0x08, 0x25, 0xA7, 0x01, 0x08, 0x59, 0xAD, 0x01, 0x08, 0x17, 0xB7, 0x01, 0x08, 0x6D,
- 0xBD, 0x01, 0x08, 0x3E, 0xC7, 0x01, 0x08, 0x4B, 0xCB, 0x01, 0x08, 0x96, 0x01, 0xEB, 0x01, 0x08,
- 0xB7, 0x01, 0xED, 0x01, 0x08, 0x19, 0xEF, 0x01, 0x08, 0x8A, 0x01, 0xFD, 0x01, 0x08, 0x40, 0x83,
- 0x02, 0x09, 0x0E, 0xA0, 0x02, 0xAF, 0x13, 0xE7, 0xEE, 0xAD, 0x1B, 0x51, 0x0F, 0x7D, 0x02, 0x8B,
- 0xBA, 0xDC, 0x17, 0x6C, 0x0C, 0xE8, 0x3F, 0xF4, 0x7A, 0x70, 0x54, 0x0E, 0x25, 0xE5, 0x6D, 0xFE,
- 0x26, 0xE1, 0xCF, 0xD5, 0xB1, 0x7A, 0xD1, 0x32, 0x1C, 0x8A, 0x5F, 0x54, 0xDA, 0xC4, 0x56, 0x9F,
- 0xFC, 0x54, 0x5C, 0x8A, 0x49, 0x94, 0x65, 0x55, 0x23, 0x49, 0x43, 0x2F, 0xE7, 0x51, 0xAE, 0x19,
- 0xFD, 0x9B, 0xCC, 0x95, 0xE7, 0x2C, 0xCB, 0xDF, 0xCF, 0x74, 0x1A, 0x01, 0x0C, 0x4D, 0x54, 0x52,
- 0x77, 0xB5, 0x8B, 0x51, 0xB3, 0x3C, 0x22, 0x31, 0x30, 0xD4, 0x5E, 0x8D, 0x41, 0x3D, 0x11, 0x88,
- 0x0D, 0xF3, 0x64, 0x9E, 0xFF, 0xD7, 0x70, 0x0F, 0x00, 0x80, 0x3D, 0x00, 0x00, 0x00, 0x80, 0x0E,
- 0xB0, 0x45, 0xA7, 0x9D, 0x65, 0x6B, 0x78, 0xC7, 0xC6, 0xBA, 0x2D, 0x46, 0x83, 0x76, 0x08, 0xAC,
- 0x14, 0x4B, 0x56, 0xA2, 0x09, 0x01, 0x00, 0x0D,
+ 0x08, 0x00, 0x00, 0x1E, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5E, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x12, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x01,
+ 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x0D, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x8D, 0xB7, 0xF5, 0x71, 0xFC, 0x8C, 0xFC, 0xC0, 0x02, 0x00, 0x01,
+ 0x05, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF3, 0xC2, 0xFB,
+ 0xF9, 0x01, 0xE3, 0xB9, 0xBB, 0x8E, 0x01, 0xC3, 0xC5, 0xD2, 0xBB, 0x02, 0x00, 0x01, 0x05, 0x01,
+ 0x00, 0x05, 0x01, 0x00, 0x06, 0x01, 0x00, 0x07, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB8, 0xBC, 0xED,
+ 0xA7, 0x03, 0x97, 0xB0, 0x9A, 0xA7, 0x02, 0xA4, 0xD6, 0xAE, 0xDB, 0x02, 0x00, 0x01, 0x05, 0x01,
+ 0x00, 0x08, 0x00, 0x01, 0x00, 0x09, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9C, 0xCD, 0x97, 0xA7,
+ 0x02, 0xFD, 0xC1, 0xAC, 0xDB, 0x02, 0x00, 0x01, 0x05, 0x01, 0x00, 0x0A, 0x01, 0x00, 0x0B, 0x01,
+ 0x00, 0x0C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x07, 0x0E, 0x08, 0x08, 0x1B, 0x1A, 0x1B, 0x41, 0x41, 0x0C, 0x11, 0x0C, 0x37, 0x3E, 0x00,
+ 0x01, 0x00, 0x01, 0x06, 0x01, 0x03, 0x09, 0x03, 0x05, 0x05, 0x07, 0x07, 0x07, 0x41, 0x09, 0x06,
+ 0x0A, 0x0B, 0x08, 0x8D, 0x01, 0x0D, 0x07, 0x10, 0x0F, 0x08, 0x71, 0x11, 0x05, 0x02, 0x13, 0x06,
+ 0x04, 0x15, 0x06, 0x0B, 0x17, 0x07, 0x5E, 0x19, 0x05, 0x0D, 0x1B, 0x07, 0xBA, 0x01, 0x1D, 0x08,
+ 0x1C, 0x1F, 0x06, 0x75, 0x21, 0x06, 0x06, 0x23, 0x06, 0x09, 0x27, 0x08, 0x4E, 0x29, 0x06, 0x12,
+ 0x2B, 0x07, 0x91, 0x01, 0x2D, 0x08, 0x14, 0x2F, 0x07, 0x73, 0x33, 0x06, 0x05, 0x35, 0x07, 0x0C,
+ 0x37, 0x08, 0x63, 0x3B, 0x07, 0xC0, 0x01, 0x3D, 0x08, 0x31, 0x3F, 0x07, 0x77, 0x43, 0x07, 0x08,
+ 0x47, 0x08, 0x48, 0x4B, 0x08, 0x90, 0x01, 0x4D, 0x07, 0x13, 0x4F, 0x07, 0x72, 0x57, 0x07, 0x62,
+ 0x5B, 0x07, 0xBD, 0x01, 0x5D, 0x07, 0x29, 0x67, 0x07, 0x57, 0x6B, 0x08, 0xA1, 0x01, 0x6D, 0x08,
+ 0x18, 0x6F, 0x08, 0x76, 0x75, 0x07, 0x0F, 0x77, 0x07, 0x68, 0x7B, 0x07, 0xD1, 0x01, 0x7D, 0x08,
+ 0x3F, 0x7F, 0x07, 0x79, 0x83, 0x01, 0x08, 0xB8, 0x01, 0x8B, 0x01, 0x08, 0x8F, 0x01, 0x8F, 0x01,
+ 0x08, 0x74, 0x9D, 0x01, 0x08, 0x25, 0xA7, 0x01, 0x08, 0x59, 0xAD, 0x01, 0x08, 0x17, 0xB7, 0x01,
+ 0x08, 0x6D, 0xBD, 0x01, 0x08, 0x3E, 0xC7, 0x01, 0x08, 0x4B, 0xCB, 0x01, 0x08, 0x96, 0x01, 0xEB,
+ 0x01, 0x08, 0xB7, 0x01, 0xED, 0x01, 0x08, 0x19, 0xEF, 0x01, 0x08, 0x8A, 0x01, 0xFD, 0x01, 0x08,
+ 0x40, 0x83, 0x02, 0x09, 0x0E, 0xA0, 0x02, 0xAF, 0x13, 0xE7, 0xEE, 0xAD, 0x1B, 0x51, 0x0F, 0x7D,
+ 0x02, 0x8B, 0xBA, 0xDC, 0x17, 0x6C, 0x0C, 0xE8, 0x3F, 0xF4, 0x7A, 0x70, 0x54, 0x0E, 0x25, 0xE5,
+ 0x6D, 0xFE, 0x26, 0xE1, 0xCF, 0xD5, 0xB1, 0x7A, 0xD1, 0x32, 0x1C, 0x8A, 0x5F, 0x54, 0xDA, 0xC4,
+ 0x56, 0x9F, 0xFC, 0x54, 0x5C, 0x8A, 0x49, 0x94, 0x65, 0x55, 0x23, 0x49, 0x43, 0x2F, 0xE7, 0x51,
+ 0xAE, 0x19, 0xFD, 0x9B, 0xCC, 0x95, 0xE7, 0x2C, 0xCB, 0xDF, 0xCF, 0x74, 0x1A, 0x01, 0x0C, 0x4D,
+ 0x54, 0x52, 0x77, 0xB5, 0x8B, 0x51, 0xB3, 0x3C, 0x22, 0x31, 0x30, 0xD4, 0x5E, 0x8D, 0x41, 0x3D,
+ 0x11, 0x88, 0x0D, 0xF3, 0x64, 0x9E, 0xFF, 0xD7, 0x70, 0x0F, 0x00, 0x80, 0x3D, 0x00, 0x00, 0x00,
+ 0x80, 0x0E, 0xB0, 0x45, 0xA7, 0x9D, 0x65, 0x6B, 0x78, 0xC7, 0xC6, 0xBA, 0x2D, 0x46, 0x83, 0x76,
+ 0x08, 0xAC, 0x14, 0x4B, 0x56, 0xA2, 0x09, 0x01, 0x00, 0x0D,
};
std::vector<uint8_t> const kBinKmlV6 = {
diff --git a/kml/serdes.cpp b/kml/serdes.cpp
index e5787c39e2..92361da636 100644
--- a/kml/serdes.cpp
+++ b/kml/serdes.cpp
@@ -28,6 +28,7 @@ std::string const kStyleMap = "StyleMap";
std::string const kStyleUrl = "styleUrl";
std::string const kPair = "Pair";
std::string const kExtendedData = "ExtendedData";
+std::string const kCompilation = "mwm:compilation";
std::string const kKmlHeader =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
@@ -44,6 +45,8 @@ std::string const kExtendedDataHeader =
std::string const kExtendedDataFooter =
"</ExtendedData>\n";
+std::string const kCompilationFooter = "</" + kCompilation + ">\n";
+
auto const kDefaultLang = StringUtf8Multilang::kDefaultCode;
auto const kDefaultTrackWidth = 5.0;
@@ -187,18 +190,19 @@ void SaveStringWithCDATA(KmlWriter::WriterWrapper & writer, std::string const &
writer << s;
}
-void SaveStyle(KmlWriter::WriterWrapper & writer, std::string const & style)
+void SaveStyle(KmlWriter::WriterWrapper & writer, std::string const & style, bool isCompilationData)
{
if (style.empty())
return;
- writer << kIndent2 << "<Style id=\"" << style << "\">\n"
- << kIndent4 << "<IconStyle>\n"
- << kIndent6 << "<Icon>\n"
- << kIndent8 << "<href>http://maps.me/placemarks/" << style << ".png</href>\n"
- << kIndent6 << "</Icon>\n"
- << kIndent4 << "</IconStyle>\n"
- << kIndent2 << "</Style>\n";
+ writer << (isCompilationData ? kIndent4 : kIndent2) << "<Style id=\"" << style << "\">\n"
+ << (isCompilationData ? kIndent6 : kIndent4) << "<IconStyle>\n"
+ << (isCompilationData ? kIndent8 : kIndent6) << "<Icon>\n"
+ << (isCompilationData ? kIndent10 : kIndent8) << "<href>http://maps.me/placemarks/"
+ << style << ".png</href>\n"
+ << (isCompilationData ? kIndent8 : kIndent6) << "</Icon>\n"
+ << (isCompilationData ? kIndent6 : kIndent4) << "</IconStyle>\n"
+ << (isCompilationData ? kIndent4 : kIndent2) << "</Style>\n";
}
void SaveColorToABGR(KmlWriter::WriterWrapper & writer, uint32_t rgba)
@@ -266,53 +270,75 @@ void SaveStringsMap(KmlWriter::WriterWrapper & writer,
writer << offsetStr << "</mwm:" << tagName << ">\n";
}
+void SaveCategoryData(KmlWriter::WriterWrapper & writer, CategoryData const & categoryData,
+ std::string const & extendedServerId,
+ std::vector<CategoryData> const * compilationData);
+
void SaveCategoryExtendedData(KmlWriter::WriterWrapper & writer, CategoryData const & categoryData,
- std::string const & extendedServerId)
+ std::string const & extendedServerId,
+ std::vector<CategoryData> const * compilationData)
{
- writer << kIndent2 << kExtendedDataHeader;
+ if (compilationData)
+ {
+ writer << kIndent2 << kExtendedDataHeader;
+ }
+ else
+ {
+ std::string compilationAttributes;
+ if (categoryData.m_compilationId != kInvalidCompilationId)
+ compilationAttributes += " id=\"" + strings::to_string(categoryData.m_compilationId) + "\"";
+ compilationAttributes += " type=\"" + DebugPrint(categoryData.m_type) + "\"";
+ writer << kIndent4 << "<" << kCompilation << compilationAttributes << ">\n";
+ }
+
+ auto const & indent = compilationData ? kIndent4 : kIndent6;
- if (!extendedServerId.empty())
- writer << kIndent4 << "<mwm:serverId>" << extendedServerId << "</mwm:serverId>\n";
+ if (!extendedServerId.empty() && compilationData)
+ writer << indent << "<mwm:serverId>" << extendedServerId << "</mwm:serverId>\n";
- SaveLocalizableString(writer, categoryData.m_name, "name", kIndent4);
- SaveLocalizableString(writer, categoryData.m_annotation, "annotation", kIndent4);
- SaveLocalizableString(writer, categoryData.m_description, "description", kIndent4);
+ SaveLocalizableString(writer, categoryData.m_name, "name", indent);
+ SaveLocalizableString(writer, categoryData.m_annotation, "annotation", indent);
+ SaveLocalizableString(writer, categoryData.m_description, "description", indent);
+
+ if (!compilationData)
+ writer << indent << "<mwm:visibility>" << (categoryData.m_visible ? "1" : "0")
+ << "</mwm:visibility>\n";
if (!categoryData.m_imageUrl.empty())
- writer << kIndent4 << "<mwm:imageUrl>" << categoryData.m_imageUrl << "</mwm:imageUrl>\n";
+ writer << indent << "<mwm:imageUrl>" << categoryData.m_imageUrl << "</mwm:imageUrl>\n";
if (!categoryData.m_authorId.empty() || !categoryData.m_authorName.empty())
{
- writer << kIndent4 << "<mwm:author id=\"" << categoryData.m_authorId << "\">";
+ writer << indent << "<mwm:author id=\"" << categoryData.m_authorId << "\">";
SaveStringWithCDATA(writer, categoryData.m_authorName);
writer << "</mwm:author>\n";
}
if (categoryData.m_lastModified != Timestamp())
{
- writer << kIndent4 << "<mwm:lastModified>" << TimestampToString(categoryData.m_lastModified)
+ writer << indent << "<mwm:lastModified>" << TimestampToString(categoryData.m_lastModified)
<< "</mwm:lastModified>\n";
}
double constexpr kEps = 1e-5;
if (fabs(categoryData.m_rating) > kEps)
{
- writer << kIndent4 << "<mwm:rating>" << strings::to_string(categoryData.m_rating)
+ writer << indent << "<mwm:rating>" << strings::to_string(categoryData.m_rating)
<< "</mwm:rating>\n";
}
if (categoryData.m_reviewsNumber > 0)
{
- writer << kIndent4 << "<mwm:reviewsNumber>"
- << strings::to_string(categoryData.m_reviewsNumber) << "</mwm:reviewsNumber>\n";
+ writer << indent << "<mwm:reviewsNumber>" << strings::to_string(categoryData.m_reviewsNumber)
+ << "</mwm:reviewsNumber>\n";
}
- writer << kIndent4 << "<mwm:accessRules>" << DebugPrint(categoryData.m_accessRules)
+ writer << indent << "<mwm:accessRules>" << DebugPrint(categoryData.m_accessRules)
<< "</mwm:accessRules>\n";
- SaveStringsArray(writer, categoryData.m_tags, "tags", kIndent4);
+ SaveStringsArray(writer, categoryData.m_tags, "tags", indent);
- SaveStringsArray(writer, categoryData.m_toponyms, "toponyms", kIndent4);
+ SaveStringsArray(writer, categoryData.m_toponyms, "toponyms", indent);
std::vector<std::string> languageCodes;
languageCodes.reserve(categoryData.m_languageCodes.size());
@@ -322,33 +348,54 @@ void SaveCategoryExtendedData(KmlWriter::WriterWrapper & writer, CategoryData co
if (!str.empty())
languageCodes.push_back(std::move(str));
}
- SaveStringsArray(writer, languageCodes, "languageCodes", kIndent4);
+ SaveStringsArray(writer, languageCodes, "languageCodes", indent);
+
+ SaveStringsMap(writer, categoryData.m_properties, "properties", indent);
- SaveStringsMap(writer, categoryData.m_properties, "properties", kIndent4);
+ if (compilationData)
+ {
+ for (auto const & compilationDatum : *compilationData)
+ SaveCategoryData(writer, compilationDatum, {} /* extendedServerId */,
+ nullptr /* compilationData */);
+ }
- writer << kIndent2 << kExtendedDataFooter;
+ if (compilationData)
+ writer << kIndent2 << kExtendedDataFooter;
+ else
+ writer << kIndent4 << kCompilationFooter;
}
void SaveCategoryData(KmlWriter::WriterWrapper & writer, CategoryData const & categoryData,
- std::string const & extendedServerId)
+ std::string const & extendedServerId,
+ std::vector<CategoryData> const * compilationData)
{
- for (uint8_t i = 0; i < base::Underlying(PredefinedColor::Count); ++i)
- SaveStyle(writer, GetStyleForPredefinedColor(static_cast<PredefinedColor>(i)));
-
- // Use CDATA if we have special symbols in the name.
- writer << kIndent2 << "<name>";
- SaveStringWithCDATA(writer, GetLocalizableString(categoryData.m_name, kDefaultLang));
- writer << "</name>\n";
- if (!categoryData.m_description.empty())
+ if (compilationData)
{
- writer << kIndent2 << "<description>";
- SaveStringWithCDATA(writer, GetLocalizableString(categoryData.m_description, kDefaultLang));
- writer << "</description>\n";
+ for (uint8_t i = 0; i < base::Underlying(PredefinedColor::Count); ++i)
+ SaveStyle(writer, GetStyleForPredefinedColor(static_cast<PredefinedColor>(i)),
+ !compilationData);
}
- writer << kIndent2 << "<visibility>" << (categoryData.m_visible ? "1" : "0") <<"</visibility>\n";
+ auto const & indent = compilationData ? kIndent2 : kIndent4;
+
+ if (compilationData)
+ {
+ // Use CDATA if we have special symbols in the name.
+ writer << indent << "<name>";
+ SaveStringWithCDATA(writer, GetLocalizableString(categoryData.m_name, kDefaultLang));
+ writer << "</name>\n";
+
+ if (!categoryData.m_description.empty())
+ {
+ writer << indent << "<description>";
+ SaveStringWithCDATA(writer, GetLocalizableString(categoryData.m_description, kDefaultLang));
+ writer << "</description>\n";
+ }
+
+ writer << indent << "<visibility>" << (categoryData.m_visible ? "1" : "0") << "</visibility>\n";
+ }
- SaveCategoryExtendedData(writer, categoryData, extendedServerId);
+ SaveCategoryExtendedData(writer, categoryData, extendedServerId, compilationData);
}
void SaveBookmarkExtendedData(KmlWriter::WriterWrapper & writer, BookmarkData const & bookmarkData)
@@ -572,7 +619,8 @@ void KmlWriter::Write(FileData const & fileData)
m_writer << kKmlHeader;
// Save category.
- SaveCategoryData(m_writer, fileData.m_categoryData, fileData.m_serverId);
+ SaveCategoryData(m_writer, fileData.m_categoryData, fileData.m_serverId,
+ &fileData.m_compilationData);
// Save bookmarks.
for (auto const & bookmarkData : fileData.m_bookmarksData)
@@ -587,6 +635,7 @@ void KmlWriter::Write(FileData const & fileData)
KmlParser::KmlParser(FileData & data)
: m_data(data)
+ , m_categoryData(&m_data.m_categoryData)
, m_attrCode(StringUtf8Multilang::kUnsupportedLanguageCode)
{
ResetPoint();
@@ -716,9 +765,14 @@ double KmlParser::GetTrackWidthForStyle(std::string const & styleUrl) const
return kDefaultTrackWidth;
}
-bool KmlParser::Push(std::string const & name)
+bool KmlParser::Push(std::string const & tag)
{
- m_tags.push_back(name);
+ m_tags.push_back(tag);
+ if (tag == kCompilation)
+ {
+ m_categoryData = &m_compilationData;
+ m_compilationData.m_accessRules = m_data.m_categoryData.m_accessRules;
+ }
return true;
}
@@ -728,16 +782,44 @@ void KmlParser::AddAttr(std::string const & attr, std::string const & value)
strings::AsciiToLower(attrInLowerCase);
if (IsValidAttribute(kStyle, value, attrInLowerCase))
+ {
m_styleId = value;
+ }
else if (IsValidAttribute(kStyleMap, value, attrInLowerCase))
+ {
m_mapStyleId = value;
+ }
+ else if (IsValidAttribute(kCompilation, value, attrInLowerCase))
+ {
+ if (!strings::to_uint64(value, m_categoryData->m_compilationId))
+ m_categoryData->m_compilationId = 0;
+ }
if (attrInLowerCase == "code")
+ {
m_attrCode = StringUtf8Multilang::GetLangIndex(value);
+ }
else if (attrInLowerCase == "id")
+ {
m_attrId = value;
+ }
else if (attrInLowerCase == "key")
+ {
m_attrKey = value;
+ }
+ else if (attrInLowerCase == "type" && !value.empty() && GetTagFromEnd(0) == kCompilation)
+ {
+ std::string valueInLowerCase = value;
+ strings::AsciiToLower(valueInLowerCase);
+ if (valueInLowerCase == "category")
+ m_categoryData->m_type = CompilationType::Category;
+ else if (valueInLowerCase == "collection")
+ m_categoryData->m_type = CompilationType::Collection;
+ else if (valueInLowerCase == "day")
+ m_categoryData->m_type = CompilationType::Day;
+ else
+ m_categoryData->m_type = CompilationType::Category;
+ }
}
bool KmlParser::IsValidAttribute(std::string const & type, std::string const & value,
@@ -832,6 +914,11 @@ void KmlParser::Pop(std::string const & tag)
m_trackWidth = kDefaultTrackWidth;
m_color = 0;
}
+ else if (tag == kCompilation)
+ {
+ m_data.m_compilationData.push_back(std::move(m_compilationData));
+ m_categoryData = &m_data.m_categoryData;
+ }
m_tags.pop_back();
}
@@ -847,94 +934,104 @@ void KmlParser::CharData(std::string value)
std::string const & prevTag = m_tags[count - 2];
std::string const ppTag = count > 2 ? m_tags[count - 3] : std::string();
std::string const pppTag = count > 3 ? m_tags[count - 4] : std::string();
+ std::string const ppppTag = count > 4 ? m_tags[count - 5] : std::string();
if (prevTag == kDocument)
{
if (currTag == "name")
- m_data.m_categoryData.m_name[kDefaultLang] = value;
+ m_categoryData->m_name[kDefaultLang] = value;
else if (currTag == "description")
- m_data.m_categoryData.m_description[kDefaultLang] = value;
+ m_categoryData->m_description[kDefaultLang] = value;
else if (currTag == "visibility")
- m_data.m_categoryData.m_visible = value != "0";
+ m_categoryData->m_visible = value != "0";
}
- else if (prevTag == kExtendedData && ppTag == kDocument)
+ else if ((prevTag == kExtendedData && ppTag == kDocument) ||
+ (prevTag == kCompilation && ppTag == kExtendedData && pppTag == kDocument))
{
if (currTag == "mwm:author")
{
- m_data.m_categoryData.m_authorName = value;
- m_data.m_categoryData.m_authorId = m_attrId;
+ m_categoryData->m_authorName = value;
+ m_categoryData->m_authorId = m_attrId;
m_attrId.clear();
}
else if (currTag == "mwm:lastModified")
{
auto const ts = base::StringToTimestamp(value);
if (ts != base::INVALID_TIME_STAMP)
- m_data.m_categoryData.m_lastModified = std::chrono::system_clock::from_time_t(ts);
+ m_categoryData->m_lastModified = std::chrono::system_clock::from_time_t(ts);
}
else if (currTag == "mwm:accessRules")
{
// 'Private' is here for back-compatibility.
if (value == "Private" || value == "Local")
- m_data.m_categoryData.m_accessRules = AccessRules::Local;
+ m_categoryData->m_accessRules = AccessRules::Local;
else if (value == "DirectLink")
- m_data.m_categoryData.m_accessRules = AccessRules::DirectLink;
+ m_categoryData->m_accessRules = AccessRules::DirectLink;
else if (value == "P2P")
- m_data.m_categoryData.m_accessRules = AccessRules::P2P;
+ m_categoryData->m_accessRules = AccessRules::P2P;
else if (value == "Paid")
- m_data.m_categoryData.m_accessRules = AccessRules::Paid;
+ m_categoryData->m_accessRules = AccessRules::Paid;
else if (value == "Public")
- m_data.m_categoryData.m_accessRules = AccessRules::Public;
+ m_categoryData->m_accessRules = AccessRules::Public;
else if (value == "AuthorOnly")
- m_data.m_categoryData.m_accessRules = AccessRules::AuthorOnly;
+ m_categoryData->m_accessRules = AccessRules::AuthorOnly;
}
else if (currTag == "mwm:imageUrl")
{
- m_data.m_categoryData.m_imageUrl = value;
+ m_categoryData->m_imageUrl = value;
}
else if (currTag == "mwm:rating")
{
- if (!strings::to_double(value, m_data.m_categoryData.m_rating))
- m_data.m_categoryData.m_rating = 0.0;
+ if (!strings::to_double(value, m_categoryData->m_rating))
+ m_categoryData->m_rating = 0.0;
}
else if (currTag == "mwm:reviewsNumber")
{
- if (!strings::to_uint(value, m_data.m_categoryData.m_reviewsNumber))
- m_data.m_categoryData.m_reviewsNumber = 0;
+ if (!strings::to_uint(value, m_categoryData->m_reviewsNumber))
+ m_categoryData->m_reviewsNumber = 0;
}
else if (currTag == "mwm:serverId")
{
m_data.m_serverId = value;
}
+ else if (currTag == "mwm:visibility")
+ {
+ m_categoryData->m_visible = value != "0";
+ }
}
- else if (pppTag == kDocument && ppTag == kExtendedData && currTag == "mwm:lang")
+ else if (((pppTag == kDocument && ppTag == kExtendedData) ||
+ (ppppTag == kDocument && pppTag == kExtendedData && ppTag == kCompilation)) &&
+ currTag == "mwm:lang")
{
if (prevTag == "mwm:name" && m_attrCode >= 0)
- m_data.m_categoryData.m_name[m_attrCode] = value;
+ m_categoryData->m_name[m_attrCode] = value;
else if (prevTag == "mwm:description" && m_attrCode >= 0)
- m_data.m_categoryData.m_description[m_attrCode] = value;
+ m_categoryData->m_description[m_attrCode] = value;
else if (prevTag == "mwm:annotation" && m_attrCode >= 0)
- m_data.m_categoryData.m_annotation[m_attrCode] = value;
+ m_categoryData->m_annotation[m_attrCode] = value;
m_attrCode = StringUtf8Multilang::kUnsupportedLanguageCode;
}
- else if (pppTag == kDocument && ppTag == kExtendedData && currTag == "mwm:value")
+ else if (((pppTag == kDocument && ppTag == kExtendedData) ||
+ (ppppTag == kDocument && pppTag == kExtendedData && ppTag == kCompilation)) &&
+ currTag == "mwm:value")
{
if (prevTag == "mwm:tags")
{
- m_data.m_categoryData.m_tags.push_back(value);
+ m_categoryData->m_tags.push_back(value);
}
else if (prevTag == "mwm:toponyms")
{
- m_data.m_categoryData.m_toponyms.push_back(value);
+ m_categoryData->m_toponyms.push_back(value);
}
else if (prevTag == "mwm:languageCodes")
{
auto const lang = StringUtf8Multilang::GetLangIndex(value);
if (lang != StringUtf8Multilang::kUnsupportedLanguageCode)
- m_data.m_categoryData.m_languageCodes.push_back(lang);
+ m_categoryData->m_languageCodes.push_back(lang);
}
else if (prevTag == "mwm:properties" && !m_attrKey.empty())
{
- m_data.m_categoryData.m_properties[m_attrKey] = value;
+ m_categoryData->m_properties[m_attrKey] = value;
m_attrKey.clear();
}
}
diff --git a/kml/serdes.hpp b/kml/serdes.hpp
index ec13e8bd47..a2e4034910 100644
--- a/kml/serdes.hpp
+++ b/kml/serdes.hpp
@@ -95,6 +95,8 @@ private:
double GetTrackWidthForStyle(std::string const & styleUrl) const;
FileData & m_data;
+ CategoryData m_compilationData;
+ CategoryData * m_categoryData;
std::vector<std::string> m_tags;
GeometryType m_geometryType;
diff --git a/kml/serdes_binary.hpp b/kml/serdes_binary.hpp
index 9c0976e326..1092a95407 100644
--- a/kml/serdes_binary.hpp
+++ b/kml/serdes_binary.hpp
@@ -21,22 +21,6 @@ namespace kml
{
namespace binary
{
-enum class Version : uint8_t
-{
- V0 = 0,
- V1 = 1, // 11th April 2018: new Point2D storage, added deviceId, feature name -> custom name.
- V2 = 2, // 25th April 2018: added serverId.
- V3 = 3, // 7th May 2018: persistent feature types. V3 is binary compatible with lower versions.
- V4 = 4, // 26th August 2019: key-value properties and nearestToponym for bookmarks and tracks,
- // cities -> toponyms.
- V5 = 5, // 21st November 2019: extended color palette.
- V6 = 6, // 3rd December 2019: extended bookmark icons. V6 is binary compatible with V4 and V5
- // versions.
- V7 = 7, // 13th February 2020: track points are replaced by points with altitude.
- V8 = 8, // TODO(tomilov):
- Latest = V8
-};
-
class SerializerKml
{
public:
@@ -86,6 +70,10 @@ public:
header.m_tracksOffset = sink.Pos() - startPos;
SerializeTracks(sink);
+ // Serialize tracks.
+ header.m_compilationsOffset = sink.Pos() - startPos;
+ SerializeCompilations(sink);
+
// Serialize strings.
header.m_stringsOffset = sink.Pos() - startPos;
SerializeStrings(sink);
@@ -118,6 +106,13 @@ public:
visitor(m_data.m_tracksData);
}
+ template <typename Sink>
+ void SerializeCompilations(Sink & sink)
+ {
+ CategorySerializerVisitor<Sink> visitor(sink, kDoubleBits);
+ visitor(m_data.m_compilationData);
+ }
+
// Serializes texts in a compressed storage with block access.
template <typename Sink>
void SerializeStrings(Sink & sink)
@@ -144,11 +139,12 @@ public:
{
// Check version.
NonOwningReaderSource source(reader);
- auto const v = ReadPrimitiveFromSource<Version>(source);
+ m_header.m_version = ReadPrimitiveFromSource<Version>(source);
- if (v != Version::V2 && v != Version::V3 && v != Version::V4 &&
- v != Version::V5 && v != Version::V6 && v != Version::V7 &&
- v != Version::V8)
+ if (m_header.m_version != Version::V2 && m_header.m_version != Version::V3 &&
+ m_header.m_version != Version::V4 && m_header.m_version != Version::V5 &&
+ m_header.m_version != Version::V6 && m_header.m_version != Version::V7 &&
+ m_header.m_version != Version::V8)
{
MYTHROW(DeserializeException, ("Incorrect file version."));
}
@@ -160,7 +156,7 @@ public:
auto subReader = reader.CreateSubReader(source.Pos(), source.Size());
InitializeIfNeeded(*subReader);
- switch (v)
+ switch (m_header.m_version)
{
case Version::Latest:
{
@@ -172,7 +168,7 @@ public:
FileDataV7 dataV7;
dataV7.m_deviceId = m_data.m_deviceId;
dataV7.m_serverId = m_data.m_serverId;
- DeserializeFileData(subReader, dataV7);
+ DeserializeFileDataBeforeV8(subReader, dataV7);
m_data = dataV7.ConvertToLatestVersion();
break;
@@ -185,7 +181,7 @@ public:
FileDataV6 dataV6;
dataV6.m_deviceId = m_data.m_deviceId;
dataV6.m_serverId = m_data.m_serverId;
- DeserializeFileData(subReader, dataV6);
+ DeserializeFileDataBeforeV8(subReader, dataV6);
m_data = dataV6.ConvertToLatestVersion();
break;
@@ -197,10 +193,10 @@ public:
FileDataV3 dataV3;
dataV3.m_deviceId = m_data.m_deviceId;
dataV3.m_serverId = m_data.m_serverId;
- DeserializeFileData(subReader, dataV3);
+ DeserializeFileDataBeforeV8(subReader, dataV3);
// Migrate bookmarks (it's necessary ony for v.2).
- if (v == Version::V2)
+ if (m_header.m_version == Version::V2)
MigrateBookmarksV2(dataV3);
m_data = dataV3.ConvertToLatestVersion();
@@ -250,7 +246,13 @@ private:
template <typename ReaderType>
std::unique_ptr<Reader> CreateTrackSubReader(ReaderType const & reader)
{
- return CreateSubReader(reader, m_header.m_tracksOffset, m_header.m_stringsOffset);
+ return CreateSubReader(reader, m_header.m_tracksOffset, m_header.m_compilationsOffset);
+ }
+
+ template <typename ReaderType>
+ std::unique_ptr<Reader> CreateCompilationsSubReader(ReaderType const & reader)
+ {
+ return CreateSubReader(reader, m_header.m_compilationsOffset, m_header.m_stringsOffset);
}
template <typename ReaderType>
@@ -289,6 +291,20 @@ private:
DeserializeCategory(subReader, data);
DeserializeBookmarks(subReader, data);
DeserializeTracks(subReader, data);
+ if (m_header.HasCompilationsSection())
+ DeserializeCompilations(subReader, data);
+ DeserializeStrings(subReader, data);
+ }
+
+ template <typename FileDataType>
+ void DeserializeFileDataBeforeV8(std::unique_ptr<Reader> & subReader, FileDataType & data)
+ {
+ // Keep in mind - deserialization/serialization works in two stages:
+ // - serialization/deserialization non-string members of structures;
+ // - serialization/deserialization string members of structures.
+ DeserializeCategory(subReader, data);
+ DeserializeBookmarks(subReader, data);
+ DeserializeTracks(subReader, data);
DeserializeStrings(subReader, data);
}
@@ -326,6 +342,15 @@ private:
}
template <typename FileDataType>
+ void DeserializeCompilations(std::unique_ptr<Reader> & subReader, FileDataType & data)
+ {
+ auto compilationsSubReader = CreateCompilationsSubReader(*subReader);
+ NonOwningReaderSource src(*compilationsSubReader);
+ CategoryDeserializerVisitor<decltype(src)> visitor(src, m_doubleBits);
+ visitor(data.m_compilationData);
+ }
+
+ template <typename FileDataType>
void DeserializeStrings(std::unique_ptr<Reader> & subReader, FileDataType & data)
{
auto textsSubReader = CreateStringsSubReader(*subReader);
diff --git a/kml/types.hpp b/kml/types.hpp
index cfe3f5940e..f7fe807d93 100644
--- a/kml/types.hpp
+++ b/kml/types.hpp
@@ -229,7 +229,6 @@ struct BookmarkData
visitor(m_visible, "visible"),
visitor(m_nearestToponym, "nearestToponym"),
visitor(m_properties, "properties"),
- //visitor(m_compilations, "compilations"), // TODO(tomilov): enable ASAP
VISITOR_COLLECTABLE)
DECLARE_COLLECTABLE(LocalizableStringIndex, m_name, m_description, m_customName,
@@ -248,8 +247,7 @@ struct BookmarkData
m_boundTracks == data.m_boundTracks &&
m_visible == data.m_visible &&
m_nearestToponym == data.m_nearestToponym &&
- m_properties == data.m_properties &&
- m_compilations == data.m_compilations;
+ m_properties == data.m_properties;
}
bool operator!=(BookmarkData const & data) const { return !operator==(data); }
@@ -283,8 +281,6 @@ struct BookmarkData
std::string m_nearestToponym;
// Key-value properties.
Properties m_properties;
- // List of compilationIds.
- std::vector<CompilationId> m_compilations;
};
// Note: any changes in binary format of this structure
@@ -365,8 +361,8 @@ struct TrackData
struct CategoryData
{
DECLARE_VISITOR_AND_DEBUG_PRINT(CategoryData, visitor(m_id, "id"),
- //visitor(m_compilationId, "compilationId"), // TODO(tomilov): enable ASAP
- //visitor(m_type, "type"), // TODO(tomilov): enable ASAP
+ visitor(m_compilationId, "compilationId"),
+ visitor(m_type, "type"),
visitor(m_name, "name"),
visitor(m_imageUrl, "imageUrl"),
visitor(m_annotation, "annotation"),
@@ -448,12 +444,14 @@ struct FileData
DECLARE_VISITOR_AND_DEBUG_PRINT(FileData, visitor(m_serverId, "serverId"),
visitor(m_categoryData, "category"),
visitor(m_bookmarksData, "bookmarks"),
- visitor(m_tracksData, "tracks"))
+ visitor(m_tracksData, "tracks"),
+ visitor(m_compilationData, "compilations"))
bool operator==(FileData const & data) const
{
return m_serverId == data.m_serverId && m_categoryData == data.m_categoryData &&
- m_bookmarksData == data.m_bookmarksData && m_tracksData == data.m_tracksData;
+ m_bookmarksData == data.m_bookmarksData && m_tracksData == data.m_tracksData &&
+ m_compilationData == data.m_compilationData;
}
bool operator!=(FileData const & data) const { return !operator==(data); }
diff --git a/kml/visitors.hpp b/kml/visitors.hpp
index 7d058c39d7..e56a5e6af4 100644
--- a/kml/visitors.hpp
+++ b/kml/visitors.hpp
@@ -281,7 +281,12 @@ public:
(*this)(static_cast<uint8_t>(rules));
}
- void operator()(Timestamp const & t, char const * name = nullptr)
+ void operator()(CompilationType type, char const * /* name */ = nullptr)
+ {
+ (*this)(static_cast<uint8_t>(type));
+ }
+
+ void operator()(Timestamp const & t, char const * /* name */ = nullptr)
{
WriteVarUint(m_sink, ToSecondsSinceEpoch(t));
}
@@ -297,6 +302,11 @@ public:
WritePointD(m_sink, pt, m_doubleBits);
}
+ void operator()(CategoryData const & compilationData, char const * /* name */ = nullptr)
+ {
+ compilationData.Visit(*this);
+ }
+
template <typename T>
void operator()(std::vector<T> const & vs, char const * /* name */ = nullptr)
{
@@ -471,6 +481,11 @@ public:
rules = static_cast<AccessRules>(ReadPrimitiveFromSource<uint8_t>(m_source));
}
+ void operator()(CompilationType & type, char const * /* name */ = nullptr)
+ {
+ type = static_cast<CompilationType>(ReadPrimitiveFromSource<uint8_t>(m_source));
+ }
+
void operator()(Timestamp & t, char const * /* name */ = nullptr)
{
auto const v = ReadVarUint<uint64_t, Source>(m_source);
@@ -488,6 +503,11 @@ public:
pt = ReadPointD(m_source, m_doubleBits);
}
+ void operator()(CategoryData & compilationData, char const * /* name */ = nullptr)
+ {
+ compilationData.Visit(*this);
+ }
+
template <typename T>
void operator()(std::vector<T> & vs, char const * /* name */ = nullptr)
{