[gpx] Implement code-review suggestions
Signed-off-by: cyber-toad <the.cyber.toad@proton.me>
This commit is contained in:
parent
a567e6eb11
commit
89d744403c
8 changed files with 104 additions and 75 deletions
15
data/gpx_test_data/empty.gpx
Normal file
15
data/gpx_test_data/empty.gpx
Normal 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>
|
|
@ -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>
|
||||
|
|
|
@ -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(), ());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Reference in a new issue