1 /* 2 * Hunt - A refined core library for D programming language. 3 * 4 * Copyright (C) 2018-2019 HuntLabs 5 * 6 * Website: https://www.huntlabs.net/ 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 12 module hunt.io.DataInputStream; 13 14 import std.conv; 15 import hunt.io.FilterInputStream; 16 import hunt.io.DataInput; 17 import hunt.Double; 18 import hunt.Float; 19 import hunt.io.Common; 20 import hunt.Exceptions; 21 import hunt.io.PushbackInputStream; 22 23 public 24 class DataInputStream : FilterInputStream , DataInput { 25 26 /** 27 * Creates a DataInputStream that uses the specified 28 * underlying InputStream. 29 * 30 * @param inputStream the specified input stream 31 */ 32 public this(InputStream inputStream) { 33 super(inputStream); 34 } 35 36 /** 37 * working arrays initialized on demand by readUTF 38 */ 39 private byte[] bytearr = new byte[80]; 40 private char[] chararr = new char[80]; 41 42 /** 43 * Reads some number of bytes from the contained input stream and 44 * stores them into the buffer array <code>b</code>. The number of 45 * bytes actually read is returned as an integer. This method blocks 46 * until input data is available, end of file is detected, or an 47 * exception is thrown. 48 * 49 * <p>If <code>b</code> is null, a <code>NullPointerException</code> is 50 * thrown. If the length of <code>b</code> is zero, then no bytes are 51 * read and <code>0</code> is returned; otherwise, there is an attempt 52 * to read at least one byte. If no byte is available because the 53 * stream is at end of file, the value <code>-1</code> is returned; 54 * otherwise, at least one byte is read and stored into <code>b</code>. 55 * 56 * <p>The first byte read is stored into element <code>b[0]</code>, the 57 * next one into <code>b[1]</code>, and so on. The number of bytes read 58 * is, at most, equal to the length of <code>b</code>. Let <code>k</code> 59 * be the number of bytes actually read; these bytes will be stored inputStream 60 * elements <code>b[0]</code> through <code>b[k-1]</code>, leaving 61 * elements <code>b[k]</code> through <code>b[b.length-1]</code> 62 * unaffected. 63 * 64 * <p>The <code>read(b)</code> method has the same effect as: 65 * <blockquote><pre> 66 * read(b, 0, b.length) 67 * </pre></blockquote> 68 * 69 * @param b the buffer into which the data is read. 70 * @return the total number of bytes read into the buffer, or 71 * <code>-1</code> if there is no more data because the end 72 * of the stream has been reached. 73 * @exception IOException if the first byte cannot be read for any reason 74 * other than end of file, the stream has been closed and the underlying 75 * input stream does not support reading after close, or another I/O 76 * error occurs. 77 * @see java.io.FilterInputStream#inputStream 78 * @see java.io.InputStream#read(byte[], int, int) 79 */ 80 override 81 public final int read(byte[] b) { 82 return inputStream.read(b, 0, cast(int)(b.length)); 83 } 84 85 /** 86 * Reads up to <code>len</code> bytes of data from the contained 87 * input stream into an array of bytes. An attempt is made to read 88 * as many as <code>len</code> bytes, but a smaller number may be read, 89 * possibly zero. The number of bytes actually read is returned as an 90 * integer. 91 * 92 * <p> This method blocks until input data is available, end of file is 93 * detected, or an exception is thrown. 94 * 95 * <p> If <code>len</code> is zero, then no bytes are read and 96 * <code>0</code> is returned; otherwise, there is an attempt to read at 97 * least one byte. If no byte is available because the stream is at end of 98 * file, the value <code>-1</code> is returned; otherwise, at least one 99 * byte is read and stored into <code>b</code>. 100 * 101 * <p> The first byte read is stored into element <code>b[off]</code>, the 102 * next one into <code>b[off+1]</code>, and so on. The number of bytes read 103 * is, at most, equal to <code>len</code>. Let <i>k</i> be the number of 104 * bytes actually read; these bytes will be stored inputStream elements 105 * <code>b[off]</code> through <code>b[off+</code><i>k</i><code>-1]</code>, 106 * leaving elements <code>b[off+</code><i>k</i><code>]</code> through 107 * <code>b[off+len-1]</code> unaffected. 108 * 109 * <p> In every case, elements <code>b[0]</code> through 110 * <code>b[off]</code> and elements <code>b[off+len]</code> through 111 * <code>b[b.length-1]</code> are unaffected. 112 * 113 * @param b the buffer into which the data is read. 114 * @param off the start offset inputStream the destination array <code>b</code> 115 * @param len the maximum number of bytes read. 116 * @return the total number of bytes read into the buffer, or 117 * <code>-1</code> if there is no more data because the end 118 * of the stream has been reached. 119 * @exception NullPointerException If <code>b</code> is <code>null</code>. 120 * @exception IndexOutOfBoundsException If <code>off</code> is negative, 121 * <code>len</code> is negative, or <code>len</code> is greater than 122 * <code>b.length - off</code> 123 * @exception IOException if the first byte cannot be read for any reason 124 * other than end of file, the stream has been closed and the underlying 125 * input stream does not support reading after close, or another I/O 126 * error occurs. 127 * @see java.io.FilterInputStream#inputStream 128 * @see java.io.InputStream#read(byte[], int, int) 129 */ 130 override 131 public final int read(byte[] b, int off, int len) { 132 return inputStream.read(b, off, len); 133 } 134 135 /** 136 * See the general contract of the {@code readFully} 137 * method of {@code DataInput}. 138 * <p> 139 * Bytes 140 * for this operation are read from the contained 141 * input stream. 142 * 143 * @param b the buffer into which the data is read. 144 * @throws NullPointerException if {@code b} is {@code null}. 145 * @throws EOFException if this input stream reaches the end before 146 * reading all the bytes. 147 * @throws IOException the stream has been closed and the contained 148 * input stream does not support reading after close, or 149 * another I/O error occurs. 150 * @see java.io.FilterInputStream#inputStream 151 */ 152 public final void readFully(byte[] b) { 153 readFully(b, 0, cast(int)(b.length)); 154 } 155 156 /** 157 * See the general contract of the {@code readFully} 158 * method of {@code DataInput}. 159 * <p> 160 * Bytes 161 * for this operation are read from the contained 162 * input stream. 163 * 164 * @param b the buffer into which the data is read. 165 * @param off the start offset inputStream the data array {@code b}. 166 * @param len the number of bytes to read. 167 * @exception NullPointerException if {@code b} is {@code null}. 168 * @exception IndexOutOfBoundsException if {@code off} is negative, 169 * {@code len} is negative, or {@code len} is greater than 170 * {@code b.length - off}. 171 * @exception EOFException if this input stream reaches the end before 172 * reading all the bytes. 173 * @exception IOException the stream has been closed and the contained 174 * input stream does not support reading after close, or 175 * another I/O error occurs. 176 * @see java.io.FilterInputStream#inputStream 177 */ 178 public final void readFully(byte[] b, int off, int len) { 179 if (len < 0) 180 throw new IndexOutOfBoundsException(); 181 int n = 0; 182 while (n < len) { 183 int count = inputStream.read(b, off + n, len - n); 184 if (count < 0) 185 throw new EOFException(); 186 n += count; 187 } 188 } 189 190 /** 191 * See the general contract of the <code>skipBytes</code> 192 * method of <code>DataInput</code>. 193 * <p> 194 * Bytes for this operation are read from the contained 195 * input stream. 196 * 197 * @param n the number of bytes to be skipped. 198 * @return the actual number of bytes skipped. 199 * @exception IOException if the contained input stream does not support 200 * seek, or the stream has been closed and 201 * the contained input stream does not support 202 * reading after close, or another I/O error occurs. 203 */ 204 public final int skipBytes(int n) { 205 int total = 0; 206 int cur = 0; 207 208 while ((total<n) && ((cur = cast(int) inputStream.skip(n-total)) > 0)) { 209 total += cur; 210 } 211 212 return total; 213 } 214 215 /** 216 * See the general contract of the <code>readBoolean</code> 217 * method of <code>DataInput</code>. 218 * <p> 219 * Bytes for this operation are read from the contained 220 * input stream. 221 * 222 * @return the <code>bool</code> value read. 223 * @exception EOFException if this input stream has reached the end. 224 * @exception IOException the stream has been closed and the contained 225 * input stream does not support reading after close, or 226 * another I/O error occurs. 227 * @see java.io.FilterInputStream#inputStream 228 */ 229 public final bool readBoolean() { 230 int ch = inputStream.read(); 231 if (ch < 0) 232 throw new EOFException(); 233 return (ch != 0); 234 } 235 236 /** 237 * See the general contract of the <code>readByte</code> 238 * method of <code>DataInput</code>. 239 * <p> 240 * Bytes 241 * for this operation are read from the contained 242 * input stream. 243 * 244 * @return the next byte of this input stream as a signed 8-bit 245 * <code>byte</code>. 246 * @exception EOFException if this input stream has reached the end. 247 * @exception IOException the stream has been closed and the contained 248 * input stream does not support reading after close, or 249 * another I/O error occurs. 250 * @see java.io.FilterInputStream#inputStream 251 */ 252 public final byte readByte() { 253 int ch = inputStream.read(); 254 if (ch < 0) 255 throw new EOFException(); 256 return cast(byte)(ch); 257 } 258 259 /** 260 * See the general contract of the <code>readUnsignedByte</code> 261 * method of <code>DataInput</code>. 262 * <p> 263 * Bytes 264 * for this operation are read from the contained 265 * input stream. 266 * 267 * @return the next byte of this input stream, interpreted as an 268 * unsigned 8-bit number. 269 * @exception EOFException if this input stream has reached the end. 270 * @exception IOException the stream has been closed and the contained 271 * input stream does not support reading after close, or 272 * another I/O error occurs. 273 * @see java.io.FilterInputStream#inputStream 274 */ 275 public final int readUnsignedByte() { 276 int ch = inputStream.read(); 277 if (ch < 0) 278 throw new EOFException(); 279 return ch; 280 } 281 282 /** 283 * See the general contract of the <code>readShort</code> 284 * method of <code>DataInput</code>. 285 * <p> 286 * Bytes 287 * for this operation are read from the contained 288 * input stream. 289 * 290 * @return the next two bytes of this input stream, interpreted as a 291 * signed 16-bit number. 292 * @exception EOFException if this input stream reaches the end before 293 * reading two bytes. 294 * @exception IOException the stream has been closed and the contained 295 * input stream does not support reading after close, or 296 * another I/O error occurs. 297 * @see java.io.FilterInputStream#inputStream 298 */ 299 public final short readShort() { 300 int ch1 = inputStream.read(); 301 int ch2 = inputStream.read(); 302 if ((ch1 | ch2) < 0) 303 throw new EOFException(); 304 return cast(short)((ch1 << 8) + (ch2 << 0)); 305 } 306 307 /** 308 * See the general contract of the <code>readUnsignedShort</code> 309 * method of <code>DataInput</code>. 310 * <p> 311 * Bytes 312 * for this operation are read from the contained 313 * input stream. 314 * 315 * @return the next two bytes of this input stream, interpreted as an 316 * unsigned 16-bit integer. 317 * @exception EOFException if this input stream reaches the end before 318 * reading two bytes. 319 * @exception IOException the stream has been closed and the contained 320 * input stream does not support reading after close, or 321 * another I/O error occurs. 322 * @see java.io.FilterInputStream#inputStream 323 */ 324 public final int readUnsignedShort() { 325 int ch1 = inputStream.read(); 326 int ch2 = inputStream.read(); 327 if ((ch1 | ch2) < 0) 328 throw new EOFException(); 329 return (ch1 << 8) + (ch2 << 0); 330 } 331 332 /** 333 * See the general contract of the <code>readChar</code> 334 * method of <code>DataInput</code>. 335 * <p> 336 * Bytes 337 * for this operation are read from the contained 338 * input stream. 339 * 340 * @return the next two bytes of this input stream, interpreted as a 341 * <code>char</code>. 342 * @exception EOFException if this input stream reaches the end before 343 * reading two bytes. 344 * @exception IOException the stream has been closed and the contained 345 * input stream does not support reading after close, or 346 * another I/O error occurs. 347 * @see java.io.FilterInputStream#inputStream 348 */ 349 public final char readChar() { 350 return readByte(); 351 // int ch1 = inputStream.read(); 352 // return cast(char)ch1; 353 // int ch2 = inputStream.read(); 354 // if ((ch1 | ch2) < 0) 355 // throw new EOFException(); 356 // return cast(char)((ch1 << 8) + (ch2 << 0)); 357 } 358 359 /** 360 * See the general contract of the <code>readInt</code> 361 * method of <code>DataInput</code>. 362 * <p> 363 * Bytes 364 * for this operation are read from the contained 365 * input stream. 366 * 367 * @return the next four bytes of this input stream, interpreted as an 368 * <code>int</code>. 369 * @exception EOFException if this input stream reaches the end before 370 * reading four bytes. 371 * @exception IOException the stream has been closed and the contained 372 * input stream does not support reading after close, or 373 * another I/O error occurs. 374 * @see java.io.FilterInputStream#inputStream 375 */ 376 public final int readInt() { 377 int ch1 = inputStream.read(); 378 int ch2 = inputStream.read(); 379 int ch3 = inputStream.read(); 380 int ch4 = inputStream.read(); 381 if ((ch1 | ch2 | ch3 | ch4) < 0) 382 throw new EOFException(); 383 return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0)); 384 } 385 386 private byte[] readBuffer = new byte[8]; 387 388 /** 389 * See the general contract of the <code>readLong</code> 390 * method of <code>DataInput</code>. 391 * <p> 392 * Bytes 393 * for this operation are read from the contained 394 * input stream. 395 * 396 * @return the next eight bytes of this input stream, interpreted as a 397 * <code>long</code>. 398 * @exception EOFException if this input stream reaches the end before 399 * reading eight bytes. 400 * @exception IOException the stream has been closed and the contained 401 * input stream does not support reading after close, or 402 * another I/O error occurs. 403 * @see java.io.FilterInputStream#inputStream 404 */ 405 public final long readLong() { 406 readFully(readBuffer, 0, 8); 407 return ((cast(long)readBuffer[0] << 56) + 408 (cast(long)(readBuffer[1] & 255) << 48) + 409 (cast(long)(readBuffer[2] & 255) << 40) + 410 (cast(long)(readBuffer[3] & 255) << 32) + 411 (cast(long)(readBuffer[4] & 255) << 24) + 412 ((readBuffer[5] & 255) << 16) + 413 ((readBuffer[6] & 255) << 8) + 414 ((readBuffer[7] & 255) << 0)); 415 } 416 417 /** 418 * See the general contract of the <code>readFloat</code> 419 * method of <code>DataInput</code>. 420 * <p> 421 * Bytes 422 * for this operation are read from the contained 423 * input stream. 424 * 425 * @return the next four bytes of this input stream, interpreted as a 426 * <code>float</code>. 427 * @exception EOFException if this input stream reaches the end before 428 * reading four bytes. 429 * @exception IOException the stream has been closed and the contained 430 * input stream does not support reading after close, or 431 * another I/O error occurs. 432 * @see java.io.DataInputStream#readInt() 433 * @see java.lang.Float#intBitsToFloat(int) 434 */ 435 public final float readFloat() { 436 return Float.intBitsToFloat(readInt()); 437 } 438 439 /** 440 * See the general contract of the <code>readDouble</code> 441 * method of <code>DataInput</code>. 442 * <p> 443 * Bytes 444 * for this operation are read from the contained 445 * input stream. 446 * 447 * @return the next eight bytes of this input stream, interpreted as a 448 * <code>double</code>. 449 * @exception EOFException if this input stream reaches the end before 450 * reading eight bytes. 451 * @exception IOException the stream has been closed and the contained 452 * input stream does not support reading after close, or 453 * another I/O error occurs. 454 * @see java.io.DataInputStream#readLong() 455 * @see java.lang.Double#longBitsToDouble(long) 456 */ 457 public final double readDouble() { 458 return Double.longBitsToDouble(readLong()); 459 } 460 461 private char[] lineBuffer; 462 463 /** 464 * See the general contract of the <code>readLine</code> 465 * method of <code>DataInput</code>. 466 * <p> 467 * Bytes 468 * for this operation are read from the contained 469 * input stream. 470 * 471 * @deprecated This method does not properly convert bytes to characters. 472 * As of JDK 1.1, the preferred way to read lines of text is via the 473 * <code>BufferedReader.readLine()</code> method. Programs that use the 474 * <code>DataInputStream</code> class to read lines can be converted to use 475 * the <code>BufferedReader</code> class by replacing code of the form: 476 * <blockquote><pre> 477 * DataInputStream d = new DataInputStream(inputStream); 478 * </pre></blockquote> 479 * with: 480 * <blockquote><pre> 481 * BufferedReader d 482 * = new BufferedReader(new InputStreamReader(inputStream)); 483 * </pre></blockquote> 484 * 485 * @return the next line of text from this input stream. 486 * @exception IOException if an I/O error occurs. 487 * @see java.io.BufferedReader#readLine() 488 * @see java.io.FilterInputStream#inputStream 489 */ 490 // @Deprecated 491 public final string readLine() { 492 char[] buf = lineBuffer; 493 494 if (buf is null) { 495 buf = lineBuffer = new char[128]; 496 } 497 498 int room = cast(int)(buf.length); 499 int offset = 0; 500 int c; 501 502 loop: while (true) { 503 switch (c = inputStream.read()) { 504 case -1: 505 case '\n': 506 break loop; 507 508 case '\r': 509 int c2 = inputStream.read(); 510 if ((c2 != '\n') && (c2 != -1)) { 511 if (!(cast(PushbackInputStream)inputStream !is null)) { 512 this.inputStream = new PushbackInputStream(inputStream); 513 } 514 (cast(PushbackInputStream)inputStream).unread(c2); 515 } 516 break loop; 517 518 default: 519 if (--room < 0) { 520 buf = new char[offset + 128]; 521 room = cast(int)(buf.length) - offset - 1; 522 // System.arraycopy(lineBuffer, 0, buf, 0, offset); 523 buf[0 .. offset ] = lineBuffer[0..offset]; 524 lineBuffer = buf; 525 } 526 buf[offset++] = cast(char) c; 527 break; 528 } 529 } 530 if ((c == -1) && (offset == 0)) { 531 return null; 532 } 533 return cast(string)buf[0..offset]; 534 } 535 536 /** 537 * See the general contract of the <code>readUTF</code> 538 * method of <code>DataInput</code>. 539 * <p> 540 * Bytes 541 * for this operation are read from the contained 542 * input stream. 543 * 544 * @return a Unicode string. 545 * @exception EOFException if this input stream reaches the end before 546 * reading all the bytes. 547 * @exception IOException the stream has been closed and the contained 548 * input stream does not support reading after close, or 549 * another I/O error occurs. 550 * @exception UTFDataFormatException if the bytes do not represent a valid 551 * modified UTF-8 encoding of a string. 552 * @see java.io.DataInputStream#readUTF(java.io.DataInput) 553 */ 554 public final string readUTF() { 555 return readUTF(this); 556 } 557 558 /** 559 * Reads from the 560 * stream <code>inputStream</code> a representation 561 * of a Unicode character string encoded inputStream 562 * <a href="DataInput.html#modified-utf-8">modified UTF-8</a> format; 563 * this string of characters is then returned as a <code>String</code>. 564 * The details of the modified UTF-8 representation 565 * are exactly the same as for the <code>readUTF</code> 566 * method of <code>DataInput</code>. 567 * 568 * @param inputStream a data input stream. 569 * @return a Unicode string. 570 * @exception EOFException if the input stream reaches the end 571 * before all the bytes. 572 * @exception IOException the stream has been closed and the contained 573 * input stream does not support reading after close, or 574 * another I/O error occurs. 575 * @exception UTFDataFormatException if the bytes do not represent a 576 * valid modified UTF-8 encoding of a Unicode string. 577 * @see java.io.DataInputStream#readUnsignedShort() 578 */ 579 public static final string readUTF(DataInput inputStream) { 580 int utflen = inputStream.readUnsignedShort(); 581 byte[] bytearr = null; 582 import hunt.logging; 583 // trace("11111111=>", utflen); 584 // char[] chararr = null; 585 if (cast(DataInputStream)inputStream !is null ) { 586 // trace("xxxx=>"); 587 // DataInputStream dis = cast(DataInputStream)inputStream; 588 // if (dis.bytearr.length < utflen){ 589 // dis.bytearr = new byte[utflen*2]; 590 // dis.chararr = new char[utflen*2]; 591 // } 592 // chararr = dis.chararr; 593 // bytearr = dis.bytearr; 594 } else { 595 // trace("yyyyyyyy=>"); 596 // bytearr = new byte[utflen]; 597 // chararr = new char[utflen]; 598 } 599 600 bytearr = new byte[utflen]; 601 602 // int c, char2, char3; 603 // int count = 0; 604 // int chararr_count=0; 605 606 inputStream.readFully(bytearr, 0, utflen); 607 608 // while (count < utflen) { 609 // c = cast(int) bytearr[count] & 0xff; 610 // if (c > 127) break; 611 // count++; 612 // auto t = cast(char)c; 613 // chararr[chararr_count++]= t; 614 // } 615 616 // trace("ccc=>", cast(string)bytearr); 617 618 return cast(string)bytearr; 619 620 // while (count < utflen) { 621 // c = cast(int) bytearr[count] & 0xff; 622 // switch (c >> 4) { 623 // case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: 624 // /* 0xxxxxxx*/ 625 // count++; 626 // chararr[chararr_count++]=cast(char)c; 627 // break; 628 // case 12: case 13: 629 // /* 110x xxxx 10xx xxxx*/ 630 // count += 2; 631 // if (count > utflen) 632 // throw new Exception( 633 // "malformed input: partial character at end"); 634 // char2 = cast(int) bytearr[count-1]; 635 // if ((char2 & 0xC0) != 0x80) 636 // throw new Exception( 637 // "malformed input around byte " ~ count.to!string); 638 // chararr[chararr_count++]=cast(char)(((c & 0x1F) << 6) | 639 // (char2 & 0x3F)); 640 // break; 641 // case 14: 642 // /* 1110 xxxx 10xx xxxx 10xx xxxx */ 643 // count += 3; 644 // if (count > utflen) 645 // throw new Exception( 646 // "malformed input: partial character at end"); 647 // char2 = cast(int) bytearr[count-2]; 648 // char3 = cast(int) bytearr[count-1]; 649 // if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80)) 650 // throw new Exception( 651 // "malformed input around byte " ~ (count-1).to!string); 652 // chararr[chararr_count++]=cast(char)(((c & 0x0F) << 12) | 653 // ((char2 & 0x3F) << 6) | 654 // ((char3 & 0x3F) << 0)); 655 // break; 656 // default: 657 // /* 10xx xxxx, 1111 xxxx */ 658 // throw new Exception( 659 // "malformed input around byte " ~ count.to!string); 660 // } 661 // } 662 // The number of chars produced may be less than utflen 663 // return cast(string)chararr[0..chararr_count]; 664 } 665 }