1 /* 2 * Copyright (C) 2012 Alberto Irurueta Carro (alberto@irurueta.com) 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.irurueta.geometry.io; 17 18 import java.io.File; 19 import java.io.IOException; 20 import java.io.RandomAccessFile; 21 import java.nio.channels.FileChannel; 22 23 /** 24 * This class provides methods to access file data at random positions. 25 */ 26 @SuppressWarnings("DuplicatedCode") 27 public class FileReaderAndWriter extends AbstractFileReaderAndWriter { 28 29 /** 30 * Underlying input file. 31 */ 32 private final RandomAccessFile randomAccessFile; 33 34 /** 35 * Constructor. 36 * 37 * @param f file to read from or write to. 38 * @param mode file opening mode (read only or read write). 39 * @throws IOException if an I/O error occurs. 40 */ 41 public FileReaderAndWriter(final File f, final FileChannel.MapMode mode) throws IOException { 42 if (mode == FileChannel.MapMode.READ_ONLY) { 43 this.randomAccessFile = new RandomAccessFile(f, "r"); 44 } else { 45 this.randomAccessFile = new RandomAccessFile(f, "rw"); 46 } 47 } 48 49 /** 50 * Reads one byte at current file position and advances one position. 51 * 52 * @return Next byte of data or -1 if end of file is reached. 53 * @throws IOException if an I/O error occurs. Not thrown if end-of-file has 54 * been reached. 55 */ 56 @Override 57 public int read() throws IOException { 58 return randomAccessFile.read(); 59 } 60 61 /** 62 * Reads up to b.length bytes of data from this file into an array of bytes. 63 * This method blocks until at least one byte of input is available. 64 * 65 * @param b The buffer into which the data is read. 66 * @return The total number of bytes read into the buffer, or -1 if there is 67 * no more data because the end of the file has been reached. 68 * @throws IOException If the first byte cannot be read for any reason other 69 * than end of file, or if the file has been closed, or if some other I/O 70 * error occurs. 71 */ 72 @Override 73 public int read(final byte[] b) throws IOException { 74 return randomAccessFile.read(b); 75 } 76 77 /** 78 * Reads up to len bytes of data from this file into an array of bytes. This 79 * method blocks until at least one byte of input is available. 80 * This method behaves in exactly the same way as the 81 * InputStream.read(byte[], int, int) method of InputStream. 82 * 83 * @param b the buffer into which the data is read. 84 * @param off the start offset in array b at which the data is written. 85 * @param len the maximum number of bytes read. 86 * @return the total number of bytes read into the buffer, or -1 if there is 87 * no more data because the end of the file has been reached. 88 * @throws IOException If the first byte cannot be read for any reason other 89 * than end of file, or if the random access file has been closed, or if 90 * some other I/O error occurs. 91 */ 92 @Override 93 public int read(final byte[] b, final int off, final int len) throws IOException { 94 return randomAccessFile.read(b, off, len); 95 } 96 97 /** 98 * Reads b.length bytes from this file into the byte array, starting at the 99 * current file pointer. This method reads repeatedly from the file until 100 * the requested number of bytes are read. This method blocks until the 101 * requested number of bytes are read, the end of the stream is detected, or 102 * an exception is thrown. 103 * 104 * @param b the buffer into which the data is read. 105 * @throws IOException if this file reaches the end before reading all the 106 * bytes. 107 */ 108 public void readFully(final byte[] b) throws IOException { 109 randomAccessFile.readFully(b); 110 } 111 112 /** 113 * Reads exactly len bytes from this file into the byte array, starting at 114 * the current file pointer. This method reads repeatedly from the file 115 * until the requested number of bytes are read. This method blocks until 116 * the requested number of bytes are read, the end of the stream is 117 * detected, or an exception is thrown. 118 * 119 * @param b the buffer into which the data is read. 120 * @param off the start offset of the data. 121 * @param len the number of byte to read. 122 * @throws IOException if this file reaches the end before reading all the 123 * bytes or if an I/O error occurs. 124 */ 125 public void readFully(final byte[] b, final int off, final int len) throws IOException { 126 randomAccessFile.readFully(b, off, len); 127 } 128 129 /** 130 * Attempts to skip over n byte of input discarding the skipped bytes. 131 * <p> 132 * This method may skip over some number of bytes, possibly zero. This may 133 * result from any of a number of conditions; reaching end of file before n 134 * bytes have been skipped is only one possibility. The actual number of 135 * bytes skipped is returned. If n is negative, no bytes are skipped. 136 * 137 * @param n the number of bytes to be skipped. 138 * @return the actual number of bytes skipped. 139 * @throws IOException if an I/O error occurs. 140 */ 141 @Override 142 public long skip(final long n) throws IOException { 143 return randomAccessFile.skipBytes((int) n); 144 } 145 146 /** 147 * Writes the specified byte to this file. The write starts at the current 148 * file pointer. 149 * 150 * @param b the byte to be written. 151 * @throws IOException if an I/O error occurs. 152 */ 153 @Override 154 public void write(final int b) throws IOException { 155 randomAccessFile.write(b); 156 } 157 158 /** 159 * Writes b.length bytes from the specified byte array to this file, 160 * starting at the current file pointer. 161 * 162 * @param b the data. 163 * @throws IOException if an I/O error occurs. 164 */ 165 @Override 166 public void write(final byte[] b) throws IOException { 167 randomAccessFile.write(b); 168 } 169 170 /** 171 * Writes len bytes from the specified byte array starting at offset off to 172 * this file. 173 * 174 * @param b the data. 175 * @param off the start offset in the data. 176 * @param len the number of bytes to write. 177 * @throws IOException if an I/O error occurs. 178 */ 179 @Override 180 public void write(final byte[] b, final int off, final int len) throws IOException { 181 randomAccessFile.write(b, off, len); 182 } 183 184 /** 185 * Returns the current offset in this file. 186 * 187 * @return the offset from the beginning of the file, in bytes, at which the 188 * next read or write occurs. 189 * @throws IOException in an I/O error occurs. 190 */ 191 @Override 192 public long getPosition() throws IOException { 193 return randomAccessFile.getFilePointer(); 194 } 195 196 /** 197 * Determines whether end of file has been reached (next read() will return 198 * -1). or not. 199 * 200 * @return True if end of file has been reached, false otherwise. 201 * @throws IOException if an I/O error occurs. 202 */ 203 @Override 204 public boolean isEndOfStream() throws IOException { 205 return getPosition() >= randomAccessFile.length(); 206 } 207 208 /** 209 * Sets the file-pointer offset, measured from the beginning of this file, 210 * at which the next read or write occurs. The offset may be set beyond the 211 * end of the file. Setting the offset beyond the end of the file does not 212 * change the file length. 213 * The file length will change only by writing after the offset has been set 214 * beyond the end of the file. 215 * 216 * @param pos the offset position, measured in bytes from the beginning of 217 * the file, at which to set the file pointer. 218 * @throws IOException if pos is less than 0 or if an I/O error occurs. 219 */ 220 @Override 221 public void seek(final long pos) throws IOException { 222 randomAccessFile.seek(pos); 223 } 224 225 /** 226 * Closes this file stream and releases any system resources associated with 227 * the stream. A closed file cannot perform input or output operations and 228 * cannot be reopened. 229 * If this file has an associated channel then the channel is closed as 230 * well. 231 * 232 * @throws IOException if an I/O error occurs. 233 */ 234 @Override 235 public void close() throws IOException { 236 randomAccessFile.close(); 237 } 238 239 /** 240 * Reads a boolean from this file. This method reads a single byte from the 241 * file, starting at the current file pointer. A value of 0 represents 242 * false. Any other value represents true. This method blocks until the byte 243 * is read, the end of the stream is detected, or an exception is thrown. 244 * 245 * @return the boolean value read. 246 * @throws IOException if an I/O error occurs. 247 */ 248 @Override 249 public boolean readBoolean() throws IOException { 250 return randomAccessFile.readBoolean(); 251 } 252 253 /** 254 * Reads a signed eight-bit value from this file. This method reads a byte 255 * from the file, starting from the current file pointer. If the byte read 256 * is b, where 0 <= b <= 255, then the result is: (byte)(b) 257 * This method blocks until the byte is read, the end of the stream is 258 * detected, or an exception is thrown. 259 * 260 * @return the next byte of this file is a signed eight-bit byte. 261 * @throws IOException if an I/O error occurs. 262 */ 263 @Override 264 public byte readByte() throws IOException { 265 return randomAccessFile.readByte(); 266 } 267 268 /** 269 * Reads an unsigned eight-bit number from this file. This method reads a 270 * byte from this file, starting at the current file pointer, and returns 271 * that byte. 272 * This method blocks until the byte is read, the end of the stream is 273 * detected, or an exception is thrown. 274 * 275 * @return the next byte of this file, interpreted as an unsigned eight-bit 276 * number. 277 * @throws IOException if an I/O error occurs. 278 */ 279 @Override 280 public short readUnsignedByte() throws IOException { 281 return (short) randomAccessFile.readUnsignedByte(); 282 } 283 284 /** 285 * Reads a signed 16-bit number from this file. The method reads two byte 286 * from this file, starting at the current file pointer. If the two bytes 287 * read, in order, are b1 and b2, where each of the two values is between 0 288 * and 255, inclusive, then the result is equal to: (short)(b1 << 8 | 289 * b2). 290 * This method blocks until the two bytes are read, the end of the stream is 291 * detected, or an exception is thrown. 292 * 293 * @return the next two bytes of this file, interpreted as a signed 16-bit 294 * number. 295 * @throws IOException if an I/O error occurs. 296 */ 297 @Override 298 public short readShort() throws IOException { 299 return randomAccessFile.readShort(); 300 } 301 302 /** 303 * Reads a signed 16-bit number from this file assuming that file is encoded 304 * using provided endian type. If endian type is big endian type, then 305 * natural binary order is preserved, otherwise byte order is reversed. 306 * This method blocks until the two bytes of the 16-bit number are read, the 307 * end of the stream is detected, or an exception is thrown. 308 * 309 * @param endianType Endian type. Big endian preserves natural binary order, 310 * little endian reverses byte order. 311 * @return the next two bytes of this file, interpreted as a signed 16-bit 312 * number encoded in provided endian type. 313 * @throws IOException if an I/O error occurs. 314 */ 315 @Override 316 public short readShort(final EndianType endianType) throws IOException { 317 final var value = randomAccessFile.readShort(); 318 return Util.fromEndianType(endianType, value); 319 } 320 321 /** 322 * Reads an unsigned 16-bit number from this file. This method reads two 323 * bytes from this file, starting at the current file pointer. If the bytes 324 * read, in order, are b1 and b2, where 0 <= b1, b2 <= 255, then the 325 * result is equal to: (b1 << 8) | b2. 326 * This method blocks until the two bytes are read, the end of the stream is 327 * detected, or an exception is thrown. 328 * 329 * @return the next two bytes of this file, interpreted as an unsigned 330 * 16-bit integer. 331 * @throws IOException if an I/O error occurs. 332 */ 333 @Override 334 public int readUnsignedShort() throws IOException { 335 return randomAccessFile.readUnsignedShort(); 336 } 337 338 /** 339 * Reads an unsigned 16-bit number from this file. This method reads two 340 * bytes from this file, starting at the current file pointer and using 341 * provided endian type. If endian type is big endian, then natural binary 342 * order is preserved, otherwise byte order is reversed. 343 * This method blocks until the two bytes are read, the end of the stream is 344 * detected, or an exception is thrown. 345 * 346 * @param endianType Endian type. Big endian preserves natural binary order, 347 * little endian reverses byte order. 348 * @return the next two bytes of this file, interpreted as an unsigned 349 * 16-bit integer. 350 * @throws IOException if an I/O error occurs. 351 */ 352 @Override 353 public int readUnsignedShort(final EndianType endianType) throws IOException { 354 final var streamValue = randomAccessFile.readShort(); 355 final var value = Util.fromEndianType(endianType, streamValue); 356 357 // convert value to byte array 358 final var firstShortByte = 0xff & (value >> 8); 359 final var secondShortByte = 0xff & ((value << 8) >> 8); 360 361 // return it as integer 362 return 0xffff & ((firstShortByte << 8) | secondShortByte); 363 } 364 365 /** 366 * Reads a signed 32-bit integer from this file. This method reads 4 bytes 367 * from the file, starting at the current file pointer. If the bytes read, 368 * in order, are b1, b2, b3, and b4, where 0 <= b1, b3, b4 <= 255, then 369 * the result is equal to: (b1 << 24) | (b2 << 16) + (b3 << 8) + 370 * b4. 371 * This method blocks until the four bytes are read, the end of the stream 372 * is detected, or an exception is thrown. 373 * 374 * @return the next four bytes of this file, interpreted as an int. 375 * @throws IOException if an I/O error occurs. 376 */ 377 @Override 378 public int readInt() throws IOException { 379 return randomAccessFile.readInt(); 380 } 381 382 /** 383 * Reads a signed 32-bit integer from this file. This method reads 4 bytes 384 * from the file, starting at the current file pointer and using provided 385 * endian type. If endian type is big endian, then natural binary order is 386 * preserved, otherwise byte order is reversed. 387 * This method blocks until the four bytes are read, the end of the stream 388 * is detected, or an exception is thrown. 389 * 390 * @param endianType Endian type. Big endian preserves natural binary order, 391 * little endian reverses byte order. 392 * @return the next four bytes of this file, interpreted as an int. 393 * @throws IOException if an I/O error occurs. 394 */ 395 @Override 396 public int readInt(final EndianType endianType) throws IOException { 397 final var value = randomAccessFile.readInt(); 398 return Util.fromEndianType(endianType, value); 399 } 400 401 /** 402 * Reads an unsigned 32-bit integer from this file. This method reads 4 403 * bytes from the file, starting at the current file pointer. If the bytes 404 * read, in order, are b1, b2, b3, and b4, where 0 <= b1, b3, b4 <= 255, 405 * then the result is equal to: (b1 << 24) | (b2 << 16) + 406 * (b3 << 8) + b4 407 * This method blocks until the four bytes are read, the end of the stream 408 * is detected, or an exception is thrown. 409 * 410 * @return the next four bytes of this file, interpreted as a long. 411 * @throws IOException if an I/O error occurs. 412 */ 413 @Override 414 public long readUnsignedInt() throws IOException { 415 final var value = randomAccessFile.readInt(); 416 417 // convert value to byte array 418 final var firstIntByte = 0xff & (value >> 24); 419 final var secondIntByte = 0xff & ((value << 8) >> 24); 420 final var thirdIntByte = 0xff & ((value << 16) >> 24); 421 final var fourthIntByte = 0xff & ((value << 24) >> 24); 422 423 // return it as integer 424 return ((long) firstIntByte << 24) | (secondIntByte << 16) | (thirdIntByte << 8) | fourthIntByte; 425 } 426 427 /** 428 * Reads an unsigned 32-bit integer from this file. This method reads 4 429 * bytes from the file, starting at the current file pointer and using 430 * provided endian type. If endian type is big endian, then natural binary 431 * order is preserved, otherwise byte order is reversed. 432 * This method blocks until the four bytes are read, the end of the stream 433 * is detected, or an exception is thrown. 434 * 435 * @param endianType Endian type. Big endian preserves natural binary order, 436 * little endian reverses byte order. 437 * @return the next four bytes of this file, interpreted as an int. 438 * @throws IOException if an I/O error occurs. 439 */ 440 @Override 441 public long readUnsignedInt(final EndianType endianType) throws IOException { 442 final var streamValue = randomAccessFile.readInt(); 443 final var value = Util.fromEndianType(endianType, streamValue); 444 445 // convert value to byte array 446 final var firstIntByte = 0xff & (value >> 24); 447 final var secondIntByte = 0xff & ((value << 8) >> 24); 448 final var thirdIntByte = 0xff & ((value << 16) >> 24); 449 final var fourthIntByte = 0xff & ((value << 24) >> 24); 450 451 // return it as integer 452 return ((long) firstIntByte << 24) | (secondIntByte << 16) | (thirdIntByte << 8) | fourthIntByte; 453 } 454 455 /** 456 * Reads a signed 64-bit integer from this file. This method reads eight 457 * bytes from the file, starting at the current file pointer. If the bytes 458 * read, in order, are b1, b2, b3, b4, b5, b6, b7, and b8, where: 459 * 0 <= b1, b2, b3, b4. b5. b6. b7. b8 <= 255, 460 * then the result is equal to: 461 * ((long)b1 << 56) + ((long)b2 << 48) 462 * + ((long)b3 << 40) + ((long)b4 << 32) 463 * + ((long)b5 << 24) + ((long)b6 << 16) 464 * + ((long)b7 << 8) + b8 465 * This method blocks until the eight bytes are read, the end of the stream 466 * is detected, or an exception is thrown. 467 * 468 * @return the next eight bytes of this file, interpreted as a long. 469 * @throws IOException if an I/O error occurs. 470 */ 471 @Override 472 public long readLong() throws IOException { 473 return randomAccessFile.readLong(); 474 } 475 476 /** 477 * Reads a signed 64-bit integer from this file. This method reads eight 478 * bytes from the file, starting at the current file pointer and using 479 * provided endian type. If endian type is big endian, then natural binary 480 * order is preserved, otherwise byte order is reversed. 481 * This method blocks until the eight bytes are read, the end of the stream 482 * is detected, or an exception is thrown. 483 * 484 * @param endianType Endian type. Big endian preserves natural binary order, 485 * little endian reverses byte order. 486 * @return the next eight bytes of this file, interpreted as a long 487 * @throws IOException if an I/O error occurs. 488 */ 489 @Override 490 public long readLong(final EndianType endianType) throws IOException { 491 final var value = randomAccessFile.readLong(); 492 return Util.fromEndianType(endianType, value); 493 } 494 495 /** 496 * Reads a float from this file. This method reads an int value, starting at 497 * the current file pointer, as if by the readInt method and then converts 498 * that in to a float using the intBitsToFloat method in class Float. 499 * This method blocks until the four bytes are read, the end of the stream 500 * is detected, or an exception is thrown. 501 * 502 * @return the next four bytes of this file, interpreted as a float. 503 * @throws IOException if an I/O error occurs. 504 */ 505 @Override 506 public float readFloat() throws IOException { 507 return randomAccessFile.readFloat(); 508 } 509 510 /** 511 * Reads a float from this file. This method reads four bytes using 512 * provided endian type. If endian type is big endian, then natural binary 513 * order is preserved, otherwise byte order is reversed. 514 * This method blocks until the four bytes are read, the end of the stream 515 * is detected, or an exception is thrown. 516 * 517 * @param endianType Endian type. Big endian preserves natural binary order, 518 * little endian reverses byte order. 519 * @return the next four bytes of this file, interpreted as a float. 520 * @throws IOException if an I/O error occurs. 521 */ 522 @Override 523 public float readFloat(final EndianType endianType) throws IOException { 524 final var value = randomAccessFile.readFloat(); 525 return Util.fromEndianType(endianType, value); 526 } 527 528 /** 529 * Reads a double from this file. This method reads a long value, starting 530 * at the current file pointer, as if by the readLong method and then 531 * converts that long to a double using the longBitsToDouble method in class 532 * Double. 533 * This method blocks until the eight bytes are read, the end of the stream 534 * is detected, or an exception is thrown. 535 * 536 * @return the next eight bytes of this file, interpreted as a double. 537 * @throws IOException if an I/O error occurs. 538 */ 539 @Override 540 public double readDouble() throws IOException { 541 return randomAccessFile.readDouble(); 542 } 543 544 /** 545 * Reads a double from this file. This method reads eight bytes using 546 * provided endian type. If endian type is big endian, then natural binary 547 * order is preserved, otherwise byte order is reversed. 548 * This method blocks until the eight bytes are read, the end of the stream 549 * is detected, or an exception is thrown. 550 * 551 * @param endianType Endian type. Big endian preserves natural binary order, 552 * little endian reverses byte order. 553 * @return the next eight bytes of this file, interpreted as a double. 554 * @throws IOException if an I/O error occurs. 555 */ 556 @Override 557 public double readDouble(final EndianType endianType) throws IOException { 558 final var value = randomAccessFile.readDouble(); 559 return Util.fromEndianType(endianType, value); 560 } 561 562 /** 563 * Reads the next line of text from this file. This method successively 564 * reads bytes from the file, starting at the current file pointer, until it 565 * reaches a line terminator of the end of the file. Each byte is converted 566 * into a character by taking the byte's value for the lower eight bits of 567 * the character and setting the high eight bits of the character to zero. 568 * This method does not, therefore, support the full Unicode character set. 569 * A line of text is terminated by a carriage-return character ('\r'), a 570 * newline character('\n'), a carriage-return character immediately followed 571 * by a newline character, or the end of the file. Line-terminating 572 * characters are discarded and are not included as part of the string 573 * returned. 574 * This method blocks until a newline character is read, a carriage return 575 * and the byte following it are read (to see if it is a newline), the end 576 * of the file is reached, or an exception is thrown. 577 * 578 * @return the next line of text from this file, or null if end of file is 579 * encountered before even one byte is read. 580 * @throws IOException if an I/O error occurs. 581 */ 582 @Override 583 public String readLine() throws IOException { 584 return randomAccessFile.readLine(); 585 } 586 587 /** 588 * Reads in a string from this file. The string has been encoded using a 589 * modified UTF-8 format. 590 * The first two bytes are read, starting from the current file pointer, as 591 * if by readUnsignedShort. This value gives the number of following bytes 592 * that are in the encoded string, not the length of the resulting string. 593 * The following bytes are then interpreted as bytes encoding characters in 594 * the modified UTF-8 format and are converted into characters. 595 * This method blocks until all the bytes are read, the end of the stream is 596 * detected, or an exception is thrown. 597 * 598 * @return a Unicode string. 599 * @throws IOException if an I/O error occurs. 600 */ 601 public String readUTF() throws IOException { 602 return randomAccessFile.readUTF(); 603 } 604 605 /** 606 * Sequentially reads characters starting at current file position until one 607 * of the characters in provided pattern is found. 608 * All characters read so far will be returned without including any of the 609 * pattern characters. 610 * 611 * @param pattern Stop characters to stop reading when they are found. 612 * @return String read so far until any of the pattern characters was found 613 * or an empty string if the first character is contained in provided 614 * pattern. 615 * @throws IOException if an I/O error occurs. 616 * @throws IllegalArgumentException if no pattern characters are provided. 617 */ 618 @Override 619 public String readUntilAnyOfTheseCharactersIsFound(final String pattern) throws IOException { 620 if (pattern.isEmpty()) { 621 throw new IllegalArgumentException(); 622 } 623 624 final var buffer = new StringBuilder(); 625 final var charBuffer = new byte[1]; 626 String character; 627 while (randomAccessFile.read(charBuffer) == 1) { 628 character = new String(charBuffer); 629 if (pattern.contains(character)) { 630 // character found 631 break; 632 } 633 // add character to output buffer 634 buffer.append(character); 635 } 636 637 return buffer.toString(); 638 } 639 640 /** 641 * Writes a boolean to the file as a one-byte value. The value true is 642 * written out as the value (byte)1; the value false is written out as the 643 * value (byte)0. The write starts at the current position of the file 644 * pointer. 645 * 646 * @param v a boolean value to be written. 647 * @throws IOException if an I/O error occurs. 648 */ 649 @Override 650 public void writeBoolean(final boolean v) throws IOException { 651 randomAccessFile.writeBoolean(v); 652 } 653 654 /** 655 * Writes a byte to the file as a one-byte value. The write starts at the 656 * current position of the file pointer. 657 * 658 * @param v a byte value to be written. 659 * @throws IOException if an I/O error occurs. 660 */ 661 @Override 662 public void writeByte(final byte v) throws IOException { 663 randomAccessFile.writeByte(v); 664 } 665 666 /** 667 * Writes provided value in the range 0-255 as an unsigned byte. The write 668 * starts at the current position of the file pointer. 669 * 670 * @param v a value to be written as an unsigned byte. 671 * @throws IOException if an I/O error occurs. 672 */ 673 @Override 674 public void writeUnsignedByte(final short v) throws IOException { 675 final var data = (byte) (0xff & v); 676 randomAccessFile.writeByte(data); 677 } 678 679 /** 680 * Writes a short to the file as two bytes, high byte first. The write 681 * starts at the current position of the file pointer. 682 * 683 * @param v a short to be written. 684 * @throws IOException if an I/O error occurs. 685 */ 686 @Override 687 public void writeShort(final short v) throws IOException { 688 randomAccessFile.writeShort(v); 689 } 690 691 /** 692 * Writes a short to the file as two bytes using provided endian type. 693 * If endian type is big endian, then natural byte order is preserved (and 694 * high byte is written first), if little endian order is chosen, then byte 695 * order is reversed. 696 * 697 * @param v a short to be written. 698 * @param endianType endian type. If it is big endian, natural byte order is 699 * preserved, otherwise byte order is reversed. 700 * @throws IOException if an I/O error occurs. 701 */ 702 @Override 703 public void writeShort(final short v, final EndianType endianType) throws IOException { 704 final var value = Util.toEndianType(endianType, v); 705 randomAccessFile.writeShort(value); 706 } 707 708 /** 709 * Writes an unsigned short to the file as two bytes, high byte first. 710 * Provided integer value is converted to an unsigned short by taking into 711 * account only the two lower bytes. The write starts at the current 712 * position of the file pointer. 713 * 714 * @param v an unsigned short to be written (int is converted to unsigned 715 * short). 716 * @throws IOException if an I/O error occurs. 717 */ 718 @Override 719 public void writeUnsignedShort(final int v) throws IOException { 720 final var firstShortByte = 0xff & (v >> 8); 721 final var secondShortByte = 0xff & ((v << 8) >> 8); 722 723 final var value = (short) ((firstShortByte << 8) | secondShortByte); 724 725 randomAccessFile.writeShort(value); 726 } 727 728 /** 729 * Writes an unsigned short to the file as two bytes, using provided endian 730 * type. 731 * Provided integer value is converted to an unsigned short by taking into 732 * account only the two lower bytes. 733 * If endian type is big endian, then natural byte order is preserved (and 734 * high byte is written first), if little endian order is chosen, then byte 735 * order is reversed. 736 * The write starts at the current position of the file pointer. 737 * 738 * @param v an unsigned short to be written (int is converted to unsigned 739 * short). 740 * @param endianType endian type. If it is big endian, natural byte order is 741 * preserved, otherwise byte order is reversed. 742 * @throws IOException if an I/O error occurs. 743 */ 744 @Override 745 public void writeUnsignedShort(final int v, final EndianType endianType) throws IOException { 746 final var firstShortByte = 0xff & (v >> 8); 747 final var secondShortByte = 0xff & ((v << 8) >> 8); 748 749 final var machineValue = (short) ((firstShortByte << 8) | secondShortByte); 750 final var value = Util.toEndianType(endianType, machineValue); 751 752 randomAccessFile.writeShort(value); 753 } 754 755 /** 756 * Writes an int to the file as four bytes, high byte first. The write 757 * starts at the current position of the file pointer. 758 * 759 * @param v an int to be written. 760 * @throws IOException if an I/O error occurs. 761 */ 762 @Override 763 public void writeInt(final int v) throws IOException { 764 randomAccessFile.writeInt(v); 765 } 766 767 /** 768 * Writes an int to the file as four bytes, using provided endian type. 769 * If endian type is big endian, then natural byte order is preserved (and 770 * high byte is written first), if little endian order is chosen, then byte 771 * order is reversed. 772 * The write starts at the current position of the file pointer. 773 * 774 * @param v an int to be written. 775 * @param endianType endian type. If it is big endian, natural byte order is 776 * preserved, otherwise byte order is reversed. 777 * @throws IOException if an I/O error occurs. 778 */ 779 @Override 780 public void writeInt(final int v, final EndianType endianType) throws IOException { 781 final var value = Util.toEndianType(endianType, v); 782 randomAccessFile.writeInt(value); 783 } 784 785 /** 786 * Writes an unsigned int to the file as four bytes, high byte first. 787 * Provided integer value is converted to an unsigned int by taking into 788 * account only the four lower bytes. The write starts at the current 789 * position of the file pointer. 790 * 791 * @param v an unsigned int to be written (long is converted to unsigned 792 * int). 793 * @throws IOException if an I/O error occurs. 794 */ 795 @Override 796 public void writeUnsignedInt(final long v) throws IOException { 797 final var firstIntByte = (int) (0xff & (v >> 24)); 798 final var secondIntByte = (int) (0xff & ((v << 8) >> 24)); 799 final var thirdIntByte = (int) (0xff & ((v << 16) >> 24)); 800 final var fourthIntByte = (int) (0xff & ((v << 24) >> 24)); 801 802 final var value = (firstIntByte << 24) | (secondIntByte << 16) | (thirdIntByte << 8) | fourthIntByte; 803 804 randomAccessFile.writeInt(value); 805 } 806 807 /** 808 * Writes an unsigned int to the file as four bytes, using provided endian 809 * type. 810 * Provided integer value is converted to an unsigned int by taking into 811 * account only the four lower bytes. 812 * If endian type is big endian, then natural byte order is preserved (and 813 * high byte is written first), if little endian order is chosen, then byte 814 * order is reversed. 815 * The write starts at the current position of the file pointer. 816 * 817 * @param v an unsigned int to be written (long is converted to unsigned 818 * short). 819 * @param endianType endian type. If it is big endian, natural byte order is 820 * preserved, otherwise byte order is reversed. 821 * @throws IOException if an I/O error occurs. 822 */ 823 @Override 824 public void writeUnsignedInt(final long v, final EndianType endianType) throws IOException { 825 final var firstIntByte = (int) (0xff & (v >> 24)); 826 final var secondIntByte = (int) (0xff & ((v << 8) >> 24)); 827 final var thirdIntByte = (int) (0xff & ((v << 16) >> 24)); 828 final var fourthIntByte = (int) (0xff & ((v << 24) >> 24)); 829 830 final var machineValue = (firstIntByte << 24) | (secondIntByte << 16) | (thirdIntByte << 8) | fourthIntByte; 831 final var value = Util.toEndianType(endianType, machineValue); 832 833 randomAccessFile.writeInt(value); 834 } 835 836 /** 837 * Writes a long to the file as eight bytes, high byte first. The write 838 * starts at the current position of the file pointer. 839 * 840 * @param v a long to be written. 841 * @throws IOException if an I/O error occurs. 842 */ 843 @Override 844 public void writeLong(final long v) throws IOException { 845 randomAccessFile.writeLong(v); 846 } 847 848 /** 849 * Writes a long to the file as eight bytes, using provided endian type. 850 * If endian type is big endian, then natural byte order is preserved (and 851 * high byte is written first), if little endian order is chosen, then byte 852 * order is reversed. 853 * The write starts at the current position of the file pointer. 854 * 855 * @param v a long to be written. 856 * @param endianType endian type. If it is big endian, natural byte order is 857 * preserved, otherwise byte order is reversed. 858 * @throws IOException if an I/O error occurs. 859 */ 860 @Override 861 public void writeLong(final long v, final EndianType endianType) throws IOException { 862 final var value = Util.toEndianType(endianType, v); 863 randomAccessFile.writeLong(value); 864 } 865 866 /** 867 * Converts the float argument to an int using the floatToIntBits method in 868 * class Float, and then write that int value to the file as a four-byte 869 * quantity, high byte first. The write starts at the current position of 870 * the file pointer. 871 * 872 * @param v a float value to be written. 873 * @throws IOException if an I/O error occurs. 874 */ 875 @Override 876 public void writeFloat(final float v) throws IOException { 877 randomAccessFile.writeFloat(v); 878 } 879 880 /** 881 * Converts the float argument to an int using the floatToIntBits method in 882 * class Float, and then write that int value to the file as a four-byte 883 * quantity, using provided endian type. 884 * If endian type is big endian, then natural byte order is preserved (and 885 * high byte is written first), if little endian order is chosen, then byte 886 * order is reversed. 887 * The write starts at the current position of the file pointer. 888 * 889 * @param v a float value to be written. 890 * @param endianType endian type. If it is big endian, natural byte order is 891 * preserved, otherwise byte order is reversed. 892 * @throws IOException if an I/O error occurs. 893 */ 894 @Override 895 public void writeFloat(final float v, final EndianType endianType) throws IOException { 896 final var value = Util.toEndianType(endianType, v); 897 randomAccessFile.writeFloat(value); 898 } 899 900 /** 901 * Converts the double argument to a long using the doubleToLongBits method 902 * in class Double, and then writes that long value to the file as an eight 903 * byte quantity, high byte first. The write starts at the current position 904 * of the file pointer. 905 * 906 * @param v a double value to be written. 907 * @throws IOException if an I/O error occurs. 908 */ 909 @Override 910 public void writeDouble(final double v) throws IOException { 911 randomAccessFile.writeDouble(v); 912 } 913 914 /** 915 * Converts the double argument to a long using the doubleToLongBits method 916 * in class Double, and then writes that long value to the file as an eight 917 * byte quantity, using provided endian type. 918 * If endian type is big endian, then natural byte order is preserved (and 919 * high byte is written first), if little endian order is chosen, then byte 920 * order is reversed. 921 * The write starts at the current position of the file pointer. 922 * 923 * @param v a double value to be written. 924 * @param endianType endian type. If it is big endian, natural byte order is 925 * preserved, otherwise byte order is reversed. 926 * @throws IOException if an I/O error occurs. 927 */ 928 @Override 929 public void writeDouble(final double v, final EndianType endianType) throws IOException { 930 final var value = Util.toEndianType(endianType, v); 931 randomAccessFile.writeDouble(value); 932 } 933 934 /** 935 * Writes the string to the file as a sequence of bytes. Each character in 936 * the string is written out, in sequence, by discarding its high eight 937 * bits. The write starts at the current position of the file pointer. 938 * 939 * @param s a string of bytes to be written. 940 * @throws IOException if an I/O error occurs. 941 */ 942 @Override 943 public void writeASCII(final String s) throws IOException { 944 randomAccessFile.writeBytes(s); 945 } 946 947 /** 948 * Writes a string to the file using modified UTF-8 encoding in a machine- 949 * independent manner. 950 * First, two bytes are written to the file, starting at the current file 951 * pointer, as if by the writeShort method giving the number of bytes to 952 * follow. This value is the number of bytes actually written out, not the 953 * length of the string. 954 * Following the length, each character of the string is output, in 955 * sequence, using the modified UTF-8 encoding for each character. 956 * 957 * @param str a string to be written. 958 * @throws IOException if an I/O error occurs. 959 */ 960 public void writeUTF(final String str) throws IOException { 961 randomAccessFile.writeUTF(str); 962 } 963 }