@@ -37,6 +37,7 @@ DEALINGS IN THE SOFTWARE.
3737#include < osmium/io/detail/pbf.hpp> // IWYU pragma: export
3838#include < osmium/io/detail/pbf_decoder.hpp>
3939#include < osmium/io/detail/protobuf_tags.hpp>
40+ #include < osmium/io/detail/read_write.hpp>
4041#include < osmium/io/file_format.hpp>
4142#include < osmium/io/header.hpp>
4243#include < osmium/osm/entity_bits.hpp>
@@ -65,6 +66,7 @@ namespace osmium {
6566 class PBFParser final : public Parser {
6667
6768 std::string m_input_buffer{};
69+ int m_fd;
6870
6971 /* *
7072 * Make sure the input data contains at least the specified
@@ -73,6 +75,7 @@ namespace osmium {
7375 * @param size Number of bytes to read
7476 */
7577 void ensure_available_in_input_queue (size_t size) {
78+ assert (m_fd == -1 );
7679 if (m_input_buffer.size () < size) {
7780 m_input_buffer.reserve (size);
7881 }
@@ -91,40 +94,62 @@ namespace osmium {
9194 * @param size Number of bytes to remove
9295 */
9396 void pop_from_input_queue (size_t size) {
97+ assert (m_fd == -1 );
9498 m_input_buffer.erase (0 , size);
9599 }
96100
101+ static uint32_t get_size_in_network_byte_order (const char * d) noexcept {
102+ return (static_cast <uint32_t >(d[3 ])) |
103+ (static_cast <uint32_t >(d[2 ]) << 8U ) |
104+ (static_cast <uint32_t >(d[1 ]) << 16U ) |
105+ (static_cast <uint32_t >(d[0 ]) << 24U );
106+ }
107+
108+ static uint32_t check_size (uint32_t size) {
109+ if (size > static_cast <uint32_t >(max_blob_header_size)) {
110+ throw osmium::pbf_error{" invalid BlobHeader size (> max_blob_header_size)" };
111+ }
112+ return size;
113+ }
114+
97115 /* *
98- * Read the given number of bytes from the input queue .
116+ * Read exactly size bytes from fd into buffer .
99117 *
100- * @param size Number of bytes to read
101- * @returns String with the data
102- * @throws osmium::pbf_error If size bytes can't be read
118+ * @returns true if size bytes could be read
119+ * false if EOF was encountered
103120 */
104- std::string read_from_input_queue ( size_t size) {
105- ensure_available_in_input_queue ( size) ;
121+ static bool read_exactly ( int fd, char * buffer, std::size_t size) {
122+ std:: size_t to_read = size;
106123
107- std::string output (m_input_buffer, 0 , size);
108- pop_from_input_queue (size);
124+ while (to_read > 0 ) {
125+ auto const read_size = osmium::io::detail::reliable_read (fd, buffer + (size - to_read), to_read);
126+ if (read_size == 0 ) { // EOF
127+ return false ;
128+ }
129+ to_read -= read_size;
130+ }
109131
110- return output ;
132+ return true ;
111133 }
112134
113135 /* *
114136 * Read 4 bytes in network byte order from file. They contain
115137 * the length of the following BlobHeader.
116138 */
117139 uint32_t read_blob_header_size_from_file () {
140+ if (m_fd != -1 ) {
141+ std::array<char , sizeof (uint32_t )> buffer;
142+ if (!read_exactly (m_fd, buffer.data (), buffer.size ())) {
143+ return 0 ; // EOF
144+ }
145+ return check_size (get_size_in_network_byte_order (buffer.data ()));
146+ }
147+
118148 uint32_t size = 0 ;
119149
120150 try {
121- // size is encoded in network byte order
122151 ensure_available_in_input_queue (sizeof (size));
123- const char * d = m_input_buffer.data ();
124- size = (static_cast <uint32_t >(d[3 ])) |
125- (static_cast <uint32_t >(d[2 ]) << 8U ) |
126- (static_cast <uint32_t >(d[1 ]) << 16U ) |
127- (static_cast <uint32_t >(d[0 ]) << 24U );
152+ size = get_size_in_network_byte_order (m_input_buffer.data ());
128153 pop_from_input_queue (sizeof (size));
129154 } catch (const osmium::pbf_error&) {
130155 return 0 ; // EOF
@@ -178,10 +203,15 @@ namespace osmium {
178203 return 0 ;
179204 }
180205
206+ if (m_fd != -1 ) {
207+ auto const buffer = read_from_input_queue_with_check (size);
208+ const auto blob_size = decode_blob_header (protozero::data_view{buffer.data (), size}, expected_type);
209+ return blob_size;
210+ }
211+
181212 ensure_available_in_input_queue (size);
182213 const auto blob_size = decode_blob_header (protozero::data_view{m_input_buffer.data (), size}, expected_type);
183214 pop_from_input_queue (size);
184-
185215 return blob_size;
186216 }
187217
@@ -190,7 +220,21 @@ namespace osmium {
190220 throw osmium::pbf_error{std::string{" invalid blob size: " } +
191221 std::to_string (size)};
192222 }
193- return read_from_input_queue (size);
223+
224+ std::string buffer;
225+ if (m_fd != -1 ) {
226+ buffer.resize (size);
227+
228+ if (!read_exactly (m_fd, &*buffer.begin (), size)) {
229+ throw osmium::pbf_error{" unexpected EOF" };
230+ }
231+ } else {
232+ ensure_available_in_input_queue (size);
233+ buffer.append (m_input_buffer, 0 , size);
234+ pop_from_input_queue (size);
235+ }
236+
237+ return buffer;
194238 }
195239
196240 // Parse the header in the PBF OSMHeader blob.
@@ -218,7 +262,8 @@ namespace osmium {
218262 public:
219263
220264 explicit PBFParser (parser_arguments& args) :
221- Parser(args) {
265+ Parser(args),
266+ m_fd(args.fd) {
222267 }
223268
224269 PBFParser (const PBFParser&) = delete ;
@@ -237,6 +282,8 @@ namespace osmium {
237282 if (read_types () != osmium::osm_entity_bits::nothing) {
238283 parse_data_blobs ();
239284 }
285+
286+ osmium::io::detail::reliable_close (m_fd);
240287 }
241288
242289 }; // class PBFParser
0 commit comments