Quellcode durchsuchen

Initial commit :>

Started 2015
Johannes Hofmann vor 8 Jahren
Commit
18b782993a
23 geänderte Dateien mit 7063 neuen und 0 gelöschten Zeilen
  1. 2
    0
      .gitignore
  2. 28
    0
      Cargo.toml
  3. 201
    0
      LICENSE-APACHE
  4. 25
    0
      LICENSE-MIT
  5. 121
    0
      README.md
  6. 15
    0
      build.rs
  7. 27
    0
      examples/count.rs
  8. 216
    0
      src/blob.rs
  9. 211
    0
      src/block.rs
  10. 196
    0
      src/dense.rs
  11. 364
    0
      src/elements.rs
  12. 15
    0
      src/errors.rs
  13. 35
    0
      src/lib.rs
  14. 142
    0
      src/mmap_blob.rs
  15. 54
    0
      src/proto/fileformat.proto
  16. 648
    0
      src/proto/fileformat.rs
  17. 2
    0
      src/proto/mod.rs
  18. 260
    0
      src/proto/osmformat.proto
  19. 4212
    0
      src/proto/osmformat.rs
  20. 207
    0
      src/reader.rs
  21. 64
    0
      tests/read.rs
  22. 18
    0
      tests/test.osm
  23. BIN
      tests/test.osm.pbf

+ 2
- 0
.gitignore Datei anzeigen

@@ -0,0 +1,2 @@
1
+target
2
+.*.swp

+ 28
- 0
Cargo.toml Datei anzeigen

@@ -0,0 +1,28 @@
1
+[package]
2
+name = "osmpbf"
3
+version = "0.1.0"
4
+authors = ["Johannes Hofmann <mail@b-r-u.org>"]
5
+license = "MIT/Apache-2.0"
6
+readme = "README.md"
7
+repository = "https://github.com/b-r-u/osmpbf"
8
+homepage = "https://github.com/b-r-u/osmpbf"
9
+build = "build.rs"
10
+description = """
11
+A reader for the OpenStreetMap PBF file format (*.osm.pbf).
12
+"""
13
+
14
+[features]
15
+default = ["system-libz"]
16
+system-libz = ["flate2"]
17
+
18
+[dependencies]
19
+protobuf = "1.4"
20
+byteorder = "1.1"
21
+flate2 = { version = "0.2", optional = true }
22
+inflate = "0.3"
23
+error-chain = "0.11"
24
+memmap = "0.6"
25
+rayon = "0.8.2"
26
+
27
+[build-dependencies]
28
+protoc-rust = "1.4"

+ 201
- 0
LICENSE-APACHE Datei anzeigen

@@ -0,0 +1,201 @@
1
+                              Apache License
2
+                        Version 2.0, January 2004
3
+                     http://www.apache.org/licenses/
4
+
5
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+1. Definitions.
8
+
9
+   "License" shall mean the terms and conditions for use, reproduction,
10
+   and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+   "Licensor" shall mean the copyright owner or entity authorized by
13
+   the copyright owner that is granting the License.
14
+
15
+   "Legal Entity" shall mean the union of the acting entity and all
16
+   other entities that control, are controlled by, or are under common
17
+   control with that entity. For the purposes of this definition,
18
+   "control" means (i) the power, direct or indirect, to cause the
19
+   direction or management of such entity, whether by contract or
20
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+   outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+   "You" (or "Your") shall mean an individual or Legal Entity
24
+   exercising permissions granted by this License.
25
+
26
+   "Source" form shall mean the preferred form for making modifications,
27
+   including but not limited to software source code, documentation
28
+   source, and configuration files.
29
+
30
+   "Object" form shall mean any form resulting from mechanical
31
+   transformation or translation of a Source form, including but
32
+   not limited to compiled object code, generated documentation,
33
+   and conversions to other media types.
34
+
35
+   "Work" shall mean the work of authorship, whether in Source or
36
+   Object form, made available under the License, as indicated by a
37
+   copyright notice that is included in or attached to the work
38
+   (an example is provided in the Appendix below).
39
+
40
+   "Derivative Works" shall mean any work, whether in Source or Object
41
+   form, that is based on (or derived from) the Work and for which the
42
+   editorial revisions, annotations, elaborations, or other modifications
43
+   represent, as a whole, an original work of authorship. For the purposes
44
+   of this License, Derivative Works shall not include works that remain
45
+   separable from, or merely link (or bind by name) to the interfaces of,
46
+   the Work and Derivative Works thereof.
47
+
48
+   "Contribution" shall mean any work of authorship, including
49
+   the original version of the Work and any modifications or additions
50
+   to that Work or Derivative Works thereof, that is intentionally
51
+   submitted to Licensor for inclusion in the Work by the copyright owner
52
+   or by an individual or Legal Entity authorized to submit on behalf of
53
+   the copyright owner. For the purposes of this definition, "submitted"
54
+   means any form of electronic, verbal, or written communication sent
55
+   to the Licensor or its representatives, including but not limited to
56
+   communication on electronic mailing lists, source code control systems,
57
+   and issue tracking systems that are managed by, or on behalf of, the
58
+   Licensor for the purpose of discussing and improving the Work, but
59
+   excluding communication that is conspicuously marked or otherwise
60
+   designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+   "Contributor" shall mean Licensor and any individual or Legal Entity
63
+   on behalf of whom a Contribution has been received by Licensor and
64
+   subsequently incorporated within the Work.
65
+
66
+2. Grant of Copyright License. Subject to the terms and conditions of
67
+   this License, each Contributor hereby grants to You a perpetual,
68
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+   copyright license to reproduce, prepare Derivative Works of,
70
+   publicly display, publicly perform, sublicense, and distribute the
71
+   Work and such Derivative Works in Source or Object form.
72
+
73
+3. Grant of Patent License. Subject to the terms and conditions of
74
+   this License, each Contributor hereby grants to You a perpetual,
75
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+   (except as stated in this section) patent license to make, have made,
77
+   use, offer to sell, sell, import, and otherwise transfer the Work,
78
+   where such license applies only to those patent claims licensable
79
+   by such Contributor that are necessarily infringed by their
80
+   Contribution(s) alone or by combination of their Contribution(s)
81
+   with the Work to which such Contribution(s) was submitted. If You
82
+   institute patent litigation against any entity (including a
83
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+   or a Contribution incorporated within the Work constitutes direct
85
+   or contributory patent infringement, then any patent licenses
86
+   granted to You under this License for that Work shall terminate
87
+   as of the date such litigation is filed.
88
+
89
+4. Redistribution. You may reproduce and distribute copies of the
90
+   Work or Derivative Works thereof in any medium, with or without
91
+   modifications, and in Source or Object form, provided that You
92
+   meet the following conditions:
93
+
94
+   (a) You must give any other recipients of the Work or
95
+       Derivative Works a copy of this License; and
96
+
97
+   (b) You must cause any modified files to carry prominent notices
98
+       stating that You changed the files; and
99
+
100
+   (c) You must retain, in the Source form of any Derivative Works
101
+       that You distribute, all copyright, patent, trademark, and
102
+       attribution notices from the Source form of the Work,
103
+       excluding those notices that do not pertain to any part of
104
+       the Derivative Works; and
105
+
106
+   (d) If the Work includes a "NOTICE" text file as part of its
107
+       distribution, then any Derivative Works that You distribute must
108
+       include a readable copy of the attribution notices contained
109
+       within such NOTICE file, excluding those notices that do not
110
+       pertain to any part of the Derivative Works, in at least one
111
+       of the following places: within a NOTICE text file distributed
112
+       as part of the Derivative Works; within the Source form or
113
+       documentation, if provided along with the Derivative Works; or,
114
+       within a display generated by the Derivative Works, if and
115
+       wherever such third-party notices normally appear. The contents
116
+       of the NOTICE file are for informational purposes only and
117
+       do not modify the License. You may add Your own attribution
118
+       notices within Derivative Works that You distribute, alongside
119
+       or as an addendum to the NOTICE text from the Work, provided
120
+       that such additional attribution notices cannot be construed
121
+       as modifying the License.
122
+
123
+   You may add Your own copyright statement to Your modifications and
124
+   may provide additional or different license terms and conditions
125
+   for use, reproduction, or distribution of Your modifications, or
126
+   for any such Derivative Works as a whole, provided Your use,
127
+   reproduction, and distribution of the Work otherwise complies with
128
+   the conditions stated in this License.
129
+
130
+5. Submission of Contributions. Unless You explicitly state otherwise,
131
+   any Contribution intentionally submitted for inclusion in the Work
132
+   by You to the Licensor shall be under the terms and conditions of
133
+   this License, without any additional terms or conditions.
134
+   Notwithstanding the above, nothing herein shall supersede or modify
135
+   the terms of any separate license agreement you may have executed
136
+   with Licensor regarding such Contributions.
137
+
138
+6. Trademarks. This License does not grant permission to use the trade
139
+   names, trademarks, service marks, or product names of the Licensor,
140
+   except as required for reasonable and customary use in describing the
141
+   origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+7. Disclaimer of Warranty. Unless required by applicable law or
144
+   agreed to in writing, Licensor provides the Work (and each
145
+   Contributor provides its Contributions) on an "AS IS" BASIS,
146
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+   implied, including, without limitation, any warranties or conditions
148
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+   PARTICULAR PURPOSE. You are solely responsible for determining the
150
+   appropriateness of using or redistributing the Work and assume any
151
+   risks associated with Your exercise of permissions under this License.
152
+
153
+8. Limitation of Liability. In no event and under no legal theory,
154
+   whether in tort (including negligence), contract, or otherwise,
155
+   unless required by applicable law (such as deliberate and grossly
156
+   negligent acts) or agreed to in writing, shall any Contributor be
157
+   liable to You for damages, including any direct, indirect, special,
158
+   incidental, or consequential damages of any character arising as a
159
+   result of this License or out of the use or inability to use the
160
+   Work (including but not limited to damages for loss of goodwill,
161
+   work stoppage, computer failure or malfunction, or any and all
162
+   other commercial damages or losses), even if such Contributor
163
+   has been advised of the possibility of such damages.
164
+
165
+9. Accepting Warranty or Additional Liability. While redistributing
166
+   the Work or Derivative Works thereof, You may choose to offer,
167
+   and charge a fee for, acceptance of support, warranty, indemnity,
168
+   or other liability obligations and/or rights consistent with this
169
+   License. However, in accepting such obligations, You may act only
170
+   on Your own behalf and on Your sole responsibility, not on behalf
171
+   of any other Contributor, and only if You agree to indemnify,
172
+   defend, and hold each Contributor harmless for any liability
173
+   incurred by, or claims asserted against, such Contributor by reason
174
+   of your accepting any such warranty or additional liability.
175
+
176
+END OF TERMS AND CONDITIONS
177
+
178
+APPENDIX: How to apply the Apache License to your work.
179
+
180
+   To apply the Apache License to your work, attach the following
181
+   boilerplate notice, with the fields enclosed by brackets "[]"
182
+   replaced with your own identifying information. (Don't include
183
+   the brackets!)  The text should be enclosed in the appropriate
184
+   comment syntax for the file format. We also recommend that a
185
+   file or class name and description of purpose be included on the
186
+   same "printed page" as the copyright notice for easier
187
+   identification within third-party archives.
188
+
189
+Copyright [yyyy] [name of copyright owner]
190
+
191
+Licensed under the Apache License, Version 2.0 (the "License");
192
+you may not use this file except in compliance with the License.
193
+You may obtain a copy of the License at
194
+
195
+	http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+Unless required by applicable law or agreed to in writing, software
198
+distributed under the License is distributed on an "AS IS" BASIS,
199
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+See the License for the specific language governing permissions and
201
+limitations under the License.

+ 25
- 0
LICENSE-MIT Datei anzeigen

@@ -0,0 +1,25 @@
1
+Copyright (c) 2014 The Rust Project Developers
2
+
3
+Permission is hereby granted, free of charge, to any
4
+person obtaining a copy of this software and associated
5
+documentation files (the "Software"), to deal in the
6
+Software without restriction, including without
7
+limitation the rights to use, copy, modify, merge,
8
+publish, distribute, sublicense, and/or sell copies of
9
+the Software, and to permit persons to whom the Software
10
+is furnished to do so, subject to the following
11
+conditions:
12
+
13
+The above copyright notice and this permission notice
14
+shall be included in all copies or substantial portions
15
+of the Software.
16
+
17
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
18
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
19
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
20
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
21
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
24
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25
+DEALINGS IN THE SOFTWARE.

+ 121
- 0
README.md Datei anzeigen

@@ -0,0 +1,121 @@
1
+osmpbf
2
+======
3
+A Rust library for reading the OpenStreetMap PBF file format (\*.osm.pbf). It
4
+strives to offer the best performance using parallelization and lazy-decoding
5
+with a simple interface while also exposing iterators for items of every level
6
+in a PBF file.
7
+
8
+## Usage
9
+
10
+Add this to your `Cargo.toml`:
11
+
12
+```toml
13
+[dependencies]
14
+osmpbf = "0.1"
15
+```
16
+
17
+and this to your crate root:
18
+
19
+```rust
20
+extern crate osmbpf;
21
+```
22
+
23
+Here's a simple example that counts all the ways in a file:
24
+
25
+```rust
26
+extern crate osmpbf;
27
+
28
+use osmpbf::*;
29
+
30
+fn main() {
31
+    let reader = ElementReader::from_path("tests/test.osm.pbf").unwrap();
32
+    let mut ways = 0_u64;
33
+
34
+    // Increment the counter by one for each way.
35
+    reader.for_each(|element| {
36
+        if let Element::Way(_) = element {
37
+            ways += 1;
38
+        }
39
+    }).unwrap();
40
+
41
+    println!("Number of ways: {}", ways);
42
+}
43
+```
44
+
45
+In this second example, we also count the ways but make use of all cores by
46
+decoding the file in parallel:
47
+
48
+```rust
49
+use osmpbf::*;
50
+ 
51
+fn main() {
52
+    let reader = ElementReader::from_path("tests/test.osm.pbf").unwrap();
53
+
54
+    // Count the ways
55
+    let ways = reader.par_map_reduce(
56
+        |element| {
57
+            match element {
58
+                Element::Way(_) => 1,
59
+                _ => 0,
60
+            }
61
+        },
62
+        || 0_u64,      // Zero is the identity value for addition
63
+        |a, b| a + b   // Sum the partial results
64
+    ).unwrap();
65
+     
66
+    println!("Number of ways: {}", ways);
67
+}
68
+```
69
+
70
+## The PBF format
71
+
72
+To effectively use the more lower-level features of this library it is useful to
73
+have an overview of the structure of a PBF file. For a more detailed format
74
+description see [here](http://wiki.openstreetmap.org/wiki/PBF_Format) or take a
75
+look at the `.proto` files in this repository.
76
+
77
+The PBF format as a hierarchy (square brackets `[]` denote arrays):
78
+```
79
+Blob[]
80
+├── HeaderBlock
81
+└── PrimitiveBlock
82
+    └── Group[]
83
+    	├── Node[]
84
+    	├── DenseNodes
85
+    	├── Way[]
86
+        └── Relation[]
87
+```
88
+
89
+At the highest level a PBF file consists of a sequence of Blobs. Each Blob can
90
+be decoded into either a HeaderBlock or a PrimitiveBlock.
91
+
92
+Iterating over Blobs is very fast, but decoding might involve a more expensive
93
+decompression step. So especially for larger files it is advisable to
94
+parallelize at the Blob level as each Blob can be decompressed independently.
95
+
96
+Usually the first Blob of a file decodes to a HeaderBlock which holds global
97
+information for all following PrimitiveBlocks, such as a list of required
98
+parser features.
99
+
100
+A PrimitiveBlock contains an array of Groups (named `PrimitiveGroup` in
101
+osmformat.proto). Each Group only contains one element type: Node, Way,
102
+Relation or DenseNodes. A DenseNodes item is an alternative and space-saving
103
+representation of a Node array. So, do not forget to check for DenseNodes when
104
+aggregating all nodes in a file.
105
+
106
+Elements reference each other using integer IDs. Corresponding elements could be
107
+stored in any Blob, so finding them can involve iterating over the whole file.
108
+Some files declare an optional feature "Sort.Type_then_ID" in the HeaderBlock to
109
+indicate that elements are stored sorted by their type and then ID. This can be
110
+used to dramatically reduce the search space.
111
+
112
+# License
113
+
114
+This project is licensed under either of
115
+
116
+ * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
117
+   http://www.apache.org/licenses/LICENSE-2.0)
118
+ * MIT license ([LICENSE-MIT](LICENSE-MIT) or
119
+   http://opensource.org/licenses/MIT)
120
+
121
+at your option.

+ 15
- 0
build.rs Datei anzeigen

@@ -0,0 +1,15 @@
1
+extern crate protoc_rust;
2
+
3
+fn main() {
4
+    let proto_files = ["src/proto/fileformat.proto", "src/proto/osmformat.proto"];
5
+
6
+    for path in &proto_files {
7
+        println!("cargo:rerun-if-changed={}", path);
8
+    }
9
+
10
+    protoc_rust::run(protoc_rust::Args {
11
+        out_dir: "src/proto",
12
+        input: &proto_files,
13
+        includes: &[],
14
+    }).expect("protoc");
15
+}

+ 27
- 0
examples/count.rs Datei anzeigen

@@ -0,0 +1,27 @@
1
+extern crate osmpbf;
2
+
3
+use osmpbf::*;
4
+
5
+fn main() {
6
+    let arg = std::env::args_os().nth(1).expect("need a *.osm.pbf file as argument");
7
+    let path = std::path::Path::new(&arg);
8
+    let reader = ElementReader::from_path(path).unwrap();
9
+
10
+    println!("Counting...");
11
+
12
+    let result = reader.par_map_reduce(
13
+        |element| {
14
+            match element {
15
+                Element::Node(_) | Element::DenseNode(_) => (1, 0, 0),
16
+                Element::Way(_) => (0, 1, 0),
17
+                Element::Relation(_) => (0, 0, 1),
18
+            }
19
+        },
20
+        || (0u64, 0u64, 0u64),
21
+        |a, b| (a.0 + b.0, a.1 + b.1, a.2 + b.2)
22
+    ).unwrap();
23
+
24
+    println!("Nodes: {}", result.0);
25
+    println!("Ways: {}", result.1);
26
+    println!("Relations: {}", result.2);
27
+}

+ 216
- 0
src/blob.rs Datei anzeigen

@@ -0,0 +1,216 @@
1
+//! Read and decode blobs
2
+
3
+extern crate protobuf;
4
+extern crate byteorder;
5
+
6
+use block::{HeaderBlock, PrimitiveBlock};
7
+use byteorder::ReadBytesExt;
8
+use errors::*;
9
+use proto::fileformat;
10
+use std::fs::File;
11
+use std::io::{BufReader, ErrorKind, Read};
12
+use std::path::Path;
13
+
14
+#[cfg(feature = "system-libz")]
15
+use flate2::read::ZlibDecoder;
16
+
17
+#[cfg(not(feature = "system-libz"))]
18
+use inflate::DeflateDecoder;
19
+
20
+
21
+#[derive(Debug, Eq, PartialEq)]
22
+pub enum BlobType<'a> {
23
+    OsmHeader,
24
+    OsmData,
25
+    Unknown(&'a str),
26
+}
27
+
28
+//TODO rename variants to fit proto files
29
+pub enum BlobDecode<'a> {
30
+    OsmHeader(HeaderBlock),
31
+    OsmData(PrimitiveBlock),
32
+    Unknown(&'a str),
33
+}
34
+
35
+/// A blob.
36
+/// 
37
+/// A PBF file consists of a sequence of blobs. This type supports decoding the content of a blob
38
+/// to different types of blocks that are usually more interesting to the user.
39
+pub struct Blob {
40
+    header: fileformat::BlobHeader,
41
+    blob: fileformat::Blob,
42
+}
43
+
44
+impl Blob {
45
+    fn new(header: fileformat::BlobHeader, blob: fileformat::Blob) -> Blob {
46
+        Blob {
47
+            header: header,
48
+            blob: blob
49
+        }
50
+    }
51
+
52
+    /// Decodes the Blob and tries to obtain the inner content (usually a `HeaderBlock` or a
53
+    /// `PrimitiveBlock`). This operation might involve an expensive decompression step.
54
+    pub fn decode(&self) -> Result<BlobDecode> {
55
+        match self.get_type() {
56
+            BlobType::OsmHeader => {
57
+                self.to_headerblock()
58
+                    .map(BlobDecode::OsmHeader)
59
+            },
60
+            BlobType::OsmData => {
61
+                self.to_primitiveblock()
62
+                    .map(BlobDecode::OsmData)
63
+            },
64
+            BlobType::Unknown(x) => Ok(BlobDecode::Unknown(x)),
65
+        }
66
+    }
67
+
68
+    /// Returns the type of a blob without decoding its content.
69
+    pub fn get_type(&self) -> BlobType {
70
+        match self.header.get_field_type() {
71
+            "OSMHeader" => BlobType::OsmHeader,
72
+            "OSMData" => BlobType::OsmData,
73
+            x => BlobType::Unknown(x),
74
+        }
75
+    }
76
+
77
+    /// Tries to decode the blob to a `HeaderBlock`. This operation might involve an expensive
78
+    /// decompression step.
79
+    pub fn to_headerblock(&self) -> Result<HeaderBlock> {
80
+        decode_blob(&self.blob)
81
+            .map(HeaderBlock::new)
82
+            .chain_err(|| "failed to decode blob to header block")
83
+    }
84
+
85
+    /// Tries to decode the blob to a `PrimitiveBlock`. This operation might involve an expensive
86
+    /// decompression step.
87
+    pub fn to_primitiveblock(&self) -> Result<PrimitiveBlock> {
88
+        decode_blob(&self.blob)
89
+            .map(PrimitiveBlock::new)
90
+            .chain_err(|| "failed to decode blob to primitive block")
91
+    }
92
+}
93
+
94
+/// A reader for PBF files that allows iterating over `Blob`s.
95
+pub struct BlobReader<R: Read> {
96
+    reader: R,
97
+    last_blob_ok: bool,
98
+}
99
+
100
+impl<R: Read> BlobReader<R> {
101
+    /// Creates a new `ElementReader`.
102
+    /// 
103
+    /// # Example
104
+    /// ```
105
+    /// use osmpbf::*;
106
+    /// 
107
+    /// # fn foo() -> Result<()> {
108
+    /// let f = std::fs::File::open("tests/test.osm.pbf")?;
109
+    /// let buf_reader = std::io::BufReader::new(f);
110
+    /// 
111
+    /// let reader = ElementReader::new(buf_reader);
112
+    /// 
113
+    /// # Ok(())
114
+    /// # }
115
+    /// ```
116
+    pub fn new(reader: R) -> BlobReader<R> {
117
+        BlobReader {
118
+            reader: reader,
119
+            last_blob_ok: true,
120
+        }
121
+    }
122
+}
123
+
124
+impl BlobReader<BufReader<File>> {
125
+    /// Tries to open the file at the given path and constructs a `BlobReader` from this.
126
+    /// 
127
+    /// # Errors
128
+    /// Returns the same errors that `std::fs::File::open` returns.
129
+    /// 
130
+    /// # Example
131
+    /// ```
132
+    /// use osmpbf::*;
133
+    /// 
134
+    /// # fn foo() -> Result<()> {
135
+    /// let reader = BlobReader::from_path("tests/test.osm.pbf")?;
136
+    /// # Ok(())
137
+    /// # }
138
+    /// ```
139
+    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Self>
140
+    {
141
+        let f = File::open(path)?;
142
+        let reader = BufReader::new(f);
143
+
144
+        Ok(BlobReader::new(reader))
145
+    }
146
+}
147
+
148
+impl<R: Read> Iterator for BlobReader<R> {
149
+    type Item = Result<Blob>;
150
+
151
+    fn next(&mut self) -> Option<Self::Item> {
152
+        // Stop iteration if there was an error.
153
+        if !self.last_blob_ok {
154
+            return None;
155
+        }
156
+
157
+        let size: u64 = match self.reader.read_u32::<byteorder::BigEndian>() {
158
+            Ok(n) => u64::from(n),
159
+            Err(e) => {
160
+                match e.kind() {
161
+                    ErrorKind::UnexpectedEof => {
162
+                        return None
163
+                    },
164
+                    _ => {
165
+                        self.last_blob_ok = false;
166
+                        return Some(Err(Error::with_chain(e, "Could not decode blob size")));
167
+                    },
168
+                }
169
+            },
170
+        };
171
+
172
+        let header: fileformat::BlobHeader = match protobuf::parse_from_reader(&mut self.reader.by_ref().take(size)) {
173
+            Ok(header) => header,
174
+            Err(e) => {
175
+                self.last_blob_ok = false;
176
+                return Some(Err(Error::with_chain(e, "Could not decode BlobHeader")));
177
+            },
178
+        };
179
+
180
+        let blob: fileformat::Blob = match protobuf::parse_from_reader(&mut self.reader.by_ref().take(header.get_datasize() as u64)) {
181
+            Ok(blob) => blob,
182
+            Err(e) => {
183
+                self.last_blob_ok = false;
184
+                return Some(Err(Error::with_chain(e, "Could not decode Blob")));
185
+            },
186
+        };
187
+
188
+        Some(Ok(Blob::new(header, blob)))
189
+    }
190
+}
191
+
192
+#[cfg(feature = "system-libz")]
193
+pub(crate) fn decode_blob<T>(blob: &fileformat::Blob) -> Result<T>
194
+    where T: protobuf::Message + protobuf::MessageStatic {
195
+    if blob.has_raw() {
196
+        protobuf::parse_from_bytes(blob.get_raw()).chain_err(|| "Could not parse raw data")
197
+    } else if blob.has_zlib_data() {
198
+        let mut decoder = ZlibDecoder::new(blob.get_zlib_data());
199
+        protobuf::parse_from_reader(&mut decoder).chain_err(|| "Could not parse zlib data")
200
+    } else {
201
+        bail!("Blob is missing fields 'raw' and 'zlib_data")
202
+    }
203
+}
204
+
205
+#[cfg(not(feature = "system-libz"))]
206
+pub(crate) fn decode_blob<T>(blob: &fileformat::Blob) -> Result<T>
207
+    where T: protobuf::Message + protobuf::MessageStatic {
208
+    if blob.has_raw() {
209
+        protobuf::parse_from_bytes(blob.get_raw()).chain_err(|| "Could not parse raw data")
210
+    } else if blob.has_zlib_data() {
211
+        let mut decoder = DeflateDecoder::from_zlib(blob.get_zlib_data());
212
+        protobuf::parse_from_reader(&mut decoder).chain_err(|| "Could not parse zlib data")
213
+    } else {
214
+        bail!("Blob is missing fields 'raw' and 'zlib_data")
215
+    }
216
+}

+ 211
- 0
src/block.rs Datei anzeigen

@@ -0,0 +1,211 @@
1
+//! `HeaderBlock`, `PrimitiveBlock` and `Group`s
2
+
3
+use dense::DenseNodeIter;
4
+use elements::{Node, Way, Relation};
5
+use errors::*;
6
+use proto::osmformat;
7
+use std;
8
+
9
+
10
+pub struct HeaderBlock {
11
+    header: osmformat::HeaderBlock,
12
+}
13
+
14
+impl HeaderBlock {
15
+    pub(crate) fn new(header: osmformat::HeaderBlock) -> HeaderBlock {
16
+        HeaderBlock { header: header }
17
+    }
18
+
19
+    pub fn required_features(&self) -> &[String] {
20
+        self.header.get_required_features()
21
+    }
22
+
23
+    pub fn optional_features(&self) -> &[String] {
24
+        self.header.get_optional_features()
25
+    }
26
+}
27
+
28
+pub struct PrimitiveBlock {
29
+    block: osmformat::PrimitiveBlock,
30
+}
31
+
32
+impl PrimitiveBlock {
33
+    pub fn new(block: osmformat::PrimitiveBlock) -> PrimitiveBlock {
34
+        PrimitiveBlock { block: block }
35
+    }
36
+
37
+    pub fn groups(&self) -> GroupIter {
38
+        GroupIter::new(&self.block)
39
+    }
40
+}
41
+
42
+pub struct PrimitiveGroup<'a> {
43
+    block: &'a osmformat::PrimitiveBlock,
44
+    group: &'a osmformat::PrimitiveGroup,
45
+}
46
+
47
+impl<'a> PrimitiveGroup<'a> {
48
+    fn new(block: &'a osmformat::PrimitiveBlock,
49
+           group: &'a osmformat::PrimitiveGroup)
50
+          -> PrimitiveGroup<'a> {
51
+        PrimitiveGroup {
52
+            block: block,
53
+            group: group,
54
+        }
55
+    }
56
+
57
+    pub fn nodes(&self) -> GroupNodeIter<'a> {
58
+        GroupNodeIter::new(self.block, self.group)
59
+    }
60
+
61
+    pub fn dense_nodes(&self) -> DenseNodeIter<'a> {
62
+        DenseNodeIter::new(self.block, self.group.get_dense())
63
+    }
64
+
65
+    pub fn ways(&self) -> GroupWayIter<'a> {
66
+        GroupWayIter::new(self.block, self.group)
67
+    }
68
+
69
+    pub fn relations(&self) -> GroupRelationIter<'a> {
70
+        GroupRelationIter::new(self.block, self.group)
71
+    }
72
+}
73
+
74
+pub struct GroupIter<'a> {
75
+    block: &'a osmformat::PrimitiveBlock,
76
+    groups: std::slice::Iter<'a, osmformat::PrimitiveGroup>,
77
+}
78
+
79
+impl<'a> GroupIter<'a> {
80
+    fn new(block: &'a osmformat::PrimitiveBlock) -> GroupIter<'a> {
81
+        GroupIter {
82
+            block: block,
83
+            groups: block.get_primitivegroup().iter(),
84
+        }
85
+    }
86
+}
87
+
88
+impl<'a> Iterator for GroupIter<'a> {
89
+    type Item = PrimitiveGroup<'a>;
90
+
91
+    fn next(&mut self) -> Option<Self::Item> {
92
+        match self.groups.next() {
93
+            Some(g) => Some(PrimitiveGroup::new(self.block, g)),
94
+            None => None,
95
+        }
96
+    }
97
+
98
+    fn size_hint(&self) -> (usize, Option<usize>) {
99
+        self.groups.size_hint()
100
+    }
101
+}
102
+
103
+impl<'a> ExactSizeIterator for GroupIter<'a> {}
104
+
105
+pub struct GroupNodeIter<'a> {
106
+    block: &'a osmformat::PrimitiveBlock,
107
+    nodes: std::slice::Iter<'a, osmformat::Node>,
108
+}
109
+
110
+impl<'a> GroupNodeIter<'a> {
111
+    fn new(block: &'a osmformat::PrimitiveBlock,
112
+           group: &'a osmformat::PrimitiveGroup)
113
+          -> GroupNodeIter<'a> {
114
+        GroupNodeIter {
115
+            block: block,
116
+            nodes: group.get_nodes().iter(),
117
+        }
118
+    }
119
+}
120
+
121
+impl<'a> Iterator for GroupNodeIter<'a> {
122
+    type Item = Node<'a>;
123
+
124
+    fn next(&mut self) -> Option<Self::Item> {
125
+        match self.nodes.next() {
126
+            Some(n) => Some(Node::new(self.block, n)),
127
+            None => None,
128
+        }
129
+    }
130
+
131
+    fn size_hint(&self) -> (usize, Option<usize>) {
132
+        self.nodes.size_hint()
133
+    }
134
+}
135
+
136
+impl<'a> ExactSizeIterator for GroupNodeIter<'a> {}
137
+
138
+pub struct GroupWayIter<'a> {
139
+    block: &'a osmformat::PrimitiveBlock,
140
+    ways: std::slice::Iter<'a, osmformat::Way>,
141
+}
142
+
143
+impl<'a> GroupWayIter<'a> {
144
+    fn new(block: &'a osmformat::PrimitiveBlock,
145
+           group: &'a osmformat::PrimitiveGroup)
146
+          -> GroupWayIter<'a> {
147
+        GroupWayIter {
148
+            block: block,
149
+            ways: group.get_ways().iter(),
150
+        }
151
+    }
152
+}
153
+
154
+impl<'a> Iterator for GroupWayIter<'a> {
155
+    type Item = Way<'a>;
156
+
157
+    fn next(&mut self) -> Option<Self::Item> {
158
+        match self.ways.next() {
159
+            Some(way) => Some(Way::new(self.block, way)),
160
+            None => None,
161
+        }
162
+    }
163
+
164
+    fn size_hint(&self) -> (usize, Option<usize>) {
165
+        self.ways.size_hint()
166
+    }
167
+}
168
+
169
+impl<'a> ExactSizeIterator for GroupWayIter<'a> {}
170
+
171
+pub struct GroupRelationIter<'a> {
172
+    block: &'a osmformat::PrimitiveBlock,
173
+    rels: std::slice::Iter<'a, osmformat::Relation>,
174
+}
175
+
176
+impl<'a> GroupRelationIter<'a> {
177
+    fn new(block: &'a osmformat::PrimitiveBlock,
178
+           group: &'a osmformat::PrimitiveGroup)
179
+          -> GroupRelationIter<'a> {
180
+        GroupRelationIter {
181
+            block: block,
182
+            rels: group.get_relations().iter(),
183
+        }
184
+    }
185
+}
186
+
187
+impl<'a> Iterator for GroupRelationIter<'a> {
188
+    type Item = Relation<'a>;
189
+
190
+    fn next(&mut self) -> Option<Self::Item> {
191
+        match self.rels.next() {
192
+            Some(rel) => Some(Relation::new(self.block, rel)),
193
+            None => None,
194
+        }
195
+    }
196
+
197
+    fn size_hint(&self) -> (usize, Option<usize>) {
198
+        self.rels.size_hint()
199
+    }
200
+}
201
+
202
+impl<'a> ExactSizeIterator for GroupRelationIter<'a> {}
203
+
204
+pub(crate) fn str_from_stringtable(block: &osmformat::PrimitiveBlock, index: usize) -> Result<&str> {
205
+    if let Some(vec) = block.get_stringtable().get_s().get(index) {
206
+        std::str::from_utf8(vec)
207
+            .chain_err(|| "failed to decode string from string table")
208
+    } else {
209
+        Err(ErrorKind::StringtableIndexOutOfBounds(index).into())
210
+    }
211
+}

+ 196
- 0
src/dense.rs Datei anzeigen

@@ -0,0 +1,196 @@
1
+//! Iterate over the dense nodes in a `PrimitiveGroup`
2
+
3
+use errors::*;
4
+use proto::osmformat;
5
+use block::str_from_stringtable;
6
+use std;
7
+
8
+
9
+//TODO Add getter functions for id, version, uid, ...
10
+/// An OpenStreetMap node element from a compressed array of DenseNodes (See [OSM wiki](http://wiki.openstreetmap.org/wiki/Node)).
11
+pub struct DenseNode<'a> {
12
+    block: &'a osmformat::PrimitiveBlock,
13
+    pub id: i64,
14
+    pub version: i32,
15
+    timestamp: i64,
16
+    pub changeset: i64,
17
+    pub uid: i32,
18
+    pub user_sid: i32,
19
+    lat: i64,
20
+    lon: i64,
21
+    keys_vals_indices: &'a [i32],
22
+}
23
+
24
+impl<'a> DenseNode<'a> {
25
+    pub fn user(&self) -> Result<&'a str> {
26
+        str_from_stringtable(self.block, self.user_sid as usize)
27
+    }
28
+
29
+    pub fn lat(&self) -> f64 {
30
+        0.000_000_001_f64 * (self.block.get_lat_offset() +
31
+                             (i64::from(self.block.get_granularity()) *
32
+                              self.lat)) as f64
33
+    }
34
+
35
+    pub fn lon(&self) -> f64 {
36
+        0.000_000_001_f64 * (self.block.get_lon_offset() +
37
+                             (i64::from(self.block.get_granularity()) *
38
+                              self.lon)) as f64
39
+    }
40
+
41
+    pub fn milli_timestamp(&self) -> i64 {
42
+        self.timestamp * i64::from(self.block.get_date_granularity())
43
+    }
44
+
45
+    pub fn tags(&self) -> DenseTagIter<'a> {
46
+        DenseTagIter {
47
+            block: self.block,
48
+            keys_vals_indices: self.keys_vals_indices.iter(),
49
+        }
50
+    }
51
+}
52
+
53
+pub struct DenseNodeIter<'a> {
54
+    block: &'a osmformat::PrimitiveBlock,
55
+    dids: std::slice::Iter<'a, i64>, // deltas
56
+    cid: i64, // current id
57
+    versions: std::slice::Iter<'a, i32>,
58
+    dtimestamps: std::slice::Iter<'a, i64>, // deltas
59
+    ctimestamp: i64,
60
+    dchangesets: std::slice::Iter<'a, i64>, // deltas
61
+    cchangeset: i64,
62
+    duids: std::slice::Iter<'a, i32>, // deltas
63
+    cuid: i32,
64
+    duser_sids: std::slice::Iter<'a, i32>, // deltas
65
+    cuser_sid: i32,
66
+    dlats: std::slice::Iter<'a, i64>, // deltas
67
+    clat: i64,
68
+    dlons: std::slice::Iter<'a, i64>, // deltas
69
+    clon: i64,
70
+    keys_vals_slice: &'a [i32],
71
+    keys_vals_index: usize,
72
+}
73
+
74
+impl<'a> DenseNodeIter<'a> {
75
+    pub fn new(block: &'a osmformat::PrimitiveBlock,
76
+           osmdense: &'a osmformat::DenseNodes) -> DenseNodeIter<'a> {
77
+        let info = osmdense.get_denseinfo();
78
+        DenseNodeIter {
79
+            block: block,
80
+            dids: osmdense.get_id().iter(),
81
+            cid: 0,
82
+            versions: info.get_version().iter(),
83
+            dtimestamps: info.get_timestamp().iter(),
84
+            ctimestamp: 0,
85
+            dchangesets: info.get_changeset().iter(),
86
+            cchangeset: 0,
87
+            duids: info.get_uid().iter(),
88
+            cuid: 0,
89
+            duser_sids: info.get_user_sid().iter(),
90
+            cuser_sid: 0,
91
+            dlats: osmdense.get_lat().iter(),
92
+            clat: 0,
93
+            dlons: osmdense.get_lon().iter(),
94
+            clon: 0,
95
+            keys_vals_slice: osmdense.get_keys_vals(),
96
+            keys_vals_index: 0,
97
+        }
98
+    }
99
+}
100
+
101
+
102
+impl<'a> Iterator for DenseNodeIter<'a> {
103
+    type Item = DenseNode<'a>;
104
+
105
+    fn next(&mut self) -> Option<Self::Item> {
106
+        match (self.dids.next(),
107
+               self.versions.next(),
108
+               self.dtimestamps.next(),
109
+               self.dchangesets.next(),
110
+               self.duids.next(),
111
+               self.duser_sids.next(),
112
+               self.dlats.next(),
113
+               self.dlons.next()) {
114
+            (Some(did),
115
+             Some(version),
116
+             Some(dtimestamp),
117
+             Some(dchangeset),
118
+             Some(duid),
119
+             Some(duser_sid),
120
+             Some(dlat),
121
+             Some(dlon)) => {
122
+                self.cid += *did;
123
+                self.ctimestamp += *dtimestamp;
124
+                self.cchangeset += *dchangeset;
125
+                self.cuid += *duid;
126
+                self.cuser_sid += *duser_sid;
127
+                self.clat += *dlat;
128
+                self.clon += *dlon;
129
+
130
+                let start_index = self.keys_vals_index;
131
+                let mut end_index = start_index;
132
+                for chunk in self.keys_vals_slice[self.keys_vals_index..].chunks(2) {
133
+                    if chunk[0] != 0 && chunk.len() == 2 {
134
+                        end_index += 2;
135
+                        self.keys_vals_index += 2;
136
+                    } else {
137
+                        self.keys_vals_index += 1;
138
+                        break;
139
+                    }
140
+                }
141
+
142
+                Some(DenseNode {
143
+                    block: self.block,
144
+                    id: self.cid,
145
+                    version: *version,
146
+                    timestamp: self.ctimestamp,
147
+                    changeset: self.cchangeset,
148
+                    uid: self.cuid,
149
+                    user_sid: self.cuser_sid,
150
+                    lat: self.clat,
151
+                    lon: self.clon,
152
+                    keys_vals_indices: &self.keys_vals_slice[start_index..end_index],
153
+                })
154
+
155
+            },
156
+            _ => None,
157
+        }
158
+    }
159
+
160
+    fn size_hint(&self) -> (usize, Option<usize>) {
161
+        self.dids.size_hint()
162
+    }
163
+}
164
+
165
+impl<'a> ExactSizeIterator for DenseNodeIter<'a> {}
166
+
167
+pub struct DenseTagIter<'a> {
168
+    block: &'a osmformat::PrimitiveBlock,
169
+    keys_vals_indices: std::slice::Iter<'a, i32>,
170
+}
171
+
172
+//TODO return Result
173
+impl<'a> Iterator for DenseTagIter<'a> {
174
+    type Item = (&'a str, &'a str);
175
+
176
+    fn next(&mut self) -> Option<Self::Item> {
177
+        match (self.keys_vals_indices.next(), self.keys_vals_indices.next()) {
178
+            (Some(&key_index), Some(&val_index)) => {
179
+                let k_res = str_from_stringtable(self.block, key_index as usize);
180
+                let v_res = str_from_stringtable(self.block, val_index as usize);
181
+                if let (Ok(k), Ok(v)) = (k_res, v_res) {
182
+                    Some((k, v))
183
+                } else {
184
+                    None
185
+                }
186
+            },
187
+            _ => None,
188
+        }
189
+    }
190
+
191
+    fn size_hint(&self) -> (usize, Option<usize>) {
192
+        self.keys_vals_indices.size_hint()
193
+    }
194
+}
195
+
196
+impl<'a> ExactSizeIterator for DenseTagIter<'a> {}

+ 364
- 0
src/elements.rs Datei anzeigen

@@ -0,0 +1,364 @@
1
+//! Nodes, ways and relations
2
+
3
+use errors::*;
4
+use block::str_from_stringtable;
5
+use proto::osmformat::PrimitiveBlock;
6
+use proto::osmformat;
7
+use std;
8
+
9
+
10
+/// An OpenStreetMap node element (See [OSM wiki](http://wiki.openstreetmap.org/wiki/Node)).
11
+pub struct Node<'a> {
12
+    block: &'a PrimitiveBlock,
13
+    osmnode: &'a osmformat::Node,
14
+}
15
+
16
+impl<'a> Node<'a> {
17
+    pub(crate) fn new(block: &'a PrimitiveBlock, osmnode: &'a osmformat::Node) -> Node<'a> {
18
+        Node {
19
+            block: block,
20
+            osmnode: osmnode,
21
+        }
22
+    }
23
+
24
+    /// Returns the node id. It should be unique between nodes and might be negative to indicate
25
+    /// that the element has not yet been uploaded to a server.
26
+    pub fn id(&self) -> i64 {
27
+        self.osmnode.get_id()
28
+    }
29
+
30
+    /// Returns an iterator over the tags of this node (See [OSM wiki](http://wiki.openstreetmap.org/wiki/Tags)).
31
+    pub fn tags(&self) -> TagIter<'a> {
32
+        TagIter {
33
+            block: self.block,
34
+            key_indices: self.osmnode.get_keys().iter(),
35
+            val_indices: self.osmnode.get_vals().iter(),
36
+        }
37
+    }
38
+
39
+    /// Returns additional metadata for this element.
40
+    pub fn info(&self) -> Info<'a> {
41
+        Info::new(self.block, self.osmnode.get_info())
42
+    }
43
+
44
+    /// Returns the latitude coordinate in degrees.
45
+    pub fn lat(&self) -> f64 {
46
+        0.000_000_001_f64 * (self.block.get_lat_offset() +
47
+                             (i64::from(self.block.get_granularity()) *
48
+                              self.osmnode.get_lat())) as f64
49
+    }
50
+
51
+    /// Returns the longitude coordinate in degrees.
52
+    pub fn lon(&self) -> f64 {
53
+        0.000_000_001_f64 * (self.block.get_lon_offset() +
54
+                             (i64::from(self.block.get_granularity()) *
55
+                              self.osmnode.get_lon())) as f64
56
+    }
57
+}
58
+
59
+/// An OpenStreetMap way element (See [OSM wiki](http://wiki.openstreetmap.org/wiki/Way)).
60
+/// 
61
+/// A way contains an ordered list of node references that can be accessed with the `refs` or the
62
+/// `refs_slice` method.
63
+pub struct Way<'a> {
64
+    block: &'a PrimitiveBlock,
65
+    osmway: &'a osmformat::Way,
66
+}
67
+
68
+impl<'a> Way<'a> {
69
+    pub(crate) fn new(block: &'a PrimitiveBlock, osmway: &'a osmformat::Way) -> Way<'a> {
70
+        Way {
71
+            block: block,
72
+            osmway: osmway,
73
+        }
74
+    }
75
+
76
+    /// Returns the way id.
77
+    pub fn id(&self) -> i64 {
78
+        self.osmway.get_id()
79
+    }
80
+
81
+    /// Returns an iterator over the tags of this way (See [OSM wiki](http://wiki.openstreetmap.org/wiki/Tags)).
82
+    pub fn tags(&self) -> TagIter<'a> {
83
+        TagIter {
84
+            block: self.block,
85
+            key_indices: self.osmway.get_keys().iter(),
86
+            val_indices: self.osmway.get_vals().iter(),
87
+        }
88
+    }
89
+
90
+    /// Returns additional metadata for this element.
91
+    pub fn info(&self) -> Info<'a> {
92
+        Info::new(self.block, self.osmway.get_info())
93
+    }
94
+
95
+    /// Returns an iterator over the references of this way. Each reference should correspond to a
96
+    /// node id.
97
+    pub fn refs(&self) -> WayRefIter<'a> {
98
+        WayRefIter {
99
+           deltas: self.osmway.get_refs().iter(),
100
+           current: 0,
101
+        }
102
+    }
103
+
104
+    /// Returns a slice of references. Each reference should correspond to a node id.
105
+    pub fn refs_slice(&self) -> &[i64] {
106
+        self.osmway.get_refs()
107
+    }
108
+}
109
+
110
+/// An OpenStreetMap relation element (See [OSM wiki](http://wiki.openstreetmap.org/wiki/Relation)).
111
+/// 
112
+/// A relation contains an ordered list of members that can be of any element type.
113
+pub struct Relation<'a> {
114
+    block: &'a PrimitiveBlock,
115
+    osmrel: &'a osmformat::Relation,
116
+}
117
+
118
+impl<'a> Relation<'a> {
119
+    pub(crate) fn new(block: &'a PrimitiveBlock, osmrel: &'a osmformat::Relation) -> Relation<'a> {
120
+        Relation {
121
+            block: block,
122
+            osmrel: osmrel,
123
+        }
124
+    }
125
+
126
+    /// Returns the relation id.
127
+    pub fn id(&self) -> i64 {
128
+        self.osmrel.get_id()
129
+    }
130
+
131
+    /// Returns an iterator over the tags of this relation (See [OSM wiki](http://wiki.openstreetmap.org/wiki/Tags)).
132
+    pub fn tags(&self) -> TagIter<'a> {
133
+        TagIter {
134
+            block: self.block,
135
+            key_indices: self.osmrel.get_keys().iter(),
136
+            val_indices: self.osmrel.get_vals().iter(),
137
+        }
138
+    }
139
+
140
+    /// Returns additional metadata for this element.
141
+    pub fn info(&self) -> Info<'a> {
142
+        Info::new(self.block, self.osmrel.get_info())
143
+    }
144
+
145
+    /// Returns an iterator over the members of this relation.
146
+    pub fn members(&self) -> RelMemberIter<'a> {
147
+        RelMemberIter::new(self.block, self.osmrel)
148
+    }
149
+}
150
+
151
+/// An iterator over the references of a way.
152
+/// 
153
+/// Each reference corresponds to a node id.
154
+pub struct WayRefIter<'a> {
155
+    deltas: std::slice::Iter<'a, i64>,
156
+    current: i64,
157
+}
158
+
159
+impl<'a> Iterator for WayRefIter<'a> {
160
+    type Item = i64;
161
+
162
+    fn next(&mut self) -> Option<Self::Item> {
163
+        match self.deltas.next() {
164
+            Some(&d) => {
165
+                self.current += d;
166
+                Some(self.current)
167
+            },
168
+            None => None,
169
+        }
170
+    }
171
+
172
+    fn size_hint(&self) -> (usize, Option<usize>) {
173
+        self.deltas.size_hint()
174
+    }
175
+}
176
+
177
+impl<'a> ExactSizeIterator for WayRefIter<'a> {}
178
+
179
+/// The element type of a relation member.
180
+pub enum RelMemberType {
181
+    Node,
182
+    Way,
183
+    Relation
184
+}
185
+
186
+impl From<osmformat::Relation_MemberType> for RelMemberType {
187
+    fn from(rmt: osmformat::Relation_MemberType) -> RelMemberType {
188
+        match rmt {
189
+            osmformat::Relation_MemberType::NODE => RelMemberType::Node,
190
+            osmformat::Relation_MemberType::WAY => RelMemberType::Way,
191
+            osmformat::Relation_MemberType::RELATION => RelMemberType::Relation,
192
+        }
193
+    }
194
+}
195
+
196
+//TODO encapsulate member_id based on member_type (NodeId, WayId, RelationId)
197
+/// A member of a relation.
198
+/// 
199
+/// Each member has a member type and a member id that references an element of that type.
200
+pub struct RelMember<'a> {
201
+    block: &'a PrimitiveBlock,
202
+    pub role_sid: i32,
203
+    pub member_id: i64,
204
+    pub member_type: RelMemberType,
205
+}
206
+
207
+impl<'a> RelMember<'a> {
208
+    /// Returns the role of a relation member.
209
+    pub fn role(&self) -> Result<&'a str> {
210
+        str_from_stringtable(self.block, self.role_sid as usize)
211
+    }
212
+}
213
+
214
+/// An iterator over the members of a relation.
215
+pub struct RelMemberIter<'a> {
216
+    block: &'a PrimitiveBlock,
217
+    role_sids: std::slice::Iter<'a, i32>,
218
+    member_id_deltas: std::slice::Iter<'a, i64>,
219
+    member_types: std::slice::Iter<'a, osmformat::Relation_MemberType>,
220
+    current_member_id: i64,
221
+}
222
+
223
+impl<'a> RelMemberIter<'a> {
224
+    fn new(block: &'a PrimitiveBlock, osmrel: &'a osmformat::Relation) -> RelMemberIter<'a> {
225
+        RelMemberIter {
226
+            block: block,
227
+            role_sids: osmrel.get_roles_sid().iter(),
228
+            member_id_deltas: osmrel.get_memids().iter(),
229
+            member_types: osmrel.get_types().iter(),
230
+            current_member_id: 0,
231
+        }
232
+    }
233
+}
234
+
235
+impl<'a> Iterator for RelMemberIter<'a> {
236
+    type Item = RelMember<'a>;
237
+
238
+    fn next(&mut self) -> Option<Self::Item> {
239
+        match (self.role_sids.next(),
240
+               self.member_id_deltas.next(),
241
+               self.member_types.next()) {
242
+            (Some(role_sid), Some(mem_id_delta), Some(member_type)) => {
243
+                self.current_member_id += *mem_id_delta;
244
+                Some(RelMember {
245
+                    block: self.block,
246
+                    role_sid: *role_sid,
247
+                    member_id: self.current_member_id,
248
+                    member_type: RelMemberType::from(*member_type),
249
+                })
250
+            },
251
+            _ => None,
252
+        }
253
+    }
254
+
255
+    fn size_hint(&self) -> (usize, Option<usize>) {
256
+        self.role_sids.size_hint()
257
+    }
258
+}
259
+
260
+impl<'a> ExactSizeIterator for RelMemberIter<'a> {}
261
+
262
+/// An iterator over the tags of an element.
263
+pub struct TagIter<'a> {
264
+    block: &'a PrimitiveBlock,
265
+    key_indices: std::slice::Iter<'a, u32>,
266
+    val_indices: std::slice::Iter<'a, u32>,
267
+}
268
+
269
+//TODO return Result?
270
+impl<'a> Iterator for TagIter<'a> {
271
+    type Item = (&'a str, &'a str);
272
+
273
+    fn next(&mut self) -> Option<Self::Item> {
274
+        match (self.key_indices.next(), self.val_indices.next()) {
275
+            (Some(&key_index), Some(&val_index)) => {
276
+                let k_res = str_from_stringtable(self.block, key_index as usize);
277
+                let v_res = str_from_stringtable(self.block, val_index as usize);
278
+                if let (Ok(k), Ok(v)) = (k_res, v_res) {
279
+                    Some((k, v))
280
+                } else {
281
+                    None
282
+                }
283
+            },
284
+            _ => None,
285
+        }
286
+    }
287
+
288
+    fn size_hint(&self) -> (usize, Option<usize>) {
289
+        self.key_indices.size_hint()
290
+    }
291
+}
292
+
293
+impl<'a> ExactSizeIterator for TagIter<'a> {}
294
+
295
+/// Additional metadata that might be included in each element.
296
+pub struct Info<'a> {
297
+    block: &'a PrimitiveBlock,
298
+    info: &'a osmformat::Info,
299
+}
300
+
301
+impl<'a> Info<'a> {
302
+    fn new(block: &'a PrimitiveBlock, info: &'a osmformat::Info) -> Info<'a> {
303
+        Info {
304
+            block: block,
305
+            info: info,
306
+        }
307
+    }
308
+
309
+    /// Returns the version of this element.
310
+    pub fn version(&self) -> Option<i32> {
311
+        if self.info.has_version() {
312
+            Some(self.info.get_version())
313
+        } else {
314
+            None
315
+        }
316
+    }
317
+
318
+    /// Returns the time stamp in milliseconds since the epoch.
319
+    pub fn milli_timestamp(&self) -> Option<i64> {
320
+        if self.info.has_timestamp() {
321
+            Some(self.info.get_timestamp() * i64::from(self.block.get_date_granularity()))
322
+        } else {
323
+            None
324
+        }
325
+    }
326
+
327
+    /// Returns the changeset id.
328
+    pub fn changeset(&self) -> Option<i64> {
329
+        if self.info.has_changeset() {
330
+            Some(self.info.get_changeset())
331
+        } else {
332
+            None
333
+        }
334
+    }
335
+
336
+    /// Returns the user id.
337
+    pub fn uid(&self) -> Option<i32> {
338
+        if self.info.has_uid() {
339
+            Some(self.info.get_uid())
340
+        } else {
341
+            None
342
+        }
343
+    }
344
+
345
+    /// Returns the user name.
346
+    pub fn user(&self) -> Option<Result<&'a str>> {
347
+        if self.info.has_user_sid() {
348
+            Some(str_from_stringtable(self.block, self.info.get_user_sid() as usize))
349
+        } else {
350
+            None
351
+        }
352
+    }
353
+
354
+    /// Returns the visibility status of an element. This is only relevant if the PBF file contains
355
+    /// historical information.
356
+    pub fn visible(&self) -> bool {
357
+        if self.info.has_visible() {
358
+            self.info.get_visible()
359
+        } else {
360
+            // If the visible flag is not present it must be assumed to be true.
361
+            true
362
+        }
363
+    }
364
+}

+ 15
- 0
src/errors.rs Datei anzeigen

@@ -0,0 +1,15 @@
1
+error_chain!{
2
+    foreign_links {
3
+        Io(::std::io::Error);
4
+        Protobuf(::protobuf::ProtobufError);
5
+    }
6
+
7
+    errors {
8
+        StringtableIndexOutOfBounds(index: usize) {
9
+            description("stringtable index out of bounds")
10
+            display("stringtable index out of bounds: {}", index)
11
+        }
12
+
13
+        //TODO add UnexpectedPrimitiveBlock
14
+    }
15
+}

+ 35
- 0
src/lib.rs Datei anzeigen

@@ -0,0 +1,35 @@
1
+//! A fast reader for the PBF file format (\*.osm.pbf) for OpenStreetMap data.
2
+
3
+#![recursion_limit = "1024"]
4
+
5
+extern crate byteorder;
6
+extern crate memmap;
7
+extern crate protobuf;
8
+extern crate rayon;
9
+#[macro_use]
10
+extern crate error_chain;
11
+
12
+#[cfg(feature = "system-libz")]
13
+extern crate flate2;
14
+
15
+#[cfg(not(feature = "system-libz"))]
16
+extern crate inflate;
17
+
18
+
19
+pub use blob::*;
20
+pub use block::*;
21
+pub use dense::*;
22
+pub use elements::*;
23
+pub use errors::{Error, ErrorKind, Result, ResultExt};
24
+pub use mmap_blob::*;
25
+pub use reader::*;
26
+
27
+mod errors;
28
+mod proto;
29
+pub mod reader;
30
+pub mod blob;
31
+pub mod block;
32
+pub mod dense;
33
+pub mod elements;
34
+pub mod mmap_blob;
35
+

+ 142
- 0
src/mmap_blob.rs Datei anzeigen

@@ -0,0 +1,142 @@
1
+//! Iterate over blobs from a memory map
2
+
3
+extern crate protobuf;
4
+extern crate byteorder;
5
+extern crate memmap;
6
+
7
+use blob::{BlobDecode, decode_blob};
8
+use byteorder::ByteOrder;
9
+use errors::*;
10
+use block::{HeaderBlock, PrimitiveBlock};
11
+use proto::{fileformat, osmformat};
12
+use self::fileformat::BlobHeader;
13
+use std::fs::File;
14
+use std::path::Path;
15
+
16
+
17
+pub struct Mmap {
18
+    mmap: memmap::Mmap,
19
+}
20
+
21
+impl Mmap {
22
+    // The underlying file should not be modified while holding the memory map.
23
+    // See https://github.com/danburkert/memmap-rs/issues/25
24
+    pub unsafe fn from_file(file: &File) -> Result<Mmap> {
25
+        memmap::Mmap::map(file)
26
+            .map(|m| Mmap { mmap: m })
27
+            .chain_err(|| "Could not create memory map from file")
28
+    }
29
+
30
+    // The underlying file should not be modified while holding the memory map.
31
+    // See https://github.com/danburkert/memmap-rs/issues/25
32
+    pub unsafe fn from_path<P: AsRef<Path>>(path: P) -> Result<Mmap> {
33
+        let file = File::open(&path)?;
34
+        memmap::Mmap::map(&file)
35
+            .map(|m| Mmap { mmap: m })
36
+            .chain_err(|| format!("Could not create memory map from path {}", path.as_ref().display()))
37
+    }
38
+
39
+    pub fn blob_iter(&self) -> MmapBlobReader {
40
+        MmapBlobReader::new(self)
41
+    }
42
+
43
+    fn as_slice(&self) -> &[u8] {
44
+        &self.mmap
45
+    }
46
+}
47
+
48
+pub struct MmapBlob<'a> {
49
+    header: BlobHeader,
50
+    data: &'a [u8],
51
+}
52
+
53
+impl<'a> MmapBlob<'a> {
54
+    pub fn decode(&'a self) -> Result<BlobDecode<'a>> {
55
+        let blob: fileformat::Blob = protobuf::parse_from_bytes(self.data)
56
+            .chain_err(|| "failed to parse Blob")?;
57
+        match self.header.get_field_type() {
58
+            "OSMHeader" => {
59
+                let block: osmformat::HeaderBlock = decode_blob(&blob).unwrap();
60
+                Ok(BlobDecode::OsmHeader(HeaderBlock::new(block)))
61
+            }
62
+            "OSMData" => {
63
+                let block: osmformat::PrimitiveBlock = decode_blob(&blob).unwrap();
64
+                Ok(BlobDecode::OsmData(PrimitiveBlock::new(block)))
65
+            }
66
+            x => Ok(BlobDecode::Unknown(x)),
67
+        }
68
+    }
69
+}
70
+
71
+#[derive(Clone)]
72
+pub struct MmapBlobReader<'a> {
73
+    mmap: &'a Mmap,
74
+    offset: usize,
75
+    last_blob_ok: bool,
76
+}
77
+
78
+impl<'a> MmapBlobReader<'a> {
79
+    pub fn new(mmap: &Mmap) -> MmapBlobReader {
80
+        MmapBlobReader {
81
+            mmap: mmap,
82
+            offset: 0,
83
+            last_blob_ok: true,
84
+        }
85
+    }
86
+}
87
+
88
+impl<'a> Iterator for MmapBlobReader<'a> {
89
+    type Item = Result<MmapBlob<'a>>;
90
+
91
+    fn next(&mut self) -> Option<Self::Item> {
92
+        let slice = &self.mmap.as_slice()[self.offset..];
93
+
94
+        match slice.len() {
95
+            0 => return None,
96
+            1 ... 3 => {
97
+                self.last_blob_ok = false;
98
+                let io_error = ::std::io::Error::new(
99
+                    ::std::io::ErrorKind::UnexpectedEof, "failed to parse blob length"
100
+                );
101
+                return Some(Err(Error::from_kind(ErrorKind::Io(io_error))));
102
+            },
103
+            _ => {},
104
+        }
105
+
106
+        let header_size = byteorder::BigEndian::read_u32(slice) as usize;
107
+
108
+        if slice.len() < 4 + header_size {
109
+            self.last_blob_ok = false;
110
+            let io_error = ::std::io::Error::new(
111
+                ::std::io::ErrorKind::UnexpectedEof, "content too short for header"
112
+            );
113
+            return Some(Err(Error::from_kind(ErrorKind::Io(io_error))));
114
+        }
115
+
116
+        let header: BlobHeader = match protobuf::parse_from_bytes(&slice[4..(4 + header_size)]) {
117
+            Ok(x) => x,
118
+            Err(e) => {
119
+                self.last_blob_ok = false;
120
+                return Some(Err(e.into()));
121
+            },
122
+        };
123
+
124
+        let data_size = header.get_datasize() as usize;
125
+        let chunk_size = 4 + header_size + data_size;
126
+
127
+        if slice.len() < chunk_size {
128
+            self.last_blob_ok = false;
129
+            let io_error = ::std::io::Error::new(
130
+                ::std::io::ErrorKind::UnexpectedEof, "content too short for block data"
131
+            );
132
+            return Some(Err(Error::from_kind(ErrorKind::Io(io_error))));
133
+        }
134
+
135
+        self.offset += chunk_size;
136
+
137
+        Some(Ok(MmapBlob {
138
+            header: header,
139
+            data: &slice[(4 + header_size)..chunk_size]
140
+        }))
141
+    }
142
+}

+ 54
- 0
src/proto/fileformat.proto Datei anzeigen

@@ -0,0 +1,54 @@
1
+/** Copyright (c) 2010 Scott A. Crosby. <scott@sacrosby.com>
2
+
3
+   This program is free software: you can redistribute it and/or modify
4
+   it under the terms of the GNU Lesser General Public License as 
5
+   published by the Free Software Foundation, either version 3 of the 
6
+   License, or (at your option) any later version.
7
+
8
+   This program is distributed in the hope that it will be useful,
9
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
+   GNU Lesser General Public License for more details.
12
+
13
+   You should have received a copy of the GNU Lesser General Public License
14
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
15
+
16
+*/
17
+
18
+option optimize_for = LITE_RUNTIME;
19
+option java_package = "crosby.binary";
20
+package OSMPBF;
21
+
22
+//protoc --java_out=../.. fileformat.proto
23
+
24
+
25
+//
26
+//  STORAGE LAYER: Storing primitives.
27
+//
28
+
29
+message Blob {
30
+  optional bytes raw = 1; // No compression
31
+  optional int32 raw_size = 2; // When compressed, the uncompressed size
32
+
33
+  // Possible compressed versions of the data.
34
+  optional bytes zlib_data = 3;
35
+
36
+  // PROPOSED feature for LZMA compressed data. SUPPORT IS NOT REQUIRED.
37
+  optional bytes lzma_data = 4;
38
+
39
+  // Formerly used for bzip2 compressed data. Depreciated in 2010.
40
+  optional bytes OBSOLETE_bzip2_data = 5 [deprecated=true]; // Don't reuse this tag number.
41
+}
42
+
43
+/* A file contains an sequence of fileblock headers, each prefixed by
44
+their length in network byte order, followed by a data block
45
+containing the actual data. types staring with a "_" are reserved.
46
+*/
47
+
48
+message BlobHeader {
49
+  required string type = 1;
50
+  optional bytes indexdata = 2;
51
+  required int32 datasize = 3;
52
+}
53
+
54
+

+ 648
- 0
src/proto/fileformat.rs Datei anzeigen

@@ -0,0 +1,648 @@
1
+// This file is generated. Do not edit
2
+// @generated
3
+
4
+// https://github.com/Manishearth/rust-clippy/issues/702
5
+#![allow(unknown_lints)]
6
+#![allow(clippy)]
7
+
8
+#![cfg_attr(rustfmt, rustfmt_skip)]
9
+
10
+#![allow(box_pointers)]
11
+#![allow(dead_code)]
12
+#![allow(missing_docs)]
13
+#![allow(non_camel_case_types)]
14
+#![allow(non_snake_case)]
15
+#![allow(non_upper_case_globals)]
16
+#![allow(trivial_casts)]
17
+#![allow(unsafe_code)]
18
+#![allow(unused_imports)]
19
+#![allow(unused_results)]
20
+
21
+use protobuf::Message as Message_imported_for_functions;
22
+use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions;
23
+
24
+#[derive(PartialEq,Clone,Default,Debug)]
25
+pub struct Blob {
26
+    // message fields
27
+    raw: ::protobuf::SingularField<::std::vec::Vec<u8>>,
28
+    raw_size: ::std::option::Option<i32>,
29
+    zlib_data: ::protobuf::SingularField<::std::vec::Vec<u8>>,
30
+    lzma_data: ::protobuf::SingularField<::std::vec::Vec<u8>>,
31
+    OBSOLETE_bzip2_data: ::protobuf::SingularField<::std::vec::Vec<u8>>,
32
+    // special fields
33
+    unknown_fields: ::protobuf::UnknownFields,
34
+    cached_size: ::protobuf::CachedSize,
35
+}
36
+
37
+// see codegen.rs for the explanation why impl Sync explicitly
38
+unsafe impl ::std::marker::Sync for Blob {}
39
+
40
+impl Blob {
41
+    pub fn new() -> Blob {
42
+        ::std::default::Default::default()
43
+    }
44
+
45
+    pub fn default_instance() -> &'static Blob {
46
+        static mut instance: ::protobuf::lazy::Lazy<Blob> = ::protobuf::lazy::Lazy {
47
+            lock: ::protobuf::lazy::ONCE_INIT,
48
+            ptr: 0 as *const Blob,
49
+        };
50
+        unsafe {
51
+            instance.get(Blob::new)
52
+        }
53
+    }
54
+
55
+    // optional bytes raw = 1;
56
+
57
+    pub fn clear_raw(&mut self) {
58
+        self.raw.clear();
59
+    }
60
+
61
+    pub fn has_raw(&self) -> bool {
62
+        self.raw.is_some()
63
+    }
64
+
65
+    // Param is passed by value, moved
66
+    pub fn set_raw(&mut self, v: ::std::vec::Vec<u8>) {
67
+        self.raw = ::protobuf::SingularField::some(v);
68
+    }
69
+
70
+    // Mutable pointer to the field.
71
+    // If field is not initialized, it is initialized with default value first.
72
+    pub fn mut_raw(&mut self) -> &mut ::std::vec::Vec<u8> {
73
+        if self.raw.is_none() {
74
+            self.raw.set_default();
75
+        }
76
+        self.raw.as_mut().unwrap()
77
+    }
78
+
79
+    // Take field
80
+    pub fn take_raw(&mut self) -> ::std::vec::Vec<u8> {
81
+        self.raw.take().unwrap_or_else(|| ::std::vec::Vec::new())
82
+    }
83
+
84
+    pub fn get_raw(&self) -> &[u8] {
85
+        match self.raw.as_ref() {
86
+            Some(v) => &v,
87
+            None => &[],
88
+        }
89
+    }
90
+
91
+    fn get_raw_for_reflect(&self) -> &::protobuf::SingularField<::std::vec::Vec<u8>> {
92
+        &self.raw
93
+    }
94
+
95
+    fn mut_raw_for_reflect(&mut self) -> &mut ::protobuf::SingularField<::std::vec::Vec<u8>> {
96
+        &mut self.raw
97
+    }
98
+
99
+    // optional int32 raw_size = 2;
100
+
101
+    pub fn clear_raw_size(&mut self) {
102
+        self.raw_size = ::std::option::Option::None;
103
+    }
104
+
105
+    pub fn has_raw_size(&self) -> bool {
106
+        self.raw_size.is_some()
107
+    }
108
+
109
+    // Param is passed by value, moved
110
+    pub fn set_raw_size(&mut self, v: i32) {
111
+        self.raw_size = ::std::option::Option::Some(v);
112
+    }
113
+
114
+    pub fn get_raw_size(&self) -> i32 {
115
+        self.raw_size.unwrap_or(0)
116
+    }
117
+
118
+    fn get_raw_size_for_reflect(&self) -> &::std::option::Option<i32> {
119
+        &self.raw_size
120
+    }
121
+
122
+    fn mut_raw_size_for_reflect(&mut self) -> &mut ::std::option::Option<i32> {
123
+        &mut self.raw_size
124
+    }
125
+
126
+    // optional bytes zlib_data = 3;
127
+
128
+    pub fn clear_zlib_data(&mut self) {
129
+        self.zlib_data.clear();
130
+    }
131
+
132
+    pub fn has_zlib_data(&self) -> bool {
133
+        self.zlib_data.is_some()
134
+    }
135
+
136
+    // Param is passed by value, moved
137
+    pub fn set_zlib_data(&mut self, v: ::std::vec::Vec<u8>) {
138
+        self.zlib_data = ::protobuf::SingularField::some(v);
139
+    }
140
+
141
+    // Mutable pointer to the field.
142
+    // If field is not initialized, it is initialized with default value first.
143
+    pub fn mut_zlib_data(&mut self) -> &mut ::std::vec::Vec<u8> {
144
+        if self.zlib_data.is_none() {
145
+            self.zlib_data.set_default();
146
+        }
147
+        self.zlib_data.as_mut().unwrap()
148
+    }
149
+
150
+    // Take field
151
+    pub fn take_zlib_data(&mut self) -> ::std::vec::Vec<u8> {
152
+        self.zlib_data.take().unwrap_or_else(|| ::std::vec::Vec::new())
153
+    }
154
+
155
+    pub fn get_zlib_data(&self) -> &[u8] {
156
+        match self.zlib_data.as_ref() {
157
+            Some(v) => &v,
158
+            None => &[],
159
+        }
160
+    }
161
+
162
+    fn get_zlib_data_for_reflect(&self) -> &::protobuf::SingularField<::std::vec::Vec<u8>> {
163
+        &self.zlib_data
164
+    }
165
+
166
+    fn mut_zlib_data_for_reflect(&mut self) -> &mut ::protobuf::SingularField<::std::vec::Vec<u8>> {
167
+        &mut self.zlib_data
168
+    }
169
+
170
+    // optional bytes lzma_data = 4;
171
+
172
+    pub fn clear_lzma_data(&mut self) {
173
+        self.lzma_data.clear();
174
+    }
175
+
176
+    pub fn has_lzma_data(&self) -> bool {
177
+        self.lzma_data.is_some()
178
+    }
179
+
180
+    // Param is passed by value, moved
181
+    pub fn set_lzma_data(&mut self, v: ::std::vec::Vec<u8>) {
182
+        self.lzma_data = ::protobuf::SingularField::some(v);
183
+    }
184
+
185
+    // Mutable pointer to the field.
186
+    // If field is not initialized, it is initialized with default value first.
187
+    pub fn mut_lzma_data(&mut self) -> &mut ::std::vec::Vec<u8> {
188
+        if self.lzma_data.is_none() {
189
+            self.lzma_data.set_default();
190
+        }
191
+        self.lzma_data.as_mut().unwrap()
192
+    }
193
+
194
+    // Take field
195
+    pub fn take_lzma_data(&mut self) -> ::std::vec::Vec<u8> {
196
+        self.lzma_data.take().unwrap_or_else(|| ::std::vec::Vec::new())
197
+    }
198
+
199
+    pub fn get_lzma_data(&self) -> &[u8] {
200
+        match self.lzma_data.as_ref() {
201
+            Some(v) => &v,
202
+            None => &[],
203
+        }
204
+    }
205
+
206
+    fn get_lzma_data_for_reflect(&self) -> &::protobuf::SingularField<::std::vec::Vec<u8>> {
207
+        &self.lzma_data
208
+    }
209
+
210
+    fn mut_lzma_data_for_reflect(&mut self) -> &mut ::protobuf::SingularField<::std::vec::Vec<u8>> {
211
+        &mut self.lzma_data
212
+    }
213
+
214
+    // optional bytes OBSOLETE_bzip2_data = 5;
215
+
216
+    pub fn clear_OBSOLETE_bzip2_data(&mut self) {
217
+        self.OBSOLETE_bzip2_data.clear();
218
+    }
219
+
220
+    pub fn has_OBSOLETE_bzip2_data(&self) -> bool {
221
+        self.OBSOLETE_bzip2_data.is_some()
222
+    }
223
+
224
+    // Param is passed by value, moved
225
+    pub fn set_OBSOLETE_bzip2_data(&mut self, v: ::std::vec::Vec<u8>) {
226
+        self.OBSOLETE_bzip2_data = ::protobuf::SingularField::some(v);
227
+    }
228
+
229
+    // Mutable pointer to the field.
230
+    // If field is not initialized, it is initialized with default value first.
231
+    pub fn mut_OBSOLETE_bzip2_data(&mut self) -> &mut ::std::vec::Vec<u8> {
232
+        if self.OBSOLETE_bzip2_data.is_none() {
233
+            self.OBSOLETE_bzip2_data.set_default();
234
+        }
235
+        self.OBSOLETE_bzip2_data.as_mut().unwrap()
236
+    }
237
+
238
+    // Take field
239
+    pub fn take_OBSOLETE_bzip2_data(&mut self) -> ::std::vec::Vec<u8> {
240
+        self.OBSOLETE_bzip2_data.take().unwrap_or_else(|| ::std::vec::Vec::new())
241
+    }
242
+
243
+    pub fn get_OBSOLETE_bzip2_data(&self) -> &[u8] {
244
+        match self.OBSOLETE_bzip2_data.as_ref() {
245
+            Some(v) => &v,
246
+            None => &[],
247
+        }
248
+    }
249
+
250
+    fn get_OBSOLETE_bzip2_data_for_reflect(&self) -> &::protobuf::SingularField<::std::vec::Vec<u8>> {
251
+        &self.OBSOLETE_bzip2_data
252
+    }
253
+
254
+    fn mut_OBSOLETE_bzip2_data_for_reflect(&mut self) -> &mut ::protobuf::SingularField<::std::vec::Vec<u8>> {
255
+        &mut self.OBSOLETE_bzip2_data
256
+    }
257
+}
258
+
259
+impl ::protobuf::Message for Blob {
260
+    fn is_initialized(&self) -> bool {
261
+        true
262
+    }
263
+
264
+    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> {
265
+        while !is.eof()? {
266
+            let (field_number, wire_type) = is.read_tag_unpack()?;
267
+            match field_number {
268
+                1 => {
269
+                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.raw)?;
270
+                },
271
+                2 => {
272
+                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
273
+                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
274
+                    }
275
+                    let tmp = is.read_int32()?;
276
+                    self.raw_size = ::std::option::Option::Some(tmp);
277
+                },
278
+                3 => {
279
+                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.zlib_data)?;
280
+                },
281
+                4 => {
282
+                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.lzma_data)?;
283
+                },
284
+                5 => {
285
+                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.OBSOLETE_bzip2_data)?;
286
+                },
287
+                _ => {
288
+                    ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
289
+                },
290
+            };
291
+        }
292
+        ::std::result::Result::Ok(())
293
+    }
294
+
295
+    // Compute sizes of nested messages
296
+    #[allow(unused_variables)]
297
+    fn compute_size(&self) -> u32 {
298
+        let mut my_size = 0;
299
+        if let Some(ref v) = self.raw.as_ref() {
300
+            my_size += ::protobuf::rt::bytes_size(1, &v);
301
+        }
302
+        if let Some(v) = self.raw_size {
303
+            my_size += ::protobuf::rt::value_size(2, v, ::protobuf::wire_format::WireTypeVarint);
304
+        }
305
+        if let Some(ref v) = self.zlib_data.as_ref() {
306
+            my_size += ::protobuf::rt::bytes_size(3, &v);
307
+        }
308
+        if let Some(ref v) = self.lzma_data.as_ref() {
309
+            my_size += ::protobuf::rt::bytes_size(4, &v);
310
+        }
311
+        if let Some(ref v) = self.OBSOLETE_bzip2_data.as_ref() {
312
+            my_size += ::protobuf::rt::bytes_size(5, &v);
313
+        }
314
+        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
315
+        self.cached_size.set(my_size);
316
+        my_size
317
+    }
318
+
319
+    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> {
320
+        if let Some(ref v) = self.raw.as_ref() {
321
+            os.write_bytes(1, &v)?;
322
+        }
323
+        if let Some(v) = self.raw_size {
324
+            os.write_int32(2, v)?;
325
+        }
326
+        if let Some(ref v) = self.zlib_data.as_ref() {
327
+            os.write_bytes(3, &v)?;
328
+        }
329
+        if let Some(ref v) = self.lzma_data.as_ref() {
330
+            os.write_bytes(4, &v)?;
331
+        }
332
+        if let Some(ref v) = self.OBSOLETE_bzip2_data.as_ref() {
333
+            os.write_bytes(5, &v)?;
334
+        }
335
+        os.write_unknown_fields(self.get_unknown_fields())?;
336
+        ::std::result::Result::Ok(())
337
+    }
338
+
339
+    fn get_cached_size(&self) -> u32 {
340
+        self.cached_size.get()
341
+    }
342
+
343
+    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
344
+        &self.unknown_fields
345
+    }
346
+
347
+    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
348
+        &mut self.unknown_fields
349
+    }
350
+
351
+    fn as_any(&self) -> &::std::any::Any {
352
+        self as &::std::any::Any
353
+    }
354
+    fn as_any_mut(&mut self) -> &mut ::std::any::Any {
355
+        self as &mut ::std::any::Any
356
+    }
357
+    fn into_any(self: Box<Self>) -> ::std::boxed::Box<::std::any::Any> {
358
+        self
359
+    }
360
+
361
+    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
362
+        ::protobuf::MessageStatic::descriptor_static(None::<Self>)
363
+    }
364
+}
365
+
366
+impl ::protobuf::MessageStatic for Blob {
367
+    fn new() -> Blob {
368
+        Blob::new()
369
+    }
370
+}
371
+
372
+impl ::protobuf::Clear for Blob {
373
+    fn clear(&mut self) {
374
+        self.clear_raw();
375
+        self.clear_raw_size();
376
+        self.clear_zlib_data();
377
+        self.clear_lzma_data();
378
+        self.clear_OBSOLETE_bzip2_data();
379
+        self.unknown_fields.clear();
380
+    }
381
+}
382
+
383
+impl ::protobuf::reflect::ProtobufValue for Blob {
384
+    fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef {
385
+        ::protobuf::reflect::ProtobufValueRef::Message(self)
386
+    }
387
+}
388
+
389
+#[derive(PartialEq,Clone,Default,Debug)]
390
+pub struct BlobHeader {
391
+    // message fields
392
+    field_type: ::protobuf::SingularField<::std::string::String>,
393
+    indexdata: ::protobuf::SingularField<::std::vec::Vec<u8>>,
394
+    datasize: ::std::option::Option<i32>,
395
+    // special fields
396
+    unknown_fields: ::protobuf::UnknownFields,
397
+    cached_size: ::protobuf::CachedSize,
398
+}
399
+
400
+// see codegen.rs for the explanation why impl Sync explicitly
401
+unsafe impl ::std::marker::Sync for BlobHeader {}
402
+
403
+impl BlobHeader {
404
+    pub fn new() -> BlobHeader {
405
+        ::std::default::Default::default()
406
+    }
407
+
408
+    pub fn default_instance() -> &'static BlobHeader {
409
+        static mut instance: ::protobuf::lazy::Lazy<BlobHeader> = ::protobuf::lazy::Lazy {
410
+            lock: ::protobuf::lazy::ONCE_INIT,
411
+            ptr: 0 as *const BlobHeader,
412
+        };
413
+        unsafe {
414
+            instance.get(BlobHeader::new)
415
+        }
416
+    }
417
+
418
+    // required string type = 1;
419
+
420
+    pub fn clear_field_type(&mut self) {
421
+        self.field_type.clear();
422
+    }
423
+
424
+    pub fn has_field_type(&self) -> bool {
425
+        self.field_type.is_some()
426
+    }
427
+
428
+    // Param is passed by value, moved
429
+    pub fn set_field_type(&mut self, v: ::std::string::String) {
430
+        self.field_type = ::protobuf::SingularField::some(v);
431
+    }
432
+
433
+    // Mutable pointer to the field.
434
+    // If field is not initialized, it is initialized with default value first.
435
+    pub fn mut_field_type(&mut self) -> &mut ::std::string::String {
436
+        if self.field_type.is_none() {
437
+            self.field_type.set_default();
438
+        }
439
+        self.field_type.as_mut().unwrap()
440
+    }
441
+
442
+    // Take field
443
+    pub fn take_field_type(&mut self) -> ::std::string::String {
444
+        self.field_type.take().unwrap_or_else(|| ::std::string::String::new())
445
+    }
446
+
447
+    pub fn get_field_type(&self) -> &str {
448
+        match self.field_type.as_ref() {
449
+            Some(v) => &v,
450
+            None => "",
451
+        }
452
+    }
453
+
454
+    fn get_field_type_for_reflect(&self) -> &::protobuf::SingularField<::std::string::String> {
455
+        &self.field_type
456
+    }
457
+
458
+    fn mut_field_type_for_reflect(&mut self) -> &mut ::protobuf::SingularField<::std::string::String> {
459
+        &mut self.field_type
460
+    }
461
+
462
+    // optional bytes indexdata = 2;
463
+
464
+    pub fn clear_indexdata(&mut self) {
465
+        self.indexdata.clear();
466
+    }
467
+
468
+    pub fn has_indexdata(&self) -> bool {
469
+        self.indexdata.is_some()
470
+    }
471
+
472
+    // Param is passed by value, moved
473
+    pub fn set_indexdata(&mut self, v: ::std::vec::Vec<u8>) {
474
+        self.indexdata = ::protobuf::SingularField::some(v);
475
+    }
476
+
477
+    // Mutable pointer to the field.
478
+    // If field is not initialized, it is initialized with default value first.
479
+    pub fn mut_indexdata(&mut self) -> &mut ::std::vec::Vec<u8> {
480
+        if self.indexdata.is_none() {
481
+            self.indexdata.set_default();
482
+        }
483
+        self.indexdata.as_mut().unwrap()
484
+    }
485
+
486
+    // Take field
487
+    pub fn take_indexdata(&mut self) -> ::std::vec::Vec<u8> {
488
+        self.indexdata.take().unwrap_or_else(|| ::std::vec::Vec::new())
489
+    }
490
+
491
+    pub fn get_indexdata(&self) -> &[u8] {
492
+        match self.indexdata.as_ref() {
493
+            Some(v) => &v,
494
+            None => &[],
495
+        }
496
+    }
497
+
498
+    fn get_indexdata_for_reflect(&self) -> &::protobuf::SingularField<::std::vec::Vec<u8>> {
499
+        &self.indexdata
500
+    }
501
+
502
+    fn mut_indexdata_for_reflect(&mut self) -> &mut ::protobuf::SingularField<::std::vec::Vec<u8>> {
503
+        &mut self.indexdata
504
+    }
505
+
506
+    // required int32 datasize = 3;
507
+
508
+    pub fn clear_datasize(&mut self) {
509
+        self.datasize = ::std::option::Option::None;
510
+    }
511
+
512
+    pub fn has_datasize(&self) -> bool {
513
+        self.datasize.is_some()
514
+    }
515
+
516
+    // Param is passed by value, moved
517
+    pub fn set_datasize(&mut self, v: i32) {
518
+        self.datasize = ::std::option::Option::Some(v);
519
+    }
520
+
521
+    pub fn get_datasize(&self) -> i32 {
522
+        self.datasize.unwrap_or(0)
523
+    }
524
+
525
+    fn get_datasize_for_reflect(&self) -> &::std::option::Option<i32> {
526
+        &self.datasize
527
+    }
528
+
529
+    fn mut_datasize_for_reflect(&mut self) -> &mut ::std::option::Option<i32> {
530
+        &mut self.datasize
531
+    }
532
+}
533
+
534
+impl ::protobuf::Message for BlobHeader {
535
+    fn is_initialized(&self) -> bool {
536
+        if self.field_type.is_none() {
537
+            return false;
538
+        }
539
+        if self.datasize.is_none() {
540
+            return false;
541
+        }
542
+        true
543
+    }
544
+
545
+    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> {
546
+        while !is.eof()? {
547
+            let (field_number, wire_type) = is.read_tag_unpack()?;
548
+            match field_number {
549
+                1 => {
550
+                    ::protobuf::rt::read_singular_string_into(wire_type, is, &mut self.field_type)?;
551
+                },
552
+                2 => {
553
+                    ::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.indexdata)?;
554
+                },
555
+                3 => {
556
+                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
557
+                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
558
+                    }
559
+                    let tmp = is.read_int32()?;
560
+                    self.datasize = ::std::option::Option::Some(tmp);
561
+                },
562
+                _ => {
563
+                    ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
564
+                },
565
+            };
566
+        }
567
+        ::std::result::Result::Ok(())
568
+    }
569
+
570
+    // Compute sizes of nested messages
571
+    #[allow(unused_variables)]
572
+    fn compute_size(&self) -> u32 {
573
+        let mut my_size = 0;
574
+        if let Some(ref v) = self.field_type.as_ref() {
575
+            my_size += ::protobuf::rt::string_size(1, &v);
576
+        }
577
+        if let Some(ref v) = self.indexdata.as_ref() {
578
+            my_size += ::protobuf::rt::bytes_size(2, &v);
579
+        }
580
+        if let Some(v) = self.datasize {
581
+            my_size += ::protobuf::rt::value_size(3, v, ::protobuf::wire_format::WireTypeVarint);
582
+        }
583
+        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
584
+        self.cached_size.set(my_size);
585
+        my_size
586
+    }
587
+
588
+    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> {
589
+        if let Some(ref v) = self.field_type.as_ref() {
590
+            os.write_string(1, &v)?;
591
+        }
592
+        if let Some(ref v) = self.indexdata.as_ref() {
593
+            os.write_bytes(2, &v)?;
594
+        }
595
+        if let Some(v) = self.datasize {
596
+            os.write_int32(3, v)?;
597
+        }
598
+        os.write_unknown_fields(self.get_unknown_fields())?;
599
+        ::std::result::Result::Ok(())
600
+    }
601
+
602
+    fn get_cached_size(&self) -> u32 {
603
+        self.cached_size.get()
604
+    }
605
+
606
+    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
607
+        &self.unknown_fields
608
+    }
609
+
610
+    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
611
+        &mut self.unknown_fields
612
+    }
613
+
614
+    fn as_any(&self) -> &::std::any::Any {
615
+        self as &::std::any::Any
616
+    }
617
+    fn as_any_mut(&mut self) -> &mut ::std::any::Any {
618
+        self as &mut ::std::any::Any
619
+    }
620
+    fn into_any(self: Box<Self>) -> ::std::boxed::Box<::std::any::Any> {
621
+        self
622
+    }
623
+
624
+    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
625
+        ::protobuf::MessageStatic::descriptor_static(None::<Self>)
626
+    }
627
+}
628
+
629
+impl ::protobuf::MessageStatic for BlobHeader {
630
+    fn new() -> BlobHeader {
631
+        BlobHeader::new()
632
+    }
633
+}
634
+
635
+impl ::protobuf::Clear for BlobHeader {
636
+    fn clear(&mut self) {
637
+        self.clear_field_type();
638
+        self.clear_indexdata();
639
+        self.clear_datasize();
640
+        self.unknown_fields.clear();
641
+    }
642
+}
643
+
644
+impl ::protobuf::reflect::ProtobufValue for BlobHeader {
645
+    fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef {
646
+        ::protobuf::reflect::ProtobufValueRef::Message(self)
647
+    }
648
+}

+ 2
- 0
src/proto/mod.rs Datei anzeigen

@@ -0,0 +1,2 @@
1
+pub mod fileformat;
2
+pub mod osmformat;

+ 260
- 0
src/proto/osmformat.proto Datei anzeigen

@@ -0,0 +1,260 @@
1
+/** Copyright (c) 2010 Scott A. Crosby. <scott@sacrosby.com>
2
+
3
+   This program is free software: you can redistribute it and/or modify
4
+   it under the terms of the GNU Lesser General Public License as 
5
+   published by the Free Software Foundation, either version 3 of the 
6
+   License, or (at your option) any later version.
7
+
8
+   This program is distributed in the hope that it will be useful,
9
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
+   GNU Lesser General Public License for more details.
12
+
13
+   You should have received a copy of the GNU Lesser General Public License
14
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
15
+
16
+*/
17
+
18
+option optimize_for = LITE_RUNTIME;
19
+option java_package = "crosby.binary";
20
+package OSMPBF;
21
+
22
+/* OSM Binary file format 
23
+
24
+This is the master schema file of the OSM binary file format. This
25
+file is designed to support limited random-access and future
26
+extendability.
27
+
28
+A binary OSM file consists of a sequence of FileBlocks (please see
29
+fileformat.proto). The first fileblock contains a serialized instance
30
+of HeaderBlock, followed by a sequence of PrimitiveBlock blocks that
31
+contain the primitives.
32
+
33
+Each primitiveblock is designed to be independently parsable. It
34
+contains a string table storing all strings in that block (keys and
35
+values in tags, roles in relations, usernames, etc.) as well as
36
+metadata containing the precision of coordinates or timestamps in that
37
+block.
38
+
39
+A primitiveblock contains a sequence of primitive groups, each
40
+containing primitives of the same type (nodes, densenodes, ways,
41
+relations). Coordinates are stored in signed 64-bit integers. Lat&lon
42
+are measured in units <granularity> nanodegrees. The default of
43
+granularity of 100 nanodegrees corresponds to about 1cm on the ground,
44
+and a full lat or lon fits into 32 bits.
45
+
46
+Converting an integer to a lattitude or longitude uses the formula:
47
+$OUT = IN * granularity / 10**9$. Many encoding schemes use delta
48
+coding when representing nodes and relations.
49
+
50
+*/
51
+
52
+//////////////////////////////////////////////////////////////////////////
53
+//////////////////////////////////////////////////////////////////////////
54
+
55
+/* Contains the file header. */
56
+
57
+message HeaderBlock {
58
+  optional HeaderBBox bbox = 1;
59
+  /* Additional tags to aid in parsing this dataset */
60
+  repeated string required_features = 4;
61
+  repeated string optional_features = 5;
62
+
63
+  optional string writingprogram = 16; 
64
+  optional string source = 17; // From the bbox field.
65
+
66
+  /* Tags that allow continuing an Osmosis replication */
67
+
68
+  // replication timestamp, expressed in seconds since the epoch, 
69
+  // otherwise the same value as in the "timestamp=..." field
70
+  // in the state.txt file used by Osmosis
71
+  optional int64 osmosis_replication_timestamp = 32;
72
+
73
+  // replication sequence number (sequenceNumber in state.txt)
74
+  optional int64 osmosis_replication_sequence_number = 33;
75
+
76
+  // replication base URL (from Osmosis' configuration.txt file)
77
+  optional string osmosis_replication_base_url = 34;
78
+}
79
+
80
+
81
+/** The bounding box field in the OSM header. BBOX, as used in the OSM
82
+header. Units are always in nanodegrees -- they do not obey
83
+granularity rules. */
84
+
85
+message HeaderBBox {
86
+   required sint64 left = 1;
87
+   required sint64 right = 2;
88
+   required sint64 top = 3;
89
+   required sint64 bottom = 4;
90
+}
91
+
92
+
93
+///////////////////////////////////////////////////////////////////////
94
+///////////////////////////////////////////////////////////////////////
95
+
96
+
97
+message PrimitiveBlock {
98
+  required StringTable stringtable = 1;
99
+  repeated PrimitiveGroup primitivegroup = 2;
100
+
101
+  // Granularity, units of nanodegrees, used to store coordinates in this block
102
+  optional int32 granularity = 17 [default=100]; 
103
+  // Offset value between the output coordinates coordinates and the granularity grid in unites of nanodegrees.
104
+  optional int64 lat_offset = 19 [default=0];
105
+  optional int64 lon_offset = 20 [default=0]; 
106
+
107
+// Granularity of dates, normally represented in units of milliseconds since the 1970 epoch.
108
+  optional int32 date_granularity = 18 [default=1000]; 
109
+
110
+
111
+  // Proposed extension:
112
+  //optional BBox bbox = XX;
113
+}
114
+
115
+// Group of OSMPrimitives. All primitives in a group must be the same type.
116
+message PrimitiveGroup {
117
+  repeated Node     nodes = 1;
118
+  optional DenseNodes dense = 2;
119
+  repeated Way      ways = 3;
120
+  repeated Relation relations = 4;
121
+  repeated ChangeSet changesets = 5;
122
+}
123
+
124
+
125
+/** String table, contains the common strings in each block.
126
+
127
+ Note that we reserve index '0' as a delimiter, so the entry at that
128
+ index in the table is ALWAYS blank and unused.
129
+
130
+ */
131
+message StringTable {
132
+   repeated bytes s = 1;
133
+}
134
+
135
+/* Optional metadata that may be included into each primitive. */
136
+message Info {
137
+   optional int32 version = 1 [default = -1];
138
+   optional int64 timestamp = 2;
139
+   optional int64 changeset = 3;
140
+   optional int32 uid = 4;
141
+   optional uint32 user_sid = 5; // String IDs
142
+
143
+   // The visible flag is used to store history information. It indicates that
144
+   // the current object version has been created by a delete operation on the
145
+   // OSM API.
146
+   // When a writer sets this flag, it MUST add a required_features tag with
147
+   // value "HistoricalInformation" to the HeaderBlock.
148
+   // If this flag is not available for some object it MUST be assumed to be
149
+   // true if the file has the required_features tag "HistoricalInformation"
150
+   // set.
151
+   optional bool visible = 6;
152
+}
153
+
154
+/** Optional metadata that may be included into each primitive. Special dense format used in DenseNodes. */
155
+message DenseInfo {
156
+   repeated int32 version = 1 [packed = true]; 
157
+   repeated sint64 timestamp = 2 [packed = true]; // DELTA coded
158
+   repeated sint64 changeset = 3 [packed = true]; // DELTA coded
159
+   repeated sint32 uid = 4 [packed = true]; // DELTA coded
160
+   repeated sint32 user_sid = 5 [packed = true]; // String IDs for usernames. DELTA coded
161
+
162
+   // The visible flag is used to store history information. It indicates that
163
+   // the current object version has been created by a delete operation on the
164
+   // OSM API.
165
+   // When a writer sets this flag, it MUST add a required_features tag with
166
+   // value "HistoricalInformation" to the HeaderBlock.
167
+   // If this flag is not available for some object it MUST be assumed to be
168
+   // true if the file has the required_features tag "HistoricalInformation"
169
+   // set.
170
+   repeated bool visible = 6 [packed = true];
171
+}
172
+
173
+
174
+// THIS IS STUB DESIGN FOR CHANGESETS. NOT USED RIGHT NOW.
175
+// TODO:    REMOVE THIS?
176
+message ChangeSet {
177
+   required int64 id = 1;
178
+//   
179
+//   // Parallel arrays.
180
+//   repeated uint32 keys = 2 [packed = true]; // String IDs.
181
+//   repeated uint32 vals = 3 [packed = true]; // String IDs.
182
+//
183
+//   optional Info info = 4;
184
+
185
+//   optional int64 created_at = 8;
186
+//   optional int64 closetime_delta = 9;
187
+//   optional bool open = 10;
188
+//   optional HeaderBBox bbox = 11;
189
+}
190
+
191
+
192
+message Node {
193
+   required sint64 id = 1;
194
+   // Parallel arrays.
195
+   repeated uint32 keys = 2 [packed = true]; // String IDs.
196
+   repeated uint32 vals = 3 [packed = true]; // String IDs.
197
+
198
+   optional Info info = 4; // May be omitted in omitmeta
199
+
200
+   required sint64 lat = 8;
201
+   required sint64 lon = 9;
202
+}
203
+
204
+/* Used to densly represent a sequence of nodes that do not have any tags.
205
+
206
+We represent these nodes columnwise as five columns: ID's, lats, and
207
+lons, all delta coded. When metadata is not omitted, 
208
+
209
+We encode keys & vals for all nodes as a single array of integers
210
+containing key-stringid and val-stringid, using a stringid of 0 as a
211
+delimiter between nodes.
212
+
213
+   ( (<keyid> <valid>)* '0' )*
214
+ */
215
+
216
+message DenseNodes {
217
+   repeated sint64 id = 1 [packed = true]; // DELTA coded
218
+
219
+   //repeated Info info = 4;
220
+   optional DenseInfo denseinfo = 5;
221
+
222
+   repeated sint64 lat = 8 [packed = true]; // DELTA coded
223
+   repeated sint64 lon = 9 [packed = true]; // DELTA coded
224
+
225
+   // Special packing of keys and vals into one array. May be empty if all nodes in this block are tagless.
226
+   repeated int32 keys_vals = 10 [packed = true]; 
227
+}
228
+
229
+
230
+message Way {
231
+   required int64 id = 1;
232
+   // Parallel arrays.
233
+   repeated uint32 keys = 2 [packed = true];
234
+   repeated uint32 vals = 3 [packed = true];
235
+
236
+   optional Info info = 4;
237
+
238
+   repeated sint64 refs = 8 [packed = true];  // DELTA coded
239
+}
240
+
241
+message Relation {
242
+  enum MemberType {
243
+    NODE = 0;
244
+    WAY = 1;
245
+    RELATION = 2;
246
+  } 
247
+   required int64 id = 1;
248
+
249
+   // Parallel arrays.
250
+   repeated uint32 keys = 2 [packed = true];
251
+   repeated uint32 vals = 3 [packed = true];
252
+
253
+   optional Info info = 4;
254
+
255
+   // Parallel arrays
256
+   repeated int32 roles_sid = 8 [packed = true];
257
+   repeated sint64 memids = 9 [packed = true]; // DELTA encoded
258
+   repeated MemberType types = 10 [packed = true];
259
+}
260
+

+ 4212
- 0
src/proto/osmformat.rs
Datei-Diff unterdrückt, da er zu groß ist
Datei anzeigen


+ 207
- 0
src/reader.rs Datei anzeigen

@@ -0,0 +1,207 @@
1
+//! High level reader interface
2
+
3
+use blob::{BlobDecode, BlobReader};
4
+use dense::DenseNode;
5
+use elements::{Node, Way, Relation};
6
+use errors::*;
7
+use rayon::prelude::*;
8
+use std::fs::File;
9
+use std::io::{BufReader, Read};
10
+use std::path::Path;
11
+
12
+
13
+/// A reader for PBF files that gives access to the stored elements: nodes, ways and relations.
14
+pub struct ElementReader<R: Read> {
15
+    blob_iter: BlobReader<R>,
16
+}
17
+
18
+impl<R: Read> ElementReader<R> {
19
+    /// Creates a new `ElementReader`.
20
+    /// 
21
+    /// # Example
22
+    /// ```
23
+    /// use osmpbf::*;
24
+    /// 
25
+    /// # fn foo() -> Result<()> {
26
+    /// let f = std::fs::File::open("tests/test.osm.pbf")?;
27
+    /// let buf_reader = std::io::BufReader::new(f);
28
+    /// 
29
+    /// let reader = ElementReader::new(buf_reader);
30
+    /// 
31
+    /// # Ok(())
32
+    /// # }
33
+    /// ```
34
+    pub fn new(reader: R) -> ElementReader<R> {
35
+        ElementReader {
36
+            blob_iter: BlobReader::new(reader),
37
+        }
38
+    }
39
+
40
+    /// Decodes the PBF structure sequentially and calls the given closure on each element.
41
+    /// Consider using `par_map_reduce` instead if you need better performance.
42
+    /// 
43
+    /// # Errors
44
+    /// Returns the first Error encountered while parsing the PBF structure.
45
+    /// 
46
+    /// # Example
47
+    /// ```
48
+    /// use osmpbf::*;
49
+    /// 
50
+    /// # fn foo() -> Result<()> {
51
+    /// let reader = ElementReader::from_path("tests/test.osm.pbf")?;
52
+    /// let mut ways = 0_u64;
53
+    ///
54
+    /// // Increment the counter by one for each way.
55
+    /// reader.for_each(|element| {
56
+    ///     if let Element::Way(_) = element {
57
+    ///         ways += 1;
58
+    ///     }
59
+    /// })?;
60
+    /// 
61
+    /// println!("Number of ways: {}", ways);
62
+    /// 
63
+    /// # Ok(())
64
+    /// # }
65
+    /// ```
66
+    pub fn for_each<F>(self, mut f: F) -> Result<()>
67
+        where F: for<'a> FnMut(Element<'a>) {
68
+
69
+        let blobs = self.blob_iter.collect::<Result<Vec<_>>>()?;
70
+
71
+        //TODO do something useful with header blocks
72
+        for blob in &blobs {
73
+            match blob.decode() {
74
+                Ok(BlobDecode::OsmHeader(_)) | Ok(BlobDecode::Unknown(_)) => {},
75
+                Ok(BlobDecode::OsmData(block)) => {
76
+                    for group in block.groups() {
77
+                        group.nodes().for_each(|dnode| f(Element::Node(dnode)));
78
+                        group.dense_nodes().for_each(|node| f(Element::DenseNode(node)));
79
+                        group.ways().for_each(|way| f(Element::Way(way)));
80
+                        group.relations().for_each(|relation| f(Element::Relation(relation)));
81
+                    }
82
+                },
83
+                Err(e) => return Err(e),
84
+            }
85
+        }
86
+
87
+        Ok(())
88
+    }
89
+
90
+    /// Parallel map/reduce. Decodes the PBF structure in parallel, calls the closure `map_op` on
91
+    /// each element and then reduces the number of results to one item with the closure
92
+    /// `reduce_op`. Similarly to the `init` argument in the `fold` method on iterators, the
93
+    /// `identity` closure should produce an identity value that is inserted into `reduce_op` when
94
+    /// necessary. The number of times that this identity value is inserted should not alter the
95
+    /// result.
96
+    /// 
97
+    /// # Errors
98
+    /// Returns the first Error encountered while parsing the PBF structure.
99
+    /// 
100
+    /// # Example
101
+    /// ```
102
+    /// use osmpbf::*;
103
+    /// 
104
+    /// # fn foo() -> Result<()> {
105
+    /// let reader = ElementReader::from_path("tests/test.osm.pbf")?;
106
+    ///
107
+    /// // Count the ways
108
+    /// let ways = reader.par_map_reduce(
109
+    ///     |element| {
110
+    ///         match element {
111
+    ///             Element::Way(_) => 1,
112
+    ///             _ => 0,
113
+    ///         }
114
+    ///     },
115
+    ///     || 0_u64,      // Zero is the identity value for addition
116
+    ///     |a, b| a + b   // Sum the partial results
117
+    /// )?;
118
+    /// 
119
+    /// println!("Number of ways: {}", ways);
120
+    /// # Ok(())
121
+    /// # }
122
+    /// ```
123
+    pub fn par_map_reduce<MP, RD, ID, T>(self, map_op: MP, identity: ID, reduce_op: RD) -> Result<T>
124
+        where MP: for<'a> Fn(Element<'a>) -> T + Sync + Send,
125
+              RD: Fn(T, T) -> T + Sync + Send,
126
+              ID: Fn() -> T + Sync + Send,
127
+              T: Send,
128
+    {
129
+        let blobs = self.blob_iter.collect::<Result<Vec<_>>>()?;
130
+
131
+        blobs.into_par_iter().map(|blob| {
132
+            match blob.decode() {
133
+                Ok(BlobDecode::OsmHeader(_)) | Ok(BlobDecode::Unknown(_)) => {
134
+                    Ok(identity())
135
+                },
136
+                Ok(BlobDecode::OsmData(block)) => {
137
+                    let dnodes = block.groups()
138
+                         .flat_map(|g| g.dense_nodes())
139
+                         .map(|dn| map_op(Element::DenseNode(dn)));
140
+                    let nodes = block.groups()
141
+                         .flat_map(|g| g.nodes())
142
+                         .map(|n| map_op(Element::Node(n)));
143
+                    let ways = block.groups()
144
+                         .flat_map(|g| g.ways())
145
+                         .map(|w| map_op(Element::Way(w)));
146
+                    let rels = block.groups()
147
+                         .flat_map(|g| g.relations())
148
+                         .map(|r| map_op(Element::Relation(r)));
149
+                
150
+                    Ok(dnodes.chain(nodes)
151
+                        .chain(ways)
152
+                        .chain(rels)
153
+                        .fold(identity(), |a, b| reduce_op(a, b)))
154
+                },
155
+                Err(e) => Err(e),
156
+            }
157
+        }).reduce(|| Ok(identity()), |a, b| {
158
+            match (a, b) {
159
+                (Ok(x), Ok(y)) => Ok(reduce_op(x, y)),
160
+                (x, y) => x.and(y),
161
+            }
162
+        })
163
+    }
164
+}
165
+
166
+impl ElementReader<BufReader<File>> {
167
+    /// Tries to open the file at the given path and constructs an `ElementReader` from this.
168
+    /// 
169
+    /// # Errors
170
+    /// Returns the same errors that `std::fs::File::open` returns.
171
+    /// 
172
+    /// # Example
173
+    /// ```
174
+    /// use osmpbf::*;
175
+    /// 
176
+    /// # fn foo() -> Result<()> {
177
+    /// let reader = ElementReader::from_path("tests/test.osm.pbf")?;
178
+    /// # Ok(())
179
+    /// # }
180
+    /// ```
181
+    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Self>
182
+    {
183
+        let f = File::open(path)?;
184
+        let reader = BufReader::new(f);
185
+
186
+        Ok(ElementReader {
187
+            blob_iter: BlobReader::new(reader),
188
+        })
189
+    }
190
+}
191
+
192
+/// An enum with the OSM core elements: nodes, ways and relations.
193
+pub enum Element<'a> {
194
+    /// A node. Also, see `DenseNode`.
195
+    Node(Node<'a>),
196
+
197
+    /// Just like `Node`, but with a different representation in memory. This distinction is
198
+    /// usually not important but is not abstracted away to avoid copying. So, if you want to match
199
+    /// `Node`, you also likely want to match `DenseNode`.
200
+    DenseNode(DenseNode<'a>),
201
+
202
+    /// A way.
203
+    Way(Way<'a>),
204
+
205
+    /// A relation.
206
+    Relation(Relation<'a>),
207
+}

+ 64
- 0
tests/read.rs Datei anzeigen

@@ -0,0 +1,64 @@
1
+extern crate osmpbf;
2
+
3
+use osmpbf::*;
4
+
5
+static TEST_FILE_PATH: &str = "tests/test.osm.pbf";
6
+
7
+fn approx_eq(a: f64, b: f64) -> bool {
8
+    (a - b).abs() < 1.0e-6
9
+}
10
+
11
+#[test]
12
+fn read() {
13
+    let reader = BlobReader::from_path(TEST_FILE_PATH).unwrap();
14
+
15
+    let blobs = reader.collect::<Result<Vec<_>>>().unwrap();
16
+
17
+    assert_eq!(blobs.len(), 2);
18
+
19
+    assert_eq!(blobs[0].get_type(), BlobType::OsmHeader);
20
+    assert_eq!(blobs[1].get_type(), BlobType::OsmData);
21
+
22
+    {
23
+        let header = blobs[0].to_headerblock().unwrap();
24
+        assert!(header.required_features().contains(&String::from("OsmSchema-V0.6")));
25
+        assert!(header.required_features().contains(&String::from("DenseNodes")));
26
+    }
27
+
28
+    {
29
+        let primitive_block = blobs[1].to_primitiveblock().unwrap();
30
+
31
+        let nodes = primitive_block.groups().flat_map(|g| g.nodes()).count();
32
+        assert_eq!(nodes, 0);
33
+
34
+        {
35
+            let dense_nodes: Vec<_> = primitive_block.groups().flat_map(|g| g.dense_nodes()).collect();
36
+            assert_eq!(dense_nodes.len(), 3);
37
+
38
+            assert!(approx_eq(dense_nodes[1].lat(), 52.11992359584));
39
+            assert!(approx_eq(dense_nodes[1].lon(), 11.62564468943));
40
+
41
+            assert!(approx_eq(dense_nodes[2].lat(), 52.11989910567));
42
+            assert!(approx_eq(dense_nodes[2].lon(), 11.63101926915));
43
+
44
+            assert_eq!(dense_nodes[0].id, 105);
45
+            assert_eq!(dense_nodes[1].id, 106);
46
+            assert_eq!(dense_nodes[2].id, 108);
47
+
48
+            assert_eq!(dense_nodes[0].uid, 17);
49
+            assert_eq!(dense_nodes[1].uid, 17);
50
+            assert_eq!(dense_nodes[2].uid, 17);
51
+        }
52
+
53
+        {
54
+            let ways: Vec<_> = primitive_block.groups().flat_map(|g| g.ways()).collect();
55
+            assert_eq!(ways.len(), 1);
56
+
57
+            let way_tags = ways[0].tags().collect::<Vec<_>>();
58
+            assert_eq!(way_tags.len(), 2);
59
+
60
+            assert!(way_tags.contains(&("building", "yes")));
61
+            assert!(way_tags.contains(&("name", "triangle")));
62
+        }
63
+    }
64
+}

+ 18
- 0
tests/test.osm Datei anzeigen

@@ -0,0 +1,18 @@
1
+<?xml version='1.0' encoding='UTF-8'?>
2
+<osm version='0.6' generator='JOSM'>
3
+  <node timestamp='2003-04-05T06:07:08Z' id='105' lat='52.12240315616' lon='11.62840177902' version='1' user='testuser' uid='17' visible='true' />
4
+  <node timestamp='2003-04-05T06:07:09Z' id='106' lat='52.11992359584' lon='11.62564468943' version='1' user='testuser' uid='17' visible='true' />
5
+  <node timestamp='2003-04-05T06:07:10Z' id='108' lat='52.11989910567' lon='11.63101926915' version='1' user='testuser' uid='17' visible='true' />
6
+  <way timestamp='2003-04-05T06:07:11Z' id='107' version='1' user='testuser' uid='17' visible='true'>
7
+    <nd ref='105' />
8
+    <nd ref='106' />
9
+    <nd ref='108' />
10
+    <nd ref='105' />
11
+    <tag k='building' v='yes' />
12
+    <tag k='name' v='triangle' />
13
+  </way>
14
+  <relation timestamp='2003-04-05T06:07:12Z' id='120' version='1' user='testuser' uid='17' visible='true'>
15
+    <member type='way' ref='107' role='test_role' />
16
+    <tag k='rel_key' v='rel_value' />
17
+  </relation>
18
+</osm>

BIN
tests/test.osm.pbf Datei anzeigen