1 15 16 package installer; 17 18 import java.io.*; 19 20 21 34 35 36 public 37 class TarInputStream 38 extends FilterInputStream 39 { 40 protected boolean debug; 41 protected boolean hasHitEOF; 42 43 protected int entrySize; 44 protected int entryOffset; 45 46 protected byte[] oneBuf; 47 protected byte[] readBuf; 48 49 protected TarBuffer buffer; 50 51 protected TarEntry currEntry; 52 53 protected EntryFactory eFactory; 54 55 56 public 57 TarInputStream( InputStream is ) 58 { 59 this( is, TarBuffer.DEFAULT_BLKSIZE, TarBuffer.DEFAULT_RCDSIZE ); 60 } 61 62 public 63 TarInputStream( InputStream is, int blockSize ) 64 { 65 this( is, blockSize, TarBuffer.DEFAULT_RCDSIZE ); 66 } 67 68 public 69 TarInputStream( InputStream is, int blockSize, int recordSize ) 70 { 71 super( is ); 72 73 this.buffer = new TarBuffer( is, blockSize, recordSize ); 74 75 this.readBuf = null; 76 this.oneBuf = new byte[1]; 77 this.debug = false; 78 this.hasHitEOF = false; 79 this.eFactory = null; 80 } 81 82 87 public void 88 setDebug( boolean debugF ) 89 { 90 this.debug = debugF; 91 } 92 93 98 public void 99 setEntryFactory( EntryFactory factory ) 100 { 101 this.eFactory = factory; 102 } 103 104 109 public void 110 setBufferDebug( boolean debug ) 111 { 112 this.buffer.setDebug( debug ); 113 } 114 115 118 public void 119 close() 120 throws IOException 121 { 122 this.buffer.close(); 123 } 124 125 130 public int 131 getRecordSize() 132 { 133 return this.buffer.getRecordSize(); 134 } 135 136 146 public int 147 available() 148 throws IOException 149 { 150 return this.entrySize - this.entryOffset; 151 } 152 153 161 public void 162 skip( int numToSkip ) 163 throws IOException 164 { 165 170 byte[] skipBuf = new byte[ 8 * 1024 ]; 171 172 for ( int num = numToSkip ; num > 0 ; ) 173 { 174 int numRead = 175 this.read( skipBuf, 0, 176 ( num > skipBuf.length ? skipBuf.length : num ) ); 177 178 if ( numRead == -1 ) 179 break; 180 181 num -= numRead; 182 } 183 } 184 185 190 public boolean 191 markSupported() 192 { 193 return false; 194 } 195 196 201 public void 202 mark( int markLimit ) 203 { 204 } 205 206 209 public void 210 reset() 211 { 212 } 213 214 226 public TarEntry 227 getNextEntry() 228 throws IOException 229 { 230 if ( this.hasHitEOF ) 231 return null; 232 233 if ( this.currEntry != null ) 234 { 235 int numToSkip = this.entrySize - this.entryOffset; 236 237 if ( this.debug ) 238 System.err.println 239 ( "TarInputStream: SKIP currENTRY '" 240 + this.currEntry.getName() + "' SZ " 241 + this.entrySize + " OFF " + this.entryOffset 242 + " skipping " + numToSkip + " bytes" ); 243 244 if ( numToSkip > 0 ) 245 { 246 this.skip( numToSkip ); 247 } 248 249 this.readBuf = null; 250 } 251 252 byte[] headerBuf = this.buffer.readRecord(); 253 254 if ( headerBuf == null ) 255 { 256 if ( this.debug ) 257 { 258 System.err.println( "READ NULL RECORD" ); 259 } 260 261 this.hasHitEOF = true; 262 } 263 else if ( this.buffer.isEOFRecord( headerBuf ) ) 264 { 265 if ( this.debug ) 266 { 267 System.err.println( "READ EOF RECORD" ); 268 } 269 270 this.hasHitEOF = true; 271 } 272 273 if ( this.hasHitEOF ) 274 { 275 this.currEntry = null; 276 } 277 else 278 { 279 try { 280 if ( this.eFactory == null ) 281 { 282 this.currEntry = new TarEntry( headerBuf ); 283 } 284 else 285 { 286 this.currEntry = 287 this.eFactory.createEntry( headerBuf ); 288 } 289 290 if ( ! ( headerBuf[257] == 'u' && headerBuf[258] == 's' 291 && headerBuf[259] == 't' && headerBuf[260] == 'a' 292 && headerBuf[261] == 'r' ) ) 293 { 294 throw new InvalidHeaderException 295 ( "header magic is not 'ustar', but '" 296 + headerBuf[257] + headerBuf[258] + headerBuf[259] 297 + headerBuf[260] + headerBuf[261] + "', or (dec) " 298 + ((int)headerBuf[257]) + ", " 299 + ((int)headerBuf[258]) + ", " 300 + ((int)headerBuf[259]) + ", " 301 + ((int)headerBuf[260]) + ", " 302 + ((int)headerBuf[261]) ); 303 } 304 305 if ( this.debug ) 306 System.err.println 307 ( "TarInputStream: SET CURRENTRY '" 308 + this.currEntry.getName() 309 + "' size = " + this.currEntry.getSize() ); 310 311 this.entryOffset = 0; 312 this.entrySize = (int) this.currEntry.getSize(); 314 } 315 catch ( InvalidHeaderException ex ) 316 { 317 this.entrySize = 0; 318 this.entryOffset = 0; 319 this.currEntry = null; 320 throw new InvalidHeaderException 321 ( "bad header in block " 322 + this.buffer.getCurrentBlockNum() 323 + " record " 324 + this.buffer.getCurrentRecordNum() 325 + ", " + ex.getMessage() ); 326 } 327 } 328 329 return this.currEntry; 330 } 331 332 339 public int 340 read() 341 throws IOException 342 { 343 int num = this.read( this.oneBuf, 0, 1 ); 344 if ( num == -1 ) 345 return num; 346 else 347 return this.oneBuf[0]; 348 } 349 350 358 public int 359 read( byte[] buf ) 360 throws IOException 361 { 362 return this.read( buf, 0, buf.length ); 363 } 364 365 377 public int 378 read( byte[] buf, int offset, int numToRead ) 379 throws IOException 380 { 381 int totalRead = 0; 382 383 if ( this.entryOffset >= this.entrySize ) 384 return -1; 385 386 if ( (numToRead + this.entryOffset) > this.entrySize ) 387 { 388 numToRead = (this.entrySize - this.entryOffset); 389 } 390 391 if ( this.readBuf != null ) 392 { 393 int sz = ( numToRead > this.readBuf.length ) 394 ? this.readBuf.length : numToRead; 395 396 System.arraycopy( this.readBuf, 0, buf, offset, sz ); 397 398 if ( sz >= this.readBuf.length ) 399 { 400 this.readBuf = null; 401 } 402 else 403 { 404 int newLen = this.readBuf.length - sz; 405 byte[] newBuf = new byte[ newLen ]; 406 System.arraycopy( this.readBuf, sz, newBuf, 0, newLen ); 407 this.readBuf = newBuf; 408 } 409 410 totalRead += sz; 411 numToRead -= sz; 412 offset += sz; 413 } 414 415 for ( ; numToRead > 0 ; ) 416 { 417 byte[] rec = this.buffer.readRecord(); 418 if ( rec == null ) 419 { 420 throw new IOException 422 ( "unexpected EOF with " + numToRead + " bytes unread" ); 423 } 424 425 int sz = numToRead; 426 int recLen = rec.length; 427 428 if ( recLen > sz ) 429 { 430 System.arraycopy( rec, 0, buf, offset, sz ); 431 this.readBuf = new byte[ recLen - sz ]; 432 System.arraycopy( rec, sz, this.readBuf, 0, recLen - sz ); 433 } 434 else 435 { 436 sz = recLen; 437 System.arraycopy( rec, 0, buf, offset, recLen ); 438 } 439 440 totalRead += sz; 441 numToRead -= sz; 442 offset += sz; 443 } 444 445 this.entryOffset += totalRead; 446 447 return totalRead; 448 } 449 450 456 public void 457 copyEntryContents( OutputStream out ) 458 throws IOException 459 { 460 byte[] buf = new byte[ 32 * 1024 ]; 461 462 for ( ; ; ) 463 { 464 int numRead = this.read( buf, 0, buf.length ); 465 if ( numRead == -1 ) 466 break; 467 out.write( buf, 0, numRead ); 468 } 469 } 470 471 476 477 public 478 interface EntryFactory 479 { 480 public TarEntry 481 createEntry( String name ); 482 483 public TarEntry 484 createEntry( File path ) 485 throws InvalidHeaderException; 486 487 public TarEntry 488 createEntry( byte[] headerBuf ) 489 throws InvalidHeaderException; 490 } 491 492 public 493 class EntryAdapter 494 implements EntryFactory 495 { 496 public TarEntry 497 createEntry( String name ) 498 { 499 return new TarEntry( name ); 500 } 501 502 public TarEntry 503 createEntry( File path ) 504 throws InvalidHeaderException 505 { 506 return new TarEntry( path ); 507 } 508 509 public TarEntry 510 createEntry( byte[] headerBuf ) 511 throws InvalidHeaderException 512 { 513 return new TarEntry( headerBuf ); 514 } 515 } 516 517 } 518 519 520 | Popular Tags |