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