[gpx] Implement code-review suggestions

Signed-off-by: cyber-toad <the.cyber.toad@proton.me>
This commit is contained in:
cyber-toad 2023-06-01 07:20:01 +02:00
parent a567e6eb11
commit 89d744403c
8 changed files with 104 additions and 75 deletions

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<gpx version="1.1">
<metadata>
<name>new</name>
<time>2023-06-01T09:14:53.000Z</time>
</metadata>
<trk>
<name>empty 1</name>
<trkseg/>
</trk>
<trk>
<name>empty 2</name>
<trkseg/>
</trk>
</gpx>

View file

@ -228,29 +228,29 @@
</dict>
</dict>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.xml</string>
</array>
<key>UTTypeDescription</key>
<string>GPS Exchange Format (GPX)</string>
<key>UTTypeIdentifier</key>
<string>com.topografix.gpx</string>
<key>UTTypeReferenceURL</key>
<string>http://www.topografix.com/GPX/1/</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>gpx</string>
<string>GPX</string>
</array>
<key>public.mime-type</key>
<array>
<string>application/gpx+xml</string>
</array>
</dict>
</dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.xml</string>
</array>
<key>UTTypeDescription</key>
<string>GPS Exchange Format (GPX)</string>
<key>UTTypeIdentifier</key>
<string>com.topografix.gpx</string>
<key>UTTypeReferenceURL</key>
<string>http://www.topografix.com/GPX/1/</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>gpx</string>
<string>GPX</string>
</array>
<key>public.mime-type</key>
<array>
<string>application/gpx+xml</string>
</array>
</dict>
</dict>
</array>
</dict>
</plist>

View file

@ -5,15 +5,15 @@
#include "geometry/mercator.hpp"
#include "platform/platform.hpp"
auto const kDefaultCode = StringUtf8Multilang::kDefaultCode;
auto constexpr kDefaultCode = StringUtf8Multilang::kDefaultCode;
kml::FileData loadGpxFromString(const std::string& content) {
kml::FileData loadGpxFromString(std::string const & content) {
kml::FileData dataFromText;
try
{
const char * input = content.c_str();
kml::DeserializerGpx des(dataFromText);
MemReader reader(input, strlen(input));
MemReader const reader(input, strlen(input));
des.Deserialize(reader);
return dataFromText;
}
@ -23,17 +23,16 @@ kml::FileData loadGpxFromString(const std::string& content) {
}
}
kml::FileData loadGpxFromFile(std::string file) {
auto fileName = GetPlatform().TestsDataPathForFile(file);
std::ifstream t(fileName);
std::stringstream buffer;
buffer << t.rdbuf();
return loadGpxFromString(buffer.str());
kml::FileData loadGpxFromFile(std::string const & file) {
auto const fileName = GetPlatform().TestsDataPathForFile(file);
std::string text;
FileReader(fileName).ReadAsString(text);
return loadGpxFromString(text);
}
UNIT_TEST(Gpx_Test_Point)
{
char const * input = R"(<?xml version="1.0" encoding="UTF-8"?>
std::string const input = R"(<?xml version="1.0" encoding="UTF-8"?>
<gpx version="1.0">
<wpt lat="42.81025" lon="-1.65727">
<time>2022-09-05T08:39:39.3700Z</time>
@ -41,7 +40,7 @@ UNIT_TEST(Gpx_Test_Point)
</wpt>
)";
kml::FileData dataFromText = loadGpxFromString(input);
kml::FileData const dataFromText = loadGpxFromString(input);
kml::FileData data;
kml::BookmarkData bookmarkData;
@ -57,7 +56,7 @@ UNIT_TEST(Gpx_Test_Point)
UNIT_TEST(Gpx_Test_Route)
{
char const * input = R"(<?xml version="1.0" encoding="UTF-8"?>
std::string const input = R"(<?xml version="1.0" encoding="UTF-8"?>
<gpx version="1.0">
<trk>
<name>new</name>
@ -77,7 +76,7 @@ UNIT_TEST(Gpx_Test_Route)
</gpx>
)";
kml::FileData dataFromText = loadGpxFromString(input);
kml::FileData const dataFromText = loadGpxFromString(input);
auto line = dataFromText.m_tracksData[0].m_geometry.m_lines[0];
TEST_EQUAL(line.size(), 3, ());
TEST_EQUAL(line[0], mercator::FromLatLon(54.23955053156179, 24.114990234375004), ());
@ -85,35 +84,35 @@ UNIT_TEST(Gpx_Test_Route)
UNIT_TEST(GoMap)
{
kml::FileData dataFromFile = loadGpxFromFile("gpx_test_data/go_map.gpx");
kml::FileData const dataFromFile = loadGpxFromFile("gpx_test_data/go_map.gpx");
auto line = dataFromFile.m_tracksData[0].m_geometry.m_lines[0];
TEST_EQUAL(line.size(), 101, ());
}
UNIT_TEST(GpxStudio)
{
kml::FileData dataFromFile = loadGpxFromFile("gpx_test_data/gpx_studio.gpx");
kml::FileData const dataFromFile = loadGpxFromFile("gpx_test_data/gpx_studio.gpx");
auto line = dataFromFile.m_tracksData[0].m_geometry.m_lines[0];
TEST_EQUAL(line.size(), 328, ());
}
UNIT_TEST(OsmTrack)
{
kml::FileData dataFromFile = loadGpxFromFile("gpx_test_data/osm_track.gpx");
kml::FileData const dataFromFile = loadGpxFromFile("gpx_test_data/osm_track.gpx");
auto line = dataFromFile.m_tracksData[0].m_geometry.m_lines[0];
TEST_EQUAL(line.size(), 182, ());
}
UNIT_TEST(TowerCollector)
{
kml::FileData dataFromFile = loadGpxFromFile("gpx_test_data/tower_collector.gpx");
kml::FileData const dataFromFile = loadGpxFromFile("gpx_test_data/tower_collector.gpx");
auto line = dataFromFile.m_tracksData[0].m_geometry.m_lines[0];
TEST_EQUAL(line.size(), 35, ());
}
UNIT_TEST(PointsOnly)
{
kml::FileData dataFromFile = loadGpxFromFile("gpx_test_data/points.gpx");
kml::FileData const dataFromFile = loadGpxFromFile("gpx_test_data/points.gpx");
auto bookmarks = dataFromFile.m_bookmarksData;
TEST_EQUAL(bookmarks.size(), 3, ());
TEST_EQUAL("Point 1", bookmarks[0].m_name[kDefaultCode], ());
@ -132,7 +131,7 @@ UNIT_TEST(Route)
UNIT_TEST(Color)
{
kml::FileData dataFromFile = loadGpxFromFile("gpx_test_data/color.gpx");
kml::FileData const dataFromFile = loadGpxFromFile("gpx_test_data/color.gpx");
TEST_EQUAL(4278190335, dataFromFile.m_tracksData[0].m_layers[0].m_color.m_rgba, ());
TEST_EQUAL(65535, dataFromFile.m_tracksData[1].m_layers[0].m_color.m_rgba, ());
}
@ -148,4 +147,11 @@ UNIT_TEST(MultiTrackNames)
TEST_EQUAL("description 2", dataFromFile.m_tracksData[1].m_description[kml::kDefaultLang], ());
}
UNIT_TEST(Empty)
{
kml::FileData dataFromFile = loadGpxFromFile("gpx_test_data/empty.gpx");
TEST_EQUAL("new", dataFromFile.m_categoryData.m_name[kml::kDefaultLang], ());
TEST_EQUAL(0, dataFromFile.m_tracksData.size(), ());
}

View file

@ -4,9 +4,9 @@
namespace kml
{
auto const kDefaultLang = StringUtf8Multilang::kDefaultCode;
auto const kDefaultTrackWidth = 5.0;
auto const kDefaultTrackColor = 0x006ec7ff;
auto constexpr kDefaultLang = StringUtf8Multilang::kDefaultCode;
auto constexpr kDefaultTrackWidth = 5.0;
auto constexpr kDefaultTrackColor = 0x006ec7ff;
template <typename Channel>
uint32_t ToRGBA(Channel red, Channel green, Channel blue, Channel alpha)
@ -15,4 +15,4 @@ uint32_t ToRGBA(Channel red, Channel green, Channel blue, Channel alpha)
static_cast<uint8_t>(blue) << 8 | static_cast<uint8_t>(alpha);
}
}
} // namespace kml

View file

@ -19,16 +19,16 @@ namespace gpx
using namespace std::string_view_literals;
std::string_view const kTrk = "trk";
std::string_view const kTrkSeg = "trkseg";
std::string_view const kRte = "rte";
std::string_view const kTrkPt = "trkpt";
std::string_view const kWpt = "wpt";
std::string_view const kRtePt = "rtept";
std::string_view const kName = "name";
std::string_view const kColor = "color";
std::string_view const kDesc = "desc";
std::string_view const kMetadata = "metadata";
std::string_view constexpr kTrk = "trk";
std::string_view constexpr kTrkSeg = "trkseg";
std::string_view constexpr kRte = "rte";
std::string_view constexpr kTrkPt = "trkpt";
std::string_view constexpr kWpt = "wpt";
std::string_view constexpr kRtePt = "rtept";
std::string_view constexpr kName = "name";
std::string_view constexpr kColor = "color";
std::string_view constexpr kDesc = "desc";
std::string_view constexpr kMetadata = "metadata";
std::string PointToString(m2::PointD const & org)
@ -42,7 +42,6 @@ std::string PointToString(m2::PointD const & org)
ss << lon << "," << lat;
return ss.str();
}
}
GpxParser::GpxParser(FileData & data)
: m_data(data)
@ -90,7 +89,7 @@ bool GpxParser::MakeValid()
return false;
}
bool GpxParser::Push(std::string_view const & tag)
bool GpxParser::Push(std::string_view tag)
{
m_tags.push_back(tag);
if (GetTagFromEnd(0) == gpx::kWpt)
@ -104,7 +103,7 @@ void GpxParser::AddAttr(std::string const & attr, std::string const & value)
{
std::string attrInLowerCase = attr;
strings::AsciiToLower(attrInLowerCase);
if (GetTagFromEnd(0) == gpx::kWpt)
{
if (attr == "lat")
@ -120,7 +119,7 @@ void GpxParser::AddAttr(std::string const & attr, std::string const & value)
else if (attr == "lon")
m_lon = stod(value);
}
}
std::string_view GpxParser::GetTagFromEnd(size_t n) const
@ -222,7 +221,9 @@ void GpxParser::CharData(std::string value)
m_name[kml::kDefaultLang] = value;
if (m_categoryData->m_name[kml::kDefaultLang].empty())
m_categoryData->m_name[kml::kDefaultLang] = value;
} else if (currTag == gpx::kDesc) {
}
else if (currTag == gpx::kDesc)
{
m_description[kml::kDefaultLang] = value;
if (m_categoryData->m_description[kml::kDefaultLang].empty())
m_categoryData->m_description[kml::kDefaultLang] = value;
@ -239,6 +240,7 @@ void GpxParser::CharData(std::string value)
ParseColor(value);
}
}
} // namespace gpx
DeserializerGpx::DeserializerGpx(FileData & fileData)
: m_fileData(fileData)
@ -246,4 +248,4 @@ DeserializerGpx::DeserializerGpx(FileData & fileData)
m_fileData = {};
}
} // namespace kml
} // namespace kml

View file

@ -18,12 +18,13 @@
namespace kml
{
namespace gpx
{
class GpxParser
{
public:
explicit GpxParser(FileData & data);
bool Push(std::string_view const & name);
bool Push(std::string_view name);
void AddAttr(std::string const & attr, std::string const & value);
std::string_view GetTagFromEnd(size_t n) const;
void Pop(std::string_view tag);
@ -36,15 +37,15 @@ private:
GEOMETRY_TYPE_POINT,
GEOMETRY_TYPE_LINE
};
void ResetPoint();
bool MakeValid();
void ParseColor(std::string const &value);
void ParseColor(std::string const & value);
FileData & m_data;
CategoryData m_compilationData;
CategoryData * m_categoryData; // never null
std::vector<std::string_view> m_tags;
GeometryType m_geometryType;
MultiGeometry m_geometry;
@ -62,6 +63,7 @@ private:
LocalizableString m_customName;
std::vector<TrackLayer> m_trackLayers;
};
} // namespace gpx
class DeserializerGpx
{
@ -75,7 +77,7 @@ public:
{
NonOwningReaderSource src(reader);
GpxParser parser(m_fileData);
gpx::GpxParser parser(m_fileData);
if (!ParseXML(src, parser, true))
{
// Print corrupted GPX file for debug and restore purposes.
@ -90,4 +92,4 @@ public:
private:
FileData & m_fileData;
};
} // namespace kml
} // namespace kml

View file

@ -276,13 +276,13 @@ std::string const kDefaultBookmarksFileName = "Bookmarks";
// Populate empty category & track names based on file name: assign file name to category name,
// if there is only one unnamed track - assign file name to it, otherwise add numbers 1, 2, 3...
// to file name to build names for all unnamed tracks
void FillEmptyNames(std::unique_ptr<kml::FileData> & kmlData, const std::string & file)
void FillEmptyNames(std::unique_ptr<kml::FileData> & kmlData, std::string const & file)
{
auto start = file.find_last_of('/') + 1;
auto end = file.find_last_of('.');
if (end == std::string::npos)
end = file.size();
auto name = file.substr(start, end - start);
auto const name = file.substr(start, end - start);
if (kmlData->m_categoryData.m_name.empty())
kmlData->m_categoryData.m_name[kml::kDefaultLang] = name;
@ -290,7 +290,7 @@ void FillEmptyNames(std::unique_ptr<kml::FileData> & kmlData, const std::string
if (kmlData->m_tracksData.empty())
return;
auto emptyNames = std::count_if(kmlData->m_tracksData.begin(), kmlData->m_tracksData.end(),
auto const emptyNames = std::count_if(kmlData->m_tracksData.begin(), kmlData->m_tracksData.end(),
[](const kml::TrackData & t) { return t.m_name.empty(); });
if (emptyNames == 0)
return;

View file

@ -1873,10 +1873,14 @@ void BookmarkManager::LoadBookmarkRoutine(std::string const & filePath, bool isT
{
auto const ext = base::GetFileExtension(filePath);
std::unique_ptr<kml::FileData> kmlData;
if (ext == ".gpx")
kmlData = LoadKmlFile(fileSavePath, KmlFileType::Gpx);
else
if (ext == ".kml" || ext == ".kmz")
kmlData = LoadKmlFile(fileSavePath, KmlFileType::Text);
else if (ext == ".gpx")
kmlData = LoadKmlFile(fileSavePath, KmlFileType::Gpx);
else if (ext == ".kmb")
kmlData = LoadKmlFile(fileSavePath, KmlFileType::Binary);
else
ASSERT(false, ("Unsupported bookmarks extension", ext));
if (m_needTeardown)
return;