tracklib/decode/
mod.rs

1use std::iter::FromIterator;
2use std::time::{UNIX_EPOCH, Duration};
3use std::collections::{BTreeMap};
4use nom::*;
5use ::crc::crc32::{checksum_ieee};
6use ::crc::crc16::{checksum_usb};
7
8mod varint;
9mod crc;
10
11use varint::{take_signed_leb128, take_unsigned_leb128};
12use crate::flagscolumn::{FlagsColumn};
13use crate::rwtfile::{RWTFMAGIC, RWTFTRAILER, RWTFHeader, RWTFile};
14use crate::metadata::{RWTFMetadata, TrackType};
15use crate::section::{Column, Section, SectionType};
16use crate::decode::crc::{CRC};
17
18trait Parsable {
19    type Return;
20
21    fn parse(i: &[u8]) -> IResult<&[u8], Self::Return>;
22}
23
24//////////////////////////////
25//          Header          //
26//////////////////////////////
27#[derive(Debug)]
28struct ParsedHeader {
29    metadata_table_offset: u16,
30    data_offset: u16,
31    crc: CRC<u16>
32}
33
34impl Parsable for RWTFHeader {
35    type Return = (Self, ParsedHeader);
36
37    fn parse(i: &[u8]) -> IResult<&[u8], Self::Return> {
38        do_parse!(i,
39                  tag!(RWTFMAGIC) >>
40                  file_version: le_u8 >>
41                  le_u24 >>
42                  creator_version: le_u8 >>
43                  le_u24 >>
44                  metadata_table_offset: le_u16 >>
45                  data_offset: le_u16 >>
46                  le_u16 >>
47                  crc: le_u16 >>
48                  ((RWTFHeader{file_version,
49                               creator_version},
50                    ParsedHeader{metadata_table_offset,
51                                 data_offset,
52                                 crc: CRC::new(crc, checksum_usb(&i[0..22]))})))
53    }
54}
55
56//////////////////////////////
57//         Metadata         //
58//////////////////////////////
59#[derive(Debug)]
60enum RWTFMetadataEntry {
61    TrackType(TrackType),
62    CreatedAt(u64),
63    Unknown,
64}
65
66fn parse_metadata_table_entry_data(i: &[u8], tag: u8) -> IResult<&[u8], RWTFMetadataEntry> {
67    match tag {
68        0x00 => {
69            match do_parse!(i,
70                            _size: le_u16 >>
71                            track_type_tag: le_u8 >>
72                            id: le_u32 >>
73                            (TrackType::from_tag(track_type_tag, id))) {
74                Ok((rest, tt)) => match tt {
75                    Some(tt) => Ok((rest, RWTFMetadataEntry::TrackType(tt))),
76                    None => Err(Err::Error(Context::Code(i, ErrorKind::Custom(0)))),
77                },
78                Err(_) => Err(Err::Error(Context::Code(i, ErrorKind::Custom(0)))),
79            }
80        }
81        0x01 => {
82            do_parse!(i,
83                      _size: le_u16 >>
84                      timestamp: le_u64 >>
85                      (RWTFMetadataEntry::CreatedAt(timestamp)))
86        }
87        _ => {
88            let (rest, size) = le_u16(i)?;
89            let (rest, _data) = take!(rest, size)?;
90            // todo: do something with data
91            Ok((rest, RWTFMetadataEntry::Unknown))
92        }
93    }
94}
95
96fn parse_metadata_table_entry(i: &[u8]) -> IResult<&[u8], RWTFMetadataEntry> {
97    do_parse!(i,
98              tag: le_u8 >>
99              entry: apply!(parse_metadata_table_entry_data, tag) >>
100              (entry))
101}
102
103impl Parsable for RWTFMetadata {
104    type Return = (Self, CRC<u16>);
105
106    fn parse(i: &[u8]) -> IResult<&[u8], Self::Return> {
107        let (rest, entries) = do_parse!(i,
108                                        count: le_u8 >>
109                                        entries: many_m_n!(count as usize, count as usize, parse_metadata_table_entry) >>
110                                        (entries))?;
111
112        let diff = i.offset(rest);
113        let (rest, crc) = le_u16(rest)?;
114
115        let mut created_at = None;
116        let mut track_type = None;
117
118        for entry in entries {
119            match entry {
120                RWTFMetadataEntry::TrackType(tt) => {
121                    track_type = Some(tt)
122                },
123                RWTFMetadataEntry::CreatedAt(time) => {
124                    created_at = UNIX_EPOCH.checked_add(Duration::new(time, 0));
125                },
126                RWTFMetadataEntry::Unknown => {},
127            }
128        }
129
130        Ok((rest, (RWTFMetadata::new(created_at, track_type),
131                   CRC::new(crc, checksum_usb(&i[..diff])))))
132    }
133}
134
135//////////////////////////////
136//       Flags Column       //
137//////////////////////////////
138impl FlagsColumn {
139    fn parse_flags_column<'a, 'b>(i: &'a [u8], types_table: &'b TypesTable, points: u32) -> IResult<&'a [u8], FlagsColumn> {
140        let width = (types_table.entries.len() + 7) / 8;
141
142        let fields = BTreeMap::from_iter(types_table.entries.iter().enumerate().map(|(i, entry)| (entry.name.clone(), i)));
143
144        let mut data = BTreeMap::new();
145        let mut remainder = i;
146        for i in 0..points {
147            let (rest, bitfield_bytes) = take!(remainder, width)?;
148            remainder = rest;
149
150            let mut bitfield_array = [0; 8];
151            for i in 0..8 {
152                bitfield_array[i] = *bitfield_bytes.get(i).unwrap_or(&0);
153            }
154
155            let bitfield_integer = u64::from_le_bytes(bitfield_array);
156
157            if bitfield_integer > 0 {
158                data.insert(i as usize, bitfield_integer);
159            }
160        }
161
162        Ok((remainder, FlagsColumn{fields: fields,
163                                   data: data,
164                                   max: (points - 1) as usize}))
165    }
166}
167
168//////////////////////////////
169//         Section          //
170//////////////////////////////
171fn parse_section_type(i: &[u8]) -> IResult<&[u8], SectionType> {
172    let (rest, tag) = le_u8(i)?;
173    match SectionType::from_tag(tag) {
174        Some(st) => Ok((rest, st)),
175        None => Err(Err::Error(Context::Code(i, ErrorKind::Custom(0)))),
176    }
177}
178
179#[derive(Debug)]
180enum ColumnType {
181    Numbers,
182    LongFloat,
183    ShortFloat,
184    Base64,
185    String,
186    Bool,
187    IDs,
188}
189
190impl ColumnType {
191    fn from_tag(tag: u8) -> Option<Self> {
192        match tag {
193            0x00 => Some(ColumnType::Numbers),
194            0x01 => Some(ColumnType::LongFloat),
195            0x02 => Some(ColumnType::ShortFloat),
196            0x03 => Some(ColumnType::Base64),
197            0x04 => Some(ColumnType::String),
198            0x05 => Some(ColumnType::Bool),
199            0x06 => Some(ColumnType::IDs),
200            _ => None
201        }
202    }
203}
204
205#[derive(Debug)]
206pub struct SectionHeader {
207    section_type: SectionType,
208    points: u32,
209    size: u64,
210    crc: CRC<u16>,
211}
212
213fn parse_section_header(i: &[u8]) -> IResult<&[u8], SectionHeader> {
214    let (rest, section_type) = parse_section_type(i)?;
215    let (rest, points) = le_u24(rest)?;
216    let (rest, size) = le_u64(rest)?;
217
218    let diff = i.offset(rest);
219    let (rest, crc) = le_u16(rest)?;
220
221    Ok((rest, SectionHeader{section_type,
222                            points,
223                            size,
224                            crc: CRC::new(crc, checksum_usb(&i[..diff]))}))
225}
226
227#[derive(Debug)]
228struct TypesTableEntry {
229    column_type: ColumnType,
230    name: String,
231}
232
233fn parse_column_type(i: &[u8]) -> IResult<&[u8], ColumnType> {
234    let (rest, tag) = le_u8(i)?;
235    match ColumnType::from_tag(tag) {
236        Some(c) => Ok((rest, c)),
237        None => Err(Err::Error(Context::Code(i, ErrorKind::Custom(0)))),
238    }
239}
240
241fn parse_types_table_entry(i: &[u8]) -> IResult<&[u8], TypesTableEntry> {
242    do_parse!(i,
243              column_type: parse_column_type >>
244              name_len: le_u8 >>
245              name: take!(name_len) >>
246              (TypesTableEntry{column_type,
247                               name: String::from_utf8_lossy(name).into_owned()}))
248}
249
250#[derive(Debug)]
251pub struct TypesTable {
252    entries: Vec<TypesTableEntry>,
253    crc: CRC<u16>,
254}
255
256fn parse_types_table(i: &[u8]) -> IResult<&[u8], TypesTable> {
257    let (rest, entries) = do_parse!(i,
258                                    count: le_u8 >>
259                                    entries: many_m_n!(count as usize, count as usize, parse_types_table_entry) >>
260                                    (entries))?;
261    let diff = i.offset(rest);
262    let (rest, crc) = le_u16(rest)?;
263
264    Ok((rest, TypesTable{entries,
265                         crc: CRC::new(crc, checksum_usb(&i[..diff]))}))
266}
267
268fn parse_number_row<'a>(i: &'a [u8]) -> IResult<&'a [u8], i64> {
269    take_signed_leb128(i)
270}
271
272fn parse_bytes_row<'a>(i: &'a [u8]) -> IResult<&'a [u8], &'a [u8]> {
273    do_parse!(i,
274              len: take_unsigned_leb128 >>
275              bytes: take!(len) >>
276              (bytes))
277
278}
279
280fn parse_bool_row<'a>(i: &'a [u8]) -> IResult<&'a [u8], bool> {
281    do_parse!(i,
282              b: le_u8 >>
283              ({
284                  if b == 0 {
285                      false
286                  } else {
287                      true
288                  }
289              }))
290}
291
292fn parse_ids_row<'a>(i: &'a [u8]) -> IResult<&'a [u8], Vec<u64>> {
293    do_parse!(i,
294              count: take_unsigned_leb128 >>
295              entries: many_m_n!(count as usize, count as usize, take_unsigned_leb128) >>
296              (entries))
297}
298
299fn parse_column<'a>(i: &'a [u8], column: &TypesTableEntry, flags: &FlagsColumn) -> IResult<&'a [u8], Column> {
300    match column.column_type {
301        ColumnType::Numbers => {
302            let mut m = BTreeMap::new();
303            let mut remainder = i;
304            let mut last = 0;
305            for index in 0..flags.len() {
306                if flags.is_present(index, &column.name) {
307                    let (rest, delta) = parse_number_row(remainder)?;
308                    remainder = rest;
309                    let v = last + delta;
310                    last = v;
311                    m.insert(index, v);
312                } else {
313                    // skip forward one byte
314                    remainder = &remainder[1..];
315                }
316            }
317
318            Ok((remainder, Column::Numbers(m)))
319        }
320        ColumnType::LongFloat => {
321            let mut m = BTreeMap::new();
322            let mut remainder = i;
323            let mut last = 0;
324            for index in 0..flags.len() {
325                if flags.is_present(index, &column.name) {
326                    let (rest, delta) = parse_number_row(remainder)?;
327                    remainder = rest;
328                    let v = last + delta;
329                    last = v;
330                    m.insert(index, v as f64 / 10000000.0);
331                } else {
332                    // skip forward one byte
333                    remainder = &remainder[1..];
334                }
335            }
336
337            Ok((remainder, Column::LongFloat(m)))
338        }
339        ColumnType::ShortFloat => {
340            let mut m = BTreeMap::new();
341            let mut remainder = i;
342            let mut last = 0;
343            for index in 0..flags.len() {
344                if flags.is_present(index, &column.name) {
345                    let (rest, delta) = parse_number_row(remainder)?;
346                    remainder = rest;
347                    let v = last + delta;
348                    last = v;
349                    m.insert(index, v as f64 / 1000.0);
350                } else {
351                    // skip forward one byte
352                    remainder = &remainder[1..];
353                }
354            }
355
356            Ok((remainder, Column::ShortFloat(m)))
357        }
358        ColumnType::Base64 => {
359            let mut m = BTreeMap::new();
360            let mut remainder = i;
361            for index in 0..flags.len() {
362                if flags.is_present(index, &column.name) {
363                    let (rest, bytes) = parse_bytes_row(remainder)?;
364                    remainder = rest;
365                    m.insert(index, bytes.to_vec());
366                } else {
367                    // skip forward one byte
368                    remainder = &remainder[1..];
369                }
370            }
371
372            Ok((remainder, Column::Base64(m)))
373        }
374        ColumnType::String => {
375            let mut m = BTreeMap::new();
376            let mut remainder = i;
377            for index in 0..flags.len() {
378                if flags.is_present(index, &column.name) {
379                    let (rest, bytes) = parse_bytes_row(remainder)?;
380                    remainder = rest;
381                    m.insert(index, String::from_utf8_lossy(bytes).into_owned());
382                } else {
383                    // skip forward one byte
384                    remainder = &remainder[1..];
385                }
386            }
387
388            Ok((remainder, Column::String(m)))
389        }
390        ColumnType::Bool => {
391            let mut m = BTreeMap::new();
392            let mut remainder = i;
393            for index in 0..flags.len() {
394                if flags.is_present(index, &column.name) {
395                    let (rest, b) = parse_bool_row(remainder)?;
396                    remainder = rest;
397                    m.insert(index, b);
398                } else {
399                    // skip forward one byte
400                    remainder = &remainder[1..];
401                }
402            }
403
404            Ok((remainder, Column::Bool(m)))
405        }
406        ColumnType::IDs => {
407            let mut m = BTreeMap::new();
408            let mut remainder = i;
409            for index in 0..flags.len() {
410                if flags.is_present(index, &column.name) {
411                    let (rest, b) = parse_ids_row(remainder)?;
412                    remainder = rest;
413                    m.insert(index, b);
414                } else {
415                    // skip forward one byte
416                    remainder = &remainder[1..];
417                }
418            }
419
420            Ok((remainder, Column::IDs(m)))
421        }
422    }
423}
424
425impl Parsable for Section {
426    type Return = Option<Self>;
427
428    fn parse(i: &[u8]) -> IResult<&[u8], Self::Return> {
429        let (rest, section_header) = alt!(i,
430                                          tag!(&RWTFTRAILER) => { |_| None } |
431                                          parse_section_header => {|header| Some(header)})?;
432
433        if let Some(header) = section_header {
434            let (rest, types_table) = parse_types_table(rest)?;
435
436            let data_column_start = i.offset(rest);
437            let (mut rest, flags) = FlagsColumn::parse_flags_column(&rest, &types_table, header.points)?;
438
439            let mut m = BTreeMap::new();
440            for column in types_table.entries.iter() {
441                let (new_rest, data) = parse_column(&rest, &column, &flags)?;
442                rest = new_rest;
443                m.insert(column.name.clone(), data);
444            }
445
446            let data_column_end = i.offset(rest);
447            let (rest, crc) = le_u32(&rest)?;
448            let _actual_crc = CRC::new(crc, checksum_ieee(&i[data_column_start..data_column_end])); // TODO: use this
449
450            Ok((rest, Some(Section{section_type: header.section_type,
451                                   max: flags.max(),
452                                   flags: flags,
453                                   columns: m})))
454        } else {
455            Ok((rest, None))
456        }
457    }
458}
459
460//////////////////////////////
461//         RWTFile          //
462//////////////////////////////
463impl Parsable for RWTFile {
464    type Return = Self;
465
466    fn parse(i: &[u8]) -> IResult<&[u8], Self::Return> {
467        let (_rest, (header, header_details)) = RWTFHeader::parse(i)?;
468        let (_rest, (metadata, _metadata_crc)) = RWTFMetadata::parse(&i[header_details.metadata_table_offset as usize..])?;
469        // TODO: use metadata_crc
470
471        let mut remainder = &i[header_details.data_offset as usize..];
472
473        let mut track_points = None;
474        let mut course_points = None;
475
476        loop {
477            let (rest, section) = Section::parse(remainder)?;
478            remainder = rest;
479
480            if let Some(section) = section {
481                match section.section_type {
482                    SectionType::TrackPoints => track_points = Some(section),
483                    SectionType::CoursePoints => course_points = Some(section),
484                    SectionType::Continuation => panic!("SectionType::Continuation unsupported"),
485                }
486            } else {
487                // parsing section returned None
488                break;
489            }
490        }
491
492        Ok((remainder, RWTFile{header,
493                               metadata,
494                               track_points: track_points.unwrap_or(Section::new(SectionType::TrackPoints)),
495                               course_points: course_points.unwrap_or(Section::new(SectionType::CoursePoints))}))
496    }
497}
498
499pub fn parse_rwtf(i: &[u8]) -> IResult<&[u8], RWTFile> {
500    RWTFile::parse(i)
501}
502
503#[cfg(test)]
504mod tests {
505
506}