ruby-mapsource 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/.rvmrc ADDED
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # This is an RVM Project .rvmrc file, used to automatically load the ruby
4
+ # development environment upon cd'ing into the directory
5
+
6
+ # First we specify our desired <ruby>[@<gemset>], the @gemset name is optional.
7
+ environment_id="ruby-1.9.3-p0@mapsource_gdb"
8
+
9
+ #
10
+ # Uncomment following line if you want options to be set only for given project.
11
+ #
12
+ # PROJECT_JRUBY_OPTS=( --1.9 )
13
+ #
14
+ # The variable PROJECT_JRUBY_OPTS requires the following to be run in shell:
15
+ #
16
+ # chmod +x ${rvm_path}/hooks/after_use_jruby_opts
17
+ #
18
+
19
+ #
20
+ # First we attempt to load the desired environment directly from the environment
21
+ # file. This is very fast and efficient compared to running through the entire
22
+ # CLI and selector. If you want feedback on which environment was used then
23
+ # insert the word 'use' after --create as this triggers verbose mode.
24
+ #
25
+ if [[ -d "${rvm_path:-$HOME/.rvm}/environments" \
26
+ && -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]]
27
+ then
28
+ \. "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
29
+
30
+ if [[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]]
31
+ then
32
+ . "${rvm_path:-$HOME/.rvm}/hooks/after_use"
33
+ fi
34
+ else
35
+ # If the environment file has not yet been created, use the RVM CLI to select.
36
+ if ! rvm --create use "$environment_id"
37
+ then
38
+ echo "Failed to create RVM environment '${environment_id}'."
39
+ return 1
40
+ fi
41
+ fi
42
+
43
+ #
44
+ # If you use an RVM gemset file to install a list of gems (*.gems), you can have
45
+ # it be automatically loaded. Uncomment the following and adjust the filename if
46
+ # necessary.
47
+ #
48
+ # filename=".gems"
49
+ # if [[ -s "$filename" ]]
50
+ # then
51
+ # rvm gemset import "$filename" | grep -v already | grep -v listed | grep -v complete | sed '/^$/d'
52
+ # fi
53
+
54
+ # If you use bundler, this might be useful to you:
55
+ # if [[ -s Gemfile ]] && ! command -v bundle >/dev/null
56
+ # then
57
+ # printf "The rubygem 'bundler' is not installed. Installing it now.\n"
58
+ # gem install bundler
59
+ # fi
60
+ # if [[ -s Gemfile ]] && command -v bundle
61
+ # then
62
+ # bundle install
63
+ # fi
64
+
65
+ if [[ $- == *i* ]] # check for interactive shells
66
+ then
67
+ echo "Using: $(tput setaf 2)$GEM_HOME$(tput sgr0)" # show the user the ruby and gemset they are using in green
68
+ else
69
+ echo "Using: $GEM_HOME" # don't use colors in interactive shells
70
+ fi
71
+
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source :rubygems
2
+
3
+ gemspec
4
+
5
+ group :development, :test do
6
+ gem 'guard-minitest', '~> 0.4'
7
+ gem 'rb-fsevent', '~> 0.4'
8
+ end
data/Guardfile ADDED
@@ -0,0 +1,10 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'minitest' do
5
+ # with Minitest::Spec
6
+ watch(%r|^spec/(.*)_spec\.rb|)
7
+ watch(%r|^lib/mapsource/(.*)\.rb|) { |m| "spec/integration/#{m[1]}_spec.rb" }
8
+ watch(%r|^lib/mapsource/(.*)\.rb|) { |m| "spec/unit/#{m[1]}_spec.rb" }
9
+ watch(%r|^spec/spec_helper\.rb|) { "spec" }
10
+ end
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (C) 2012 Vitor Peres Capela Pereira
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7
+ of the Software, and to permit persons to whom the Software is furnished to do
8
+ so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,16 @@
1
+ ruby-mapsource is a library that allows ruby programs to read files created by Garmin's MapSource and BaseCamp.
2
+
3
+ # Usage
4
+
5
+ TODO
6
+
7
+ # Tools
8
+
9
+ TODO:
10
+
11
+ - gdbtokml - makes a kml file from a gdb
12
+ - gdbtocsv - creates a csv file from a gdb
13
+
14
+ # Thanks
15
+
16
+ GPSBabel
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs.push 'spec'
6
+ t.pattern = 'spec/**/*_spec.rb'
7
+ end
@@ -0,0 +1,44 @@
1
+ module MapSource
2
+ # Public: A Color attributed to a Track, Route or Waypoint.
3
+ class Color
4
+ attr_reader :name, :r, :g, :b
5
+
6
+ def initialize(name, r=-1, g=-1, b=-1)
7
+ @name = name
8
+ @r = @r
9
+ @g = @g
10
+ @b = @b
11
+ end
12
+
13
+ # Public: Converts GDB color index to color object.
14
+ #
15
+ # idx - GDB index
16
+ #
17
+ # Returns Color corresponding to index.
18
+ def self.from_index(idx)
19
+ COLORS[idx] || COLORS.first
20
+ end
21
+ end
22
+
23
+ # Public: A set of default colors.
24
+ COLORS = [
25
+ Color.new('Unknown'),
26
+ Color.new('Black', 0, 0, 0),
27
+ Color.new('DarkRed', 139, 0, 0),
28
+ Color.new('DarkGreen', 0, 100, 0),
29
+ Color.new('DarkYellow', 139, 139, 0),
30
+ Color.new('DarkBlue', 0, 0, 139),
31
+ Color.new('DarkMagenta', 139, 0, 139),
32
+ Color.new('DarkCyan', 0, 139, 139),
33
+ Color.new('LightGray', 211, 211, 211),
34
+ Color.new('DarkGray', 169, 169, 169),
35
+ Color.new('Red', 255, 0, 0),
36
+ Color.new('Green', 0, 255, 0),
37
+ Color.new('Yellow', 255, 255, 0),
38
+ Color.new('Blue', 0, 0, 255),
39
+ Color.new('Magenta', 255, 0, 255),
40
+ Color.new('Cyan', 0, 255, 255),
41
+ Color.new('White', 255, 255, 255),
42
+ Color.new('Transparent')
43
+ ]
44
+ end
@@ -0,0 +1,248 @@
1
+ module MapSource
2
+ class InvalidFormatError < StandardError; end
3
+ class UnsupportedVersionError < StandardError; end
4
+
5
+ # Public: Parses GDB files and extracts waypoints, tracks and routes.
6
+ #
7
+ # Examples:
8
+ #
9
+ # reader = MapSource::Reader.new(open('around_the_world.gdb'))
10
+ # reader.waypoints
11
+ # # => [MapSource::Waypoint<...>, ...]
12
+ class Reader
13
+ # Public: Range of format versions supported.
14
+ SUPPORTED_VERSIONS = (1..3)
15
+
16
+ attr_reader :header, :waypoints
17
+
18
+ # Public: Creates a Reader.
19
+ #
20
+ # gdb - An IO object pointing to a GDB.
21
+ def initialize(gdb)
22
+ @gdb = gdb
23
+ @header = read_header
24
+
25
+ @parsed = false
26
+ end
27
+
28
+ # Public: Read waypoints from file.
29
+ #
30
+ # Returns a list of waypoints.
31
+ def waypoints
32
+ read_data
33
+ @waypoints
34
+ end
35
+
36
+ def tracks
37
+ read_data
38
+ @tracks
39
+ end
40
+
41
+ private
42
+ # Internal: Reads data from the GDB file.
43
+ #
44
+ # Returns list of waypoints, list of tracks, list of routes.
45
+ def read_data
46
+ return if @parsed
47
+
48
+ @waypoints = []
49
+ @tracks = []
50
+ @routes = []
51
+
52
+ while true
53
+ len = @gdb.read(4).unpack('l').shift
54
+ record = @gdb.read(len + 1)
55
+
56
+ case record
57
+ when /^W/
58
+ @waypoints << read_waypoint(record)
59
+ when /^T/
60
+ @tracks << read_track(record)
61
+ when /^V/
62
+ break
63
+ else
64
+ end
65
+ end
66
+
67
+ @parsed = true
68
+ end
69
+
70
+ # Internal: Converts coordinates in semicircles to degrees.
71
+ #
72
+ # v - coordinate as semicircle
73
+ #
74
+ # Returns coordinate in degrees.
75
+ def semicircle_to_degrees(v)
76
+ (v.to_f / (1 << 31)) * 180.0
77
+ end
78
+
79
+ # Internal: Reads a waypoint record from the GDB.
80
+ #
81
+ # record - a binary string containing waypoint data.
82
+ #
83
+ # Returns waypoint.
84
+ def read_waypoint(record)
85
+ io = StringIO.new(record)
86
+
87
+ read_char io
88
+ shortname = read_string(io)
89
+ wptclass = read_int(io)
90
+
91
+ read_string(io)
92
+ io.read 22 # skip 22 bytes
93
+
94
+ lat = semicircle_to_degrees(read_int(io))
95
+ lon = semicircle_to_degrees(read_int(io))
96
+
97
+ wpt = Waypoint.new(lat, lon)
98
+ wpt.shortname = shortname
99
+
100
+ if read_char(io) == 1
101
+ alt = read_double(io)
102
+
103
+ wpt.altitude = alt if alt < 1.0e24
104
+ end
105
+
106
+ wpt.notes = read_string(io)
107
+ wpt.proximity = read_double(io) if read_char(io) == 1
108
+
109
+ read_int io # display
110
+ read_int io # color, not implemented
111
+
112
+ wpt.icon = read_int(io)
113
+ wpt.city = read_string(io)
114
+ wpt.state = read_string(io)
115
+ wpt.facility = read_string(io)
116
+
117
+ wpt.depth = read_double(io) if read_char(io) == 1
118
+
119
+ wpt
120
+ end
121
+
122
+ def read_track(record)
123
+ header = record.unpack('AZ*all')
124
+ _, name, _, color, npoints = *header
125
+ contents = record.sub(/^#{Regexp.quote(header.pack('AZ*all'))}/, '')
126
+
127
+ track = Track.new(name, Color::from_index(color))
128
+ io = StringIO.new(contents)
129
+
130
+ 0.upto(npoints - 1) do
131
+ lat = semicircle_to_degrees(read_int(io))
132
+ lon = semicircle_to_degrees(read_int(io))
133
+
134
+ wpt = Waypoint.new(lat, lon)
135
+
136
+ if read_char(io) == 1
137
+ alt = read_double(io)
138
+ wpt.altitude = alt if alt < 1.0e24
139
+ end
140
+
141
+ wpt.creation_time = read_int(io) if read_char(io) == 1
142
+ wpt.depth = read_double(io) if read_char(io) == 1
143
+ wpt.temperature = read_double(io) if read_char(io) == 1
144
+
145
+ track.add_waypoint wpt
146
+ end
147
+
148
+ track
149
+ end
150
+
151
+ # Internal: Reads a string from an IO object.
152
+ #
153
+ # io - an IO object
154
+ # chars - number of chars to read. If not specified, read_string stops at
155
+ # the null string terminator.
156
+ #
157
+ # Returns a string.
158
+ def read_string(io, chars=nil)
159
+ if chars
160
+ io.read chars
161
+ else
162
+ str = ''
163
+ while c = io.read(1)
164
+ break if c == "\x00"
165
+ str += c
166
+ end
167
+
168
+ str
169
+ end
170
+ end
171
+
172
+ # Internal: Reads an Integer from an IO object, unpacking it appropriately.
173
+ #
174
+ # io - an IO object.
175
+ #
176
+ # Returns an Integer.
177
+ def read_int(io)
178
+ io.read(4).unpack('l').shift
179
+ end
180
+
181
+ # Internal: Reads a Double from an IO object, unpacking it appropriately.
182
+ #
183
+ # io - an IO object.
184
+ #
185
+ # Returns an Double.
186
+ def read_double(io)
187
+ io.read(8).unpack('E').shift
188
+ end
189
+
190
+ # Internal: Reads a single character from an IO object, unpacking it
191
+ # appropriately.
192
+ #
193
+ # io - an IO object.
194
+ #
195
+ # Returns a single character.
196
+ def read_char(io)
197
+ io.read(1).unpack('c').shift
198
+ end
199
+
200
+ # Internal: Reads a GDB's header to determine the version being parsed, its creator
201
+ # and signer.
202
+ #
203
+ # Returns a properly filled header.
204
+ # Raises MapSource::InvalidFormatError if it's not a GDB file.
205
+ # Raises MapSource::InvalidFormatError if GDB is malformed.
206
+ # Raises MapSource::UnsupportedVersionError if file format version is not supported.
207
+ def read_header
208
+ header = Header.new
209
+
210
+ mscrf = @gdb.read(6).unpack('A*').shift
211
+
212
+ raise InvalidFormatError, "Invalid gdb file" if mscrf != 'MsRcf'
213
+
214
+ record_length = @gdb.read(4).unpack('l').shift
215
+ buffer = @gdb.read(record_length + 1)
216
+
217
+ raise InvalidFormatError, "Invalid gdb file" if buffer[0] != ?D
218
+ gdb_version = buffer[1].getbyte(0) - ?k.getbyte(0) + 1
219
+
220
+ raise UnsupportedVersionError, "Unsupported version: #{gdb_version}. Supported versions are #{SUPPORTED_VERSIONS.to_a.join(', ')}" if !SUPPORTED_VERSIONS.member?(gdb_version)
221
+
222
+ header.version = gdb_version
223
+
224
+ record_length = @gdb.read(4).unpack('l').shift
225
+ buffer = @gdb.read(record_length + 1)
226
+ creator = buffer.unpack('Z*').shift
227
+
228
+ header.created_by = if creator =~ /SQA$/
229
+ 'MapSource'
230
+ elsif creator =~ /neaderhi$/
231
+ 'MapSource BETA'
232
+ end
233
+
234
+ signer = @gdb.read(10)
235
+ signer += @gdb.read(1) until signer =~ /\x00$/
236
+
237
+ signer = signer.unpack('Z*').shift
238
+
239
+ if signer !~ /MapSource|BaseCamp/
240
+ raise InvalidFormatError, "Unknown file signature: #{signer}"
241
+ end
242
+
243
+ header.signed_by = signer
244
+
245
+ header
246
+ end
247
+ end
248
+ end
@@ -0,0 +1,45 @@
1
+ # Defines the structure
2
+ module MapSource
3
+ # Public: GDB header. Contains name of creator software, signature and
4
+ # format version.
5
+ class Header
6
+ attr_accessor :created_by, :signed_by, :version
7
+ end
8
+
9
+ # Public: A Waypoint.
10
+ class Waypoint
11
+ attr_accessor :shortname, :latitude, :longitude, :altitude, :temperature, :depth, :notes, :creation_time, :proximity, :icon, :city, :state, :facility
12
+
13
+ def initialize(latitude, longitude)
14
+ @latitude = latitude
15
+ @longitude = longitude
16
+ end
17
+ end
18
+
19
+ # Public: A Track.
20
+ class Track
21
+ attr_reader :name, :color
22
+
23
+ def initialize(name, color)
24
+ @name = name
25
+ @color = color
26
+ @waypoints = []
27
+ end
28
+
29
+ def waypoints
30
+ @waypoints.dup
31
+ end
32
+
33
+ def add_waypoint(wpt)
34
+ @waypoints << wpt
35
+ end
36
+
37
+ def size
38
+ @waypoints.size
39
+ end
40
+
41
+ def each
42
+ @waypoints.each { |wpt| yield wpt if block_given? }
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,3 @@
1
+ module MapSource
2
+ VERSION = "0.0.1"
3
+ end
data/lib/mapsource.rb ADDED
@@ -0,0 +1,30 @@
1
+ #--
2
+ # Copyright (C) 2012 Vitor Peres Capela Pereira
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+ # this software and associated documentation files (the "Software"), to deal in
6
+ # the Software without restriction, including without limitation the rights to
7
+ # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8
+ # of the Software, and to permit persons to whom the Software is furnished to do
9
+ # so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in all
12
+ # copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ # SOFTWARE.
21
+ #++
22
+
23
+ mapsource_path = File.dirname(__FILE__)
24
+ $:.unshift(mapsource_path) if File.directory?(mapsource_path) && !$:.include?(mapsource_path)
25
+
26
+ require 'stringio'
27
+
28
+ require 'mapsource/structure'
29
+ require 'mapsource/defs'
30
+ require 'mapsource/reader'
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "mapsource/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "ruby-mapsource"
7
+ s.version = MapSource::VERSION
8
+ s.authors = ["Vitor Capela"]
9
+ s.email = ["dodecaphonic@gmail.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{A Ruby library for reading MapSource/BaseCamp-created GDB files}
12
+ s.description = %q{A Ruby library for reading MapSource/BaseCamp-created GDB files}
13
+
14
+ s.rubyforge_project = "ruby-mapsource"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_development_dependency "minitest", "~> 2.10"
22
+ s.add_development_dependency "mocha", "~> 0.10"
23
+ end
Binary file
Binary file
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe MapSource::Reader do
4
+ before :each do
5
+ @gdb_file = open(File.dirname(__FILE__) + '/../assets/sample.gdb')
6
+ @reader = MapSource::Reader.new(@gdb_file)
7
+ end
8
+
9
+ after :each do
10
+ @gdb_file.close
11
+ end
12
+
13
+ it "parses the header correctly" do
14
+ @reader.header.created_by.must_equal 'MapSource'
15
+ @reader.header.signed_by.must_equal 'MapSource'
16
+ end
17
+
18
+ it "parses all waypoints" do
19
+ @reader.waypoints.size.must_equal 312
20
+ end
21
+
22
+ it "parses every track" do
23
+ tracks = @reader.tracks
24
+ al = tracks.find { |t| t.name == 'ACTIVE LOG 009' }
25
+ al.wont_be_nil
26
+ al.size.must_equal 296
27
+
28
+ wpt = al.waypoints[9]
29
+ wpt.latitude.must_be_close_to -23.17172
30
+ wpt.longitude.must_be_close_to -44.83632
31
+ wpt.altitude.must_be_close_to 1471, 0.05
32
+ end
33
+ end
@@ -0,0 +1,66 @@
1
+ $: << File.dirname(__FILE__) + '/../lib'
2
+
3
+ require 'bundler/setup'
4
+ require 'minitest/autorun'
5
+ require 'mocha'
6
+
7
+ require 'mapsource'
8
+
9
+ module MapSource::Spec
10
+ # Internal: Creates a basic mock object containing expectations for a part of
11
+ # (or all of) the header. How much is created is determined by the _options_
12
+ # hash.
13
+ #
14
+ # options - a hash of options. Currently supports ":before" and the following
15
+ # states:
16
+ # - :start - before expecting on the first string in the file
17
+ # - :version - before expectations regarding the version
18
+ # - :creator - before expectations regarding the creator of the file
19
+ # - :signer - before expectations regarding the signer of the file
20
+ #
21
+ # Returns an array with a mocha mock object and a mocha sequence object.
22
+ def create_basic_valid_state(options={ before: nil })
23
+ gdb_file = mock('gdb')
24
+ header = sequence('parsing')
25
+
26
+ unless options[:before] == :start
27
+ gdb_file.expects(:read).in_sequence(header).with(6).returns "MsRcf\x00"
28
+ else
29
+ return [gdb_file, header]
30
+ end
31
+
32
+ unless options[:before] == :version
33
+ reclen = mock('reclen')
34
+ reclen.expects(:unpack).with('l').returns [2]
35
+ gdb_file.expects(:read).in_sequence(header).with(4).returns reclen
36
+
37
+ gdb_file.expects(:read).in_sequence(header).with(3).returns "Dm\x00"
38
+ else
39
+ return [gdb_file, header]
40
+ end
41
+
42
+ unless options[:before] == :creator
43
+ reclen = mock('reclen 2')
44
+ reclen.expects(:unpack).with('l').returns [27]
45
+ gdb_file.expects(:read).in_sequence(header).with(4).returns reclen
46
+
47
+ creator = mock('creator')
48
+ creator.expects(:unpack).with('Z*').returns ["Ae\u0002SQA"]
49
+ gdb_file.expects(:read).in_sequence(header).with(28).returns creator
50
+ else
51
+ return [gdb_file, header]
52
+ end
53
+
54
+ unless options[:before] == :signer
55
+ gdb_file.expects(:read).in_sequence(header).with(10).returns "MapSource\x00"
56
+ else
57
+ return [gdb_file, header]
58
+ end
59
+
60
+ [gdb_file, header]
61
+ end
62
+
63
+ SAMPLE_TRACK = File.dirname(__FILE__) + '/assets/track.bin'
64
+ end
65
+
66
+ include MapSource::Spec
@@ -0,0 +1,127 @@
1
+ require 'spec_helper'
2
+
3
+ describe MapSource::Reader do
4
+ describe "when reading the header" do
5
+ it "fails when first portion of the file doesn't pass validation" do
6
+ gdb_file, sequence = *create_basic_valid_state(before: :start)
7
+
8
+ bogus = mock('bogus')
9
+ bogus.expects(:unpack).with('A*').returns ['Bogus']
10
+ gdb_file.expects(:read).with(6).returns bogus
11
+
12
+ lambda {
13
+ MapSource::Reader.new gdb_file
14
+ }.must_raise MapSource::InvalidFormatError
15
+ end
16
+
17
+ it "fails when header is malformed" do
18
+ gdb_file, sequence = *create_basic_valid_state(before: :version)
19
+
20
+ reclen = mock('reclen')
21
+ reclen.expects(:unpack).with('l').returns [2]
22
+ gdb_file.expects(:read).in_sequence(sequence).with(4).returns reclen
23
+
24
+ gdb_file.expects(:read).in_sequence(sequence).with(3).returns "Am\x00"
25
+
26
+ lambda {
27
+ MapSource::Reader.new gdb_file
28
+ }.must_raise MapSource::InvalidFormatError
29
+ end
30
+
31
+ it "fails when version is unsupported" do
32
+ gdb_file, sequence = *create_basic_valid_state(before: :version)
33
+
34
+ reclen = mock('reclen')
35
+ reclen.expects(:unpack).with('l').returns [2]
36
+ gdb_file.expects(:read).in_sequence(sequence).with(4).returns reclen
37
+
38
+ gdb_file.expects(:read).in_sequence(sequence).with(3).returns "Dn\x00"
39
+
40
+ lambda {
41
+ MapSource::Reader.new gdb_file
42
+ }.must_raise MapSource::UnsupportedVersionError
43
+ end
44
+
45
+ it "determines which version of the format it has" do
46
+ gdb_file, _ = *create_basic_valid_state
47
+
48
+ reader = MapSource::Reader.new(gdb_file)
49
+ reader.header.version.must_equal 3
50
+ end
51
+
52
+ it "determines which software created the file" do
53
+ gdb_file, _ = *create_basic_valid_state
54
+
55
+ reader = MapSource::Reader.new(gdb_file)
56
+ reader.header.created_by.must_equal 'MapSource'
57
+ end
58
+
59
+ it "determines which software signed the file" do
60
+ gdb_file, _ = *create_basic_valid_state
61
+
62
+ reader = MapSource::Reader.new(gdb_file)
63
+ reader.header.signed_by.must_equal 'MapSource'
64
+ end
65
+
66
+ it "fails when creator is not recognized" do
67
+ gdb_file, sequence = *create_basic_valid_state(before: :signer)
68
+
69
+ gdb_file.expects(:read).in_sequence(sequence).with(10).returns 'BogusSoftw'
70
+ gdb_file.expects(:read).in_sequence(sequence).with(1).times(3).returns 'x'
71
+ gdb_file.expects(:read).in_sequence(sequence).with(1).returns "\x00"
72
+
73
+ lambda {
74
+ MapSource::Reader.new gdb_file
75
+ }.must_raise MapSource::InvalidFormatError
76
+ end
77
+ end
78
+
79
+ describe "when reading the content" do
80
+ it "parses waypoints" do
81
+ gdb_file, seq = *create_basic_valid_state
82
+
83
+ gdb_file.expects(:read).in_sequence(seq).with(4).returns "\l\x00\x00\x00"
84
+ gdb_file.expects(:read).in_sequence(seq).with(109).returns "W001\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF\xE7\xB7\x85\xEF\xDE\xCB\x1D\xE0\x01\x00\x00\x00\x80\xF9X\x97@15-DEZ-11 12:06:43PM\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x8D\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
85
+ gdb_file.expects(:read).in_sequence(seq).with(4).returns "\x01\x00\x00\x00"
86
+ gdb_file.expects(:read).in_sequence(seq).with(2).returns "V\x00"
87
+
88
+ reader = MapSource::Reader.new(gdb_file)
89
+
90
+ reader.waypoints.size.must_equal 1
91
+ wpt = reader.waypoints.first
92
+ wpt.shortname.must_equal "001"
93
+ wpt.latitude.must_be_close_to -23.17171306349337
94
+ wpt.longitude.must_be_close_to -44.836323726922274
95
+ wpt.notes.must_equal "15-DEZ-11 12:06:43PM"
96
+ wpt.altitude.floor.must_be_close_to 1494
97
+ end
98
+
99
+ it "parses tracks" do
100
+ track = open(SAMPLE_TRACK, 'rb').read
101
+ gdb_file, seq = *create_basic_valid_state
102
+ gdb_file.expects(:read).in_sequence(seq).with(4).returns "\xC0r\x00\x00"
103
+ gdb_file.expects(:read).in_sequence(seq).with(29377).returns track
104
+ gdb_file.expects(:read).in_sequence(seq).with(4).returns "\x01\x00\x00\x00"
105
+ gdb_file.expects(:read).in_sequence(seq).with(2).returns "V\x00"
106
+
107
+ reader = MapSource::Reader.new(gdb_file)
108
+ reader.tracks.size.must_equal 1
109
+
110
+ track = reader.tracks.first
111
+ track.name.must_equal "ACTIVE LOG"
112
+ track.color.name.must_equal "Red"
113
+ track.size.must_equal 1223
114
+
115
+ wpt = track.waypoints.first
116
+ wpt.latitude.must_be_close_to -22.17333
117
+ wpt.longitude.must_be_close_to -42.41256
118
+ wpt.altitude.must_be_close_to 675.0, 0.5
119
+
120
+ wpt = track.waypoints[1]
121
+ wpt.latitude.must_be_close_to -22.17332
122
+ wpt.longitude.must_be_close_to -42.41264
123
+ wpt.altitude.must_be_close_to 673.0, 0.5
124
+ end
125
+ end
126
+ end
127
+
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-mapsource
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Vitor Capela
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-01-20 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: minitest
16
+ requirement: &70324053963740 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '2.10'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70324053963740
25
+ - !ruby/object:Gem::Dependency
26
+ name: mocha
27
+ requirement: &70324053976040 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: '0.10'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70324053976040
36
+ description: A Ruby library for reading MapSource/BaseCamp-created GDB files
37
+ email:
38
+ - dodecaphonic@gmail.com
39
+ executables: []
40
+ extensions: []
41
+ extra_rdoc_files: []
42
+ files:
43
+ - .gitignore
44
+ - .rvmrc
45
+ - Gemfile
46
+ - Guardfile
47
+ - LICENSE
48
+ - README.md
49
+ - Rakefile
50
+ - lib/mapsource.rb
51
+ - lib/mapsource/defs.rb
52
+ - lib/mapsource/reader.rb
53
+ - lib/mapsource/structure.rb
54
+ - lib/mapsource/version.rb
55
+ - ruby-mapsource.gemspec
56
+ - spec/assets/sample.gdb
57
+ - spec/assets/track.bin
58
+ - spec/integration/reader_spec.rb
59
+ - spec/spec_helper.rb
60
+ - spec/unit/reader_spec.rb
61
+ homepage: ''
62
+ licenses: []
63
+ post_install_message:
64
+ rdoc_options: []
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ! '>='
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ requirements: []
80
+ rubyforge_project: ruby-mapsource
81
+ rubygems_version: 1.8.10
82
+ signing_key:
83
+ specification_version: 3
84
+ summary: A Ruby library for reading MapSource/BaseCamp-created GDB files
85
+ test_files:
86
+ - spec/assets/sample.gdb
87
+ - spec/assets/track.bin
88
+ - spec/integration/reader_spec.rb
89
+ - spec/spec_helper.rb
90
+ - spec/unit/reader_spec.rb