1 #include "config.h"
2
3 // if liblightgrep isn't present, compiles to nothing
4 #ifdef HAVE_LIBLIGHTGREP
5
6 #include <string>
7
8 #include "be13_api/scanner_params.h"
9
10 #include "pattern_scanner.h"
11
12 namespace gps {
13 const char* const DefaultEncodingsCStrings[] = {"UTF-8", "UTF-16LE"};
14
15 const vector<string> DefaultEncodings(
16 DefaultEncodingsCStrings,
17 DefaultEncodingsCStrings +
18 sizeof(DefaultEncodingsCStrings)/sizeof(DefaultEncodingsCStrings[0])
19 );
20
21 const LG_KeyOptions DefaultOptions = { 0, 0 }; // patterns, case-sensitive
22
23 //
24 // helper functions
25 //
26
27 /**
28 * Return NNN in <tag attrib="NNN">
29 */
get_quoted_attrib(string text,string attrib)30 string get_quoted_attrib(string text, string attrib) {
31 const size_t pos = text.find(attrib);
32 if (pos == string::npos) return ""; /* no attrib */
33 const ssize_t quote1 = text.find('"', pos);
34 if (quote1 < 0) return ""; /* no opening quote */
35 const ssize_t quote2 = text.find('"', quote1+1);
36 if (quote2 < 0) return ""; /* no closing quote */
37 return text.substr(quote1+1, quote2-(quote1+1));
38 }
39
40 /**
41 * Return NNN in <tag>NNN</tag>
42 */
get_cdata(string text)43 string get_cdata(string text) {
44 const ssize_t gt = text.find('>');
45 if (gt < 0) return ""; /* no > */
46 const ssize_t lt = text.find('<', gt+1);
47 if (lt < 0) return ""; /* no < */
48 return text.substr(gt+1, lt-(gt+1));
49 }
50
51 //
52 // subpatterns
53 //
54
55 const string LATLON("(-?[0-9]{1,3}\\.[0-9]{6,8})");
56 const string ELEV("(-?[0-9]{1,6}\\.[0-9]{0,3})");
57
58 //
59 // the scanner
60 //
61
62 class Scanner: public PatternScanner {
63 public:
Scanner()64 Scanner(): PatternScanner("gps_lg"), Recorder(0), Lat(), Lon(), Ele(), Time(), Speed(), Course() {}
~Scanner()65 virtual ~Scanner() {}
66
clone() const67 virtual Scanner* clone() const { return new Scanner(*this); }
68
69 virtual void startup(const scanner_params& sp);
70 virtual void init(const scanner_params& sp);
71 virtual void initScan(const scanner_params&);
72
73 feature_recorder* Recorder {};
74
75 void trkptHandler(const LG_SearchHit& hit, const scanner_params& sp);
76
77 void eleHandler(const LG_SearchHit& hit, const scanner_params& sp);
78
79 void timeHandler(const LG_SearchHit& hit, const scanner_params& sp);
80
81 void speedHandler(const LG_SearchHit& hit, const scanner_params& sp);
82
83 void courseHandler(const LG_SearchHit& hit, const scanner_params& sp);
84
85 private:
Scanner(const Scanner & s)86 Scanner(const Scanner& s): PatternScanner(s), Recorder(s.Recorder), Lat(s.Lat), Lon(s.Lon), Ele(s.Ele), Time(s.Time), Speed(s.Speed), Course(s.Course) {}
87 Scanner& operator=(const Scanner&);
88
89 void clear(const scanner_params& sp, size_t pos);
90
91 string Lat, Lon, Ele, Time, Speed, Course;
92 };
93
startup(const scanner_params & sp)94 void Scanner::startup(const scanner_params& sp) {
95 sp.check_version();
96
97 sp.info->name = "gps_lg";
98 sp.info->author = "Simson L. Garfinkel";
99 sp.info->description = "Garmin Trackpt XML info";
100 sp.info->scanner_version = "1.0";
101 sp.info->feature_defs.push_back( feature_recorder_def("gps"));
102 }
103
init(const scanner_params & sp)104 void Scanner::init(const scanner_params& sp) {
105 //
106 // patterns
107 //
108
109 const string TRKPT("<trkpt lat=\"" + LATLON + "\" lon=\"" + LATLON + '"');
110
111 new Handler(
112 *this,
113 TRKPT,
114 DefaultEncodings,
115 DefaultOptions,
116 &Scanner::trkptHandler
117 );
118
119 const string ELE("<ele>" + ELEV + "</ele>");
120
121 new Handler(
122 *this,
123 ELE,
124 DefaultEncodings,
125 DefaultOptions,
126 &Scanner::eleHandler
127 );
128
129 const string TIME("<time>[0-9]{4}(-[0-9]{2}){2}[ T]([0-9]{2}:){2}[0-9]{2}(Z|([-+][0-9.]))</time>");
130
131 new Handler(
132 *this,
133 TIME,
134 DefaultEncodings,
135 DefaultOptions,
136 &Scanner::timeHandler
137 );
138
139 const string GPXTPX_SPEED("<gpxtpx:speed>" + ELEV + "</gpxtpx:speed>");
140
141 new Handler(
142 *this,
143 GPXTPX_SPEED,
144 DefaultEncodings,
145 DefaultOptions,
146 &Scanner::speedHandler
147 );
148
149 const string GPXTPX_COURSE("<gpxtpx:course>" + ELEV + "</gpxtpx:course>");
150
151 new Handler(
152 *this,
153 GPXTPX_COURSE,
154 DefaultEncodings,
155 DefaultOptions,
156 &Scanner::courseHandler
157 );
158 }
159
initScan(const scanner_params & sp)160 void Scanner::initScan(const scanner_params& sp) {
161 Recorder = &sp.named_feature_recorder("gps");
162 }
163
clear(const scanner_params & sp,size_t pos)164 void Scanner::clear(const scanner_params& sp, size_t pos) {
165 // dump the current and go to the next
166 if (!Time.empty() || !Lat.empty() || !Lon.empty() ||
167 !Ele.empty() || !Speed.empty() || !Course.empty()) {
168 const string what = Time + "," + Lat + "," + Lon + "," +
169 Ele + "," + Speed + "," + Course;
170 // NB: the pos is the *end* of the "hit"
171 Recorder->write(sp.sbuf.pos0 + pos, what, "");
172
173 Time.clear();
174 Lat.clear();
175 Lon.clear();
176 Ele.clear();
177 Speed.clear();
178 Course.clear();
179 }
180 }
181
trkptHandler(const LG_SearchHit & hit,const scanner_params & sp)182 void Scanner::trkptHandler(const LG_SearchHit& hit, const scanner_params& sp) {
183 clear(sp, hit.Start);
184 Lat = get_quoted_attrib(reinterpret_cast<const char*>(sp.sbuf.buf), "lat");
185 Lon = get_quoted_attrib(reinterpret_cast<const char*>(sp.sbuf.buf), "lon");
186 }
187
eleHandler(const LG_SearchHit & hit,const scanner_params & sp)188 void Scanner::eleHandler(const LG_SearchHit& hit, const scanner_params& sp) {
189 Ele = get_cdata(reinterpret_cast<const char*>(sp.sbuf.buf));
190 }
191
timeHandler(const LG_SearchHit & hit,const scanner_params & sp)192 void Scanner::timeHandler(const LG_SearchHit& hit, const scanner_params& sp) {
193 Time = get_cdata(reinterpret_cast<const char*>(sp.sbuf.buf));
194 }
195
speedHandler(const LG_SearchHit & hit,const scanner_params & sp)196 void Scanner::speedHandler(const LG_SearchHit& hit, const scanner_params& sp) {
197 Speed = get_cdata(reinterpret_cast<const char*>(sp.sbuf.buf));
198 }
199
courseHandler(const LG_SearchHit & hit,const scanner_params & sp)200 void Scanner::courseHandler(const LG_SearchHit& hit, const scanner_params& sp) {
201 Course = get_cdata(reinterpret_cast<const char*>(sp.sbuf.buf));
202 }
203
204 Scanner TheScanner;
205 }
206
207 extern "C"
scan_gps_lg(scanner_params & sp)208 void scan_gps_lg(scanner_params &sp) {
209 scan_lg(gps::TheScanner, sp, rcb);
210 }
211
212 #endif // HAVE_LIBLIGHTGREP
213