| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * Copyright (c) 2000-2022 Inria | ||
| 3 | * All rights reserved. | ||
| 4 | * | ||
| 5 | * Redistribution and use in source and binary forms, with or without | ||
| 6 | * modification, are permitted provided that the following conditions are met: | ||
| 7 | * | ||
| 8 | * * Redistributions of source code must retain the above copyright notice, | ||
| 9 | * this list of conditions and the following disclaimer. | ||
| 10 | * * Redistributions in binary form must reproduce the above copyright notice, | ||
| 11 | * this list of conditions and the following disclaimer in the documentation | ||
| 12 | * and/or other materials provided with the distribution. | ||
| 13 | * * Neither the name of the ALICE Project-Team nor the names of its | ||
| 14 | * contributors may be used to endorse or promote products derived from this | ||
| 15 | * software without specific prior written permission. | ||
| 16 | * | ||
| 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
| 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
| 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
| 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | ||
| 21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
| 22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
| 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
| 24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
| 25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
| 26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
| 27 | * POSSIBILITY OF SUCH DAMAGE. | ||
| 28 | * | ||
| 29 | * Contact: Bruno Levy | ||
| 30 | * | ||
| 31 | * https://www.inria.fr/fr/bruno-levy | ||
| 32 | * | ||
| 33 | * Inria, | ||
| 34 | * Domaine de Voluceau, | ||
| 35 | * 78150 Le Chesnay - Rocquencourt | ||
| 36 | * FRANCE | ||
| 37 | * | ||
| 38 | */ | ||
| 39 | |||
| 40 | /* | ||
| 41 | * | ||
| 42 | * b_stream.cpp | ||
| 43 | * | ||
| 44 | */ | ||
| 45 | |||
| 46 | #include <geogram/basic/b_stream.h> | ||
| 47 | #include <geogram/basic/assert.h> | ||
| 48 | #include <geogram/basic/logger.h> | ||
| 49 | |||
| 50 | #include <iostream> | ||
| 51 | #include <stdlib.h> | ||
| 52 | |||
| 53 | namespace GEO { | ||
| 54 | |||
| 55 | 25 | BinaryStream::BinaryStream(int stream_endian) { | |
| 56 | 25 | has_record_markers_ = true; | |
| 57 | 25 | detect_machine_endian(); | |
| 58 | 25 | set_stream_endian(stream_endian); | |
| 59 | 25 | } | |
| 60 | |||
| 61 | 25 | void BinaryStream::detect_machine_endian() { | |
| 62 | |||
| 63 | 25 | Numeric::int32 data = 0x04030201; | |
| 64 | 25 | Numeric::uint8* pointer = (Numeric::uint8*) &data; | |
| 65 | |||
| 66 | 25 | if( | |
| 67 |
1/2✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
|
25 | pointer[0] == 1 && |
| 68 |
1/2✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
|
25 | pointer[1] == 2 && |
| 69 |
1/2✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
|
25 | pointer[2] == 3 && |
| 70 |
1/2✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
|
25 | pointer[3] == 4 |
| 71 | ) { | ||
| 72 | 25 | machine_endian_ = GEO_LITTLE_ENDIAN; | |
| 73 | ✗ | } else if( | |
| 74 | ✗ | pointer[0] == 4 && | |
| 75 | ✗ | pointer[1] == 3 && | |
| 76 | ✗ | pointer[2] == 2 && | |
| 77 | ✗ | pointer[3] == 1) { | |
| 78 | ✗ | machine_endian_ = GEO_BIG_ENDIAN; | |
| 79 | } else { | ||
| 80 | ✗ | Logger::err("BinaryStream") | |
| 81 | ✗ | << "invalid processor type" << std::endl; | |
| 82 | // Should not occur, nowadays machines are either little or | ||
| 83 | // big endian. | ||
| 84 | ✗ | ::abort(); | |
| 85 | } | ||
| 86 | 25 | } | |
| 87 | |||
| 88 | 25 | void BinaryStream::set_stream_endian(int stream_endian) { | |
| 89 | 25 | stream_endian_ = stream_endian; | |
| 90 | 25 | swapped_ = stream_endian_ != machine_endian_; | |
| 91 | 25 | } | |
| 92 | |||
| 93 | /************************************************************************/ | ||
| 94 | |||
| 95 | 25 | BinaryInputStream::BinaryInputStream( | |
| 96 | const std::string& file_name, int stream_endian_in | ||
| 97 | 25 | ) : | |
| 98 | 25 | BinaryStream(stream_endian_in) { | |
| 99 | 25 | record_OK_ = true; | |
| 100 | 25 | record_count_ = 0; | |
| 101 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
25 | input_ = new std::ifstream( |
| 102 | file_name.c_str(), | ||
| 103 | std::fstream::in | std::fstream::binary | ||
| 104 |
1/2✓ Branch 4 taken 25 times.
✗ Branch 5 not taken.
|
25 | ); |
| 105 | 25 | owns_input_ = true; | |
| 106 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
|
25 | if(!input_) { |
| 107 | ✗ | delete input_; | |
| 108 | ✗ | input_ = nullptr; | |
| 109 | } | ||
| 110 | 25 | } | |
| 111 | |||
| 112 | ✗ | BinaryInputStream::BinaryInputStream( | |
| 113 | std::istream& input, int stream_endian_in | ||
| 114 | ✗ | ) : | |
| 115 | ✗ | BinaryStream(stream_endian_in) { | |
| 116 | ✗ | record_OK_ = true; | |
| 117 | ✗ | record_count_ = 0; | |
| 118 | ✗ | input_ = &input; | |
| 119 | ✗ | owns_input_ = false; | |
| 120 | ✗ | } | |
| 121 | |||
| 122 | 18552 | bool BinaryInputStream::OK() const { | |
| 123 |
3/6✓ Branch 0 taken 18552 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18552 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 18552 times.
✗ Branch 6 not taken.
|
18552 | return record_OK_ && input_ != nullptr && input_->good(); |
| 124 | } | ||
| 125 | |||
| 126 | ✗ | bool BinaryInputStream::more() const { | |
| 127 | ✗ | return !input_->eof(); | |
| 128 | } | ||
| 129 | |||
| 130 | ✗ | void BinaryInputStream::begin_record() { | |
| 131 | ✗ | if(input_->eof()) { | |
| 132 | ✗ | record_OK_ = false; | |
| 133 | } else { | ||
| 134 | ✗ | if(has_record_markers()) { | |
| 135 | ✗ | (*this) >> count1_; | |
| 136 | } | ||
| 137 | } | ||
| 138 | ✗ | } | |
| 139 | |||
| 140 | ✗ | void BinaryInputStream::end_record() { | |
| 141 | ✗ | record_count_++; | |
| 142 | ✗ | if(input_->eof()) { | |
| 143 | ✗ | record_OK_ = false; | |
| 144 | } else { | ||
| 145 | ✗ | if(has_record_markers()) { | |
| 146 | ✗ | (*this) >> count2_; | |
| 147 | ✗ | if(count1_ != count2_) { | |
| 148 | ✗ | record_OK_ = false; | |
| 149 | ✗ | Logger::err("BinaryStream") | |
| 150 | ✗ | << "Invalid record length in record #" | |
| 151 | ✗ | << record_count_ << std::endl; | |
| 152 | ✗ | Logger::err("BinaryStream") | |
| 153 | ✗ | << " count1=" << count1_ | |
| 154 | ✗ | << " count2=" << count2_ << std::endl; | |
| 155 | } | ||
| 156 | } | ||
| 157 | } | ||
| 158 | ✗ | } | |
| 159 | |||
| 160 | 25 | BinaryInputStream::~BinaryInputStream() { | |
| 161 |
2/4✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
|
25 | if(input_ != nullptr && owns_input_) { |
| 162 |
1/2✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
|
25 | delete input_; |
| 163 | } | ||
| 164 | 25 | input_ = nullptr; | |
| 165 | 25 | } | |
| 166 | |||
| 167 | 18502 | BinaryInputStream& BinaryInputStream::read( | |
| 168 | char* data, size_t n, ItemSize<2> | ||
| 169 | ) { | ||
| 170 | 18502 | const size_t size = 2; | |
| 171 |
1/2✓ Branch 0 taken 18502 times.
✗ Branch 1 not taken.
|
18502 | if(!swapped_) { |
| 172 | 18502 | input_->read(data, (std::streamsize) (size * n)); | |
| 173 | } else { | ||
| 174 | char buffer[size]; | ||
| 175 | ✗ | for(; n != 0; --n) { | |
| 176 | ✗ | input_->read(buffer, size); | |
| 177 | ✗ | data[0] = buffer[1]; | |
| 178 | ✗ | data[1] = buffer[0]; | |
| 179 | ✗ | data += size; | |
| 180 | } | ||
| 181 | } | ||
| 182 | 18502 | return *this; | |
| 183 | } | ||
| 184 | |||
| 185 | 222049 | BinaryInputStream& BinaryInputStream::read( | |
| 186 | char* data, size_t n, ItemSize<4> | ||
| 187 | ) { | ||
| 188 | 222049 | const size_t size = 4; | |
| 189 |
1/2✓ Branch 0 taken 222049 times.
✗ Branch 1 not taken.
|
222049 | if(!swapped_) { |
| 190 | 222049 | input_->read(data, (std::streamsize) (size * n)); | |
| 191 | } else { | ||
| 192 | char buffer[size]; | ||
| 193 | ✗ | for(; n != 0; --n) { | |
| 194 | ✗ | input_->read(buffer, size); | |
| 195 | ✗ | data[0] = buffer[3]; | |
| 196 | ✗ | data[1] = buffer[2]; | |
| 197 | ✗ | data[2] = buffer[1]; | |
| 198 | ✗ | data[3] = buffer[0]; | |
| 199 | ✗ | data += size; | |
| 200 | } | ||
| 201 | } | ||
| 202 | 222049 | return *this; | |
| 203 | } | ||
| 204 | |||
| 205 | ✗ | BinaryInputStream& BinaryInputStream::read( | |
| 206 | char* data, size_t n, ItemSize<8> | ||
| 207 | ) { | ||
| 208 | ✗ | const size_t size = 8; | |
| 209 | ✗ | if(!swapped_) { | |
| 210 | ✗ | input_->read(data, (std::streamsize) (size * n)); | |
| 211 | } else { | ||
| 212 | char buffer[size]; | ||
| 213 | ✗ | for(; n != 0; --n) { | |
| 214 | ✗ | input_->read(buffer, size); | |
| 215 | ✗ | data[0] = buffer[7]; | |
| 216 | ✗ | data[1] = buffer[6]; | |
| 217 | ✗ | data[2] = buffer[5]; | |
| 218 | ✗ | data[3] = buffer[4]; | |
| 219 | ✗ | data[4] = buffer[3]; | |
| 220 | ✗ | data[5] = buffer[2]; | |
| 221 | ✗ | data[6] = buffer[1]; | |
| 222 | ✗ | data[7] = buffer[0]; | |
| 223 | ✗ | data += size; | |
| 224 | } | ||
| 225 | } | ||
| 226 | ✗ | return *this; | |
| 227 | } | ||
| 228 | |||
| 229 | /************************************************************************/ | ||
| 230 | |||
| 231 | ✗ | BinaryOutputStream::BinaryOutputStream( | |
| 232 | const std::string& file_name, int stream_endian_in | ||
| 233 | ✗ | ) : | |
| 234 | ✗ | BinaryStream(stream_endian_in) { | |
| 235 | ✗ | output_ = new std::ofstream( | |
| 236 | file_name.c_str(), | ||
| 237 | std::fstream::out | std::fstream::trunc | std::fstream::binary | ||
| 238 | ✗ | ); | |
| 239 | ✗ | if(!output_) { | |
| 240 | ✗ | delete output_; | |
| 241 | ✗ | output_ = nullptr; | |
| 242 | } | ||
| 243 | ✗ | owns_output_ = true; | |
| 244 | ✗ | } | |
| 245 | |||
| 246 | ✗ | BinaryOutputStream::BinaryOutputStream( | |
| 247 | std::ostream& output, int stream_endian_in | ||
| 248 | ✗ | ) : | |
| 249 | ✗ | BinaryStream(stream_endian_in) { | |
| 250 | ✗ | output_ = &output; | |
| 251 | ✗ | owns_output_ = false; | |
| 252 | ✗ | } | |
| 253 | |||
| 254 | ✗ | bool BinaryOutputStream::OK() const { | |
| 255 | ✗ | return output_ != nullptr && output_->good(); | |
| 256 | } | ||
| 257 | |||
| 258 | ✗ | void BinaryOutputStream::begin_record() { | |
| 259 | ✗ | if(has_record_markers()) { | |
| 260 | ✗ | count_ = 0; | |
| 261 | ✗ | pos_ = output_->tellp(); | |
| 262 | ✗ | write_marker(Numeric::uint32(count_)); | |
| 263 | } | ||
| 264 | ✗ | } | |
| 265 | |||
| 266 | ✗ | void BinaryOutputStream::end_record() { | |
| 267 | ✗ | if(has_record_markers()) { | |
| 268 | ✗ | write_marker(Numeric::uint32(count_)); | |
| 269 | ✗ | std::streamoff pos = output_->tellp(); | |
| 270 | ✗ | output_->seekp(pos_); | |
| 271 | ✗ | write_marker(Numeric::uint32(count_)); | |
| 272 | ✗ | output_->seekp(pos); | |
| 273 | } | ||
| 274 | ✗ | } | |
| 275 | |||
| 276 | ✗ | BinaryOutputStream::~BinaryOutputStream() { | |
| 277 | ✗ | if(output_ != nullptr && owns_output_) { | |
| 278 | ✗ | delete output_; | |
| 279 | } | ||
| 280 | ✗ | output_ = nullptr; | |
| 281 | ✗ | } | |
| 282 | |||
| 283 | ✗ | void BinaryOutputStream::write_marker(Numeric::uint32 x) { | |
| 284 | ✗ | geo_assert(output_ != nullptr); | |
| 285 | ✗ | BinaryOutputStream::operator<< (x); | |
| 286 | |||
| 287 | // Warning: operator<<() increments count_! | ||
| 288 | ✗ | count_ -= sizeof(x); | |
| 289 | ✗ | } | |
| 290 | |||
| 291 | ✗ | BinaryOutputStream& BinaryOutputStream::write( | |
| 292 | const char* data, size_t n, ItemSize<2> | ||
| 293 | ) { | ||
| 294 | ✗ | const size_t size = 2; | |
| 295 | ✗ | if(!swapped_) { | |
| 296 | ✗ | output_->write(data, (std::streamsize) (size * n)); | |
| 297 | } else { | ||
| 298 | char buffer[size]; | ||
| 299 | ✗ | for(; n != 0; --n) { | |
| 300 | ✗ | buffer[0] = data[1]; | |
| 301 | ✗ | buffer[1] = data[0]; | |
| 302 | ✗ | output_->write(buffer, size); | |
| 303 | ✗ | data += size; | |
| 304 | } | ||
| 305 | } | ||
| 306 | ✗ | count_ += size * n; | |
| 307 | ✗ | return *this; | |
| 308 | } | ||
| 309 | |||
| 310 | ✗ | BinaryOutputStream& BinaryOutputStream::write( | |
| 311 | const char* data, size_t n, ItemSize<4> | ||
| 312 | ) { | ||
| 313 | ✗ | const size_t size = 4; | |
| 314 | ✗ | if(!swapped_) { | |
| 315 | ✗ | output_->write(data, (std::streamsize) (size * n)); | |
| 316 | } else { | ||
| 317 | char buffer[size]; | ||
| 318 | ✗ | for(; n != 0; --n) { | |
| 319 | ✗ | buffer[0] = data[3]; | |
| 320 | ✗ | buffer[1] = data[2]; | |
| 321 | ✗ | buffer[2] = data[1]; | |
| 322 | ✗ | buffer[3] = data[0]; | |
| 323 | ✗ | output_->write(buffer, size); | |
| 324 | ✗ | data += size; | |
| 325 | } | ||
| 326 | } | ||
| 327 | ✗ | count_ += size * n; | |
| 328 | ✗ | return *this; | |
| 329 | } | ||
| 330 | |||
| 331 | ✗ | BinaryOutputStream& BinaryOutputStream::write( | |
| 332 | const char* data, size_t n, ItemSize<8> | ||
| 333 | ) { | ||
| 334 | ✗ | const size_t size = 8; | |
| 335 | ✗ | if(!swapped_) { | |
| 336 | ✗ | output_->write(data, (std::streamsize) (size * n)); | |
| 337 | } else { | ||
| 338 | char buffer[size]; | ||
| 339 | ✗ | for(; n != 0; --n) { | |
| 340 | ✗ | buffer[0] = data[7]; | |
| 341 | ✗ | buffer[1] = data[6]; | |
| 342 | ✗ | buffer[2] = data[5]; | |
| 343 | ✗ | buffer[3] = data[4]; | |
| 344 | ✗ | buffer[4] = data[3]; | |
| 345 | ✗ | buffer[5] = data[2]; | |
| 346 | ✗ | buffer[6] = data[1]; | |
| 347 | ✗ | buffer[7] = data[0]; | |
| 348 | ✗ | output_->write(buffer, size); | |
| 349 | ✗ | data += size; | |
| 350 | } | ||
| 351 | } | ||
| 352 | ✗ | count_ += size * n; | |
| 353 | ✗ | return *this; | |
| 354 | } | ||
| 355 | } | ||
| 356 |