diff --git a/generator/feature_builder.cpp b/generator/feature_builder.cpp index 47e7880b2..dba90fd59 100644 --- a/generator/feature_builder.cpp +++ b/generator/feature_builder.cpp @@ -11,16 +11,13 @@ #include "coding/byte_stream.hpp" #include "coding/geometry_coding.hpp" #include "coding/read_write_utils.hpp" -#include "coding/reader.hpp" #include "geometry/region2d.hpp" #include "base/logging.hpp" #include "base/math.hpp" -#include "base/string_utils.hpp" #include -#include #include namespace feature @@ -630,7 +627,9 @@ void FeatureBuilder::SerializeForMwm(SupportingData & data, serial::GeometryCodi PushBackByteSink sink(data.m_buffer); FeatureParams(m_params).Write(sink); - if (m_params.GetGeomType() == GeomType::Point) + GeomType const type = m_params.GetGeomType(); + CHECK(type != GeomType::Undefined, ()); + if (type == GeomType::Point) { serial::SavePoint(sink, m_center, params); return; @@ -640,26 +639,23 @@ void FeatureBuilder::SerializeForMwm(SupportingData & data, serial::GeometryCodi uint8_t trgCount = base::asserted_cast(data.m_innerTrg.size()); if (trgCount > 0) { - ASSERT_GREATER(trgCount, 2, ()); + CHECK_GREATER(trgCount, 2, ()); trgCount -= 2; } - GeomType const type = m_params.GetGeomType(); - { BitWriter> bitSink(sink); if (type == GeomType::Line) { - bitSink.Write(ptsCount, 4); - if (ptsCount == 0) - bitSink.Write(data.m_ptsMask, 4); + bitSink.Write(ptsCount != 0 ? ptsCount : data.m_ptsMask, 4); + bitSink.Write(ptsCount == 0 ? 1 : 0, 1); } - else if (type == GeomType::Area) + else { - bitSink.Write(trgCount, 4); - if (trgCount == 0) - bitSink.Write(data.m_trgMask, 4); + CHECK_EQUAL(type, GeomType::Area, ()); + bitSink.Write(trgCount != 0 ? trgCount : data.m_trgMask, 4); + bitSink.Write(trgCount == 0 ? 1 : 0, 1); } } @@ -671,6 +667,7 @@ void FeatureBuilder::SerializeForMwm(SupportingData & data, serial::GeometryCodi { uint32_t v = data.m_ptsSimpMask; int const count = (ptsCount - 2 + 3) / 4; + CHECK_LESS(count, 4, ()); for (int i = 0; i < count; ++i) { WriteToSink(sink, static_cast(v)); @@ -683,7 +680,7 @@ void FeatureBuilder::SerializeForMwm(SupportingData & data, serial::GeometryCodi else { auto const & poly = GetOuterGeometry(); - ASSERT_GREATER(poly.size(), 2, ()); + CHECK_GREATER(poly.size(), 2, ()); // Store first point once for outer linear features. serial::SavePoint(sink, poly[0], params); @@ -693,8 +690,10 @@ void FeatureBuilder::SerializeForMwm(SupportingData & data, serial::GeometryCodi WriteVarUintArray(data.m_ptsOffset, sink); } } - else if (type == GeomType::Area) + else { + CHECK_EQUAL(type, GeomType::Area, ()); + if (trgCount > 0) serial::SaveInnerTriangles(data.m_innerTrg, params, sink); else diff --git a/libs/indexer/dat_section_header.hpp b/libs/indexer/dat_section_header.hpp index 07e5e6a29..6ff8d714c 100644 --- a/libs/indexer/dat_section_header.hpp +++ b/libs/indexer/dat_section_header.hpp @@ -10,13 +10,13 @@ public: enum class Version : uint8_t { V0 = 0, - Latest = V0 + V1, // 2025.06, get some free bits in Feature::Header2 + Latest = V1 }; template void Serialize(Sink & sink) const { - CHECK_EQUAL(m_version, Version::V0, ()); WriteToSink(sink, static_cast(m_version)); WriteToSink(sink, m_featuresOffset); WriteToSink(sink, m_featuresSize); @@ -26,7 +26,8 @@ public: void Read(Source & source) { m_version = static_cast(ReadPrimitiveFromSource(source)); - CHECK_EQUAL(static_cast(m_version), static_cast(Version::V0), ()); + CHECK(Version::V0 <= m_version && m_version <= Version::Latest, (m_version)); + m_featuresOffset = ReadPrimitiveFromSource(source); m_featuresSize = ReadPrimitiveFromSource(source); } @@ -39,7 +40,10 @@ public: inline std::string DebugPrint(DatSectionHeader::Version v) { - CHECK(v == DatSectionHeader::Version::V0, ()); - return "V0"; + switch (v) + { + case DatSectionHeader::Version::V0: return "V0"; + default: return "Latest(V1)"; + } } } // namespace feature diff --git a/libs/indexer/feature.cpp b/libs/indexer/feature.cpp index 8361e8395..c534e6e16 100644 --- a/libs/indexer/feature.cpp +++ b/libs/indexer/feature.cpp @@ -297,7 +297,6 @@ void FeatureType::ParseCommon() if (m_parsed.m_common) return; - CHECK(m_loadInfo, ()); ParseTypes(); ArrayByteSource source(m_data.data() + m_offsets.m_common); @@ -342,21 +341,35 @@ void FeatureType::ParseHeader2() if (m_parsed.m_header2) return; - CHECK(m_loadInfo, ()); ParseCommon(); - uint8_t elemsCount = 0, geomScalesMask = 0; - BitSource bitSource(m_data.data() + m_offsets.m_header2); - auto const headerGeomType = static_cast(Header(m_data) & HEADER_MASK_GEOMTYPE); + m_parsed.m_header2 = true; - if (headerGeomType == HeaderGeomType::Line || headerGeomType == HeaderGeomType::Area) + auto const headerGeomType = static_cast(Header(m_data) & HEADER_MASK_GEOMTYPE); + if (headerGeomType != HeaderGeomType::Line && headerGeomType != HeaderGeomType::Area) + return; + + BitSource bitSource(m_data.data() + m_offsets.m_header2); + uint8_t elemsCount = bitSource.Read(4); + uint8_t geomScalesMask = 0; + + if (m_loadInfo->m_version == DatSectionHeader::Version::V0) { - elemsCount = bitSource.Read(4); // For outer geometry read the geom scales (offsets) mask. // For inner geometry remaining 4 bits are not used. if (elemsCount == 0) geomScalesMask = bitSource.Read(4); } + else + { + ASSERT_EQUAL(m_loadInfo->m_version, DatSectionHeader::Version::V1, ()); + bool const isOuter = (bitSource.Read(1) == 1); + if (isOuter) + { + geomScalesMask = elemsCount; + elemsCount = 0; + } + } ArrayByteSource src(bitSource.RoundPtr()); serial::GeometryCodingParams const & cp = m_loadInfo->GetDefGeometryCodingParams(); @@ -370,7 +383,8 @@ void FeatureType::ParseHeader2() // first and last points are never simplified/discarded, // 2 bits are used per each other point, i.e. // 3-6 pts - 1 byte, 7-10 pts - 2b, 11-14 pts - 3b. - int const count = ((elemsCount - 2) + 4 - 1) / 4; + /// @see FeatureBuilder::SerializeForMwm + int const count = (elemsCount - 2 + 3) / 4; ASSERT_LESS(count, 4, ()); for (int i = 0; i < count; ++i) @@ -393,8 +407,9 @@ void FeatureType::ParseHeader2() ReadOffsets(*m_loadInfo, src, geomScalesMask, m_offsets.m_pts); } } - else if (headerGeomType == HeaderGeomType::Area) + else { + ASSERT(headerGeomType == HeaderGeomType::Area, ()); if (elemsCount > 0) { // Inner geometry (strips). @@ -413,7 +428,6 @@ void FeatureType::ParseHeader2() // Size of the whole header incl. inner geometry / triangles. m_innerStats.m_size = CalcOffset(src, m_data.data()); - m_parsed.m_header2 = true; } void FeatureType::ResetGeometry() @@ -438,7 +452,6 @@ void FeatureType::ParseGeometry(int scale) { if (!m_parsed.m_points) { - CHECK(m_loadInfo, ()); ParseHeader2(); auto const headerGeomType = static_cast(Header(m_data) & HEADER_MASK_GEOMTYPE); @@ -539,7 +552,6 @@ void FeatureType::ParseTriangles(int scale) { if (!m_parsed.m_triangles) { - CHECK(m_loadInfo, ()); ParseHeader2(); auto const headerGeomType = static_cast(Header(m_data) & HEADER_MASK_GEOMTYPE); diff --git a/libs/indexer/features_vector.cpp b/libs/indexer/features_vector.cpp index af2bd5dd6..b7c45d0a6 100644 --- a/libs/indexer/features_vector.cpp +++ b/libs/indexer/features_vector.cpp @@ -21,7 +21,8 @@ void FeaturesVector::InitRecordsReader() feature::DatSectionHeader header; header.Read(src); - CHECK_EQUAL(header.m_version, feature::DatSectionHeader::Version::V0, ()); + m_loadInfo.m_version = header.m_version; + m_recordReader = std::make_unique(reader.SubReader(header.m_featuresOffset, header.m_featuresSize)); } diff --git a/libs/indexer/shared_load_info.hpp b/libs/indexer/shared_load_info.hpp index 157a3ea04..e16927f1e 100644 --- a/libs/indexer/shared_load_info.hpp +++ b/libs/indexer/shared_load_info.hpp @@ -1,5 +1,6 @@ #pragma once +#include "indexer/dat_section_header.hpp" #include "indexer/data_header.hpp" #include "coding/files_container.hpp" @@ -47,6 +48,7 @@ private: public: indexer::MetadataDeserializer * m_metaDeserializer; + feature::DatSectionHeader::Version m_version; DISALLOW_COPY_AND_MOVE(SharedLoadInfo); };