Summary

Class:ICSharpCode.SharpZipLib.Zip.EntryPatchData
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipHelperStream.cs
Covered lines:0
Uncovered lines:4
Coverable lines:4
Total lines:560
Line coverage:0%

File(s)

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipHelperStream.cs

#LineLine coverage
 1using System;
 2using System.IO;
 3using System.Text;
 4
 5namespace ICSharpCode.SharpZipLib.Zip
 6{
 7  /// <summary>
 8  /// Holds data pertinent to a data descriptor.
 9  /// </summary>
 10  public class DescriptorData
 11  {
 12    /// <summary>
 13    /// Get /set the compressed size of data.
 14    /// </summary>
 15    public long CompressedSize {
 16      get { return compressedSize; }
 17      set { compressedSize = value; }
 18    }
 19
 20    /// <summary>
 21    /// Get / set the uncompressed size of data
 22    /// </summary>
 23    public long Size {
 24      get { return size; }
 25      set { size = value; }
 26    }
 27
 28    /// <summary>
 29    /// Get /set the crc value.
 30    /// </summary>
 31    public long Crc {
 32      get { return crc; }
 33      set { crc = (value & 0xffffffff); }
 34    }
 35
 36    #region Instance Fields
 37    long size;
 38    long compressedSize;
 39    long crc;
 40    #endregion
 41  }
 42
 43  class EntryPatchData
 44  {
 45    public long SizePatchOffset {
 046      get { return sizePatchOffset_; }
 047      set { sizePatchOffset_ = value; }
 48    }
 49
 50    public long CrcPatchOffset {
 051      get { return crcPatchOffset_; }
 052      set { crcPatchOffset_ = value; }
 53    }
 54
 55    #region Instance Fields
 56    long sizePatchOffset_;
 57    long crcPatchOffset_;
 58    #endregion
 59  }
 60
 61  /// <summary>
 62  /// This class assists with writing/reading from Zip files.
 63  /// </summary>
 64  internal class ZipHelperStream : Stream
 65  {
 66    #region Constructors
 67    /// <summary>
 68    /// Initialise an instance of this class.
 69    /// </summary>
 70    /// <param name="name">The name of the file to open.</param>
 71    public ZipHelperStream(string name)
 72    {
 73      stream_ = new FileStream(name, FileMode.Open, FileAccess.ReadWrite);
 74      isOwner_ = true;
 75    }
 76
 77    /// <summary>
 78    /// Initialise a new instance of <see cref="ZipHelperStream"/>.
 79    /// </summary>
 80    /// <param name="stream">The stream to use.</param>
 81    public ZipHelperStream(Stream stream)
 82    {
 83      stream_ = stream;
 84    }
 85    #endregion
 86
 87    /// <summary>
 88    /// Get / set a value indicating wether the the underlying stream is owned or not.
 89    /// </summary>
 90    /// <remarks>If the stream is owned it is closed when this instance is closed.</remarks>
 91    public bool IsStreamOwner {
 92      get { return isOwner_; }
 93      set { isOwner_ = value; }
 94    }
 95
 96    #region Base Stream Methods
 97    public override bool CanRead {
 98      get { return stream_.CanRead; }
 99    }
 100
 101    public override bool CanSeek {
 102      get { return stream_.CanSeek; }
 103    }
 104
 105    public override bool CanTimeout {
 106      get { return stream_.CanTimeout; }
 107    }
 108
 109    public override long Length {
 110      get { return stream_.Length; }
 111    }
 112
 113    public override long Position {
 114      get { return stream_.Position; }
 115      set { stream_.Position = value; }
 116    }
 117
 118    public override bool CanWrite {
 119      get { return stream_.CanWrite; }
 120    }
 121
 122    public override void Flush()
 123    {
 124      stream_.Flush();
 125    }
 126
 127    public override long Seek(long offset, SeekOrigin origin)
 128    {
 129      return stream_.Seek(offset, origin);
 130    }
 131
 132    public override void SetLength(long value)
 133    {
 134      stream_.SetLength(value);
 135    }
 136
 137    public override int Read(byte[] buffer, int offset, int count)
 138    {
 139      return stream_.Read(buffer, offset, count);
 140    }
 141
 142    public override void Write(byte[] buffer, int offset, int count)
 143    {
 144      stream_.Write(buffer, offset, count);
 145    }
 146
 147    /// <summary>
 148    /// Close the stream.
 149    /// </summary>
 150    /// <remarks>
 151    /// The underlying stream is closed only if <see cref="IsStreamOwner"/> is true.
 152    /// </remarks>
 153    override public void Close()
 154    {
 155      Stream toClose = stream_;
 156      stream_ = null;
 157      if (isOwner_ && (toClose != null)) {
 158        isOwner_ = false;
 159        toClose.Close();
 160      }
 161    }
 162    #endregion
 163
 164    // Write the local file header
 165    // TODO: ZipHelperStream.WriteLocalHeader is not yet used and needs checking for ZipFile and ZipOuptutStream usage
 166    void WriteLocalHeader(ZipEntry entry, EntryPatchData patchData)
 167    {
 168      CompressionMethod method = entry.CompressionMethod;
 169      bool headerInfoAvailable = true; // How to get this?
 170      bool patchEntryHeader = false;
 171
 172      WriteLEInt(ZipConstants.LocalHeaderSignature);
 173
 174      WriteLEShort(entry.Version);
 175      WriteLEShort(entry.Flags);
 176      WriteLEShort((byte)method);
 177      WriteLEInt((int)entry.DosTime);
 178
 179      if (headerInfoAvailable == true) {
 180        WriteLEInt((int)entry.Crc);
 181        if (entry.LocalHeaderRequiresZip64) {
 182          WriteLEInt(-1);
 183          WriteLEInt(-1);
 184        } else {
 185          WriteLEInt(entry.IsCrypted ? (int)entry.CompressedSize + ZipConstants.CryptoHeaderSize : (int)entry.Compressed
 186          WriteLEInt((int)entry.Size);
 187        }
 188      } else {
 189        if (patchData != null) {
 190          patchData.CrcPatchOffset = stream_.Position;
 191        }
 192        WriteLEInt(0);  // Crc
 193
 194        if (patchData != null) {
 195          patchData.SizePatchOffset = stream_.Position;
 196        }
 197
 198        // For local header both sizes appear in Zip64 Extended Information
 199        if (entry.LocalHeaderRequiresZip64 && patchEntryHeader) {
 200          WriteLEInt(-1);
 201          WriteLEInt(-1);
 202        } else {
 203          WriteLEInt(0);  // Compressed size
 204          WriteLEInt(0);  // Uncompressed size
 205        }
 206      }
 207
 208      byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
 209
 210      if (name.Length > 0xFFFF) {
 211        throw new ZipException("Entry name too long.");
 212      }
 213
 214      var ed = new ZipExtraData(entry.ExtraData);
 215
 216      if (entry.LocalHeaderRequiresZip64 && (headerInfoAvailable || patchEntryHeader)) {
 217        ed.StartNewEntry();
 218        if (headerInfoAvailable) {
 219          ed.AddLeLong(entry.Size);
 220          ed.AddLeLong(entry.CompressedSize);
 221        } else {
 222          ed.AddLeLong(-1);
 223          ed.AddLeLong(-1);
 224        }
 225        ed.AddNewEntry(1);
 226
 227        if (!ed.Find(1)) {
 228          throw new ZipException("Internal error cant find extra data");
 229        }
 230
 231        if (patchData != null) {
 232          patchData.SizePatchOffset = ed.CurrentReadIndex;
 233        }
 234      } else {
 235        ed.Delete(1);
 236      }
 237
 238      byte[] extra = ed.GetEntryData();
 239
 240      WriteLEShort(name.Length);
 241      WriteLEShort(extra.Length);
 242
 243      if (name.Length > 0) {
 244        stream_.Write(name, 0, name.Length);
 245      }
 246
 247      if (entry.LocalHeaderRequiresZip64 && patchEntryHeader) {
 248        patchData.SizePatchOffset += stream_.Position;
 249      }
 250
 251      if (extra.Length > 0) {
 252        stream_.Write(extra, 0, extra.Length);
 253      }
 254    }
 255
 256    /// <summary>
 257    /// Locates a block with the desired <paramref name="signature"/>.
 258    /// </summary>
 259    /// <param name="signature">The signature to find.</param>
 260    /// <param name="endLocation">Location, marking the end of block.</param>
 261    /// <param name="minimumBlockSize">Minimum size of the block.</param>
 262    /// <param name="maximumVariableData">The maximum variable data.</param>
 263    /// <returns>Eeturns the offset of the first byte after the signature; -1 if not found</returns>
 264    public long LocateBlockWithSignature(int signature, long endLocation, int minimumBlockSize, int maximumVariableData)
 265    {
 266      long pos = endLocation - minimumBlockSize;
 267      if (pos < 0) {
 268        return -1;
 269      }
 270
 271      long giveUpMarker = Math.Max(pos - maximumVariableData, 0);
 272
 273      // TODO: This loop could be optimised for speed.
 274      do {
 275        if (pos < giveUpMarker) {
 276          return -1;
 277        }
 278        Seek(pos--, SeekOrigin.Begin);
 279      } while (ReadLEInt() != signature);
 280
 281      return Position;
 282    }
 283
 284    /// <summary>
 285    /// Write Zip64 end of central directory records (File header and locator).
 286    /// </summary>
 287    /// <param name="noOfEntries">The number of entries in the central directory.</param>
 288    /// <param name="sizeEntries">The size of entries in the central directory.</param>
 289    /// <param name="centralDirOffset">The offset of the dentral directory.</param>
 290    public void WriteZip64EndOfCentralDirectory(long noOfEntries, long sizeEntries, long centralDirOffset)
 291    {
 292      long centralSignatureOffset = stream_.Position;
 293      WriteLEInt(ZipConstants.Zip64CentralFileHeaderSignature);
 294      WriteLELong(44);    // Size of this record (total size of remaining fields in header or full size - 12)
 295      WriteLEShort(ZipConstants.VersionMadeBy);   // Version made by
 296      WriteLEShort(ZipConstants.VersionZip64);   // Version to extract
 297      WriteLEInt(0);      // Number of this disk
 298      WriteLEInt(0);      // number of the disk with the start of the central directory
 299      WriteLELong(noOfEntries);       // No of entries on this disk
 300      WriteLELong(noOfEntries);       // Total No of entries in central directory
 301      WriteLELong(sizeEntries);       // Size of the central directory
 302      WriteLELong(centralDirOffset);  // offset of start of central directory
 303                      // zip64 extensible data sector not catered for here (variable size)
 304
 305      // Write the Zip64 end of central directory locator
 306      WriteLEInt(ZipConstants.Zip64CentralDirLocatorSignature);
 307
 308      // no of the disk with the start of the zip64 end of central directory
 309      WriteLEInt(0);
 310
 311      // relative offset of the zip64 end of central directory record
 312      WriteLELong(centralSignatureOffset);
 313
 314      // total number of disks
 315      WriteLEInt(1);
 316    }
 317
 318    /// <summary>
 319    /// Write the required records to end the central directory.
 320    /// </summary>
 321    /// <param name="noOfEntries">The number of entries in the directory.</param>
 322    /// <param name="sizeEntries">The size of the entries in the directory.</param>
 323    /// <param name="startOfCentralDirectory">The start of the central directory.</param>
 324    /// <param name="comment">The archive comment.  (This can be null).</param>
 325    public void WriteEndOfCentralDirectory(long noOfEntries, long sizeEntries,
 326      long startOfCentralDirectory, byte[] comment)
 327    {
 328
 329      if ((noOfEntries >= 0xffff) ||
 330        (startOfCentralDirectory >= 0xffffffff) ||
 331        (sizeEntries >= 0xffffffff)) {
 332        WriteZip64EndOfCentralDirectory(noOfEntries, sizeEntries, startOfCentralDirectory);
 333      }
 334
 335      WriteLEInt(ZipConstants.EndOfCentralDirectorySignature);
 336
 337      // TODO: ZipFile Multi disk handling not done
 338      WriteLEShort(0);                    // number of this disk
 339      WriteLEShort(0);                    // no of disk with start of central dir
 340
 341
 342      // Number of entries
 343      if (noOfEntries >= 0xffff) {
 344        WriteLEUshort(0xffff);  // Zip64 marker
 345        WriteLEUshort(0xffff);
 346      } else {
 347        WriteLEShort((short)noOfEntries);          // entries in central dir for this disk
 348        WriteLEShort((short)noOfEntries);          // total entries in central directory
 349      }
 350
 351      // Size of the central directory
 352      if (sizeEntries >= 0xffffffff) {
 353        WriteLEUint(0xffffffff);    // Zip64 marker
 354      } else {
 355        WriteLEInt((int)sizeEntries);
 356      }
 357
 358
 359      // offset of start of central directory
 360      if (startOfCentralDirectory >= 0xffffffff) {
 361        WriteLEUint(0xffffffff);    // Zip64 marker
 362      } else {
 363        WriteLEInt((int)startOfCentralDirectory);
 364      }
 365
 366      int commentLength = (comment != null) ? comment.Length : 0;
 367
 368      if (commentLength > 0xffff) {
 369        throw new ZipException(string.Format("Comment length({0}) is too long can only be 64K", commentLength));
 370      }
 371
 372      WriteLEShort(commentLength);
 373
 374      if (commentLength > 0) {
 375        Write(comment, 0, comment.Length);
 376      }
 377    }
 378
 379    #region LE value reading/writing
 380    /// <summary>
 381    /// Read an unsigned short in little endian byte order.
 382    /// </summary>
 383    /// <returns>Returns the value read.</returns>
 384    /// <exception cref="IOException">
 385    /// An i/o error occurs.
 386    /// </exception>
 387    /// <exception cref="EndOfStreamException">
 388    /// The file ends prematurely
 389    /// </exception>
 390    public int ReadLEShort()
 391    {
 392      int byteValue1 = stream_.ReadByte();
 393
 394      if (byteValue1 < 0) {
 395        throw new EndOfStreamException();
 396      }
 397
 398      int byteValue2 = stream_.ReadByte();
 399      if (byteValue2 < 0) {
 400        throw new EndOfStreamException();
 401      }
 402
 403      return byteValue1 | (byteValue2 << 8);
 404    }
 405
 406    /// <summary>
 407    /// Read an int in little endian byte order.
 408    /// </summary>
 409    /// <returns>Returns the value read.</returns>
 410    /// <exception cref="IOException">
 411    /// An i/o error occurs.
 412    /// </exception>
 413    /// <exception cref="System.IO.EndOfStreamException">
 414    /// The file ends prematurely
 415    /// </exception>
 416    public int ReadLEInt()
 417    {
 418      return ReadLEShort() | (ReadLEShort() << 16);
 419    }
 420
 421    /// <summary>
 422    /// Read a long in little endian byte order.
 423    /// </summary>
 424    /// <returns>The value read.</returns>
 425    public long ReadLELong()
 426    {
 427      return (uint)ReadLEInt() | ((long)ReadLEInt() << 32);
 428    }
 429
 430    /// <summary>
 431    /// Write an unsigned short in little endian byte order.
 432    /// </summary>
 433    /// <param name="value">The value to write.</param>
 434    public void WriteLEShort(int value)
 435    {
 436      stream_.WriteByte((byte)(value & 0xff));
 437      stream_.WriteByte((byte)((value >> 8) & 0xff));
 438    }
 439
 440    /// <summary>
 441    /// Write a ushort in little endian byte order.
 442    /// </summary>
 443    /// <param name="value">The value to write.</param>
 444    public void WriteLEUshort(ushort value)
 445    {
 446      stream_.WriteByte((byte)(value & 0xff));
 447      stream_.WriteByte((byte)(value >> 8));
 448    }
 449
 450    /// <summary>
 451    /// Write an int in little endian byte order.
 452    /// </summary>
 453    /// <param name="value">The value to write.</param>
 454    public void WriteLEInt(int value)
 455    {
 456      WriteLEShort(value);
 457      WriteLEShort(value >> 16);
 458    }
 459
 460    /// <summary>
 461    /// Write a uint in little endian byte order.
 462    /// </summary>
 463    /// <param name="value">The value to write.</param>
 464    public void WriteLEUint(uint value)
 465    {
 466      WriteLEUshort((ushort)(value & 0xffff));
 467      WriteLEUshort((ushort)(value >> 16));
 468    }
 469
 470    /// <summary>
 471    /// Write a long in little endian byte order.
 472    /// </summary>
 473    /// <param name="value">The value to write.</param>
 474    public void WriteLELong(long value)
 475    {
 476      WriteLEInt((int)value);
 477      WriteLEInt((int)(value >> 32));
 478    }
 479
 480    /// <summary>
 481    /// Write a ulong in little endian byte order.
 482    /// </summary>
 483    /// <param name="value">The value to write.</param>
 484    public void WriteLEUlong(ulong value)
 485    {
 486      WriteLEUint((uint)(value & 0xffffffff));
 487      WriteLEUint((uint)(value >> 32));
 488    }
 489
 490    #endregion
 491
 492    /// <summary>
 493    /// Write a data descriptor.
 494    /// </summary>
 495    /// <param name="entry">The entry to write a descriptor for.</param>
 496    /// <returns>Returns the number of descriptor bytes written.</returns>
 497    public int WriteDataDescriptor(ZipEntry entry)
 498    {
 499      if (entry == null) {
 500        throw new ArgumentNullException(nameof(entry));
 501      }
 502
 503      int result = 0;
 504
 505      // Add data descriptor if flagged as required
 506      if ((entry.Flags & (int)GeneralBitFlags.Descriptor) != 0) {
 507        // The signature is not PKZIP originally but is now described as optional
 508        // in the PKZIP Appnote documenting trhe format.
 509        WriteLEInt(ZipConstants.DataDescriptorSignature);
 510        WriteLEInt(unchecked((int)(entry.Crc)));
 511
 512        result += 8;
 513
 514        if (entry.LocalHeaderRequiresZip64) {
 515          WriteLELong(entry.CompressedSize);
 516          WriteLELong(entry.Size);
 517          result += 16;
 518        } else {
 519          WriteLEInt((int)entry.CompressedSize);
 520          WriteLEInt((int)entry.Size);
 521          result += 8;
 522        }
 523      }
 524
 525      return result;
 526    }
 527
 528    /// <summary>
 529    /// Read data descriptor at the end of compressed data.
 530    /// </summary>
 531    /// <param name="zip64">if set to <c>true</c> [zip64].</param>
 532    /// <param name="data">The data to fill in.</param>
 533    /// <returns>Returns the number of bytes read in the descriptor.</returns>
 534    public void ReadDataDescriptor(bool zip64, DescriptorData data)
 535    {
 536      int intValue = ReadLEInt();
 537
 538      // In theory this may not be a descriptor according to PKZIP appnote.
 539      // In practise its always there.
 540      if (intValue != ZipConstants.DataDescriptorSignature) {
 541        throw new ZipException("Data descriptor signature not found");
 542      }
 543
 544      data.Crc = ReadLEInt();
 545
 546      if (zip64) {
 547        data.CompressedSize = ReadLELong();
 548        data.Size = ReadLELong();
 549      } else {
 550        data.CompressedSize = ReadLEInt();
 551        data.Size = ReadLEInt();
 552      }
 553    }
 554
 555    #region Instance Fields
 556    bool isOwner_;
 557    Stream stream_;
 558    #endregion
 559  }
 560}