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