温馨提示:代码在线浏览功能只能做为源码浏览参考,如果想更进一步了解该代码请下载:X3BLOG 单用户1.0 build80707(ACCESS)源代码
当前文件:
x3blogAccessBuild80707/SharpZipLib/Tar/TarInputStream.cs[18K,2009-6-12 11:58:58],打开代码结构图
x3blogAccessBuild80707/SharpZipLib/Tar/TarInputStream.cs[18K,2009-6-12 11:58:58],打开代码结构图1// TarInputStream.cs 2
// 3
// Copyright (C) 2001 Mike Krueger 4
// 5
// This program is free software; you can redistribute it and/or 6
// modify it under the terms of the GNU General Public License 7
// as published by the Free Software Foundation; either version 2 8
// of the License, or (at your option) any later version. 9
// 10
// This program is distributed in the hope that it will be useful, 11
// but WITHOUT ANY WARRANTY; without even the implied warranty of 12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13
// GNU General Public License for more details. 14
// 15
// You should have received a copy of the GNU General Public License 16
// along with this program; if not, write to the Free Software 17
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18
// 19
// Linking this library statically or dynamically with other modules is 20
// making a combined work based on this library. Thus, the terms and 21
// conditions of the GNU General Public License cover the whole 22
// combination. 23
// 24
// As a special exception, the copyright holders of this library give you 25
// permission to link this library with independent modules to produce an 26
// executable, regardless of the license terms of these independent 27
// modules, and to copy and distribute the resulting executable under 28
// terms of your choice, provided that you also meet, for each linked 29
// independent module, the terms and conditions of the license of that 30
// module. An independent module is a module which is not derived from 31
// or based on this library. If you modify this library, you may extend 32
// this exception to your version of the library, but you are not 33
// obligated to do so. If you do not wish to do so, delete this 34
// exception statement from your version. 35
36
using System; 37
using System.IO; 38
using System.Text; 39
40
namespace ICSharpCode.SharpZipLib.Tar 41
{ 42
43
/// <summary> 44
/// The TarInputStream reads a UNIX tar archive as an InputStream. 45
/// methods are provided to position at each successive entry in 46
/// the archive, and the read each entry as a normal input stream 47
/// using read(). 48
/// </summary> 49
public class TarInputStream : Stream 50
{ 51
/// <summary> 52
/// Flag set when last block has been read 53
/// </summary> 54
protected bool hasHitEOF; 55
56
/// <summary> 57
/// Size of this entry as recorded in header 58
/// </summary> 59
protected long entrySize; 60
61
/// <summary> 62
/// Number of bytes read for this entry so far 63
/// </summary> 64
protected long entryOffset; 65
66
/// <summary> 67
/// Buffer used with calls to <code>Read()</code> 68
/// </summary> 69
protected byte[] readBuf; 70
71
/// <summary> 72
/// Working buffer 73
/// </summary> 74
protected TarBuffer buffer; 75
76
/// <summary> 77
/// Current entry being read 78
/// </summary> 79
protected TarEntry currEntry; 80
81
/// <summary> 82
/// Factory used to create TarEntry or descendant class instance 83
/// </summary> 84
protected IEntryFactory eFactory; 85
86
Stream inputStream; 87
88
/// <summary> 89
/// Gets a value indicating whether the current stream supports reading 90
/// </summary> 91
public override bool CanRead { 92
get { 93
return inputStream.CanRead; 94
} 95
} 96
97
/// <summary> 98
/// Gets a value indicating whether the current stream supports seeking 99
/// This property always returns false. 100
/// </summary> 101
public override bool CanSeek { 102
get { 103
return false; 104
} 105
} 106
107
/// <summary> 108
/// Gets a value indicating if the stream supports writing. 109
/// This property always returns false. 110
/// </summary> 111
public override bool CanWrite { 112
get { 113
return false; 114
} 115
} 116
117
/// <summary> 118
/// The length in bytes of the stream 119
/// </summary> 120
public override long Length { 121
get { 122
return inputStream.Length; 123
} 124
} 125
126
/// <summary> 127
/// Gets or sets the position within the stream. 128
/// Setting the Position is not supported and throws a NotSupportedExceptionNotSupportedException 129
/// </summary> 130
/// <exception cref="NotSupportedException">Any attempt to set position</exception> 131
public override long Position { 132
get { 133
return inputStream.Position; 134
} 135
set { 136
throw new NotSupportedException("TarInputStream Seek not supported"); 137
} 138
} 139
140
/// <summary> 141
/// Flushes the baseInputStream 142
/// </summary> 143
public override void Flush() 144
{ 145
inputStream.Flush(); 146
} 147
148
/// <summary> 149
/// Set the streams position. This operation is not supported and will throw a NotSupportedException 150
/// </summary> 151
/// <exception cref="NotSupportedException">Any access</exception> 152
public override long Seek(long offset, SeekOrigin origin) 153
{ 154
throw new NotSupportedException("TarInputStream Seek not supported"); 155
} 156
157
/// <summary> 158
/// Sets the length of the stream 159
/// This operation is not supported and will throw a NotSupportedException 160
/// </summary> 161
/// <exception cref="NotSupportedException">Any access</exception> 162
public override void SetLength(long val) 163
{ 164
throw new NotSupportedException("TarInputStream SetLength not supported"); 165
} 166
167
/// <summary> 168
/// Writes a block of bytes to this stream using data from a buffer. 169
/// This operation is not supported and will throw a NotSupportedException 170
/// </summary> 171
/// <exception cref="NotSupportedException">Any access</exception> 172
public override void Write(byte[] array, int offset, int count) 173
{ 174
throw new NotSupportedException("TarInputStream Write not supported"); 175
} 176
177
/// <summary> 178
/// Writes a byte to the current position in the file stream. 179
/// This operation is not supported and will throw a NotSupportedException 180
/// </summary> 181
/// <exception cref="NotSupportedException">Any access</exception> 182
public override void WriteByte(byte val) 183
{ 184
throw new NotSupportedException("TarInputStream WriteByte not supported"); 185
} 186
187
188
/// <summary> 189
/// Construct a TarInputStream with default block factor 190
/// </summary> 191
/// <param name="inputStream">stream to source data from</param> 192
public TarInputStream(Stream inputStream) : this(inputStream, TarBuffer.DefaultBlockFactor) 193
{ 194
} 195
196
/// <summary> 197
/// Construct a TarInputStream with user specified block factor 198
/// </summary> 199
/// <param name="inputStream">stream to source data from</param> 200
/// <param name="blockFactor">block factor to apply to archive</param> 201
public TarInputStream(Stream inputStream, int blockFactor) 202
{ 203
this.inputStream = inputStream; 204
this.buffer = TarBuffer.CreateInputTarBuffer(inputStream, blockFactor); 205
206
this.readBuf = null; 207
this.hasHitEOF = false; 208
this.eFactory = null; 209
} 210
211
/// <summary> 212
/// Set the entry factory for this instance. 213
/// </summary> 214
/// <param name="factory">The factory for creating new entries</param> 215
public void SetEntryFactory(IEntryFactory factory) 216
{ 217
this.eFactory = factory; 218
} 219
220
/// <summary> 221
/// Closes this stream. Calls the TarBuffer's close() method. 222
/// The underlying stream is closed by the TarBuffer. 223
/// </summary> 224
public override void Close() 225
{ 226
this.buffer.Close(); 227
} 228
229
/// <summary> 230
/// Get the record size being used by this stream's TarBuffer. 231
/// </summary> 232
/// <returns> 233
/// TarBuffer record size. 234
/// </returns> 235
public int GetRecordSize() 236
{ 237
return this.buffer.GetRecordSize(); 238
} 239
240
/// <summary> 241
/// Get the available data that can be read from the current 242
/// entry in the archive. This does not indicate how much data 243
/// is left in the entire archive, only in the current entry. 244
/// This value is determined from the entry's size header field 245
/// and the amount of data already read from the current entry. 246
/// </summary> 247
/// <returns> 248
/// The number of available bytes for the current entry. 249
/// </returns> 250
public long Available { 251
get { 252
return this.entrySize - this.entryOffset; 253
} 254
} 255
256
/// <summary> 257
/// Skip bytes in the input buffer. This skips bytes in the 258
/// current entry's data, not the entire archive, and will 259
/// stop at the end of the current entry's data if the number 260
/// to skip extends beyond that point. 261
/// </summary> 262
/// <param name="numToSkip"> 263
/// The number of bytes to skip. 264
/// </param> 265
public void Skip(long numToSkip) 266
{ 267
// TODO: REVIEW 268
// This is horribly inefficient, but it ensures that we 269
// properly skip over bytes via the TarBuffer... 270
// 271
byte[] skipBuf = new byte[8 * 1024]; 272
273
for (long num = numToSkip; num > 0;) { 274
int toRead = num > skipBuf.Length ? skipBuf.Length : (int)num; 275
int numRead = this.Read(skipBuf, 0, toRead); 276
277
if (numRead == -1) { 278
break; 279
} 280
281
num -= numRead; 282
} 283
} 284
285
/// <summary> 286
/// Since we do not support marking just yet, we return false. 287
/// </summary> 288
public bool IsMarkSupported { 289
get { 290
return false; 291
} 292
} 293
294
/// <summary> 295
/// Since we do not support marking just yet, we do nothing. 296
/// </summary> 297
/// <param name ="markLimit"> 298
/// The limit to mark. 299
/// </param> 300
public void Mark(int markLimit) 301
{ 302
} 303
304
/// <summary> 305
/// Since we do not support marking just yet, we do nothing. 306
/// </summary> 307
public void Reset() 308
{ 309
} 310
311
void SkipToNextEntry() 312
{ 313
long numToSkip = this.entrySize - this.entryOffset; 314
315
if (numToSkip > 0) { 316
this.Skip(numToSkip); 317
} 318
319
this.readBuf = null; 320
} 321
322
/// <summary> 323
/// Get the next entry in this tar archive. This will skip 324
/// over any remaining data in the current entry, if there 325
/// is one, and place the input stream at the header of the 326
/// next entry, and read the header and instantiate a new 327
/// TarEntry from the header bytes and return that entry. 328
/// If there are no more entries in the archive, null will 329
/// be returned to indicate that the end of the archive has 330
/// been reached. 331
/// </summary> 332
/// <returns> 333
/// The next TarEntry in the archive, or null. 334
/// </returns> 335
public TarEntry GetNextEntry() 336
{ 337
if (this.hasHitEOF) { 338
return null; 339
} 340
341
if (this.currEntry != null) { 342
SkipToNextEntry(); 343
} 344
345
byte[] headerBuf = this.buffer.ReadBlock(); 346
347
if (headerBuf == null) { 348
this.hasHitEOF = true; 349
} else if (this.buffer.IsEOFBlock(headerBuf)) { 350
this.hasHitEOF = true; 351
} 352
353
if (this.hasHitEOF) { 354
this.currEntry = null; 355
} else { 356
try { 357
TarHeader header = new TarHeader(); 358
header.ParseBuffer(headerBuf); 359
if ( !header.IsChecksumValid ) 360
{ 361
throw new TarException("Header checksum is invalid"); 362
} 363
this.entryOffset = 0; 364
this.entrySize = header.Size; 365
366
StringBuilder longName = null; 367
368
if (header.TypeFlag == TarHeader.LF_GNU_LONGNAME) { 369
370
byte[] nameBuffer = new byte[TarBuffer.BlockSize]; 371
372
long numToRead = this.entrySize; 373
374
longName = new StringBuilder(); 375
376
while (numToRead > 0) { 377
int numRead = this.Read(nameBuffer, 0, (numToRead > nameBuffer.Length ? nameBuffer.Length : (int)numToRead)); 378
379
if (numRead == -1) { 380
throw new InvalidHeaderException("Failed to read long name entry"); 381
} 382
383
longName.Append(TarHeader.ParseName(nameBuffer, 0, numRead).ToString()); 384
numToRead -= numRead; 385
} 386
387
SkipToNextEntry(); 388
headerBuf = this.buffer.ReadBlock(); 389
} else if (header.TypeFlag == TarHeader.LF_GHDR) { // POSIX global extended header 390
// Ignore things we dont understand completely for now 391
SkipToNextEntry(); 392
headerBuf = this.buffer.ReadBlock(); 393
} else if (header.TypeFlag == TarHeader.LF_XHDR) { // POSIX extended header 394
// Ignore things we dont understand completely for now 395
SkipToNextEntry(); 396
headerBuf = this.buffer.ReadBlock(); 397
} else if (header.TypeFlag == TarHeader.LF_GNU_VOLHDR) { 398
// TODO: could show volume name when verbose 399
SkipToNextEntry(); 400
headerBuf = this.buffer.ReadBlock(); 401
} else if (header.TypeFlag != TarHeader.LF_NORMAL && 402
header.TypeFlag != TarHeader.LF_OLDNORM && 403
header.TypeFlag != TarHeader.LF_DIR) { 404
// Ignore things we dont understand completely for now 405
SkipToNextEntry(); 406
headerBuf = this.buffer.ReadBlock(); 407
} 408
409
if (this.eFactory == null) { 410
this.currEntry = new TarEntry(headerBuf); 411
if (longName != null) { 412
currEntry.Name = longName.ToString(); 413
} 414
} else { 415
this.currEntry = this.eFactory.CreateEntry(headerBuf); 416
} 417
418
// Magic was checked here for 'ustar' but there are multiple valid possibilities 419
// so this is not done anymore. 420
421
this.entryOffset = 0; 422
423
// TODO: Review How do we resolve this discrepancy?! 424
this.entrySize = this.currEntry.Size; 425
} catch (InvalidHeaderException ex) { 426
this.entrySize = 0; 427
this.entryOffset = 0; 428
this.currEntry = null; 429
throw new InvalidHeaderException("bad header in record " + this.buffer.GetCurrentBlockNum() + " block " + this.buffer.GetCurrentBlockNum() + ", " + ex.Message); 430
} 431
} 432
return this.currEntry; 433
} 434
435
/// <summary> 436
/// Reads a byte from the current tar archive entry. 437
/// This method simply calls read(byte[], int, int). 438
/// </summary> 439
public override int ReadByte() 440
{ 441
byte[] oneByteBuffer = new byte[1]; 442
int num = this.Read(oneByteBuffer, 0, 1); 443
if (num <= 0) { // return -1 to indicate that no byte was read. 444
return -1; 445
} 446
return (int)oneByteBuffer[0]; 447
} 448
449
/// <summary> 450
/// Reads bytes from the current tar archive entry. 451
/// 452
/// This method is aware of the boundaries of the current 453
/// entry in the archive and will deal with them appropriately 454
/// </summary> 455
/// <param name="outputBuffer"> 456
/// The buffer into which to place bytes read. 457
/// </param> 458
/// <param name="offset"> 459
/// The offset at which to place bytes read. 460
/// </param> 461
/// <param name="count"> 462
/// The number of bytes to read. 463
/// </param> 464
/// <returns> 465
/// The number of bytes read, or 0 at end of stream/EOF. 466
/// </returns> 467
public override int Read(byte[] outputBuffer, int offset, int count) 468
{ 469
int totalRead = 0; 470
471
if (this.entryOffset >= this.entrySize) { 472
return 0; 473
} 474
475
long numToRead = count; 476
477
if ((numToRead + this.entryOffset) > this.entrySize) { 478
numToRead = this.entrySize - this.entryOffset; 479
} 480
481
if (this.readBuf != null) { 482
int sz = (numToRead > this.readBuf.Length) ? this.readBuf.Length : (int)numToRead; 483
484
Array.Copy(this.readBuf, 0, outputBuffer, offset, sz); 485
486
if (sz >= this.readBuf.Length) { 487
this.readBuf = null; 488
} else { 489
int newLen = this.readBuf.Length - sz; 490
byte[] newBuf = new byte[newLen]; 491
Array.Copy(this.readBuf, sz, newBuf, 0, newLen); 492
this.readBuf = newBuf; 493
} 494
495
totalRead += sz; 496
numToRead -= sz; 497
offset += sz; 498
} 499
500
while (numToRead > 0) { 501
byte[] rec = this.buffer.ReadBlock(); 502
if (rec == null) { 503
// Unexpected EOF! 504
throw new TarException("unexpected EOF with " + numToRead + " bytes unread"); 505
} 506
507
int sz = (int)numToRead; 508
int recLen = rec.Length; 509
510
if (recLen > sz) { 511
Array.Copy(rec, 0, outputBuffer, offset, sz); 512
this.readBuf = new byte[recLen - sz]; 513
Array.Copy(rec, sz, this.readBuf, 0, recLen - sz); 514
} else { 515
sz = recLen; 516
Array.Copy(rec, 0, outputBuffer, offset, recLen); 517
} 518
519
totalRead += sz; 520
numToRead -= sz; 521
offset += sz; 522
} 523
524
this.entryOffset += totalRead; 525
526
return totalRead; 527
} 528
529
/// <summary> 530
/// Copies the contents of the current tar archive entry directly into 531
/// an output stream. 532
/// </summary> 533
/// <param name="outputStream"> 534
/// The OutputStream into which to write the entry's data. 535
/// </param> 536
public void CopyEntryContents(Stream outputStream) 537
{ 538
byte[] buf = new byte[32 * 1024]; 539
540
while (true) { 541
int numRead = this.Read(buf, 0, buf.Length); 542
if (numRead <= 0) { 543
break; 544
} 545
outputStream.Write(buf, 0, numRead); 546
} 547
} 548
549
/// <summary> 550
/// This interface is provided, along with the method setEntryFactory(), to allow 551
/// the programmer to have their own TarEntry subclass instantiated for the 552
/// entries return from getNextEntry(). 553
/// </summary> 554
public interface IEntryFactory 555
{ 556
/// <summary> 557
/// Create an entry based on name alone 558
/// </summary> 559
/// <param name="name"> 560
/// Name of the new EntryPointNotFoundException to create 561
/// </param> 562
/// <returns>created TarEntry or descendant class</returns> 563
TarEntry CreateEntry(string name); 564
565
/// <summary> 566
/// Create an instance based on an actual file 567
/// </summary> 568
/// <param name="fileName"> 569
/// Name of file to represent in the entry 570
/// </param> 571
/// <returns> 572
/// Created TarEntry or descendant class 573
/// </returns> 574
TarEntry CreateEntryFromFile(string fileName); 575
576
/// <summary> 577
/// Create a tar entry based on the header information passed 578
/// </summary> 579
/// <param name="headerBuf"> 580
/// Buffer containing header information to base entry on 581
/// </param> 582
/// <returns> 583
/// Created TarEntry or descendant class 584
/// </returns> 585
TarEntry CreateEntry(byte[] headerBuf); 586
} 587
588
/// <summary> 589
/// Standard entry factory class creating instances of the class TarEntry 590
/// </summary> 591
public class EntryFactoryAdapter : IEntryFactory 592
{ 593
/// <summary> 594
/// Create a TarEntry based on named 595
/// </summary> 596
public TarEntry CreateEntry(string name) 597
{ 598
return TarEntry.CreateTarEntry(name); 599
} 600
601
/// <summary> 602
/// Create a tar entry with details obtained from <paramref name="fileName">file</paramref> 603
/// </summary> 604
public TarEntry CreateEntryFromFile(string fileName) 605
{ 606
return TarEntry.CreateEntryFromFile(fileName); 607
} 608
609
/// <summary> 610
/// Create and entry based on details in <paramref name="headerBuf">header</paramref> 611
/// </summary> 612
public TarEntry CreateEntry(byte[] headerBuf) 613
{ 614
return new TarEntry(headerBuf); 615
} 616
} 617
} 618
619
620
} 621
622
/* The original Java file had this header: 623
** Authored by Timothy Gerard Endres 624
** <mailto:time@gjt.org> <http://www.trustice.com> 625
** 626
** This work has been placed into the public domain. 627
** You may use this work in any way and for any purpose you wish. 628
** 629
** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND, 630
** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR 631
** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY 632
** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR 633
** REDISTRIBUTION OF THIS SOFTWARE. 634
** 635
*/ 636
637






}