diff --git a/3177.pdf b/3177.pdf
new file mode 100644
index 0000000..fe3b522
Binary files /dev/null and b/3177.pdf differ
diff --git a/3178.pdf b/3178.pdf
new file mode 100644
index 0000000..1d57503
Binary files /dev/null and b/3178.pdf differ
diff --git a/3502.html b/3502.html
new file mode 100644
index 0000000..ab53ab5
--- /dev/null
+++ b/3502.html
@@ -0,0 +1,146 @@
+
+
+
+
+
+
+
+
+Errata
+
+
+
+
+
+
+
+
+
+
+
+
Errata
+
+
Pro BizTalk 2006
+
+
1590596994
+
+
+
+
Note from author, George Dunphy:
+
+
+
+
“For requests related to the database disassembler
+in chapter 5, please inform people that we had to remove the code for the
+application due to an issue discovered after the book was released. I am
+planning on updating the samples when the errata is
+released in the coming months.”
needsInput() returns true because the input buffer is empty.
+ /// You have to provide more input with setInput().
+ /// NOTE: needsInput() also returns true when, the stream is finished.
+ ///
+ ///
needsDictionary() returns true, you have to provide a preset
+ /// dictionary with setDictionary().
+ ///
finished() returns true, the inflater has finished.
+ ///
+ /// Once the first output byte is produced, a dictionary will not be
+ /// needed at a later stage.
+ ///
+ /// author of the original java version : John Leuner, Jochen Hoenicke
+ ///
+ public class Inflater
+ {
+ ///
+ /// Copy lengths for literal codes 257..285
+ ///
+ static int[] CPLENS = {
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258
+ };
+
+ ///
+ /// Extra bits for literal codes 257..285
+ ///
+ static int[] CPLEXT = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
+ };
+
+ ///
+ /// Copy offsets for distance codes 0..29
+ ///
+ static int[] CPDIST = {
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577
+ };
+
+ ///
+ /// Extra bits for distance codes
+ ///
+ static int[] CPDEXT = {
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+ 12, 12, 13, 13
+ };
+
+ ///
+ /// These are the possible states for an inflater
+ ///
+ const int DECODE_HEADER = 0;
+ const int DECODE_DICT = 1;
+ const int DECODE_BLOCKS = 2;
+ const int DECODE_STORED_LEN1 = 3;
+ const int DECODE_STORED_LEN2 = 4;
+ const int DECODE_STORED = 5;
+ const int DECODE_DYN_HEADER = 6;
+ const int DECODE_HUFFMAN = 7;
+ const int DECODE_HUFFMAN_LENBITS = 8;
+ const int DECODE_HUFFMAN_DIST = 9;
+ const int DECODE_HUFFMAN_DISTBITS = 10;
+ const int DECODE_CHKSUM = 11;
+ const int FINISHED = 12;
+
+ ///
+ /// This variable contains the current state.
+ ///
+ int mode;
+
+ ///
+ /// The adler checksum of the dictionary or of the decompressed
+ /// stream, as it is written in the header resp. footer of the
+ /// compressed stream.
+ /// Only valid if mode is DECODE_DICT or DECODE_CHKSUM.
+ ///
+ int readAdler;
+
+ ///
+ /// The number of bits needed to complete the current state. This
+ /// is valid, if mode is DECODE_DICT, DECODE_CHKSUM,
+ /// DECODE_HUFFMAN_LENBITS or DECODE_HUFFMAN_DISTBITS.
+ ///
+ int neededBits;
+ int repLength;
+ int repDist;
+ int uncomprLen;
+
+ ///
+ /// True, if the last block flag was set in the last block of the
+ /// inflated stream. This means that the stream ends after the
+ /// current block.
+ ///
+ bool isLastBlock;
+
+ ///
+ /// The total number of inflated bytes.
+ ///
+ int totalOut;
+
+ ///
+ /// The total number of bytes set with setInput(). This is not the
+ /// value returned by the TotalIn property, since this also includes the
+ /// unprocessed input.
+ ///
+ int totalIn;
+
+ ///
+ /// This variable stores the noHeader flag that was given to the constructor.
+ /// True means, that the inflated stream doesn't contain a Zlib header or
+ /// footer.
+ ///
+ bool noHeader;
+
+ StreamManipulator input;
+ OutputWindow outputWindow;
+ InflaterDynHeader dynHeader;
+ InflaterHuffmanTree litlenTree, distTree;
+ Adler32 adler;
+
+ ///
+ /// Creates a new inflater or RFC1951 decompressor
+ /// RFC1950/Zlib headers and footers will be expected in the input data
+ ///
+ public Inflater() : this(false)
+ {
+ }
+
+ ///
+ /// Creates a new inflater.
+ ///
+ ///
+ /// True if no RFC1950/Zlib header and footer fields are expected in the input data
+ ///
+ /// This is used for GZIPed/Zipped input.
+ ///
+ /// For compatibility with
+ /// Sun JDK you should provide one byte of input more than needed in
+ /// this case.
+ ///
+ public Inflater(bool noHeader)
+ {
+ this.noHeader = noHeader;
+ this.adler = new Adler32();
+ input = new StreamManipulator();
+ outputWindow = new OutputWindow();
+ mode = noHeader ? DECODE_BLOCKS : DECODE_HEADER;
+ }
+
+ ///
+ /// Resets the inflater so that a new stream can be decompressed. All
+ /// pending input and output will be discarded.
+ ///
+ public void Reset()
+ {
+ mode = noHeader ? DECODE_BLOCKS : DECODE_HEADER;
+ totalIn = totalOut = 0;
+ input.Reset();
+ outputWindow.Reset();
+ dynHeader = null;
+ litlenTree = null;
+ distTree = null;
+ isLastBlock = false;
+ adler.Reset();
+ }
+
+ ///
+ /// Decodes a zlib/RFC1950 header.
+ ///
+ ///
+ /// False if more input is needed.
+ ///
+ ///
+ /// The header is invalid.
+ ///
+ private bool DecodeHeader()
+ {
+ int header = input.PeekBits(16);
+ if (header < 0) {
+ return false;
+ }
+ input.DropBits(16);
+
+ /* The header is written in "wrong" byte order */
+ header = ((header << 8) | (header >> 8)) & 0xffff;
+ if (header % 31 != 0) {
+ throw new ApplicationException("Header checksum illegal");
+ }
+
+ if ((header & 0x0f00) != (Deflater.DEFLATED << 8)) {
+ throw new ApplicationException("Compression Method unknown");
+ }
+
+ /* Maximum size of the backwards window in bits.
+ * We currently ignore this, but we could use it to make the
+ * inflater window more space efficient. On the other hand the
+ * full window (15 bits) is needed most times, anyway.
+ int max_wbits = ((header & 0x7000) >> 12) + 8;
+ */
+
+ if ((header & 0x0020) == 0) { // Dictionary flag?
+ mode = DECODE_BLOCKS;
+ } else {
+ mode = DECODE_DICT;
+ neededBits = 32;
+ }
+ return true;
+ }
+
+ ///
+ /// Decodes the dictionary checksum after the deflate header.
+ ///
+ ///
+ /// False if more input is needed.
+ ///
+ private bool DecodeDict()
+ {
+ while (neededBits > 0) {
+ int dictByte = input.PeekBits(8);
+ if (dictByte < 0) {
+ return false;
+ }
+ input.DropBits(8);
+ readAdler = (readAdler << 8) | dictByte;
+ neededBits -= 8;
+ }
+ return false;
+ }
+
+ ///
+ /// Decodes the huffman encoded symbols in the input stream.
+ ///
+ ///
+ /// false if more input is needed, true if output window is
+ /// full or the current block ends.
+ ///
+ ///
+ /// if deflated stream is invalid.
+ ///
+ private bool DecodeHuffman()
+ {
+ int free = outputWindow.GetFreeSpace();
+ while (free >= 258) {
+ int symbol;
+ switch (mode) {
+ case DECODE_HUFFMAN:
+ /* This is the inner loop so it is optimized a bit */
+ while (((symbol = litlenTree.GetSymbol(input)) & ~0xff) == 0) {
+ outputWindow.Write(symbol);
+ if (--free < 258) {
+ return true;
+ }
+ }
+
+ if (symbol < 257) {
+ if (symbol < 0) {
+ return false;
+ } else {
+ /* symbol == 256: end of block */
+ distTree = null;
+ litlenTree = null;
+ mode = DECODE_BLOCKS;
+ return true;
+ }
+ }
+
+ try {
+ repLength = CPLENS[symbol - 257];
+ neededBits = CPLEXT[symbol - 257];
+ } catch (Exception) {
+ throw new ApplicationException("Illegal rep length code");
+ }
+ goto case DECODE_HUFFMAN_LENBITS; /* fall through */
+
+ case DECODE_HUFFMAN_LENBITS:
+ if (neededBits > 0) {
+ mode = DECODE_HUFFMAN_LENBITS;
+ int i = input.PeekBits(neededBits);
+ if (i < 0) {
+ return false;
+ }
+ input.DropBits(neededBits);
+ repLength += i;
+ }
+ mode = DECODE_HUFFMAN_DIST;
+ goto case DECODE_HUFFMAN_DIST;/* fall through */
+
+ case DECODE_HUFFMAN_DIST:
+ symbol = distTree.GetSymbol(input);
+ if (symbol < 0) {
+ return false;
+ }
+
+ try {
+ repDist = CPDIST[symbol];
+ neededBits = CPDEXT[symbol];
+ } catch (Exception) {
+ throw new ApplicationException("Illegal rep dist code");
+ }
+
+ goto case DECODE_HUFFMAN_DISTBITS;/* fall through */
+
+ case DECODE_HUFFMAN_DISTBITS:
+ if (neededBits > 0) {
+ mode = DECODE_HUFFMAN_DISTBITS;
+ int i = input.PeekBits(neededBits);
+ if (i < 0) {
+ return false;
+ }
+ input.DropBits(neededBits);
+ repDist += i;
+ }
+
+ outputWindow.Repeat(repLength, repDist);
+ free -= repLength;
+ mode = DECODE_HUFFMAN;
+ break;
+
+ default:
+ throw new ApplicationException("Inflater unknown mode");
+ }
+ }
+ return true;
+ }
+
+ ///
+ /// Decodes the adler checksum after the deflate stream.
+ ///
+ ///
+ /// false if more input is needed.
+ ///
+ ///
+ /// If checksum doesn't match.
+ ///
+ private bool DecodeChksum()
+ {
+ while (neededBits > 0) {
+ int chkByte = input.PeekBits(8);
+ if (chkByte < 0) {
+ return false;
+ }
+ input.DropBits(8);
+ readAdler = (readAdler << 8) | chkByte;
+ neededBits -= 8;
+ }
+ if ((int) adler.Value != readAdler) {
+ throw new ApplicationException("Adler chksum doesn't match: " + (int)adler.Value + " vs. " + readAdler);
+ }
+ mode = FINISHED;
+ return false;
+ }
+
+ ///
+ /// Decodes the deflated stream.
+ ///
+ ///
+ /// false if more input is needed, or if finished.
+ ///
+ ///
+ /// ApplicationException, if deflated stream is invalid.
+ ///
+ private bool Decode()
+ {
+ switch (mode) {
+ case DECODE_HEADER:
+ return DecodeHeader();
+ case DECODE_DICT:
+ return DecodeDict();
+ case DECODE_CHKSUM:
+ return DecodeChksum();
+
+ case DECODE_BLOCKS:
+ if (isLastBlock) {
+ if (noHeader) {
+ mode = FINISHED;
+ return false;
+ } else {
+ input.SkipToByteBoundary();
+ neededBits = 32;
+ mode = DECODE_CHKSUM;
+ return true;
+ }
+ }
+
+ int type = input.PeekBits(3);
+ if (type < 0) {
+ return false;
+ }
+ input.DropBits(3);
+
+ if ((type & 1) != 0) {
+ isLastBlock = true;
+ }
+ switch (type >> 1){
+ case DeflaterConstants.STORED_BLOCK:
+ input.SkipToByteBoundary();
+ mode = DECODE_STORED_LEN1;
+ break;
+ case DeflaterConstants.STATIC_TREES:
+ litlenTree = InflaterHuffmanTree.defLitLenTree;
+ distTree = InflaterHuffmanTree.defDistTree;
+ mode = DECODE_HUFFMAN;
+ break;
+ case DeflaterConstants.DYN_TREES:
+ dynHeader = new InflaterDynHeader();
+ mode = DECODE_DYN_HEADER;
+ break;
+ default:
+ throw new ApplicationException("Unknown block type " + type);
+ }
+ return true;
+
+ case DECODE_STORED_LEN1:
+ {
+ if ((uncomprLen = input.PeekBits(16)) < 0) {
+ return false;
+ }
+ input.DropBits(16);
+ mode = DECODE_STORED_LEN2;
+ }
+ goto case DECODE_STORED_LEN2; /* fall through */
+
+ case DECODE_STORED_LEN2:
+ {
+ int nlen = input.PeekBits(16);
+ if (nlen < 0) {
+ return false;
+ }
+ input.DropBits(16);
+ if (nlen != (uncomprLen ^ 0xffff)) {
+ throw new ApplicationException("broken uncompressed block");
+ }
+ mode = DECODE_STORED;
+ }
+ goto case DECODE_STORED;/* fall through */
+
+ case DECODE_STORED:
+ {
+ int more = outputWindow.CopyStored(input, uncomprLen);
+ uncomprLen -= more;
+ if (uncomprLen == 0) {
+ mode = DECODE_BLOCKS;
+ return true;
+ }
+ return !input.IsNeedingInput;
+ }
+
+ case DECODE_DYN_HEADER:
+ if (!dynHeader.Decode(input)) {
+ return false;
+ }
+
+ litlenTree = dynHeader.BuildLitLenTree();
+ distTree = dynHeader.BuildDistTree();
+ mode = DECODE_HUFFMAN;
+ goto case DECODE_HUFFMAN; /* fall through */
+
+ case DECODE_HUFFMAN:
+ case DECODE_HUFFMAN_LENBITS:
+ case DECODE_HUFFMAN_DIST:
+ case DECODE_HUFFMAN_DISTBITS:
+ return DecodeHuffman();
+
+ case FINISHED:
+ return false;
+
+ default:
+ throw new ApplicationException("Inflater.Decode unknown mode");
+ }
+ }
+
+ ///
+ /// Sets the preset dictionary. This should only be called, if
+ /// needsDictionary() returns true and it should set the same
+ /// dictionary, that was used for deflating. The getAdler()
+ /// function returns the checksum of the dictionary needed.
+ ///
+ ///
+ /// The dictionary.
+ ///
+ ///
+ /// No dictionary is needed.
+ ///
+ ///
+ /// if the dictionary checksum is wrong.
+ ///
+ public void SetDictionary(byte[] buffer)
+ {
+ SetDictionary(buffer, 0, buffer.Length);
+ }
+
+ ///
+ /// Sets the preset dictionary. This should only be called, if
+ /// needsDictionary() returns true and it should set the same
+ /// dictionary, that was used for deflating. The getAdler()
+ /// function returns the checksum of the dictionary needed.
+ ///
+ ///
+ /// The dictionary.
+ ///
+ ///
+ /// The offset into buffer where the dictionary starts.
+ ///
+ ///
+ /// The length of the dictionary.
+ ///
+ ///
+ /// No dictionary is needed.
+ ///
+ ///
+ /// The adler checksum for the buffer is invalid
+ ///
+ public void SetDictionary(byte[] buffer, int offset, int len)
+ {
+ if (!IsNeedingDictionary) {
+ throw new InvalidOperationException();
+ }
+
+ adler.Update(buffer, offset, len);
+ if ((int)adler.Value != readAdler) {
+ throw new ApplicationException("Wrong adler checksum");
+ }
+ adler.Reset();
+ outputWindow.CopyDict(buffer, offset, len);
+ mode = DECODE_BLOCKS;
+ }
+
+ ///
+ /// Sets the input. This should only be called, if needsInput()
+ /// returns true.
+ ///
+ ///
+ /// the input.
+ ///
+ ///
+ /// if no input is needed.
+ ///
+ public void SetInput(byte[] buf)
+ {
+ SetInput(buf, 0, buf.Length);
+ }
+
+ ///
+ /// Sets the input. This should only be called, if needsInput()
+ /// returns true.
+ ///
+ ///
+ /// The source of input data
+ ///
+ ///
+ /// The offset into buffer where the input starts.
+ ///
+ ///
+ /// The number of bytes of input to use.
+ ///
+ ///
+ /// No input is needed.
+ ///
+ ///
+ /// The off and/or len are wrong.
+ ///
+ public void SetInput(byte[] buffer, int offset, int length)
+ {
+ input.SetInput(buffer, offset, length);
+ totalIn += length;
+ }
+
+ ///
+ /// Inflates the compressed stream to the output buffer. If this
+ /// returns 0, you should check, whether needsDictionary(),
+ /// needsInput() or finished() returns true, to determine why no
+ /// further output is produced.
+ ///
+ ///
+ /// the output buffer.
+ ///
+ ///
+ /// the number of bytes written to the buffer, 0 if no further
+ /// output can be produced.
+ ///
+ ///
+ /// if buf has length 0.
+ ///
+ ///
+ /// if deflated stream is invalid.
+ ///
+ public int Inflate(byte[] buf)
+ {
+ return Inflate(buf, 0, buf.Length);
+ }
+
+ ///
+ /// Inflates the compressed stream to the output buffer. If this
+ /// returns 0, you should check, whether needsDictionary(),
+ /// needsInput() or finished() returns true, to determine why no
+ /// further output is produced.
+ ///
+ ///
+ /// the output buffer.
+ ///
+ ///
+ /// the offset into buffer where the output should start.
+ ///
+ ///
+ /// the maximum length of the output.
+ ///
+ ///
+ /// the number of bytes written to the buffer, 0 if no further output can be produced.
+ ///
+ ///
+ /// if len is <= 0.
+ ///
+ ///
+ /// if the offset and/or len are wrong.
+ ///
+ ///
+ /// if deflated stream is invalid.
+ ///
+ public int Inflate(byte[] buf, int offset, int len)
+ {
+ if (len < 0) {
+ throw new ArgumentOutOfRangeException("len < 0");
+ }
+
+ // Special case: len may be zero
+ if (len == 0) {
+ if (IsFinished == false) {// -jr- 08-Nov-2003 INFLATE_BUG fix..
+ Decode();
+ }
+ return 0;
+ }
+/*
+ // Check for correct buff, off, len triple
+ if (off < 0 || off + len >= buf.Length) {
+ throw new ArgumentException("off/len outside buf bounds");
+ }
+*/
+ int count = 0;
+ int more;
+ do {
+ if (mode != DECODE_CHKSUM) {
+ /* Don't give away any output, if we are waiting for the
+ * checksum in the input stream.
+ *
+ * With this trick we have always:
+ * needsInput() and not finished()
+ * implies more output can be produced.
+ */
+ more = outputWindow.CopyOutput(buf, offset, len);
+ adler.Update(buf, offset, more);
+ offset += more;
+ count += more;
+ totalOut += more;
+ len -= more;
+ if (len == 0) {
+ return count;
+ }
+ }
+ } while (Decode() || (outputWindow.GetAvailable() > 0 && mode != DECODE_CHKSUM));
+ return count;
+ }
+
+ ///
+ /// Returns true, if the input buffer is empty.
+ /// You should then call setInput().
+ /// NOTE: This method also returns true when the stream is finished.
+ ///
+ public bool IsNeedingInput {
+ get {
+ return input.IsNeedingInput;
+ }
+ }
+
+ ///
+ /// Returns true, if a preset dictionary is needed to inflate the input.
+ ///
+ public bool IsNeedingDictionary {
+ get {
+ return mode == DECODE_DICT && neededBits == 0;
+ }
+ }
+
+ ///
+ /// Returns true, if the inflater has finished. This means, that no
+ /// input is needed and no output can be produced.
+ ///
+ public bool IsFinished {
+ get {
+ return mode == FINISHED && outputWindow.GetAvailable() == 0;
+ }
+ }
+
+ ///
+ /// Gets the adler checksum. This is either the checksum of all
+ /// uncompressed bytes returned by inflate(), or if needsDictionary()
+ /// returns true (and thus no output was yet produced) this is the
+ /// adler checksum of the expected dictionary.
+ ///
+ ///
+ /// the adler checksum.
+ ///
+ public int Adler {
+ get {
+ return IsNeedingDictionary ? readAdler : (int) adler.Value;
+ }
+ }
+
+ ///
+ /// Gets the total number of output bytes returned by inflate().
+ ///
+ ///
+ /// the total number of output bytes.
+ ///
+ public int TotalOut {
+ get {
+ return totalOut;
+ }
+ }
+
+ ///
+ /// Gets the total number of processed compressed input bytes.
+ ///
+ ///
+ /// The total number of bytes of processed input bytes.
+ ///
+ public int TotalIn {
+ get {
+ return totalIn - RemainingInput;
+ }
+ }
+
+#if TEST_HAK
+ ///
+ /// -jr test hak trying to figure out a bug
+ ///
+ public int UnseenInput {
+ get {
+ return totalIn - ((input.AvailableBits + 7) >> 3);
+ }
+ }
+
+ ///
+ /// -jr test hak trying to figure out a bug
+ ///
+ public int PlainTotalIn {
+ get {
+ return totalIn;
+ }
+ }
+#endif
+
+ ///
+ /// Gets the number of unprocessed input bytes. Useful, if the end of the
+ /// stream is reached and you want to further process the bytes after
+ /// the deflate stream.
+ ///
+ ///
+ /// The number of bytes of the input which have not been processed.
+ ///
+ public int RemainingInput {
+ get {
+ return input.AvailableBytes;
+ }
+ }
+ }
+}
diff --git a/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/Compression/InflaterDynHeader.cs b/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/Compression/InflaterDynHeader.cs
new file mode 100644
index 0000000..ad90558
--- /dev/null
+++ b/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/Compression/InflaterDynHeader.cs
@@ -0,0 +1,207 @@
+// InflaterDynHeader.cs
+// Copyright (C) 2001 Mike Krueger
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+
+using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
+
+namespace ICSharpCode.SharpZipLib.Zip.Compression
+{
+
+ class InflaterDynHeader
+ {
+ const int LNUM = 0;
+ const int DNUM = 1;
+ const int BLNUM = 2;
+ const int BLLENS = 3;
+ const int LENS = 4;
+ const int REPS = 5;
+
+ static readonly int[] repMin = { 3, 3, 11 };
+ static readonly int[] repBits = { 2, 3, 7 };
+
+ byte[] blLens;
+ byte[] litdistLens;
+
+ InflaterHuffmanTree blTree;
+
+ int mode;
+ int lnum, dnum, blnum, num;
+ int repSymbol;
+ byte lastLen;
+ int ptr;
+
+ static readonly int[] BL_ORDER =
+ { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
+
+ public InflaterDynHeader()
+ {
+ }
+
+ public bool Decode(StreamManipulator input)
+ {
+ decode_loop:
+ for (;;) {
+ switch (mode) {
+ case LNUM:
+ lnum = input.PeekBits(5);
+ if (lnum < 0) {
+ return false;
+ }
+ lnum += 257;
+ input.DropBits(5);
+ // System.err.println("LNUM: "+lnum);
+ mode = DNUM;
+ goto case DNUM; // fall through
+ case DNUM:
+ dnum = input.PeekBits(5);
+ if (dnum < 0) {
+ return false;
+ }
+ dnum++;
+ input.DropBits(5);
+ // System.err.println("DNUM: "+dnum);
+ num = lnum+dnum;
+ litdistLens = new byte[num];
+ mode = BLNUM;
+ goto case BLNUM; // fall through
+ case BLNUM:
+ blnum = input.PeekBits(4);
+ if (blnum < 0) {
+ return false;
+ }
+ blnum += 4;
+ input.DropBits(4);
+ blLens = new byte[19];
+ ptr = 0;
+ // System.err.println("BLNUM: "+blnum);
+ mode = BLLENS;
+ goto case BLLENS; // fall through
+ case BLLENS:
+ while (ptr < blnum) {
+ int len = input.PeekBits(3);
+ if (len < 0) {
+ return false;
+ }
+ input.DropBits(3);
+ // System.err.println("blLens["+BL_ORDER[ptr]+"]: "+len);
+ blLens[BL_ORDER[ptr]] = (byte) len;
+ ptr++;
+ }
+ blTree = new InflaterHuffmanTree(blLens);
+ blLens = null;
+ ptr = 0;
+ mode = LENS;
+ goto case LENS; // fall through
+ case LENS:
+ {
+ int symbol;
+ while (((symbol = blTree.GetSymbol(input)) & ~15) == 0) {
+ /* Normal case: symbol in [0..15] */
+
+ // System.err.println("litdistLens["+ptr+"]: "+symbol);
+ litdistLens[ptr++] = lastLen = (byte)symbol;
+
+ if (ptr == num) {
+ /* Finished */
+ return true;
+ }
+ }
+
+ /* need more input ? */
+ if (symbol < 0) {
+ return false;
+ }
+
+ /* otherwise repeat code */
+ if (symbol >= 17) {
+ /* repeat zero */
+ // System.err.println("repeating zero");
+ lastLen = 0;
+ } else {
+ if (ptr == 0) {
+ throw new Exception();
+ }
+ }
+ repSymbol = symbol-16;
+ }
+ mode = REPS;
+ goto case REPS; // fall through
+ case REPS:
+ {
+ int bits = repBits[repSymbol];
+ int count = input.PeekBits(bits);
+ if (count < 0) {
+ return false;
+ }
+ input.DropBits(bits);
+ count += repMin[repSymbol];
+ // System.err.println("litdistLens repeated: "+count);
+
+ if (ptr + count > num) {
+ throw new Exception();
+ }
+ while (count-- > 0) {
+ litdistLens[ptr++] = lastLen;
+ }
+
+ if (ptr == num) {
+ /* Finished */
+ return true;
+ }
+ }
+ mode = LENS;
+ goto decode_loop;
+ }
+ }
+ }
+
+ public InflaterHuffmanTree BuildLitLenTree()
+ {
+ byte[] litlenLens = new byte[lnum];
+ Array.Copy(litdistLens, 0, litlenLens, 0, lnum);
+ return new InflaterHuffmanTree(litlenLens);
+ }
+
+ public InflaterHuffmanTree BuildDistTree()
+ {
+ byte[] distLens = new byte[dnum];
+ Array.Copy(litdistLens, lnum, distLens, 0, dnum);
+ return new InflaterHuffmanTree(distLens);
+ }
+ }
+}
diff --git a/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/Compression/InflaterHuffmanTree.cs b/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/Compression/InflaterHuffmanTree.cs
new file mode 100644
index 0000000..1984932
--- /dev/null
+++ b/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/Compression/InflaterHuffmanTree.cs
@@ -0,0 +1,225 @@
+// InflaterHuffmanTree.cs
+// Copyright (C) 2001 Mike Krueger
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+
+using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
+
+namespace ICSharpCode.SharpZipLib.Zip.Compression
+{
+
+ ///
+ /// Huffman tree used for inflation
+ ///
+ public class InflaterHuffmanTree
+ {
+ static int MAX_BITLEN = 15;
+ short[] tree;
+
+ ///
+ /// Literal length tree
+ ///
+ public static InflaterHuffmanTree defLitLenTree;
+
+ ///
+ /// Distance tree
+ ///
+ public static InflaterHuffmanTree defDistTree;
+
+ static InflaterHuffmanTree()
+ {
+ try {
+ byte[] codeLengths = new byte[288];
+ int i = 0;
+ while (i < 144) {
+ codeLengths[i++] = 8;
+ }
+ while (i < 256) {
+ codeLengths[i++] = 9;
+ }
+ while (i < 280) {
+ codeLengths[i++] = 7;
+ }
+ while (i < 288) {
+ codeLengths[i++] = 8;
+ }
+ defLitLenTree = new InflaterHuffmanTree(codeLengths);
+
+ codeLengths = new byte[32];
+ i = 0;
+ while (i < 32) {
+ codeLengths[i++] = 5;
+ }
+ defDistTree = new InflaterHuffmanTree(codeLengths);
+ } catch (Exception) {
+ throw new ApplicationException("InflaterHuffmanTree: static tree length illegal");
+ }
+ }
+
+ ///
+ /// Constructs a Huffman tree from the array of code lengths.
+ ///
+ ///
+ /// the array of code lengths
+ ///
+ public InflaterHuffmanTree(byte[] codeLengths)
+ {
+ BuildTree(codeLengths);
+ }
+
+ void BuildTree(byte[] codeLengths)
+ {
+ int[] blCount = new int[MAX_BITLEN + 1];
+ int[] nextCode = new int[MAX_BITLEN + 1];
+
+ for (int i = 0; i < codeLengths.Length; i++) {
+ int bits = codeLengths[i];
+ if (bits > 0) {
+ blCount[bits]++;
+ }
+ }
+
+ int code = 0;
+ int treeSize = 512;
+ for (int bits = 1; bits <= MAX_BITLEN; bits++) {
+ nextCode[bits] = code;
+ code += blCount[bits] << (16 - bits);
+ if (bits >= 10) {
+ /* We need an extra table for bit lengths >= 10. */
+ int start = nextCode[bits] & 0x1ff80;
+ int end = code & 0x1ff80;
+ treeSize += (end - start) >> (16 - bits);
+ }
+ }
+
+/* -jr comment this out! doesnt work for dynamic trees and pkzip 2.04g
+ if (code != 65536)
+ {
+ throw new Exception("Code lengths don't add up properly.");
+ }
+*/
+ /* Now create and fill the extra tables from longest to shortest
+ * bit len. This way the sub trees will be aligned.
+ */
+ tree = new short[treeSize];
+ int treePtr = 512;
+ for (int bits = MAX_BITLEN; bits >= 10; bits--) {
+ int end = code & 0x1ff80;
+ code -= blCount[bits] << (16 - bits);
+ int start = code & 0x1ff80;
+ for (int i = start; i < end; i += 1 << 7) {
+ tree[DeflaterHuffman.BitReverse(i)] = (short) ((-treePtr << 4) | bits);
+ treePtr += 1 << (bits-9);
+ }
+ }
+
+ for (int i = 0; i < codeLengths.Length; i++) {
+ int bits = codeLengths[i];
+ if (bits == 0) {
+ continue;
+ }
+ code = nextCode[bits];
+ int revcode = DeflaterHuffman.BitReverse(code);
+ if (bits <= 9) {
+ do {
+ tree[revcode] = (short) ((i << 4) | bits);
+ revcode += 1 << bits;
+ } while (revcode < 512);
+ } else {
+ int subTree = tree[revcode & 511];
+ int treeLen = 1 << (subTree & 15);
+ subTree = -(subTree >> 4);
+ do {
+ tree[subTree | (revcode >> 9)] = (short) ((i << 4) | bits);
+ revcode += 1 << bits;
+ } while (revcode < treeLen);
+ }
+ nextCode[bits] = code + (1 << (16 - bits));
+ }
+
+ }
+
+ ///
+ /// Reads the next symbol from input. The symbol is encoded using the
+ /// huffman tree.
+ ///
+ ///
+ /// input the input source.
+ ///
+ ///
+ /// the next symbol, or -1 if not enough input is available.
+ ///
+ public int GetSymbol(StreamManipulator input)
+ {
+ int lookahead, symbol;
+ if ((lookahead = input.PeekBits(9)) >= 0) {
+ if ((symbol = tree[lookahead]) >= 0) {
+ input.DropBits(symbol & 15);
+ return symbol >> 4;
+ }
+ int subtree = -(symbol >> 4);
+ int bitlen = symbol & 15;
+ if ((lookahead = input.PeekBits(bitlen)) >= 0) {
+ symbol = tree[subtree | (lookahead >> 9)];
+ input.DropBits(symbol & 15);
+ return symbol >> 4;
+ } else {
+ int bits = input.AvailableBits;
+ lookahead = input.PeekBits(bits);
+ symbol = tree[subtree | (lookahead >> 9)];
+ if ((symbol & 15) <= bits) {
+ input.DropBits(symbol & 15);
+ return symbol >> 4;
+ } else {
+ return -1;
+ }
+ }
+ } else {
+ int bits = input.AvailableBits;
+ lookahead = input.PeekBits(bits);
+ symbol = tree[lookahead];
+ if (symbol >= 0 && (symbol & 15) <= bits) {
+ input.DropBits(symbol & 15);
+ return symbol >> 4;
+ } else {
+ return -1;
+ }
+ }
+ }
+ }
+}
+
diff --git a/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/Compression/PendingBuffer.cs b/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/Compression/PendingBuffer.cs
new file mode 100644
index 0000000..4fc0240
--- /dev/null
+++ b/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/Compression/PendingBuffer.cs
@@ -0,0 +1,274 @@
+// PendingBuffer.cs
+//
+// Copyright (C) 2001 Mike Krueger
+// Copyright (C) 2004 John Reilly
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+
+namespace ICSharpCode.SharpZipLib.Zip.Compression
+{
+
+ ///
+ /// This class is general purpose class for writing data to a buffer.
+ ///
+ /// It allows you to write bits as well as bytes
+ /// Based on DeflaterPending.java
+ ///
+ /// author of the original java version : Jochen Hoenicke
+ ///
+ public class PendingBuffer
+ {
+ /// Internal work buffer
+ ///
+ protected byte[] buf;
+
+ int start;
+ int end;
+
+ uint bits;
+ int bitCount;
+
+ ///
+ /// construct instance using default buffer size of 4096
+ ///
+ public PendingBuffer() : this( 4096 )
+ {
+
+ }
+
+ ///
+ /// construct instance using specified buffer size
+ ///
+ ///
+ /// size to use for internal buffer
+ ///
+ public PendingBuffer(int bufsize)
+ {
+ buf = new byte[bufsize];
+ }
+
+ ///
+ /// Clear internal state/buffers
+ ///
+ public void Reset()
+ {
+ start = end = bitCount = 0;
+ }
+
+ ///
+ /// write a byte to buffer
+ ///
+ ///
+ /// value to write
+ ///
+ public void WriteByte(int b)
+ {
+ if (DeflaterConstants.DEBUGGING && start != 0) {
+ throw new Exception();
+ }
+ buf[end++] = (byte) b;
+ }
+
+ ///
+ /// Write a short value to buffer LSB first
+ ///
+ ///
+ /// value to write
+ ///
+ public void WriteShort(int s)
+ {
+ if (DeflaterConstants.DEBUGGING && start != 0) {
+ throw new Exception();
+ }
+ buf[end++] = (byte) s;
+ buf[end++] = (byte) (s >> 8);
+ }
+
+ ///
+ /// write an integer LSB first
+ ///
+ /// value to write
+ public void WriteInt(int s)
+ {
+ if (DeflaterConstants.DEBUGGING && start != 0) {
+ throw new Exception();
+ }
+ buf[end++] = (byte) s;
+ buf[end++] = (byte) (s >> 8);
+ buf[end++] = (byte) (s >> 16);
+ buf[end++] = (byte) (s >> 24);
+ }
+
+ ///
+ /// Write a block of data to buffer
+ ///
+ /// data to write
+ /// offset of first byte to write
+ /// number of bytes to write
+ public void WriteBlock(byte[] block, int offset, int len)
+ {
+ if (DeflaterConstants.DEBUGGING && start != 0) {
+ throw new Exception();
+ }
+ System.Array.Copy(block, offset, buf, end, len);
+ end += len;
+ }
+
+ ///
+ /// The number of bits written to the buffer
+ ///
+ public int BitCount {
+ get {
+ return bitCount;
+ }
+ }
+
+ ///
+ /// Align internal buffer on a byte boundary
+ ///
+ public void AlignToByte()
+ {
+ if (DeflaterConstants.DEBUGGING && start != 0) {
+ throw new Exception();
+ }
+ if (bitCount > 0) {
+ buf[end++] = (byte) bits;
+ if (bitCount > 8) {
+ buf[end++] = (byte) (bits >> 8);
+ }
+ }
+ bits = 0;
+ bitCount = 0;
+ }
+
+ ///
+ /// Write bits to internal buffer
+ ///
+ /// source of bits
+ /// number of bits to write
+ public void WriteBits(int b, int count)
+ {
+ if (DeflaterConstants.DEBUGGING && start != 0) {
+ throw new Exception();
+ }
+ // if (DeflaterConstants.DEBUGGING) {
+ // //Console.WriteLine("writeBits("+b+","+count+")");
+ // }
+ bits |= (uint)(b << bitCount);
+ bitCount += count;
+ if (bitCount >= 16) {
+ buf[end++] = (byte) bits;
+ buf[end++] = (byte) (bits >> 8);
+ bits >>= 16;
+ bitCount -= 16;
+ }
+ }
+
+ ///
+ /// Write a short value to internal buffer most significant byte first
+ ///
+ /// value to write
+ public void WriteShortMSB(int s)
+ {
+ if (DeflaterConstants.DEBUGGING && start != 0) {
+ throw new Exception();
+ }
+ buf[end++] = (byte) (s >> 8);
+ buf[end++] = (byte) s;
+ }
+
+ ///
+ /// Indicates if buffer has been flushed
+ ///
+ public bool IsFlushed {
+ get {
+ return end == 0;
+ }
+ }
+
+ ///
+ /// Flushes the pending buffer into the given output array. If the
+ /// output array is to small, only a partial flush is done.
+ ///
+ ///
+ /// the output array;
+ ///
+ ///
+ /// the offset into output array;
+ ///
+ ///
+ /// length the maximum number of bytes to store;
+ ///
+ ///
+ /// IndexOutOfBoundsException if offset or length are invalid.
+ ///
+ public int Flush(byte[] output, int offset, int length)
+ {
+ if (bitCount >= 8) {
+ buf[end++] = (byte) bits;
+ bits >>= 8;
+ bitCount -= 8;
+ }
+ if (length > end - start) {
+ length = end - start;
+ System.Array.Copy(buf, start, output, offset, length);
+ start = 0;
+ end = 0;
+ } else {
+ System.Array.Copy(buf, start, output, offset, length);
+ start += length;
+ }
+ return length;
+ }
+
+ ///
+ /// Convert internal buffer to byte array.
+ /// Buffer is empty on completion
+ ///
+ ///
+ /// converted buffer contents contents
+ ///
+ public byte[] ToByteArray()
+ {
+ byte[] ret = new byte[end - start];
+ System.Array.Copy(buf, start, ret, 0, ret.Length);
+ start = 0;
+ end = 0;
+ return ret;
+ }
+ }
+}
diff --git a/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/Compression/Streams/DeflaterOutputStream.cs b/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/Compression/Streams/DeflaterOutputStream.cs
new file mode 100644
index 0000000..a289f59
--- /dev/null
+++ b/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/Compression/Streams/DeflaterOutputStream.cs
@@ -0,0 +1,449 @@
+// DeflaterOutputStream.cs
+//
+// Copyright (C) 2001 Mike Krueger
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using System.IO;
+using ICSharpCode.SharpZipLib.Checksums;
+using ICSharpCode.SharpZipLib.Zip.Compression;
+
+namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams
+{
+
+ ///
+ /// A special stream deflating or compressing the bytes that are
+ /// written to it. It uses a Deflater to perform actual deflating.
+ ///
+ /// authors of the original java version : Tom Tromey, Jochen Hoenicke
+ ///
+ public class DeflaterOutputStream : Stream
+ {
+ ///
+ /// This buffer is used temporarily to retrieve the bytes from the
+ /// deflater and write them to the underlying output stream.
+ ///
+ protected byte[] buf;
+
+ ///
+ /// The deflater which is used to deflate the stream.
+ ///
+ protected Deflater def;
+
+ ///
+ /// Base stream the deflater depends on.
+ ///
+ protected Stream baseOutputStream;
+
+ ///
+ /// Allows client to determine if an entry can be patched after its added
+ ///
+ public bool CanPatchEntries {
+ get {
+ return baseOutputStream.CanSeek;
+ }
+ }
+
+ ///
+ /// Gets value indicating stream can be read from
+ ///
+ public override bool CanRead {
+ get {
+ return baseOutputStream.CanRead;
+ }
+ }
+
+ ///
+ /// Gets a value indicating if seeking is supported for this stream
+ /// This property always returns false
+ ///
+ public override bool CanSeek {
+ get {
+ return false;
+ }
+ }
+
+ ///
+ /// Get value indicating if this stream supports writing
+ ///
+ public override bool CanWrite {
+ get {
+ return baseOutputStream.CanWrite;
+ }
+ }
+
+ ///
+ /// Get current length of stream
+ ///
+ public override long Length {
+ get {
+ return baseOutputStream.Length;
+ }
+ }
+
+ ///
+ /// The current position within the stream.
+ /// Always throws a NotSupportedExceptionNotSupportedException
+ ///
+ /// Any attempt to set position
+ public override long Position {
+ get {
+ return baseOutputStream.Position;
+ }
+ set {
+// baseOutputStream.Position = value;
+ throw new NotSupportedException("DefalterOutputStream Position not supported");
+ }
+ }
+
+ ///
+ /// Sets the current position of this stream to the given value. Not supported by this class!
+ ///
+ /// Any access
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ throw new NotSupportedException("DeflaterOutputStream Seek not supported");
+// return baseOutputStream.Seek(offset, origin);
+ }
+
+ ///
+ /// Sets the length of this stream to the given value. Not supported by this class!
+ ///
+ /// Any access
+ public override void SetLength(long val)
+ {
+// baseOutputStream.SetLength(val);
+ throw new NotSupportedException("DeflaterOutputStream SetLength not supported");
+ }
+
+ ///
+ /// Read a byte from stream advancing position by one
+ ///
+ /// Any access
+ public override int ReadByte()
+ {
+// return baseOutputStream.ReadByte();
+ throw new NotSupportedException("DeflaterOutputStream ReadByte not supported");
+ }
+
+ ///
+ /// Read a block of bytes from stream
+ ///
+ /// Any access
+ public override int Read(byte[] b, int off, int len)
+ {
+// return baseOutputStream.Read(b, off, len);
+ throw new NotSupportedException("DeflaterOutputStream Read not supported");
+ }
+
+ ///
+ /// Asynchronous reads are not supported a NotSupportedException is always thrown
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Any access
+ public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
+ {
+ throw new NotSupportedException("DeflaterOutputStream BeginRead not currently supported");
+ }
+
+ ///
+ /// Asynchronous writes arent supported, a NotSupportedException is always thrown
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Any access
+ public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
+ {
+ throw new NotSupportedException("DeflaterOutputStream BeginWrite not currently supported");
+ }
+
+ ///
+ /// Deflates everything in the def's input buffers. This will call
+ /// def.deflate() until all bytes from the input buffers
+ /// are processed.
+ ///
+ protected void Deflate()
+ {
+ while (!def.IsNeedingInput) {
+ int len = def.Deflate(buf, 0, buf.Length);
+
+ if (len <= 0) {
+ break;
+ }
+
+ if (this.Password != null) {
+ this.EncryptBlock(buf, 0, len);
+ }
+
+ baseOutputStream.Write(buf, 0, len);
+ }
+
+ if (!def.IsNeedingInput) {
+ throw new ApplicationException("DeflaterOutputStream can't deflate all input?");
+ }
+ }
+
+ ///
+ /// Creates a new DeflaterOutputStream with a default Deflater and default buffer size.
+ ///
+ ///
+ /// the output stream where deflated output should be written.
+ ///
+ public DeflaterOutputStream(Stream baseOutputStream) : this(baseOutputStream, new Deflater(), 512)
+ {
+ }
+
+ ///
+ /// Creates a new DeflaterOutputStream with the given Deflater and
+ /// default buffer size.
+ ///
+ ///
+ /// the output stream where deflated output should be written.
+ ///
+ ///
+ /// the underlying deflater.
+ ///
+ public DeflaterOutputStream(Stream baseOutputStream, Deflater defl) : this(baseOutputStream, defl, 512)
+ {
+ }
+
+ ///
+ /// Creates a new DeflaterOutputStream with the given Deflater and
+ /// buffer size.
+ ///
+ ///
+ /// The output stream where deflated output is written.
+ ///
+ ///
+ /// The underlying deflater to use
+ ///
+ ///
+ /// The buffer size to use when deflating
+ ///
+ ///
+ /// bufsize is less than or equal to zero.
+ ///
+ ///
+ /// baseOutputStream does not support writing
+ ///
+ ///
+ /// deflater instance is null
+ ///
+ public DeflaterOutputStream(Stream baseOutputStream, Deflater deflater, int bufsize)
+ {
+ if (baseOutputStream.CanWrite == false) {
+ throw new ArgumentException("baseOutputStream", "must support writing");
+ }
+
+ if (deflater == null) {
+ throw new ArgumentNullException("deflater");
+ }
+
+ if (bufsize <= 0) {
+ throw new ArgumentOutOfRangeException("bufsize", "Non-negative number required");
+ }
+
+ this.baseOutputStream = baseOutputStream;
+ buf = new byte[bufsize];
+ def = deflater;
+ }
+
+ ///
+ /// Flushes the stream by calling flush() on the deflater and then
+ /// on the underlying stream. This ensures that all bytes are
+ /// flushed.
+ ///
+ public override void Flush()
+ {
+ def.Flush();
+ Deflate();
+ baseOutputStream.Flush();
+ }
+
+ ///
+ /// Finishes the stream by calling finish() on the deflater.
+ ///
+ public virtual void Finish()
+ {
+ def.Finish();
+ while (!def.IsFinished) {
+ int len = def.Deflate(buf, 0, buf.Length);
+ if (len <= 0) {
+ break;
+ }
+
+ if (this.Password != null) {
+ this.EncryptBlock(buf, 0, len);
+ }
+
+ baseOutputStream.Write(buf, 0, len);
+ }
+ if (!def.IsFinished) {
+ throw new ApplicationException("Can't deflate all input?");
+ }
+ baseOutputStream.Flush();
+ }
+
+ ///
+ /// Calls finish() and closes the stream.
+ ///
+ public override void Close()
+ {
+ Finish();
+ baseOutputStream.Close();
+ }
+
+ ///
+ /// Writes a single byte to the compressed output stream.
+ ///
+ ///
+ /// The byte value.
+ ///
+ public override void WriteByte(byte bval)
+ {
+ byte[] b = new byte[1];
+ b[0] = bval;
+ Write(b, 0, 1);
+ }
+
+ ///
+ /// Writes bytes from an array to the compressed stream.
+ ///
+ ///
+ /// The byte array
+ ///
+ ///
+ /// The offset into the byte array where to start.
+ ///
+ ///
+ /// The number of bytes to write.
+ ///
+ public override void Write(byte[] buf, int off, int len)
+ {
+ def.SetInput(buf, off, len);
+ Deflate();
+ }
+
+ #region Encryption
+
+ // TODO Refactor this code. The presence of Zip specific code in this low level class is wrong
+ string password = null;
+ uint[] keys = null;
+
+ ///
+ /// Get/set the password used for encryption. When null no encryption is performed
+ ///
+ public string Password {
+ get {
+ return password;
+ }
+ set {
+ password = value;
+ }
+ }
+
+
+ ///
+ /// Encrypt a single byte
+ ///
+ ///
+ /// The encrypted value
+ ///
+ protected byte EncryptByte()
+ {
+ uint temp = ((keys[2] & 0xFFFF) | 2);
+ return (byte)((temp * (temp ^ 1)) >> 8);
+ }
+
+
+ ///
+ /// Encrypt a block of data
+ ///
+ ///
+ /// Data to encrypt. NOTE the original contents of the buffer are lost
+ ///
+ ///
+ /// Offset of first byte in buffer to encrypt
+ ///
+ ///
+ /// Number of bytes in buffer to encrypt
+ ///
+ protected void EncryptBlock(byte[] buffer, int offset, int length)
+ {
+ for (int i = offset; i < offset + length; ++i) {
+ byte oldbyte = buffer[i];
+ buffer[i] ^= EncryptByte();
+ UpdateKeys(oldbyte);
+ }
+ }
+
+ ///
+ /// Initializes encryption keys based on given password
+ ///
+ protected void InitializePassword(string password) {
+ keys = new uint[] {
+ 0x12345678,
+ 0x23456789,
+ 0x34567890
+ };
+
+ for (int i = 0; i < password.Length; ++i) {
+ UpdateKeys((byte)password[i]);
+ }
+ }
+
+ ///
+ /// Update encryption keys
+ ///
+ protected void UpdateKeys(byte ch)
+ {
+ keys[0] = Crc32.ComputeCrc32(keys[0], ch);
+ keys[1] = keys[1] + (byte)keys[0];
+ keys[1] = keys[1] * 134775813 + 1;
+ keys[2] = Crc32.ComputeCrc32(keys[2], (byte)(keys[1] >> 24));
+ }
+ #endregion
+ }
+}
diff --git a/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/Compression/Streams/InflaterInputStream.cs b/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/Compression/Streams/InflaterInputStream.cs
new file mode 100644
index 0000000..a272b59
--- /dev/null
+++ b/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/Compression/Streams/InflaterInputStream.cs
@@ -0,0 +1,540 @@
+// InflaterInputStream.cs
+//
+// Copyright (C) 2001 Mike Krueger
+// Copyright (C) 2004 John Reilly
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using System.IO;
+
+using ICSharpCode.SharpZipLib.Zip.Compression;
+using ICSharpCode.SharpZipLib.Checksums;
+
+namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams
+{
+
+ ///
+ /// This filter stream is used to decompress data compressed using the "deflate"
+ /// format. The "deflate" format is described in RFC 1951.
+ ///
+ /// This stream may form the basis for other decompression filters, such
+ /// as the GZipInputStream.
+ ///
+ /// Author of the original java version : John Leuner.
+ ///
+ public class InflaterInputStream : Stream
+ {
+ ///
+ /// Decompressor for this stream
+ ///
+ protected Inflater inf;
+
+ ///
+ /// Byte array used for buffering input.
+ ///
+ protected byte[] buf;
+
+ ///
+ /// Size of buffer
+ ///
+ protected int len;
+
+ // Used for reading single bytes the ReadByte() call
+ private byte[] onebytebuffer = new byte[1];
+
+ ///
+ /// Base stream the inflater reads from.
+ ///
+ protected Stream baseInputStream;
+
+ ///
+ /// The compressed size
+ ///
+ protected long csize;
+
+ ///
+ /// Gets a value indicating whether the current stream supports reading
+ ///
+ public override bool CanRead {
+ get {
+ return baseInputStream.CanRead;
+ }
+ }
+
+ ///
+ /// Value of false indicating seeking is not supported for this stream
+ /// This property always returns false
+ ///
+ public override bool CanSeek {
+ get {
+ return false;
+ }
+ }
+
+ ///
+ /// Get true if stream is writeable
+ /// This property always returns false
+ ///
+ public override bool CanWrite {
+ get {
+ return false;
+ }
+ }
+
+ ///
+ /// A value representing the length of the stream in bytes.
+ ///
+ public override long Length {
+ get {
+ return len;
+ }
+ }
+
+ ///
+ /// The current position within the stream
+ /// Throws a NotSupportedException when attempting to set the position
+ ///
+ /// Attempting to set the position
+ public override long Position {
+ get {
+ return baseInputStream.Position;
+ }
+ set {
+ throw new NotSupportedException("InflaterInputStream Position not supported");
+ }
+ }
+
+ ///
+ /// Flushes the baseInputStream
+ ///
+ public override void Flush()
+ {
+ baseInputStream.Flush();
+ }
+
+ ///
+ /// Sets the position within the current stream
+ /// Always throws a NotSupportedException
+ ///
+ /// Any access
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ throw new NotSupportedException("Seek not supported");
+ }
+
+ ///
+ /// Set the length of the current stream
+ /// Always throws a NotSupportedException
+ ///
+ /// Any access
+ public override void SetLength(long val)
+ {
+ throw new NotSupportedException("InflaterInputStream SetLength not supported");
+ }
+
+ ///
+ /// Writes a sequence of bytes to stream and advances the current position
+ /// This method always throws a NotSupportedException
+ ///
+ /// Any access
+ public override void Write(byte[] array, int offset, int count)
+ {
+ throw new NotSupportedException("InflaterInputStream Write not supported");
+ }
+
+ ///
+ /// Writes one byte to the current stream and advances the current position
+ /// Always throws a NotSupportedException
+ ///
+ /// Any access
+ public override void WriteByte(byte val)
+ {
+ throw new NotSupportedException("InflaterInputStream WriteByte not supported");
+ }
+
+ ///
+ /// Entry point to begin an asynchronous write. Always throws a NotSupportedException.
+ ///
+ /// The buffer to write data from
+ /// Offset of first byte to write
+ /// The maximum number of bytes to write
+ /// The method to be called when the asynchronous write operation is completed
+ /// A user-provided object that distinguishes this particular asynchronous write request from other requests
+ /// An IAsyncResult that references the asynchronous write
+ /// Any access
+ public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
+ {
+ throw new NotSupportedException("InflaterInputStream BeginWrite not supported");
+ }
+
+ ///
+ /// Create an InflaterInputStream with the default decompressor
+ /// and a default buffer size of 4KB.
+ ///
+ ///
+ /// The InputStream to read bytes from
+ ///
+ public InflaterInputStream(Stream baseInputStream) : this(baseInputStream, new Inflater(), 4096)
+ {
+ }
+
+ ///
+ /// Create an InflaterInputStream with the specified decompressor
+ /// and a default buffer size of 4KB.
+ ///
+ ///
+ /// The source of input data
+ ///
+ ///
+ /// The decompressor used to decompress data read from baseInputStream
+ ///
+ public InflaterInputStream(Stream baseInputStream, Inflater inf) : this(baseInputStream, inf, 4096)
+ {
+ }
+
+ ///
+ /// Create an InflaterInputStream with the specified decompressor
+ /// and the specified buffer size.
+ ///
+ ///
+ /// The InputStream to read bytes from
+ ///
+ ///
+ /// The decompressor to use
+ ///
+ ///
+ /// Size of the buffer to use
+ ///
+ public InflaterInputStream(Stream baseInputStream, Inflater inflater, int bufferSize)
+ {
+ if (baseInputStream == null) {
+ throw new ArgumentNullException("InflaterInputStream baseInputStream is null");
+ }
+
+ if (inflater == null) {
+ throw new ArgumentNullException("InflaterInputStream Inflater is null");
+ }
+
+ if (bufferSize <= 0) {
+ throw new ArgumentOutOfRangeException("bufferSize");
+ }
+
+ this.baseInputStream = baseInputStream;
+ this.inf = inflater;
+ buf = new byte[bufferSize];
+
+ // TODO rework this!! The original code will mask real exceptions.
+/* Is this valid in all cases?
+ if (baseInputStream.CanSeek) {
+ this.len = baseInputStream.Length;
+ } else {
+ this.len = 0;
+ }
+*/
+ try {
+ this.len = (int)baseInputStream.Length;
+ } catch (Exception) {
+ // the stream may not support Length property
+ this.len = 0;
+ }
+
+ }
+
+ ///
+ /// Returns 0 once the end of the stream (EOF) has been reached.
+ /// Otherwise returns 1.
+ ///
+ /// TODO make this a bool property?
+ public virtual int Available {
+ get {
+ return inf.IsFinished ? 0 : 1;
+ }
+ }
+
+ ///
+ /// Closes the input stream
+ ///
+ public override void Close()
+ {
+ baseInputStream.Close();
+ }
+
+ int readChunkSize = 0;
+
+ // TODO this is an ineficient way of handling this situation
+ // revamp this to operate better...
+
+ ///
+ /// Sets the size of chunks to read from the input stream
+ /// 0 means as larger as possible.
+ ///
+ ///
+ /// Used to handle decryption where the length of stream is unknown.
+ ///
+ protected int BufferReadSize {
+ get {
+ return readChunkSize;
+ }
+
+ set {
+ readChunkSize = value;
+ }
+ }
+
+ ///
+ /// Fill input buffer with a chunk of data.
+ ///
+ ///
+ /// Stream ends early
+ ///
+ protected void FillInputBuffer()
+ {
+ if (readChunkSize <= 0) {
+ len = baseInputStream.Read(buf, 0, buf.Length);
+ } else {
+ len = baseInputStream.Read(buf, 0, readChunkSize);
+ }
+
+ }
+ ///
+ /// Fills the buffer with more data to decompress.
+ ///
+ ///
+ /// Stream ends early
+ ///
+ protected void Fill()
+ {
+ FillInputBuffer();
+
+ if (keys != null) {
+ DecryptBlock(buf, 0, len);
+ }
+
+#if READ_SINGLE_WHEN_DECRYPTING
+ // This solves some decryption problems but there are still some lurking.
+ // At issue is exactly where the stream and decryption should finish.
+ if (keys == null) {
+ len = baseInputStream.Read(buf, 0, buf.Length);
+ } else {
+ len = baseInputStream.Read(buf, 0, 1);
+ }
+
+ if (keys != null) {
+ DecryptBlock(buf, 0, len);
+ }
+#endif
+
+#if STANDARD
+ len = baseInputStream.Read(buf, 0, buf.Length);
+
+ if (keys != null) {
+ DecryptBlock(buf, 0, System.Math.Min((int)(csize - inf.TotalIn), len));
+ }
+#endif
+
+ if (len <= 0) {
+ throw new ZipException("Deflated stream ends early.");
+ }
+
+ inf.SetInput(buf, 0, len);
+ }
+
+ ///
+ /// Reads one byte of decompressed data.
+ ///
+ /// The byte is baseInputStream the lower 8 bits of the int.
+ ///
+ ///
+ /// The byte read cast to an int, or -1 on end of stream.
+ ///
+ public override int ReadByte()
+ {
+ int nread = Read(onebytebuffer, 0, 1); // read one byte
+ if (nread > 0) {
+ return onebytebuffer[0] & 0xff;
+ }
+ return -1; // ok
+ }
+
+ ///
+ /// Decompresses data into the byte array
+ ///
+ ///
+ /// The array to read and decompress data into
+ ///
+ ///
+ /// The offset indicating where the data should be placed
+ ///
+ ///
+ /// The number of bytes to decompress
+ ///
+ /// The number of bytes read. Zero signals the end of stream
+ ///
+ /// Inflater needs a dictionary
+ ///
+ public override int Read(byte[] b, int off, int len)
+ {
+ for (;;) {
+ int count;
+ try {
+ count = inf.Inflate(b, off, len);
+ } catch (Exception e) {
+ throw new ZipException(e.ToString());
+ }
+
+ if (count > 0) {
+ return count;
+ }
+
+ if (inf.IsNeedingDictionary) {
+ throw new ZipException("Need a dictionary");
+ } else if (inf.IsFinished) {
+ return 0;
+ } else if (inf.IsNeedingInput) {
+ Fill();
+ } else {
+ throw new InvalidOperationException("Don't know what to do");
+ }
+ }
+ }
+
+ ///
+ /// Skip specified number of bytes of uncompressed data
+ ///
+ ///
+ /// Number of bytes to skip
+ ///
+ ///
+ /// The number of bytes skipped, zero if the end of
+ /// stream has been reached
+ ///
+ ///
+ /// Number of bytes to skip is zero or less
+ ///
+ public long Skip(long n)
+ {
+ if (n <= 0) {
+ throw new ArgumentOutOfRangeException("n");
+ }
+
+ // v0.80 Skip by seeking if underlying stream supports it...
+ if (baseInputStream.CanSeek) {
+ baseInputStream.Seek(n, SeekOrigin.Current);
+ return n;
+ } else {
+ int len = 2048;
+ if (n < len) {
+ len = (int) n;
+ }
+ byte[] tmp = new byte[len];
+ return (long)baseInputStream.Read(tmp, 0, tmp.Length);
+ }
+ }
+
+ #region Encryption stuff
+
+ // TODO Refactor this code. The presence of Zip specific code in this low level class is wrong
+
+ ///
+ /// A buffer used for decrypting data. Used to hold Zip crypto header.
+ ///
+ protected byte[] cryptbuffer = null;
+
+ uint[] keys = null;
+
+ ///
+ /// Decrypt a single byte
+ ///
+ /// plain text byte value
+ protected byte DecryptByte()
+ {
+ uint temp = ((keys[2] & 0xFFFF) | 2);
+ return (byte)((temp * (temp ^ 1)) >> 8);
+ }
+
+ ///
+ /// Decrypt cipher text block, updating keys
+ ///
+ /// Data to decrypt
+ /// Offset of first byte to process
+ /// Number of bytes to process
+ protected void DecryptBlock(byte[] buf, int off, int len)
+ {
+ for (int i = off; i < off + len; ++i) {
+ buf[i] ^= DecryptByte();
+ UpdateKeys(buf[i]);
+ }
+ }
+
+ ///
+ /// Initialise the decryption keys
+ ///
+ /// The password used to initialise the keys
+ protected void InitializePassword(string password)
+ {
+ keys = new uint[] {
+ 0x12345678,
+ 0x23456789,
+ 0x34567890
+ };
+ for (int i = 0; i < password.Length; ++i) {
+ UpdateKeys((byte)password[i]);
+ }
+ }
+
+ ///
+ /// Update the decryption keys
+ ///
+ /// Character to update the keys with
+ protected void UpdateKeys(byte ch)
+ {
+ keys[0] = Crc32.ComputeCrc32(keys[0], ch);
+ keys[1] = keys[1] + (byte)keys[0];
+ keys[1] = keys[1] * 134775813 + 1;
+ keys[2] = Crc32.ComputeCrc32(keys[2], (byte)(keys[1] >> 24));
+ }
+
+ ///
+ /// Clear any cryptographic state.
+ ///
+ protected void StopDecrypting()
+ {
+ keys = null;
+ cryptbuffer = null;
+ }
+ #endregion
+ }
+}
diff --git a/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/Compression/Streams/OutputWindow.cs b/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/Compression/Streams/OutputWindow.cs
new file mode 100644
index 0000000..058f51f
--- /dev/null
+++ b/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/Compression/Streams/OutputWindow.cs
@@ -0,0 +1,227 @@
+// OutputWindow.cs
+//
+// Copyright (C) 2001 Mike Krueger
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+
+namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams
+{
+
+ ///
+ /// Contains the output from the Inflation process.
+ /// We need to have a window so that we can refer backwards into the output stream
+ /// to repeat stuff.
+ ///
+ /// author of the original java version : John Leuner
+ ///
+ public class OutputWindow
+ {
+ private static int WINDOW_SIZE = 1 << 15;
+ private static int WINDOW_MASK = WINDOW_SIZE - 1;
+
+ private byte[] window = new byte[WINDOW_SIZE]; //The window is 2^15 bytes
+ private int windowEnd = 0;
+ private int windowFilled = 0;
+
+ ///
+ /// write a byte to this output window
+ ///
+ /// value to write
+ ///
+ /// if window is full
+ ///
+ public void Write(int abyte)
+ {
+ if (windowFilled++ == WINDOW_SIZE) {
+ throw new InvalidOperationException("Window full");
+ }
+ window[windowEnd++] = (byte) abyte;
+ windowEnd &= WINDOW_MASK;
+ }
+
+
+ private void SlowRepeat(int repStart, int len, int dist)
+ {
+ while (len-- > 0) {
+ window[windowEnd++] = window[repStart++];
+ windowEnd &= WINDOW_MASK;
+ repStart &= WINDOW_MASK;
+ }
+ }
+
+ ///
+ /// Append a byte pattern already in the window itself
+ ///
+ /// length of pattern to copy
+ /// distance from end of window pattern occurs
+ ///
+ /// If the repeated data overflows the window
+ ///
+ public void Repeat(int len, int dist)
+ {
+ if ((windowFilled += len) > WINDOW_SIZE) {
+ throw new InvalidOperationException("Window full");
+ }
+
+ int rep_start = (windowEnd - dist) & WINDOW_MASK;
+ int border = WINDOW_SIZE - len;
+ if (rep_start <= border && windowEnd < border) {
+ if (len <= dist) {
+ System.Array.Copy(window, rep_start, window, windowEnd, len);
+ windowEnd += len;
+ } else {
+ /* We have to copy manually, since the repeat pattern overlaps. */
+ while (len-- > 0) {
+ window[windowEnd++] = window[rep_start++];
+ }
+ }
+ } else {
+ SlowRepeat(rep_start, len, dist);
+ }
+ }
+
+ ///
+ /// Copy from input manipulator to internal window
+ ///
+ /// source of data
+ /// length of data to copy
+ /// the number of bytes copied
+ public int CopyStored(StreamManipulator input, int len)
+ {
+ len = Math.Min(Math.Min(len, WINDOW_SIZE - windowFilled), input.AvailableBytes);
+ int copied;
+
+ int tailLen = WINDOW_SIZE - windowEnd;
+ if (len > tailLen) {
+ copied = input.CopyBytes(window, windowEnd, tailLen);
+ if (copied == tailLen) {
+ copied += input.CopyBytes(window, 0, len - tailLen);
+ }
+ } else {
+ copied = input.CopyBytes(window, windowEnd, len);
+ }
+
+ windowEnd = (windowEnd + copied) & WINDOW_MASK;
+ windowFilled += copied;
+ return copied;
+ }
+
+ ///
+ /// Copy dictionary to window
+ ///
+ /// source dictionary
+ /// offset of start in source dictionary
+ /// length of dictionary
+ ///
+ /// If window isnt empty
+ ///
+ public void CopyDict(byte[] dict, int offset, int len)
+ {
+ if (windowFilled > 0) {
+ throw new InvalidOperationException();
+ }
+
+ if (len > WINDOW_SIZE) {
+ offset += len - WINDOW_SIZE;
+ len = WINDOW_SIZE;
+ }
+ System.Array.Copy(dict, offset, window, 0, len);
+ windowEnd = len & WINDOW_MASK;
+ }
+
+ ///
+ /// Get remaining unfilled space in window
+ ///
+ /// Number of bytes left in window
+ public int GetFreeSpace()
+ {
+ return WINDOW_SIZE - windowFilled;
+ }
+
+ ///
+ /// Get bytes available for output in window
+ ///
+ /// Number of bytes filled
+ public int GetAvailable()
+ {
+ return windowFilled;
+ }
+
+ ///
+ /// Copy contents of window to output
+ ///
+ /// buffer to copy to
+ /// offset to start at
+ /// number of bytes to count
+ /// The number of bytes copied
+ ///
+ /// If a window underflow occurs
+ ///
+ public int CopyOutput(byte[] output, int offset, int len)
+ {
+ int copy_end = windowEnd;
+ if (len > windowFilled) {
+ len = windowFilled;
+ } else {
+ copy_end = (windowEnd - windowFilled + len) & WINDOW_MASK;
+ }
+
+ int copied = len;
+ int tailLen = len - copy_end;
+
+ if (tailLen > 0) {
+ System.Array.Copy(window, WINDOW_SIZE - tailLen, output, offset, tailLen);
+ offset += tailLen;
+ len = copy_end;
+ }
+ System.Array.Copy(window, copy_end - len, output, offset, len);
+ windowFilled -= copied;
+ if (windowFilled < 0) {
+ throw new InvalidOperationException();
+ }
+ return copied;
+ }
+
+ ///
+ /// Reset by clearing window so GetAvailable returns 0
+ ///
+ public void Reset()
+ {
+ windowFilled = windowEnd = 0;
+ }
+ }
+}
diff --git a/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/Compression/Streams/StreamManipulator.cs b/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/Compression/Streams/StreamManipulator.cs
new file mode 100644
index 0000000..cf4fb1a
--- /dev/null
+++ b/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/Compression/Streams/StreamManipulator.cs
@@ -0,0 +1,270 @@
+// StreamManipulator.cs
+//
+// Copyright (C) 2001 Mike Krueger
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+
+namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams
+{
+
+ ///
+ /// This class allows us to retrieve a specified number of bits from
+ /// the input buffer, as well as copy big byte blocks.
+ ///
+ /// It uses an int buffer to store up to 31 bits for direct
+ /// manipulation. This guarantees that we can get at least 16 bits,
+ /// but we only need at most 15, so this is all safe.
+ ///
+ /// There are some optimizations in this class, for example, you must
+ /// never peek more than 8 bits more than needed, and you must first
+ /// peek bits before you may drop them. This is not a general purpose
+ /// class but optimized for the behaviour of the Inflater.
+ ///
+ /// authors of the original java version : John Leuner, Jochen Hoenicke
+ ///
+ public class StreamManipulator
+ {
+ private byte[] window;
+ private int window_start = 0;
+ private int window_end = 0;
+
+ private uint buffer = 0;
+ private int bits_in_buffer = 0;
+
+ ///
+ /// Get the next n bits but don't increase input pointer. n must be
+ /// less or equal 16 and if this call succeeds, you must drop
+ /// at least n - 8 bits in the next call.
+ ///
+ ///
+ /// the value of the bits, or -1 if not enough bits available. */
+ ///
+ public int PeekBits(int n)
+ {
+ if (bits_in_buffer < n) {
+ if (window_start == window_end) {
+ return -1; // ok
+ }
+ buffer |= (uint)((window[window_start++] & 0xff |
+ (window[window_start++] & 0xff) << 8) << bits_in_buffer);
+ bits_in_buffer += 16;
+ }
+ return (int)(buffer & ((1 << n) - 1));
+ }
+
+ ///
+ /// Drops the next n bits from the input. You should have called PeekBits
+ /// with a bigger or equal n before, to make sure that enough bits are in
+ /// the bit buffer.
+ ///
+ public void DropBits(int n)
+ {
+ buffer >>= n;
+ bits_in_buffer -= n;
+ }
+
+ ///
+ /// Gets the next n bits and increases input pointer. This is equivalent
+ /// to PeekBits followed by dropBits, except for correct error handling.
+ ///
+ ///
+ /// the value of the bits, or -1 if not enough bits available.
+ ///
+ public int GetBits(int n)
+ {
+ int bits = PeekBits(n);
+ if (bits >= 0) {
+ DropBits(n);
+ }
+ return bits;
+ }
+
+ ///
+ /// Gets the number of bits available in the bit buffer. This must be
+ /// only called when a previous PeekBits() returned -1.
+ ///
+ ///
+ /// the number of bits available.
+ ///
+ public int AvailableBits {
+ get {
+ return bits_in_buffer;
+ }
+ }
+
+ ///
+ /// Gets the number of bytes available.
+ ///
+ ///
+ /// The number of bytes available.
+ ///
+ public int AvailableBytes {
+ get {
+ return window_end - window_start + (bits_in_buffer >> 3);
+ }
+ }
+
+ ///
+ /// Skips to the next byte boundary.
+ ///
+ public void SkipToByteBoundary()
+ {
+ buffer >>= (bits_in_buffer & 7);
+ bits_in_buffer &= ~7;
+ }
+
+ ///
+ /// Returns true when SetInput can be called
+ ///
+ public bool IsNeedingInput {
+ get {
+ return window_start == window_end;
+ }
+ }
+
+ ///
+ /// Copies length bytes from input buffer to output buffer starting
+ /// at output[offset]. You have to make sure, that the buffer is
+ /// byte aligned. If not enough bytes are available, copies fewer
+ /// bytes.
+ ///
+ ///
+ /// The buffer to copy bytes to.
+ ///
+ ///
+ /// The offset in the buffer at which copying starts
+ ///
+ ///
+ /// The length to copy, 0 is allowed.
+ ///
+ ///
+ /// The number of bytes copied, 0 if no bytes were available.
+ ///
+ ///
+ /// Length is less than zero
+ ///
+ ///
+ /// Bit buffer isnt byte aligned
+ ///
+ public int CopyBytes(byte[] output, int offset, int length)
+ {
+ if (length < 0) {
+ throw new ArgumentOutOfRangeException("length", "negative");
+ }
+ if ((bits_in_buffer & 7) != 0) {
+ /* bits_in_buffer may only be 0 or a multiple of 8 */
+ throw new InvalidOperationException("Bit buffer is not byte aligned!");
+ }
+
+ int count = 0;
+ while (bits_in_buffer > 0 && length > 0) {
+ output[offset++] = (byte) buffer;
+ buffer >>= 8;
+ bits_in_buffer -= 8;
+ length--;
+ count++;
+ }
+
+ if (length == 0) {
+ return count;
+ }
+
+ int avail = window_end - window_start;
+ if (length > avail) {
+ length = avail;
+ }
+ System.Array.Copy(window, window_start, output, offset, length);
+ window_start += length;
+
+ if (((window_start - window_end) & 1) != 0) {
+ /* We always want an even number of bytes in input, see peekBits */
+ buffer = (uint)(window[window_start++] & 0xff);
+ bits_in_buffer = 8;
+ }
+ return count + length;
+ }
+
+ ///
+ /// Constructs a default StreamManipulator with all buffers empty
+ ///
+ public StreamManipulator()
+ {
+ }
+
+
+ ///
+ /// resets state and empties internal buffers
+ ///
+ public void Reset()
+ {
+ buffer = (uint)(window_start = window_end = bits_in_buffer = 0);
+ }
+
+ ///
+ /// Add more input for consumption.
+ /// Only call when IsNeedingInput returns true
+ ///
+ /// data to be input
+ /// offset of first byte of input
+ /// length of input
+ public void SetInput(byte[] buf, int off, int len)
+ {
+ if (window_start < window_end) {
+ throw new InvalidOperationException("Old input was not completely processed");
+ }
+
+ int end = off + len;
+
+ /* We want to throw an ArrayIndexOutOfBoundsException early. The
+ * check is very tricky: it also handles integer wrap around.
+ */
+ if (0 > off || off > end || end > buf.Length) {
+ throw new ArgumentOutOfRangeException();
+ }
+
+ if ((len & 1) != 0) {
+ /* We always want an even number of bytes in input, see peekBits */
+ buffer |= (uint)((buf[off++] & 0xff) << bits_in_buffer);
+ bits_in_buffer += 8;
+ }
+
+ window = buf;
+ window_start = off;
+ window_end = end;
+ }
+ }
+}
diff --git a/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/ZipConstants.cs b/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/ZipConstants.cs
new file mode 100644
index 0000000..b075771
--- /dev/null
+++ b/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/ZipConstants.cs
@@ -0,0 +1,418 @@
+// ZipConstants.cs
+//
+// Copyright (C) 2001 Mike Krueger
+// Copyright (C) 2004 John Reilly
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System.Text;
+
+namespace ICSharpCode.SharpZipLib.Zip
+{
+
+ ///
+ /// The kind of compression used for an entry in an archive
+ ///
+ public enum CompressionMethod
+ {
+ ///
+ /// A direct copy of the file contents is held in the archive
+ ///
+ Stored = 0,
+
+ ///
+ /// Common Zip compression method using a sliding dictionary
+ /// of up to 32KB and secondary compression from Huffman/Shannon-Fano trees
+ ///
+ Deflated = 8,
+
+ ///
+ /// An extension to deflate with a 64KB window. Not supported
+ ///
+ Deflate64 = 9,
+
+ ///
+ /// Not supported
+ ///
+ BZip2 = 11,
+
+ ///
+ /// WinZip special for AES encryption, Not supported
+ ///
+ WinZipAES = 99,
+
+ }
+
+ ///
+ /// This class contains constants used for Zip format files
+ ///
+ public sealed class ZipConstants
+ {
+ ///
+ /// The version made by field for entries in the central header when created by this library
+ ///
+ ///
+ /// This is also the Zip version for the library when comparing against the version required to extract
+ /// for an entry. See ZipInputStream.CanDecompressEntry.
+ ///
+ public const int VERSION_MADE_BY = 20;
+
+ // The local entry header
+
+ ///
+ /// Size of local entry header (excluding variable length fields at end)
+ ///
+ public const int LOCHDR = 30;
+
+ ///
+ /// Signature for local entry header
+ ///
+ public const int LOCSIG = 'P' | ('K' << 8) | (3 << 16) | (4 << 24);
+
+ ///
+ /// Offset of version to extract in local entry header
+ ///
+ public const int LOCVER = 4;
+
+ ///
+ /// Offset of general purpose flags in local entry header
+ ///
+ public const int LOCFLG = 6;
+
+ ///
+ /// Offset of compression method in local entry header
+ ///
+ public const int LOCHOW = 8;
+
+ ///
+ /// Offset of last mod file time + date in local entry header
+ ///
+ public const int LOCTIM = 10;
+
+ ///
+ /// Offset of crc-32 in local entry header
+ ///
+ public const int LOCCRC = 14;
+
+ ///
+ /// Offset of compressed size in local entry header
+ ///
+ public const int LOCSIZ = 18;
+
+ ///
+ /// Offset of uncompressed size in local entry header
+ ///
+ public const int LOCLEN = 22;
+
+ ///
+ /// Offset of file name length in local entry header
+ ///
+ public const int LOCNAM = 26;
+
+ ///
+ /// Offset of extra field length in local entry header
+ ///
+ public const int LOCEXT = 28;
+
+
+ ///
+ /// Signature for spanning entry
+ ///
+ public const int SPANNINGSIG = 'P' | ('K' << 8) | (7 << 16) | (8 << 24);
+
+ ///
+ /// Signature for temporary spanning entry
+ ///
+ public const int SPANTEMPSIG = 'P' | ('K' << 8) | ('0' << 16) | ('0' << 24);
+
+ ///
+ /// Signature for data descriptor
+ ///
+ ///
+ /// This is only used where the length, Crc, or compressed size isnt known when the
+ /// entry is created and the output stream doesnt support seeking.
+ /// The local entry cannot be 'patched' with the correct values in this case
+ /// so the values are recorded after the data prefixed by this header, as well as in the central directory.
+ ///
+ public const int EXTSIG = 'P' | ('K' << 8) | (7 << 16) | (8 << 24);
+
+ ///
+ /// Size of data descriptor
+ ///
+ public const int EXTHDR = 16;
+
+ ///
+ /// Offset of crc-32 in data descriptor
+ ///
+ public const int EXTCRC = 4;
+
+ ///
+ /// Offset of compressed size in data descriptor
+ ///
+ public const int EXTSIZ = 8;
+
+ ///
+ /// Offset of uncompressed length in data descriptor
+ ///
+ public const int EXTLEN = 12;
+
+
+ ///
+ /// Signature for central header
+ ///
+ public const int CENSIG = 'P' | ('K' << 8) | (1 << 16) | (2 << 24);
+
+ ///
+ /// Size of central header entry
+ ///
+ public const int CENHDR = 46;
+
+ ///
+ /// Offset of version made by in central file header
+ ///
+ public const int CENVEM = 4;
+
+ ///
+ /// Offset of version needed to extract in central file header
+ ///
+ public const int CENVER = 6;
+
+ ///
+ /// Offset of general purpose bit flag in central file header
+ ///
+ public const int CENFLG = 8;
+
+ ///
+ /// Offset of compression method in central file header
+ ///
+ public const int CENHOW = 10;
+
+ ///
+ /// Offset of time/date in central file header
+ ///
+ public const int CENTIM = 12;
+
+ ///
+ /// Offset of crc-32 in central file header
+ ///
+ public const int CENCRC = 16;
+
+ ///
+ /// Offset of compressed size in central file header
+ ///
+ public const int CENSIZ = 20;
+
+ ///
+ /// Offset of uncompressed size in central file header
+ ///
+ public const int CENLEN = 24;
+
+ ///
+ /// Offset of file name length in central file header
+ ///
+ public const int CENNAM = 28;
+
+ ///
+ /// Offset of extra field length in central file header
+ ///
+ public const int CENEXT = 30;
+
+ ///
+ /// Offset of file comment length in central file header
+ ///
+ public const int CENCOM = 32;
+
+ ///
+ /// Offset of disk start number in central file header
+ ///
+ public const int CENDSK = 34;
+
+ ///
+ /// Offset of internal file attributes in central file header
+ ///
+ public const int CENATT = 36;
+
+ ///
+ /// Offset of external file attributes in central file header
+ ///
+ public const int CENATX = 38;
+
+ ///
+ /// Offset of relative offset of local header in central file header
+ ///
+ public const int CENOFF = 42;
+
+
+ ///
+ /// Signature for Zip64 central file header
+ ///
+ public const int CENSIG64 = 'P' | ('K' << 8) | (6 << 16) | (6 << 24);
+
+
+
+ ///
+ /// Central header digitial signature
+ ///
+ public const int CENDIGITALSIG = 'P' | ('K' << 8) | (5 << 16) | (5 << 24);
+
+
+ // The entries at the end of central directory
+
+ ///
+ /// End of central directory record signature
+ ///
+ public const int ENDSIG = 'P' | ('K' << 8) | (5 << 16) | (6 << 24);
+
+ ///
+ /// Size of end of central record (excluding variable fields)
+ ///
+ public const int ENDHDR = 22;
+
+ // The following two fields are missing in SUN JDK
+
+ ///
+ /// Offset of number of this disk
+ ///
+ public const int ENDNRD = 4;
+
+ ///
+ /// Offset of number of disk with start of central directory
+ ///
+ public const int ENDDCD = 6;
+
+ ///
+ /// Offset of number of entries in the central directory of this disk
+ ///
+ public const int ENDSUB = 8;
+
+ ///
+ /// Offset of total number of entries in the central directory
+ ///
+ public const int ENDTOT = 10;
+
+ ///
+ /// Offset of size of central directory
+ ///
+ public const int ENDSIZ = 12;
+
+ ///
+ /// Offset of offset of start of central directory with respect to starting disk number
+ ///
+ public const int ENDOFF = 16;
+
+ ///
+ /// Offset of ZIP file comment length
+ ///
+ public const int ENDCOM = 20;
+
+ ///
+ /// Size of cryptographic header stored before entry data
+ ///
+ public const int CRYPTO_HEADER_SIZE = 12;
+
+
+#if !COMPACT_FRAMEWORK
+
+ static int defaultCodePage = 0;
+
+ ///
+ /// Default encoding used for string conversion. 0 gives default system ansi code page.
+ /// Dont use unicode encodings if you want to be Zip compatible!
+ /// Using the default code page isnt the full solution neccessarily
+ /// there are many variable factors, codepage 850 is often a good choice for
+ /// European users, however be careful about compatability.
+ ///
+ public static int DefaultCodePage {
+ get {
+ return defaultCodePage;
+ }
+ set {
+ defaultCodePage = value;
+ }
+ }
+#endif
+
+ ///
+ /// Convert a portion of a byte array to a string.
+ ///
+ ///
+ /// Data to convert to string
+ ///
+ ///
+ /// Number of bytes to convert starting from index 0
+ ///
+ ///
+ /// data[0]..data[length - 1] converted to a string
+ ///
+ public static string ConvertToString(byte[] data, int length)
+ {
+#if COMPACT_FRAMEWORK
+ return Encoding.ASCII.GetString(data, 0, length);
+#else
+ return Encoding.GetEncoding(DefaultCodePage).GetString(data, 0, length);
+#endif
+ }
+
+ ///
+ /// Convert byte array to string
+ ///
+ ///
+ /// Byte array to convert
+ ///
+ ///
+ /// dataconverted to a string
+ ///
+ public static string ConvertToString(byte[] data)
+ {
+ return ConvertToString(data, data.Length);
+ }
+
+ ///
+ /// Convert a string to a byte array
+ ///
+ ///
+ /// String to convert to an array
+ ///
+ /// Converted array
+ public static byte[] ConvertToArray(string str)
+ {
+#if COMPACT_FRAMEWORK
+ return Encoding.ASCII.GetBytes(str);
+#else
+ return Encoding.GetEncoding(DefaultCodePage).GetBytes(str);
+#endif
+ }
+ }
+}
diff --git a/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/ZipEntry.cs b/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/ZipEntry.cs
new file mode 100644
index 0000000..8847a0b
--- /dev/null
+++ b/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/ZipEntry.cs
@@ -0,0 +1,693 @@
+// ZipEntry.cs
+//
+// Copyright (C) 2001 Mike Krueger
+// Copyright (C) 2004 John Reilly
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using System.IO;
+
+namespace ICSharpCode.SharpZipLib.Zip
+{
+
+ ///
+ /// This class represents an entry in a zip archive. This can be a file
+ /// or a directory
+ /// ZipFile and ZipInputStream will give you instances of this class as
+ /// information about the members in an archive. ZipOutputStream
+ /// uses an instance of this class when creating an entry in a Zip file.
+ ///
+ /// Author of the original java version : Jochen Hoenicke
+ ///
+ public class ZipEntry : ICloneable
+ {
+ static int KNOWN_SIZE = 1;
+ static int KNOWN_CSIZE = 2;
+ static int KNOWN_CRC = 4;
+ static int KNOWN_TIME = 8;
+ static int KNOWN_EXTERN_ATTRIBUTES = 16;
+
+ ushort known = 0; // Bit flags made up of above bits
+ int externalFileAttributes = -1; // contains external attributes (os dependant)
+
+ ushort versionMadeBy; // Contains host system and version information
+ // only relevant for central header entries
+
+ string name;
+ ulong size;
+ ulong compressedSize;
+ ushort versionToExtract; // Version required to extract (library handles <= 2.0)
+ uint crc;
+ uint dosTime;
+
+ CompressionMethod method = CompressionMethod.Deflated;
+ byte[] extra = null;
+ string comment = null;
+
+ int flags; // general purpose bit flags
+
+ int zipFileIndex = -1; // used by ZipFile
+ int offset; // used by ZipFile and ZipOutputStream
+
+ ///
+ /// Get/Set flag indicating if entry is encrypted.
+ /// A simple helper routine to aid interpretation of flags
+ ///
+ public bool IsCrypted {
+ get {
+ return (flags & 1) != 0;
+ }
+ set {
+ if (value) {
+ flags |= 1;
+ } else {
+ flags &= ~1;
+ }
+ }
+ }
+
+ ///
+ /// Get/Set general purpose bit flag for entry
+ ///
+ ///
+ /// General purpose bit flag
+ /// Bit 0: If set, indicates the file is encrypted
+ /// Bit 1-2 Only used for compression type 6 Imploding, and 8, 9 deflating
+ /// Imploding:
+ /// Bit 1 if set indicates an 8K sliding dictionary was used. If clear a 4k dictionary was used
+ /// Bit 2 if set indicates 3 Shannon-Fanno trees were used to encode the sliding dictionary, 2 otherwise
+ ///
+ /// Deflating:
+ /// Bit 2 Bit 1
+ /// 0 0 Normal compression was used
+ /// 0 1 Maximum compression was used
+ /// 1 0 Fast compression was used
+ /// 1 1 Super fast compression was used
+ ///
+ /// Bit 3: If set, the fields crc-32, compressed size
+ /// and uncompressed size are were not able to be written during zip file creation
+ /// The correct values are held in a data descriptor immediately following the compressed data.
+ /// Bit 4: Reserved for use by PKZIP for enhanced deflating
+ /// Bit 5: If set indicates the file contains compressed patch data
+ /// Bit 6: If set indicates strong encryption was used.
+ /// Bit 7-15: Unused or reserved
+ ///
+ public int Flags {
+ get {
+ return flags;
+ }
+ set {
+ flags = value;
+ }
+ }
+
+
+ ///
+ /// Get/Set index of this entry in Zip file
+ ///
+ public int ZipFileIndex {
+ get {
+ return zipFileIndex;
+ }
+ set {
+ zipFileIndex = value;
+ }
+ }
+
+ ///
+ /// Get/set offset for use in central header
+ ///
+ public int Offset {
+ get {
+ return offset;
+ }
+ set {
+ if (((ulong)value & 0xFFFFFFFF00000000L) != 0) {
+ throw new ArgumentOutOfRangeException("Offset");
+ }
+ offset = value;
+ }
+ }
+
+
+ ///
+ /// Get/Set external file attributes as an integer.
+ /// The values of this are operating system dependant see
+ /// HostSystem for details
+ ///
+ public int ExternalFileAttributes {
+ get {
+ if ((known & KNOWN_EXTERN_ATTRIBUTES) == 0) {
+ return -1;
+ } else {
+ return externalFileAttributes;
+ }
+ }
+
+ set {
+ externalFileAttributes = value;
+ known |= (ushort)KNOWN_EXTERN_ATTRIBUTES;
+ }
+ }
+
+ ///
+ /// Get the version made by for this entry or zero if unknown.
+ /// The value / 10 indicates the major version number, and
+ /// the value mod 10 is the minor version number
+ ///
+ public int VersionMadeBy {
+ get {
+ return versionMadeBy & 0xff;
+ }
+ }
+
+ ///
+ /// Gets the compatability information for the external file attribute
+ /// If the external file attributes are compatible with MS-DOS and can be read
+ /// by PKZIP for DOS version 2.04g then this value will be zero. Otherwise the value
+ /// will be non-zero and identify the host system on which the attributes are compatible.
+ ///
+ ///
+ ///
+ /// The values for this as defined in the Zip File format and by others are shown below. The values are somewhat
+ /// misleading in some cases as they are not all used as shown. You should consult the relevant documentation
+ /// to obtain up to date and correct information. The modified appnote by the infozip group is
+ /// particularly helpful as it documents a lot of peculiarities. The document is however a little dated.
+ ///
+ /// 0 - MS-DOS and OS/2 (FAT / VFAT / FAT32 file systems)
+ /// 1 - Amiga
+ /// 2 - OpenVMS
+ /// 3 - Unix
+ /// 4 - VM/CMS
+ /// 5 - Atari ST
+ /// 6 - OS/2 HPFS
+ /// 7 - Macintosh
+ /// 8 - Z-System
+ /// 9 - CP/M
+ /// 10 - Windows NTFS
+ /// 11 - MVS (OS/390 - Z/OS)
+ /// 12 - VSE
+ /// 13 - Acorn Risc
+ /// 14 - VFAT
+ /// 15 - Alternate MVS
+ /// 16 - BeOS
+ /// 17 - Tandem
+ /// 18 - OS/400
+ /// 19 - OS/X (Darwin)
+ /// 99 - WinZip AES
+ /// remainder - unused
+ ///
+ ///
+
+ public int HostSystem {
+ get { return (versionMadeBy >> 8) & 0xff; }
+ }
+
+ ///
+ /// Creates a zip entry with the given name.
+ ///
+ ///
+ /// The name for this entry. Can include directory components.
+ /// The convention for names is 'unix' style paths with no device names and
+ /// path elements separated by '/' characters. This is not enforced see CleanName
+ /// on how to ensure names are valid if this is desired.
+ ///
+ ///
+ /// The name passed is null
+ ///
+ public ZipEntry(string name) : this(name, 0, ZipConstants.VERSION_MADE_BY)
+ {
+ }
+
+ ///
+ /// Creates a zip entry with the given name and version required to extract
+ ///
+ ///
+ /// The name for this entry. Can include directory components.
+ /// The convention for names is 'unix' style paths with no device names and
+ /// path elements separated by '/' characters. This is not enforced see CleanName
+ /// on how to ensure names are valid if this is desired.
+ ///
+ ///
+ /// The minimum 'feature version' required this entry
+ ///
+ ///
+ /// The name passed is null
+ ///
+ public ZipEntry(string name, int versionRequiredToExtract) : this(name, versionRequiredToExtract, ZipConstants.VERSION_MADE_BY)
+ {
+ }
+
+ ///
+ /// Initializes an entry with the given name and made by information
+ ///
+ /// Name for this entry
+ /// Version and HostSystem Information
+ /// Minimum required zip feature version required to extract this entry
+ ///
+ /// The name passed is null
+ ///
+ ///
+ /// versionRequiredToExtract should be 0 (auto-calculate) or > 10
+ ///
+ ///
+ /// This constructor is used by the ZipFile class when reading from the central header
+ /// It is not generally useful, use the constructor specifying the name only.
+ ///
+ public ZipEntry(string name, int versionRequiredToExtract, int madeByInfo)
+ {
+ if (name == null) {
+ throw new System.ArgumentNullException("ZipEntry name");
+ }
+
+ if (versionRequiredToExtract != 0 && versionRequiredToExtract < 10) {
+ throw new ArgumentOutOfRangeException("versionRequiredToExtract");
+ }
+
+ this.DateTime = System.DateTime.Now;
+ this.name = name;
+ this.versionMadeBy = (ushort)madeByInfo;
+ this.versionToExtract = (ushort)versionRequiredToExtract;
+ }
+
+ ///
+ /// Creates a copy of the given zip entry.
+ ///
+ ///
+ /// The entry to copy.
+ ///
+ public ZipEntry(ZipEntry e)
+ {
+ known = e.known;
+ name = e.name;
+ size = e.size;
+ compressedSize = e.compressedSize;
+ crc = e.crc;
+ dosTime = e.dosTime;
+ method = e.method;
+ ExtraData = e.ExtraData; // Note use of property ensuring data is unique
+ comment = e.comment;
+ versionToExtract = e.versionToExtract;
+ versionMadeBy = e.versionMadeBy;
+ externalFileAttributes = e.externalFileAttributes;
+ flags = e.flags;
+
+ zipFileIndex = -1;
+ offset = 0;
+ }
+
+ ///
+ /// Get minimum Zip feature version required to extract this entry
+ ///
+ ///
+ /// Minimum features are defined as:
+ /// 1.0 - Default value
+ /// 1.1 - File is a volume label
+ /// 2.0 - File is a folder/directory
+ /// 2.0 - File is compressed using Deflate compression
+ /// 2.0 - File is encrypted using traditional encryption
+ /// 2.1 - File is compressed using Deflate64
+ /// 2.5 - FIle is compressed using PKWARE DCL Implode
+ /// 2.7 - File is a patch data set
+ /// 4.5 - File uses Zip64 format extensions
+ /// 4.6 - File is compressed using BZIP2 compression
+ /// 5.0 - File is encrypted using DES
+ /// 5.0 - File is encrypted using 3DES
+ /// 5.0 - File is encrypted using original RC2 encryption
+ /// 5.0 - File is encrypted using RC4 encryption
+ /// 5.1 - File is encrypted using AES encryption
+ /// 5.1 - File is encrypted using corrected RC2 encryption
+ /// 5.1 - File is encrypted using corrected RC2-64 encryption
+ /// 6.1 - File is encrypted using non-OAEP key wrapping
+ /// 6.2 - Central directory encryption (not confirmed yet)
+ ///
+ public int Version {
+ get {
+ if (versionToExtract != 0) {
+ return versionToExtract;
+ } else {
+ int result = 10;
+ if (CompressionMethod.Deflated == method) {
+ result = 20;
+ } else if (IsDirectory == true) {
+ result = 20;
+ } else if (IsCrypted == true) {
+ result = 20;
+ } else if ((known & KNOWN_EXTERN_ATTRIBUTES) != 0 && (externalFileAttributes & 0x08) != 0) {
+ result = 11;
+ }
+ return result;
+ }
+ }
+ }
+
+ ///
+ /// Get/Set DosTime
+ ///
+ public long DosTime {
+ get {
+ if ((known & KNOWN_TIME) == 0) {
+ return 0;
+ } else {
+ return dosTime;
+ }
+ }
+ set {
+ this.dosTime = (uint)value;
+ known |= (ushort)KNOWN_TIME;
+ }
+ }
+
+
+ ///
+ /// Gets/Sets the time of last modification of the entry.
+ ///
+ public DateTime DateTime {
+ get {
+ uint sec = 2 * (dosTime & 0x1f);
+ uint min = (dosTime >> 5) & 0x3f;
+ uint hrs = (dosTime >> 11) & 0x1f;
+ uint day = (dosTime >> 16) & 0x1f;
+ uint mon = ((dosTime >> 21) & 0xf);
+ uint year = ((dosTime >> 25) & 0x7f) + 1980;
+ return new System.DateTime((int)year, (int)mon, (int)day, (int)hrs, (int)min, (int)sec);
+ }
+ set {
+ DosTime = ((uint)value.Year - 1980 & 0x7f) << 25 |
+ ((uint)value.Month) << 21 |
+ ((uint)value.Day) << 16 |
+ ((uint)value.Hour) << 11 |
+ ((uint)value.Minute) << 5 |
+ ((uint)value.Second) >> 1;
+ }
+ }
+
+ ///
+ /// Returns the entry name. The path components in the entry should
+ /// always separated by slashes ('/'). Dos device names like C: should also
+ /// be removed. See CleanName.
+ ///
+ public string Name {
+ get {
+ return name;
+ }
+ }
+
+ ///
+ /// Cleans a name making it conform to Zip file conventions.
+ /// Devices names ('c:\') and UNC share names ('\\server\share') are removed
+ /// and forward slashes ('\') are converted to back slashes ('/').
+ ///
+ /// Name to clean
+ /// Make names relative if true or absolute if false
+ static public string CleanName(string name, bool relativePath)
+ {
+ if (name == null) {
+ return "";
+ }
+
+ if (Path.IsPathRooted(name) == true) {
+ // NOTE:
+ // for UNC names... \\machine\share\zoom\beet.txt gives \zoom\beet.txt
+ name = name.Substring(Path.GetPathRoot(name).Length);
+ }
+
+ name = name.Replace(@"\", "/");
+
+ if (relativePath == true) {
+ if (name.Length > 0 && (name[0] == Path.AltDirectorySeparatorChar || name[0] == Path.DirectorySeparatorChar)) {
+ name = name.Remove(0, 1);
+ }
+ } else {
+ if (name.Length > 0 && name[0] != Path.AltDirectorySeparatorChar && name[0] != Path.DirectorySeparatorChar) {
+ name = name.Insert(0, "/");
+ }
+ }
+ return name;
+ }
+
+ ///
+ /// Cleans a name making it conform to Zip file conventions.
+ /// Devices names ('c:\') and UNC share names ('\\server\share') are removed
+ /// and forward slashes ('\') are converted to back slashes ('/').
+ /// Names are made relative by trimming leading slashes which is compatible
+ /// with Windows-XPs built in Zip file handling.
+ ///
+ /// Name to clean
+ static public string CleanName(string name)
+ {
+ return CleanName(name, true);
+ }
+
+ ///
+ /// Gets/Sets the size of the uncompressed data.
+ ///
+ ///
+ /// If the size is not in the range 0..0xffffffffL
+ ///
+ ///
+ /// The size or -1 if unknown.
+ ///
+ public long Size {
+ get {
+ return (known & KNOWN_SIZE) != 0 ? (long)size : -1L;
+ }
+ set {
+ if (((ulong)value & 0xFFFFFFFF00000000L) != 0) {
+ throw new ArgumentOutOfRangeException("size");
+ }
+ this.size = (ulong)value;
+ this.known |= (ushort)KNOWN_SIZE;
+ }
+ }
+
+ ///
+ /// Gets/Sets the size of the compressed data.
+ ///
+ ///
+ /// Size is not in the range 0..0xffffffff
+ ///
+ ///
+ /// The size or -1 if unknown.
+ ///
+ public long CompressedSize {
+ get {
+ return (known & KNOWN_CSIZE) != 0 ? (long)compressedSize : -1L;
+ }
+ set {
+ if (((ulong)value & 0xffffffff00000000L) != 0) {
+ throw new ArgumentOutOfRangeException();
+ }
+ this.compressedSize = (ulong)value;
+ this.known |= (ushort)KNOWN_CSIZE;
+ }
+ }
+
+ ///
+ /// Gets/Sets the crc of the uncompressed data.
+ ///
+ ///
+ /// Crc is not in the range 0..0xffffffffL
+ ///
+ ///
+ /// The crc value or -1 if unknown.
+ ///
+ public long Crc {
+ get {
+ return (known & KNOWN_CRC) != 0 ? crc & 0xffffffffL : -1L;
+ }
+ set {
+ if (((ulong)crc & 0xffffffff00000000L) != 0) {
+ throw new ArgumentOutOfRangeException();
+ }
+ this.crc = (uint)value;
+ this.known |= (ushort)KNOWN_CRC;
+ }
+ }
+
+ ///
+ /// Gets/Sets the compression method. Only Deflated and Stored are supported.
+ ///
+ ///
+ /// The compression method for this entry
+ ///
+ ///
+ ///
+ public CompressionMethod CompressionMethod {
+ get {
+ return method;
+ }
+ set {
+ this.method = value;
+ }
+ }
+
+ ///
+ /// Gets/Sets the extra data.
+ ///
+ ///
+ /// Extra data is longer than 0xffff bytes.
+ ///
+ ///
+ /// Extra data or null if not set.
+ ///
+ public byte[] ExtraData {
+ get {
+ return extra;
+ }
+ set {
+ if (value == null) {
+ this.extra = null;
+ return;
+ }
+
+ if (value.Length > 0xffff) {
+ throw new System.ArgumentOutOfRangeException();
+ }
+
+ this.extra = new byte[value.Length];
+ Array.Copy(value, this.extra, value.Length);
+
+ try {
+ int pos = 0;
+ while (pos < extra.Length) {
+ int sig = (extra[pos++] & 0xff) | (extra[pos++] & 0xff) << 8;
+ int len = (extra[pos++] & 0xff) | (extra[pos++] & 0xff) << 8;
+
+ if (len < 0 || pos + len > extra.Length) {
+ // This is still lenient but the extra data is corrupt
+ // TODO drop the extra data? or somehow indicate to user
+ // there is a problem...
+ break;
+ }
+
+ if (sig == 0x5455) {
+ // extended time stamp, unix format by Rainer Prem
+ int flags = extra[pos];
+ // Can include other times but these are ignored. Length of data should
+ // actually be 1 + 4 * no of bits in flags.
+ if ((flags & 1) != 0 && len >= 5) {
+ int iTime = ((extra[pos+1] & 0xff) |
+ (extra[pos + 2] & 0xff) << 8 |
+ (extra[pos + 3] & 0xff) << 16 |
+ (extra[pos + 4] & 0xff) << 24);
+
+ DateTime = (new DateTime ( 1970, 1, 1, 0, 0, 0 ) + new TimeSpan ( 0, 0, 0, iTime, 0 )).ToLocalTime ();
+ known |= (ushort)KNOWN_TIME;
+ }
+ } else if (sig == 0x0001) {
+ // ZIP64 extended information extra field
+ // Of variable size depending on which fields in header are too small
+ // fields appear here if the corresponding local or central directory record field
+ // is set to 0xFFFF or 0xFFFFFFFF
+ //
+ // Original Size 8 bytes
+ // Compressed size 8 bytes
+ // Relative header offset 8 bytes
+ // Disk start number 4 bytes
+ }
+ pos += len;
+ }
+ } catch (Exception) {
+ /* be lenient */
+ return;
+ }
+ }
+ }
+
+
+ ///
+ /// Gets/Sets the entry comment.
+ ///
+ ///
+ /// If comment is longer than 0xffff.
+ ///
+ ///
+ /// The comment or null if not set.
+ ///
+ public string Comment {
+ get {
+ return comment;
+ }
+ set {
+ // TODO this test is strictly incorrect as the length is in characters
+ // While the test is correct in that a comment of this length or greater
+ // is definitely invalid, shorter comments may also have an invalid length.
+ if (value != null && value.Length > 0xffff) {
+ throw new ArgumentOutOfRangeException();
+ }
+ this.comment = value;
+ }
+ }
+
+ ///
+ /// Gets a value indicating of the if the entry is a directory. A directory is determined by
+ /// an entry name with a trailing slash '/'. The external file attributes
+ /// can also mark a file as a directory. The trailing slash convention should always be followed
+ /// however.
+ ///
+ public bool IsDirectory {
+ get {
+ bool result = false;
+ int nlen = name.Length;
+ result = nlen > 0 && name[nlen - 1] == '/';
+
+ if (result == false && (known & KNOWN_EXTERN_ATTRIBUTES) != 0) {
+ if (HostSystem == 0 && (ExternalFileAttributes & 16) != 0) {
+ result = true;
+ }
+ }
+ return result;
+ }
+ }
+
+ ///
+ /// Creates a copy of this zip entry.
+ ///
+ public object Clone()
+ {
+ return this.MemberwiseClone();
+ }
+
+ ///
+ /// Gets the string representation of this ZipEntry.
+ ///
+ public override string ToString()
+ {
+ return name;
+ }
+ }
+}
diff --git a/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/ZipFile.cs b/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/ZipFile.cs
new file mode 100644
index 0000000..565b201
--- /dev/null
+++ b/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/ZipFile.cs
@@ -0,0 +1,620 @@
+// ZipFile.cs
+//
+// Copyright (C) 2001 Mike Krueger
+// Copyright (C) 2004 John Reilly
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
+using ICSharpCode.SharpZipLib.Zip.Compression;
+
+namespace ICSharpCode.SharpZipLib.Zip
+{
+
+ ///
+ /// This class represents a Zip archive. You can ask for the contained
+ /// entries, or get an input stream for a file entry. The entry is
+ /// automatically decompressed.
+ ///
+ /// This class is thread safe: You can open input streams for arbitrary
+ /// entries in different threads.
+ ///
+ /// Author of the original java version : Jochen Hoenicke
+ ///
+ ///
+ ///
+ /// using System;
+ /// using System.Text;
+ /// using System.Collections;
+ /// using System.IO;
+ ///
+ /// using ICSharpCode.SharpZipLib.Zip;
+ ///
+ /// class MainClass
+ /// {
+ /// static public void Main(string[] args)
+ /// {
+ /// ZipFile zFile = new ZipFile(args[0]);
+ /// Console.WriteLine("Listing of : " + zFile.Name);
+ /// Console.WriteLine("");
+ /// Console.WriteLine("Raw Size Size Date Time Name");
+ /// Console.WriteLine("-------- -------- -------- ------ ---------");
+ /// foreach (ZipEntry e in zFile) {
+ /// DateTime d = e.DateTime;
+ /// Console.WriteLine("{0, -10}{1, -10}{2} {3} {4}", e.Size, e.CompressedSize,
+ /// d.ToString("dd-MM-yy"), d.ToString("t"),
+ /// e.Name);
+ /// }
+ /// }
+ /// }
+ ///
+ ///
+ public class ZipFile : IEnumerable
+ {
+ string name;
+ string comment;
+ Stream baseStream;
+ ZipEntry[] entries;
+
+ ///
+ /// Opens a Zip file with the given name for reading.
+ ///
+ ///
+ /// An i/o error occurs
+ ///
+ ///
+ /// The file doesn't contain a valid zip archive.
+ ///
+ public ZipFile(string name) : this(File.OpenRead(name))
+ {
+ }
+
+ ///
+ /// Opens a Zip file reading the given FileStream
+ ///
+ ///
+ /// An i/o error occurs.
+ ///
+ ///
+ /// The file doesn't contain a valid zip archive.
+ ///
+ public ZipFile(FileStream file)
+ {
+ this.baseStream = file;
+ this.name = file.Name;
+ ReadEntries();
+ }
+
+ ///
+ /// Opens a Zip file reading the given Stream
+ ///
+ ///
+ /// An i/o error occurs
+ ///
+ ///
+ /// The file doesn't contain a valid zip archive.
+ /// The stream provided cannot seek
+ ///
+ public ZipFile(Stream baseStream)
+ {
+ if (baseStream.CanSeek == false) {
+ throw new ZipException("ZipFile stream must be seekable");
+ }
+ this.baseStream = baseStream;
+ this.name = null;
+ ReadEntries();
+ }
+
+
+ ///
+ /// Read an unsigned short in little endian byte order.
+ ///
+ ///
+ /// An i/o error occurs.
+ ///
+ ///
+ /// The file ends prematurely
+ ///
+ int ReadLeShort()
+ {
+ return baseStream.ReadByte() | baseStream.ReadByte() << 8;
+ }
+
+ ///
+ /// Read an int in little endian byte order.
+ ///
+ ///
+ /// An i/o error occurs.
+ ///
+ ///
+ /// The file ends prematurely
+ ///
+ int ReadLeInt()
+ {
+ return ReadLeShort() | ReadLeShort() << 16;
+ }
+
+ ///
+ /// Read the central directory of a zip file and fill the entries
+ /// array. This is called exactly once by the constructors.
+ ///
+ ///
+ /// An i/o error occurs.
+ ///
+ ///
+ /// The central directory is malformed or cannot be found
+ ///
+ void ReadEntries()
+ {
+ /* Search for the End Of Central Directory. When a zip comment is
+ * present the directory may start earlier.
+ *
+ * TODO: The search is limited to 64K which is the maximum size of a trailing comment field to aid speed.
+ * This should be compatible with both SFX and ZIP files but has only been tested for Zip files
+ * Need to confirm this is valid in all cases.
+ */
+
+ long pos = baseStream.Length - ZipConstants.ENDHDR;
+ long giveUpMarker = Math.Max(pos - 0x10000, 0);
+
+ do {
+ if (pos < giveUpMarker) {
+ throw new ZipException("central directory not found, probably not a zip file");
+ }
+ baseStream.Seek(pos--, SeekOrigin.Begin);
+ } while (ReadLeInt() != ZipConstants.ENDSIG);
+
+ long oldPos = baseStream.Position;
+ baseStream.Position += ZipConstants.ENDTOT - ZipConstants.ENDNRD;
+
+ if (baseStream.Position - oldPos != ZipConstants.ENDTOT - ZipConstants.ENDNRD) {
+ throw new EndOfStreamException();
+ }
+ int count = ReadLeShort();
+
+ oldPos = baseStream.Position;
+ baseStream.Position += ZipConstants.ENDOFF - ZipConstants.ENDSIZ;
+
+ if (baseStream.Position - oldPos != ZipConstants.ENDOFF - ZipConstants.ENDSIZ) {
+ throw new EndOfStreamException();
+ }
+
+ int centralOffset = ReadLeInt();
+
+ int commentSize = ReadLeShort();
+ byte[] zipComment = new byte[commentSize];
+ baseStream.Read(zipComment, 0, zipComment.Length);
+ comment = ZipConstants.ConvertToString(zipComment);
+
+ entries = new ZipEntry[count];
+ baseStream.Seek(centralOffset, SeekOrigin.Begin);
+
+ for (int i = 0; i < count; i++) {
+ if (ReadLeInt() != ZipConstants.CENSIG) {
+ throw new ZipException("Wrong Central Directory signature");
+ }
+
+ int versionMadeBy = ReadLeShort();
+ int versionToExtract = ReadLeShort();
+ int bitFlags = ReadLeShort();
+ int method = ReadLeShort();
+ int dostime = ReadLeInt();
+ int crc = ReadLeInt();
+ int csize = ReadLeInt();
+ int size = ReadLeInt();
+ int nameLen = ReadLeShort();
+ int extraLen = ReadLeShort();
+ int commentLen = ReadLeShort();
+
+ int diskStartNo = ReadLeShort(); // Not currently used
+ int internalAttributes = ReadLeShort(); // Not currently used
+ int externalAttributes = ReadLeInt();
+ int offset = ReadLeInt();
+
+ byte[] buffer = new byte[Math.Max(nameLen, commentLen)];
+
+ baseStream.Read(buffer, 0, nameLen);
+ string name = ZipConstants.ConvertToString(buffer, nameLen);
+
+ ZipEntry entry = new ZipEntry(name, versionToExtract, versionMadeBy);
+ entry.CompressionMethod = (CompressionMethod)method;
+ entry.Crc = crc & 0xffffffffL;
+ entry.Size = size & 0xffffffffL;
+ entry.CompressedSize = csize & 0xffffffffL;
+ entry.DosTime = (uint)dostime;
+
+ if (extraLen > 0) {
+ byte[] extra = new byte[extraLen];
+ baseStream.Read(extra, 0, extraLen);
+ entry.ExtraData = extra;
+ }
+
+ if (commentLen > 0) {
+ baseStream.Read(buffer, 0, commentLen);
+ entry.Comment = ZipConstants.ConvertToString(buffer, commentLen);
+ }
+
+ entry.ZipFileIndex = i;
+ entry.Offset = offset;
+ entry.ExternalFileAttributes = externalAttributes;
+
+ entries[i] = entry;
+ }
+ }
+
+ ///
+ /// Closes the ZipFile. This also closes all input streams managed by
+ /// this class. Once closed, no further instance methods should be
+ /// called.
+ ///
+ ///
+ /// An i/o error occurs.
+ ///
+ public void Close()
+ {
+ entries = null;
+ lock(baseStream) {
+ baseStream.Close();
+ }
+ }
+
+ ///
+ /// Returns an enumerator for the Zip entries in this Zip file.
+ ///
+ ///
+ /// The Zip file has been closed.
+ ///
+ public IEnumerator GetEnumerator()
+ {
+ if (entries == null) {
+ throw new InvalidOperationException("ZipFile has closed");
+ }
+
+ return new ZipEntryEnumeration(entries);
+ }
+
+ ///
+ /// Return the index of the entry with a matching name
+ ///
+ /// Entry name to find
+ /// If true the comparison is case insensitive
+ /// The index position of the matching entry or -1 if not found
+ ///
+ /// The Zip file has been closed.
+ ///
+ public int FindEntry(string name, bool ignoreCase)
+ {
+ if (entries == null) {
+ throw new InvalidOperationException("ZipFile has been closed");
+ }
+
+ for (int i = 0; i < entries.Length; i++) {
+ if (string.Compare(name, entries[i].Name, ignoreCase) == 0) {
+ return i;
+ }
+ }
+ return -1; // ok
+ }
+
+ ///
+ /// Indexer property for ZipEntries
+ ///
+ [System.Runtime.CompilerServices.IndexerNameAttribute("EntryByIndex")]
+ public ZipEntry this[int index] {
+ get {
+ return (ZipEntry) entries[index].Clone();
+ }
+ }
+
+ ///
+ /// Searches for a zip entry in this archive with the given name.
+ /// String comparisons are case insensitive
+ ///
+ ///
+ /// The name to find. May contain directory components separated by slashes ('/').
+ ///
+ ///
+ /// The zip entry, or null if no entry with that name exists.
+ ///
+ ///
+ /// The Zip file has been closed.
+ ///
+ public ZipEntry GetEntry(string name)
+ {
+ if (entries == null) {
+ throw new InvalidOperationException("ZipFile has been closed");
+ }
+
+ int index = FindEntry(name, true);
+ return index >= 0 ? (ZipEntry) entries[index].Clone() : null;
+ }
+
+ ///
+ /// Checks, if the local header of the entry at index i matches the
+ /// central directory, and returns the offset to the data.
+ ///
+ ///
+ /// The start offset of the (compressed) data.
+ ///
+ ///
+ /// The stream ends prematurely
+ ///
+ ///
+ /// The local header signature is invalid, the entry and central header file name lengths are different
+ /// or the local and entry compression methods dont match
+ ///
+ long CheckLocalHeader(ZipEntry entry)
+ {
+ lock(baseStream) {
+ baseStream.Seek(entry.Offset, SeekOrigin.Begin);
+ if (ReadLeInt() != ZipConstants.LOCSIG) {
+ throw new ZipException("Wrong Local header signature");
+ }
+
+ short shortValue = (short)ReadLeShort(); // version required to extract
+ if (shortValue > ZipConstants.VERSION_MADE_BY) {
+ throw new ZipException(string.Format("Version required to extract this entry not supported ({0})", shortValue));
+ }
+
+ shortValue = (short)ReadLeShort(); // general purpose bit flags.
+ if ((shortValue & 0x30) != 0) {
+ throw new ZipException("The library doesnt support the zip version required to extract this entry");
+ }
+
+ if (entry.CompressionMethod != (CompressionMethod)ReadLeShort()) {
+ throw new ZipException("Compression method mismatch");
+ }
+
+ // Skip time, crc, size and csize
+ long oldPos = baseStream.Position;
+ baseStream.Position += ZipConstants.LOCNAM - ZipConstants.LOCTIM;
+
+ if (baseStream.Position - oldPos != ZipConstants.LOCNAM - ZipConstants.LOCTIM) {
+ throw new EndOfStreamException();
+ }
+
+ if (entry.Name.Length != ReadLeShort()) {
+ throw new ZipException("file name length mismatch");
+ }
+
+ int extraLen = entry.Name.Length + ReadLeShort();
+ return entry.Offset + ZipConstants.LOCHDR + extraLen;
+ }
+ }
+
+ ///
+ /// Creates an input stream reading the given zip entry as
+ /// uncompressed data. Normally zip entry should be an entry
+ /// returned by GetEntry().
+ ///
+ ///
+ /// the input stream.
+ ///
+ ///
+ /// The ZipFile has already been closed
+ ///
+ ///
+ /// The compression method for the entry is unknown
+ ///
+ ///
+ /// The entry is not found in the ZipFile
+ ///
+ public Stream GetInputStream(ZipEntry entry)
+ {
+ if (entries == null) {
+ throw new InvalidOperationException("ZipFile has closed");
+ }
+
+ int index = entry.ZipFileIndex;
+ if (index < 0 || index >= entries.Length || entries[index].Name != entry.Name) {
+ index = FindEntry(entry.Name, true);
+ if (index < 0) {
+ throw new IndexOutOfRangeException();
+ }
+ }
+ return GetInputStream(index);
+ }
+
+
+ ///
+ /// Creates an input stream reading the zip entry based on the index passed
+ ///
+ ///
+ /// An input stream.
+ ///
+ ///
+ /// The ZipFile has already been closed
+ ///
+ ///
+ /// The compression method for the entry is unknown
+ ///
+ ///
+ /// The entry is not found in the ZipFile
+ ///
+ public Stream GetInputStream(int entryIndex)
+ {
+ if (entries == null)
+ {
+ throw new InvalidOperationException("ZipFile has closed");
+ }
+
+ long start = CheckLocalHeader(entries[entryIndex]);
+ CompressionMethod method = entries[entryIndex].CompressionMethod;
+ Stream istr = new PartialInputStream(baseStream, start, entries[entryIndex].CompressedSize);
+
+ switch (method) {
+ case CompressionMethod.Stored:
+ return istr;
+ case CompressionMethod.Deflated:
+ return new InflaterInputStream(istr, new Inflater(true));
+ default:
+ throw new ZipException("Unknown compression method " + method);
+ }
+ }
+
+ ///
+ /// Gets the comment for the zip file.
+ ///
+ public string ZipFileComment {
+ get {
+ return comment;
+ }
+ }
+
+ ///
+ /// Gets the name of this zip file.
+ ///
+ public string Name {
+ get {
+ return name;
+ }
+ }
+
+ ///
+ /// Gets the number of entries in this zip file.
+ ///
+ ///
+ /// The Zip file has been closed.
+ ///
+ public int Size {
+ get {
+ if (entries != null) {
+ return entries.Length;
+ } else {
+ throw new InvalidOperationException("ZipFile is closed");
+ }
+ }
+ }
+
+ class ZipEntryEnumeration : IEnumerator
+ {
+ ZipEntry[] array;
+ int ptr = -1;
+
+ public ZipEntryEnumeration(ZipEntry[] arr)
+ {
+ array = arr;
+ }
+
+ public object Current {
+ get {
+ return array[ptr];
+ }
+ }
+
+ public void Reset()
+ {
+ ptr = -1;
+ }
+
+ public bool MoveNext()
+ {
+ return (++ptr < array.Length);
+ }
+ }
+
+ class PartialInputStream : InflaterInputStream
+ {
+ Stream baseStream;
+ long filepos, end;
+
+ public PartialInputStream(Stream baseStream, long start, long len) : base(baseStream)
+ {
+ this.baseStream = baseStream;
+ filepos = start;
+ end = start + len;
+ }
+
+ public override int Available
+ {
+ get {
+ long amount = end - filepos;
+ if (amount > Int32.MaxValue) {
+ return Int32.MaxValue;
+ }
+
+ return (int) amount;
+ }
+ }
+
+ public override int ReadByte()
+ {
+ if (filepos == end) {
+ return -1; //ok
+ }
+
+ lock(baseStream) {
+ baseStream.Seek(filepos++, SeekOrigin.Begin);
+ return baseStream.ReadByte();
+ }
+ }
+
+ public override int Read(byte[] b, int off, int len)
+ {
+ if (len > end - filepos) {
+ len = (int) (end - filepos);
+ if (len == 0) {
+ return 0;
+ }
+ }
+ lock(baseStream) {
+ baseStream.Seek(filepos, SeekOrigin.Begin);
+ int count = baseStream.Read(b, off, len);
+ if (count > 0) {
+ filepos += len;
+ }
+ return count;
+ }
+ }
+
+ public long SkipBytes(long amount)
+ {
+ if (amount < 0) {
+ throw new ArgumentOutOfRangeException();
+ }
+ if (amount > end - filepos) {
+ amount = end - filepos;
+ }
+ filepos += amount;
+ return amount;
+ }
+ }
+ }
+}
diff --git a/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/ZipInputStream.cs b/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/ZipInputStream.cs
new file mode 100644
index 0000000..ecf596a
--- /dev/null
+++ b/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/ZipInputStream.cs
@@ -0,0 +1,595 @@
+// ZipInputStream.cs
+//
+// Copyright (C) 2001 Mike Krueger
+// Copyright (C) 2004 John Reilly
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using System.Text;
+using System.IO;
+
+using ICSharpCode.SharpZipLib.Checksums;
+using ICSharpCode.SharpZipLib.Zip.Compression;
+using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
+
+namespace ICSharpCode.SharpZipLib.Zip
+{
+ ///
+ /// This is an InflaterInputStream that reads the files baseInputStream an zip archive
+ /// one after another. It has a special method to get the zip entry of
+ /// the next file. The zip entry contains information about the file name
+ /// size, compressed size, Crc, etc.
+ /// It includes support for Stored and Deflated entries.
+ ///
+ /// Author of the original java version : Jochen Hoenicke
+ ///
+ ///
+ /// This sample shows how to read a zip file
+ ///
+ /// using System;
+ /// using System.Text;
+ /// using System.IO;
+ ///
+ /// using ICSharpCode.SharpZipLib.Zip;
+ ///
+ /// class MainClass
+ /// {
+ /// public static void Main(string[] args)
+ /// {
+ /// ZipInputStream s = new ZipInputStream(File.OpenRead(args[0]));
+ ///
+ /// ZipEntry theEntry;
+ /// while ((theEntry = s.GetNextEntry()) != null) {
+ /// int size = 2048;
+ /// byte[] data = new byte[2048];
+ ///
+ /// Console.Write("Show contents (y/n) ?");
+ /// if (Console.ReadLine() == "y") {
+ /// while (true) {
+ /// size = s.Read(data, 0, data.Length);
+ /// if (size > 0) {
+ /// Console.Write(new ASCIIEncoding().GetString(data, 0, size));
+ /// } else {
+ /// break;
+ /// }
+ /// }
+ /// }
+ /// }
+ /// s.Close();
+ /// }
+ /// }
+ ///
+ ///
+ public class ZipInputStream : InflaterInputStream
+ {
+ Crc32 crc = new Crc32();
+ ZipEntry entry = null;
+
+ long size;
+ int method;
+ int flags;
+ long avail;
+ string password = null;
+
+ ///
+ /// Optional password used for encryption when non-null
+ ///
+ public string Password {
+ get {
+ return password;
+ }
+ set {
+ password = value;
+ }
+ }
+
+
+ ///
+ /// Gets a value indicating if the entry can be decompressed
+ ///
+ ///
+ /// The entry can only be decompressed if the library supports the zip features required to extract it.
+ /// See the ZipEntry Version property for more details.
+ ///
+ public bool CanDecompressEntry {
+ get {
+ return entry != null && entry.Version <= ZipConstants.VERSION_MADE_BY;
+ }
+ }
+
+ ///
+ /// Creates a new Zip input stream, for reading a zip archive.
+ ///
+ public ZipInputStream(Stream baseInputStream) : base(baseInputStream, new Inflater(true))
+ {
+ }
+
+ void FillBuf(int size)
+ {
+ avail = len = baseInputStream.Read(buf, 0, Math.Min(buf.Length, size));
+ }
+
+ int ReadBuf(byte[] outBuf, int offset, int length)
+ {
+ if (avail <= 0) {
+ FillBuf(length);
+ if (avail <= 0) {
+ return 0;
+ }
+ }
+
+ if (length > avail) {
+ length = (int)avail;
+ }
+
+ System.Array.Copy(buf, len - (int)avail, outBuf, offset, length);
+ avail -= length;
+ return length;
+ }
+
+ void ReadFully(byte[] outBuf)
+ {
+ int off = 0;
+ int len = outBuf.Length;
+ while (len > 0) {
+ int count = ReadBuf(outBuf, off, len);
+ if (count <= 0) {
+ throw new ZipException("Unexpected EOF");
+ }
+ off += count;
+ len -= count;
+ }
+ }
+
+ int ReadLeByte()
+ {
+ if (avail <= 0) {
+ FillBuf(1);
+ if (avail <= 0) {
+ throw new ZipException("EOF in header");
+ }
+ }
+ return buf[len - avail--] & 0xff;
+ }
+
+ ///
+ /// Read an unsigned short baseInputStream little endian byte order.
+ ///
+ int ReadLeShort()
+ {
+ return ReadLeByte() | (ReadLeByte() << 8);
+ }
+
+ ///
+ /// Read an int baseInputStream little endian byte order.
+ ///
+ int ReadLeInt()
+ {
+ return ReadLeShort() | (ReadLeShort() << 16);
+ }
+
+ ///
+ /// Read an int baseInputStream little endian byte order.
+ ///
+ long ReadLeLong()
+ {
+ return ReadLeInt() | (ReadLeInt() << 32);
+ }
+
+ ///
+ /// Advances to the next entry in the archive
+ ///
+ ///
+ /// The next entry in the archive or null if there are no more entries.
+ ///
+ ///
+ /// If the previous entry is still open CloseEntry is called.
+ ///
+ ///
+ /// Input stream is closed
+ ///
+ ///
+ /// Password is not set, password is invalid, compression method is invalid,
+ /// version required to extract is not supported
+ ///
+ public ZipEntry GetNextEntry()
+ {
+ if (crc == null) {
+ throw new InvalidOperationException("Closed.");
+ }
+
+ if (entry != null) {
+ CloseEntry();
+ }
+
+ if (this.cryptbuffer != null) {
+
+ if (inf.IsFinished == false && (entry.Flags & 8) != 0) {
+ throw new ZipException("NextEntry location not known");
+ }
+
+ if (avail == 0 && inf.RemainingInput != 0) {
+ avail = inf.RemainingInput - 16;
+ inf.Reset();
+ }
+ baseInputStream.Position -= this.len;
+ baseInputStream.Read(this.buf, 0, this.len);
+
+ }
+
+ if (avail <= 0) {
+ FillBuf(ZipConstants.LOCHDR);
+ }
+
+ int header = ReadLeInt();
+
+ if (header == ZipConstants.CENSIG ||
+ header == ZipConstants.ENDSIG ||
+ header == ZipConstants.CENDIGITALSIG ||
+ header == ZipConstants.CENSIG64) {
+ // No more individual entries exist
+ Close();
+ return null;
+ }
+
+ // -jr- 07-Dec-2003 Ignore spanning temporary signatures if found
+ // SPANNINGSIG is same as descriptor signature and is untested as yet.
+ if (header == ZipConstants.SPANTEMPSIG || header == ZipConstants.SPANNINGSIG) {
+ header = ReadLeInt();
+ }
+
+ if (header != ZipConstants.LOCSIG) {
+ throw new ZipException("Wrong Local header signature: 0x" + String.Format("{0:X}", header));
+ }
+
+ short versionRequiredToExtract = (short)ReadLeShort();
+
+ flags = ReadLeShort();
+ method = ReadLeShort();
+ uint dostime = (uint)ReadLeInt();
+ int crc2 = ReadLeInt();
+ csize = ReadLeInt();
+ size = ReadLeInt();
+ int nameLen = ReadLeShort();
+ int extraLen = ReadLeShort();
+
+ bool isCrypted = (flags & 1) == 1;
+
+ byte[] buffer = new byte[nameLen];
+ ReadFully(buffer);
+
+ string name = ZipConstants.ConvertToString(buffer);
+
+ entry = new ZipEntry(name, versionRequiredToExtract);
+ entry.Flags = flags;
+
+ if (method == (int)CompressionMethod.Stored && (!isCrypted && csize != size || (isCrypted && csize - ZipConstants.CRYPTO_HEADER_SIZE != size))) {
+ throw new ZipException("Stored, but compressed != uncompressed");
+ }
+
+ if (method != (int)CompressionMethod.Stored && method != (int)CompressionMethod.Deflated) {
+ throw new ZipException("unknown compression method " + method);
+ }
+
+ entry.CompressionMethod = (CompressionMethod)method;
+
+ if ((flags & 8) == 0) {
+ entry.Crc = crc2 & 0xFFFFFFFFL;
+ entry.Size = size & 0xFFFFFFFFL;
+ entry.CompressedSize = csize & 0xFFFFFFFFL;
+ BufferReadSize = 0;
+ } else {
+
+ if (isCrypted) {
+ BufferReadSize = 1;
+ } else {
+ BufferReadSize = 0;
+ }
+
+ // This allows for GNU, WinZip and possibly other archives, the PKZIP spec says these are zero
+ // under these circumstances.
+ if (crc2 != 0) {
+ entry.Crc = crc2 & 0xFFFFFFFFL;
+ }
+
+ if (size != 0) {
+ entry.Size = size & 0xFFFFFFFFL;
+ }
+ if (csize != 0) {
+ entry.CompressedSize = csize & 0xFFFFFFFFL;
+ }
+ }
+
+
+ entry.DosTime = dostime;
+
+ if (extraLen > 0) {
+ byte[] extra = new byte[extraLen];
+ ReadFully(extra);
+ entry.ExtraData = extra;
+ }
+
+ // TODO How to handle this?
+ // This library cannot handle versions greater than 20
+ // Throwing an exception precludes getting at later possibly useable entries.
+ // Could also skip this entry entirely
+ // Letting it slip past here isnt so great as it wont work
+ if (versionRequiredToExtract > 20) {
+ throw new ZipException("Libray cannot extract this entry version required (" + versionRequiredToExtract.ToString() + ")");
+ }
+
+ // test for encryption
+ if (isCrypted) {
+ if (password == null) {
+ throw new ZipException("No password set.");
+ }
+ InitializePassword(password);
+ cryptbuffer = new byte[ZipConstants.CRYPTO_HEADER_SIZE];
+ ReadFully(cryptbuffer);
+ DecryptBlock(cryptbuffer, 0, cryptbuffer.Length);
+
+ if ((flags & 8) == 0) {
+ if (cryptbuffer[ZipConstants.CRYPTO_HEADER_SIZE - 1] != (byte)(crc2 >> 24)) {
+ throw new ZipException("Invalid password");
+ }
+ }
+ else {
+ if (cryptbuffer[ZipConstants.CRYPTO_HEADER_SIZE - 1] != (byte)((dostime >> 8) & 0xff)) {
+ throw new ZipException("Invalid password");
+ }
+ }
+
+ if (csize >= ZipConstants.CRYPTO_HEADER_SIZE) {
+ csize -= ZipConstants.CRYPTO_HEADER_SIZE;
+ }
+ } else {
+ cryptbuffer = null;
+ }
+
+ if (method == (int)CompressionMethod.Deflated && avail > 0) {
+ System.Array.Copy(buf, len - (int)avail, buf, 0, (int)avail);
+ len = (int)avail;
+ avail = 0;
+ if (isCrypted) {
+ DecryptBlock(buf, 0, Math.Min((int)csize, len));
+ }
+ inf.SetInput(buf, 0, len);
+ }
+
+ return entry;
+ }
+
+ void ReadDataDescriptor()
+ {
+ if (ReadLeInt() != ZipConstants.EXTSIG) {
+ throw new ZipException("Data descriptor signature not found");
+ }
+
+ entry.Crc = ReadLeInt() & 0xFFFFFFFFL;
+ csize = ReadLeInt();
+ size = ReadLeInt();
+
+ entry.Size = size & 0xFFFFFFFFL;
+ entry.CompressedSize = csize & 0xFFFFFFFFL;
+ }
+
+ ///
+ /// Closes the current zip entry and moves to the next one.
+ ///
+ ///
+ /// The stream is closed
+ ///
+ ///
+ /// The Zip stream ends early
+ ///
+ public void CloseEntry()
+ {
+ if (crc == null) {
+ throw new InvalidOperationException("Closed.");
+ }
+
+ if (entry == null) {
+ return;
+ }
+
+ if (method == (int)CompressionMethod.Deflated) {
+ if ((flags & 8) != 0) {
+ // We don't know how much we must skip, read until end.
+ byte[] tmp = new byte[2048];
+ while (Read(tmp, 0, tmp.Length) > 0)
+ ;
+ // read will close this entry
+ return;
+ }
+ csize -= inf.TotalIn;
+ avail = inf.RemainingInput;
+ }
+
+ if (avail > csize && csize >= 0) {
+ avail -= csize;
+ } else {
+ csize -= avail;
+ avail = 0;
+ while (csize != 0) {
+ int skipped = (int)base.Skip(csize & 0xFFFFFFFFL);
+
+ if (skipped <= 0) {
+ throw new ZipException("Zip archive ends early.");
+ }
+
+ csize -= skipped;
+ }
+ }
+
+ size = 0;
+ crc.Reset();
+ if (method == (int)CompressionMethod.Deflated) {
+ inf.Reset();
+ }
+ entry = null;
+ }
+
+ ///
+ /// Returns 1 if there is an entry available
+ /// Otherwise returns 0.
+ ///
+ public override int Available {
+ get {
+ return entry != null ? 1 : 0;
+ }
+ }
+
+ ///
+ /// Reads a byte from the current zip entry.
+ ///
+ ///
+ /// The byte or -1 if end of stream is reached.
+ ///
+ ///
+ /// An i/o error occured.
+ ///
+ ///
+ /// The deflated stream is corrupted.
+ ///
+ public override int ReadByte()
+ {
+ byte[] b = new byte[1];
+ if (Read(b, 0, 1) <= 0) {
+ return -1; // ok
+ }
+ return b[0] & 0xff;
+ }
+
+ ///
+ /// Reads a block of bytes from the current zip entry.
+ ///
+ ///
+ /// The number of bytes read (this may be less than the length requested, even before the end of stream), or 0 on end of stream.
+ ///
+ ///
+ /// An i/o error occured.
+ ///
+ ///
+ /// The deflated stream is corrupted.
+ ///
+ ///
+ /// The stream is not open.
+ ///
+ public override int Read(byte[] b, int off, int len)
+ {
+ if (crc == null) {
+ throw new InvalidOperationException("Closed.");
+ }
+
+ if (entry == null) {
+ return 0;
+ }
+
+ bool finished = false;
+
+ switch (method) {
+ case (int)CompressionMethod.Deflated:
+ len = base.Read(b, off, len);
+ if (len <= 0) {
+ if (!inf.IsFinished) {
+ throw new ZipException("Inflater not finished!?");
+ }
+ avail = inf.RemainingInput;
+
+ if ((flags & 8) == 0 && (inf.TotalIn != csize || inf.TotalOut != size)) {
+ throw new ZipException("size mismatch: " + csize + ";" + size + " <-> " + inf.TotalIn + ";" + inf.TotalOut);
+ }
+ inf.Reset();
+ finished = true;
+ }
+ break;
+
+ case (int)CompressionMethod.Stored:
+ if (len > csize && csize >= 0) {
+ len = (int)csize;
+ }
+ len = ReadBuf(b, off, len);
+ if (len > 0) {
+ csize -= len;
+ size -= len;
+ }
+
+ if (csize == 0) {
+ finished = true;
+ } else {
+ if (len < 0) {
+ throw new ZipException("EOF in stored block");
+ }
+ }
+
+ // cipher text needs decrypting
+ if (cryptbuffer != null) {
+ DecryptBlock(b, off, len);
+ }
+
+ break;
+ }
+
+ if (len > 0) {
+ crc.Update(b, off, len);
+ }
+
+ if (finished) {
+ StopDecrypting();
+ if ((flags & 8) != 0) {
+ ReadDataDescriptor();
+ }
+
+ if ((crc.Value & 0xFFFFFFFFL) != entry.Crc && entry.Crc != -1) {
+ throw new ZipException("CRC mismatch");
+ }
+ crc.Reset();
+ entry = null;
+ }
+ return len;
+ }
+
+ ///
+ /// Closes the zip input stream
+ ///
+ public override void Close()
+ {
+ base.Close();
+ crc = null;
+ entry = null;
+ }
+ }
+}
diff --git a/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/ZipOutputStream.cs b/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/ZipOutputStream.cs
new file mode 100644
index 0000000..3fc8818
--- /dev/null
+++ b/Samples/Chapter5/Zip Pipeline Component/ICSharpCode.SharpZipLib/zip/ZipOutputStream.cs
@@ -0,0 +1,589 @@
+// ZipOutputStream.cs
+//
+// Copyright (C) 2001 Mike Krueger
+// Copyright (C) 2004 John Reilly
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// Linking this library statically or dynamically with other modules is
+// making a combined work based on this library. Thus, the terms and
+// conditions of the GNU General Public License cover the whole
+// combination.
+//
+// As a special exception, the copyright holders of this library give you
+// permission to link this library with independent modules to produce an
+// executable, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting executable under
+// terms of your choice, provided that you also meet, for each linked
+// independent module, the terms and conditions of the license of that
+// module. An independent module is a module which is not derived from
+// or based on this library. If you modify this library, you may extend
+// this exception to your version of the library, but you are not
+// obligated to do so. If you do not wish to do so, delete this
+// exception statement from your version.
+
+using System;
+using System.IO;
+using System.Collections;
+using System.Text;
+
+using ICSharpCode.SharpZipLib.Checksums;
+using ICSharpCode.SharpZipLib.Zip.Compression;
+using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
+
+namespace ICSharpCode.SharpZipLib.Zip
+{
+ ///
+ /// This is a DeflaterOutputStream that writes the files into a zip
+ /// archive one after another. It has a special method to start a new
+ /// zip entry. The zip entries contains information about the file name
+ /// size, compressed size, CRC, etc.
+ ///
+ /// It includes support for Stored and Deflated entries.
+ /// This class is not thread safe.
+ ///
+ /// Author of the original java version : Jochen Hoenicke
+ ///
+ /// This sample shows how to create a zip file
+ ///
+ /// using System;
+ /// using System.IO;
+ ///
+ /// using ICSharpCode.SharpZipLib.Zip;
+ ///
+ /// class MainClass
+ /// {
+ /// public static void Main(string[] args)
+ /// {
+ /// string[] filenames = Directory.GetFiles(args[0]);
+ ///
+ /// ZipOutputStream s = new ZipOutputStream(File.Create(args[1]));
+ ///
+ /// s.SetLevel(5); // 0 - store only to 9 - means best compression
+ ///
+ /// foreach (string file in filenames) {
+ /// FileStream fs = File.OpenRead(file);
+ ///
+ /// byte[] buffer = new byte[fs.Length];
+ /// fs.Read(buffer, 0, buffer.Length);
+ ///
+ /// ZipEntry entry = new ZipEntry(file);
+ ///
+ /// s.PutNextEntry(entry);
+ ///
+ /// s.Write(buffer, 0, buffer.Length);
+ ///
+ /// }
+ ///
+ /// s.Finish();
+ /// s.Close();
+ /// }
+ /// }
+ ///
+ ///
+ public class ZipOutputStream : DeflaterOutputStream
+ {
+ private ArrayList entries = new ArrayList();
+ private Crc32 crc = new Crc32();
+ private ZipEntry curEntry = null;
+
+ int defaultCompressionLevel = Deflater.DEFAULT_COMPRESSION;
+ CompressionMethod curMethod = CompressionMethod.Deflated;
+
+
+ private long size;
+ private long offset = 0;
+
+ private byte[] zipComment = new byte[0];
+
+ ///
+ /// Gets boolean indicating central header has been added for this archive...
+ /// No further entries can be added once this has been done.
+ ///
+ public bool IsFinished {
+ get {
+ return entries == null;
+ }
+ }
+
+ ///
+ /// Creates a new Zip output stream, writing a zip archive.
+ ///
+ ///
+ /// The output stream to which the archive contents are written.
+ ///
+ public ZipOutputStream(Stream baseOutputStream) : base(baseOutputStream, new Deflater(Deflater.DEFAULT_COMPRESSION, true))
+ {
+ }
+
+ ///
+ /// Set the zip file comment.
+ ///
+ ///
+ /// The comment string
+ ///
+ ///
+ /// Encoding of comment is longer than 0xffff bytes.
+ ///
+ public void SetComment(string comment)
+ {
+ byte[] commentBytes = ZipConstants.ConvertToArray(comment);
+ if (commentBytes.Length > 0xffff) {
+ throw new ArgumentOutOfRangeException("comment", "Comment too long.");
+ }
+ zipComment = commentBytes;
+ }
+
+ ///
+ /// Sets default compression level. The new level will be activated
+ /// immediately.
+ ///
+ ///
+ /// Level specified is not supported.
+ ///
+ ///
+ public void SetLevel(int level)
+ {
+ defaultCompressionLevel = level;
+ def.SetLevel(level);
+ }
+
+ ///
+ /// Get the current deflate compression level
+ ///
+ /// The current compression level
+ public int GetLevel()
+ {
+ return def.GetLevel();
+ }
+
+ ///
+ /// Write an unsigned short in little endian byte order.
+ ///
+ private void WriteLeShort(int value)
+ {
+ baseOutputStream.WriteByte((byte)value);
+ baseOutputStream.WriteByte((byte)(value >> 8));
+ }
+
+ ///
+ /// Write an int in little endian byte order.
+ ///
+ private void WriteLeInt(int value)
+ {
+ WriteLeShort(value);
+ WriteLeShort(value >> 16);
+ }
+
+ ///
+ /// Write an int in little endian byte order.
+ ///
+ private void WriteLeLong(long value)
+ {
+ WriteLeInt((int)value);
+ WriteLeInt((int)(value >> 32));
+ }
+
+
+ bool patchEntryHeader = false;
+
+ long headerPatchPos = -1;
+
+ ///
+ /// Starts a new Zip entry. It automatically closes the previous
+ /// entry if present.
+ /// All entry elements bar name are optional, but must be correct if present.
+ /// If the compression method is stored and the output is not patchable
+ /// the compression for that entry is automatically changed to deflate level 0
+ ///
+ ///
+ /// the entry.
+ ///
+ ///
+ /// if an I/O error occured.
+ ///
+ ///
+ /// if stream was finished
+ ///
+ ///
+ /// Too many entries in the Zip file
+ /// Entry name is too long
+ /// Finish has already been called
+ ///
+ public void PutNextEntry(ZipEntry entry)
+ {
+ if (entries == null) {
+ throw new InvalidOperationException("ZipOutputStream was finished");
+ }
+
+ if (curEntry != null) {
+ CloseEntry();
+ }
+
+ if (entries.Count >= 0xffff) {
+ throw new ZipException("Too many entries for Zip file");
+ }
+
+ CompressionMethod method = entry.CompressionMethod;
+ int compressionLevel = defaultCompressionLevel;
+
+ entry.Flags = 0;
+ patchEntryHeader = false;
+ bool headerInfoAvailable = true;
+
+ if (method == CompressionMethod.Stored) {
+ if (entry.CompressedSize >= 0) {
+ if (entry.Size < 0) {
+ entry.Size = entry.CompressedSize;
+ } else if (entry.Size != entry.CompressedSize) {
+ throw new ZipException("Method STORED, but compressed size != size");
+ }
+ } else {
+ if (entry.Size >= 0) {
+ entry.CompressedSize = entry.Size;
+ }
+ }
+
+ if (entry.Size < 0 || entry.Crc < 0) {
+ if (CanPatchEntries == true) {
+ headerInfoAvailable = false;
+ }
+ else {
+ method = CompressionMethod.Deflated;
+ compressionLevel = 0;
+ }
+ }
+ }
+
+ if (method == CompressionMethod.Deflated) {
+ if (entry.Size == 0) {
+ entry.CompressedSize = entry.Size;
+ entry.Crc = 0;
+ method = CompressionMethod.Stored;
+ } else if (entry.CompressedSize < 0 || entry.Size < 0 || entry.Crc < 0) {
+ headerInfoAvailable = false;
+ }
+ }
+
+ if (headerInfoAvailable == false) {
+ if (CanPatchEntries == false) {
+ entry.Flags |= 8;
+ } else {
+ patchEntryHeader = true;
+ }
+ }
+
+ if (Password != null) {
+ entry.IsCrypted = true;
+ if (entry.Crc < 0) {
+ entry.Flags |= 8;
+ }
+ }
+ entry.Offset = (int)offset;
+ entry.CompressionMethod = (CompressionMethod)method;
+
+ curMethod = method;
+
+ // Write the local file header
+ WriteLeInt(ZipConstants.LOCSIG);
+
+ WriteLeShort(entry.Version);
+ WriteLeShort(entry.Flags);
+ WriteLeShort((byte)method);
+ WriteLeInt((int)entry.DosTime);
+ if (headerInfoAvailable == true) {
+ WriteLeInt((int)entry.Crc);
+ WriteLeInt(entry.IsCrypted ? (int)entry.CompressedSize + ZipConstants.CRYPTO_HEADER_SIZE : (int)entry.CompressedSize);
+ WriteLeInt((int)entry.Size);
+ } else {
+ if (patchEntryHeader == true) {
+ headerPatchPos = baseOutputStream.Position;
+ }
+ WriteLeInt(0); // Crc
+ WriteLeInt(0); // Compressed size
+ WriteLeInt(0); // Uncompressed size
+ }
+
+ byte[] name = ZipConstants.ConvertToArray(entry.Name);
+
+ if (name.Length > 0xFFFF) {
+ throw new ZipException("Entry name too long.");
+ }
+
+ byte[] extra = entry.ExtraData;
+ if (extra == null) {
+ extra = new byte[0];
+ }
+
+ if (extra.Length > 0xFFFF) {
+ throw new ZipException("Extra data too long.");
+ }
+
+ WriteLeShort(name.Length);
+ WriteLeShort(extra.Length);
+ baseOutputStream.Write(name, 0, name.Length);
+ baseOutputStream.Write(extra, 0, extra.Length);
+
+ offset += ZipConstants.LOCHDR + name.Length + extra.Length;
+
+ // Activate the entry.
+ curEntry = entry;
+ crc.Reset();
+ if (method == CompressionMethod.Deflated) {
+ def.Reset();
+ def.SetLevel(compressionLevel);
+ }
+ size = 0;
+
+ if (entry.IsCrypted == true) {
+ if (entry.Crc < 0) { // so testing Zip will says its ok
+ WriteEncryptionHeader(entry.DosTime << 16);
+ } else {
+ WriteEncryptionHeader(entry.Crc);
+ }
+ }
+ }
+
+ ///
+ /// Closes the current entry, updating header and footer information as required
+ ///
+ ///
+ /// An I/O error occurs.
+ ///
+ ///
+ /// No entry is active.
+ ///
+ public void CloseEntry()
+ {
+ if (curEntry == null) {
+ throw new InvalidOperationException("No open entry");
+ }
+
+ // First finish the deflater, if appropriate
+ if (curMethod == CompressionMethod.Deflated) {
+ base.Finish();
+ }
+
+ long csize = curMethod == CompressionMethod.Deflated ? def.TotalOut : size;
+
+ if (curEntry.Size < 0) {
+ curEntry.Size = size;
+ } else if (curEntry.Size != size) {
+ throw new ZipException("size was " + size + ", but I expected " + curEntry.Size);
+ }
+
+ if (curEntry.CompressedSize < 0) {
+ curEntry.CompressedSize = csize;
+ } else if (curEntry.CompressedSize != csize) {
+ throw new ZipException("compressed size was " + csize + ", but I expected " + curEntry.CompressedSize);
+ }
+
+ if (curEntry.Crc < 0) {
+ curEntry.Crc = crc.Value;
+ } else if (curEntry.Crc != crc.Value) {
+ throw new ZipException("crc was " + crc.Value + ", but I expected " + curEntry.Crc);
+ }
+
+ offset += csize;
+
+ if (offset > 0xffffffff) {
+ throw new ZipException("Maximum Zip file size exceeded");
+ }
+
+ if (curEntry.IsCrypted == true) {
+ curEntry.CompressedSize += ZipConstants.CRYPTO_HEADER_SIZE;
+ }
+
+ // Patch the header if possible
+ if (patchEntryHeader == true) {
+ long curPos = baseOutputStream.Position;
+ baseOutputStream.Seek(headerPatchPos, SeekOrigin.Begin);
+ WriteLeInt((int)curEntry.Crc);
+ WriteLeInt((int)curEntry.CompressedSize);
+ WriteLeInt((int)curEntry.Size);
+ baseOutputStream.Seek(curPos, SeekOrigin.Begin);
+ patchEntryHeader = false;
+ }
+
+ // Add data descriptor if flagged as required
+ if ((curEntry.Flags & 8) != 0) {
+ WriteLeInt(ZipConstants.EXTSIG);
+ WriteLeInt((int)curEntry.Crc);
+ WriteLeInt((int)curEntry.CompressedSize);
+ WriteLeInt((int)curEntry.Size);
+ offset += ZipConstants.EXTHDR;
+ }
+
+ entries.Add(curEntry);
+ curEntry = null;
+ }
+
+ void WriteEncryptionHeader(long crcValue)
+ {
+ offset += ZipConstants.CRYPTO_HEADER_SIZE;
+
+ InitializePassword(Password);
+
+ byte[] cryptBuffer = new byte[ZipConstants.CRYPTO_HEADER_SIZE];
+ Random rnd = new Random();
+ rnd.NextBytes(cryptBuffer);
+ cryptBuffer[11] = (byte)(crcValue >> 24);
+
+ EncryptBlock(cryptBuffer, 0, cryptBuffer.Length);
+ baseOutputStream.Write(cryptBuffer, 0, cryptBuffer.Length);
+ }
+
+ ///
+ /// Writes the given buffer to the current entry.
+ ///
+ ///
+ /// Archive size is invalid
+ ///
+ ///
+ /// No entry is active.
+ ///
+ public override void Write(byte[] b, int off, int len)
+ {
+ if (curEntry == null) {
+ throw new InvalidOperationException("No open entry.");
+ }
+
+ if (len <= 0)
+ return;
+
+ crc.Update(b, off, len);
+ size += len;
+
+ if (size > 0xffffffff || size < 0) {
+ throw new ZipException("Maximum entry size exceeded");
+ }
+
+
+ switch (curMethod) {
+ case CompressionMethod.Deflated:
+ base.Write(b, off, len);
+ break;
+
+ case CompressionMethod.Stored:
+ if (Password != null) {
+ byte[] buf = new byte[len];
+ Array.Copy(b, off, buf, 0, len);
+ EncryptBlock(buf, 0, len);
+ baseOutputStream.Write(buf, off, len);
+ } else {
+ baseOutputStream.Write(b, off, len);
+ }
+ break;
+ }
+ }
+
+ ///
+ /// Finishes the stream. This will write the central directory at the
+ /// end of the zip file and flush the stream.
+ ///
+ ///
+ /// This is automatically called when the stream is closed.
+ ///
+ ///
+ /// An I/O error occurs.
+ ///
+ ///
+ /// Comment exceeds the maximum length
+ /// Entry name exceeds the maximum length
+ ///
+ public override void Finish()
+ {
+ if (entries == null) {
+ return;
+ }
+
+ if (curEntry != null) {
+ CloseEntry();
+ }
+
+ int numEntries = 0;
+ int sizeEntries = 0;
+
+ foreach (ZipEntry entry in entries) {
+ CompressionMethod method = entry.CompressionMethod;
+ WriteLeInt(ZipConstants.CENSIG);
+ WriteLeShort(ZipConstants.VERSION_MADE_BY);
+ WriteLeShort(entry.Version);
+ WriteLeShort(entry.Flags);
+ WriteLeShort((short)method);
+ WriteLeInt((int)entry.DosTime);
+ WriteLeInt((int)entry.Crc);
+ WriteLeInt((int)entry.CompressedSize);
+ WriteLeInt((int)entry.Size);
+
+ byte[] name = ZipConstants.ConvertToArray(entry.Name);
+
+ if (name.Length > 0xffff) {
+ throw new ZipException("Name too long.");
+ }
+
+ byte[] extra = entry.ExtraData;
+ if (extra == null) {
+ extra = new byte[0];
+ }
+
+ byte[] entryComment = entry.Comment != null ? ZipConstants.ConvertToArray(entry.Comment) : new byte[0];
+ if (entryComment.Length > 0xffff) {
+ throw new ZipException("Comment too long.");
+ }
+
+ WriteLeShort(name.Length);
+ WriteLeShort(extra.Length);
+ WriteLeShort(entryComment.Length);
+ WriteLeShort(0); // disk number
+ WriteLeShort(0); // internal file attr
+ // external file attribute
+
+ if (entry.ExternalFileAttributes != -1) {
+ WriteLeInt(entry.ExternalFileAttributes);
+ } else {
+ if (entry.IsDirectory) { // mark entry as directory (from nikolam.AT.perfectinfo.com)
+ WriteLeInt(16);
+ } else {
+ WriteLeInt(0);
+ }
+ }
+
+ WriteLeInt(entry.Offset);
+
+ baseOutputStream.Write(name, 0, name.Length);
+ baseOutputStream.Write(extra, 0, extra.Length);
+ baseOutputStream.Write(entryComment, 0, entryComment.Length);
+ ++numEntries;
+ sizeEntries += ZipConstants.CENHDR + name.Length + extra.Length + entryComment.Length;
+ }
+
+ WriteLeInt(ZipConstants.ENDSIG);
+ WriteLeShort(0); // number of this disk
+ WriteLeShort(0); // no of disk with start of central dir
+ WriteLeShort(numEntries); // entries in central dir for this disk
+ WriteLeShort(numEntries); // total entries in central directory
+ WriteLeInt(sizeEntries); // size of the central directory
+ WriteLeInt((int)offset); // offset of start of central dir
+ WriteLeShort(zipComment.Length);
+ baseOutputStream.Write(zipComment, 0, zipComment.Length);
+ baseOutputStream.Flush();
+ entries = null;
+ }
+ }
+}
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/AssemblyInfo.cs b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/AssemblyInfo.cs
new file mode 100644
index 0000000..2a20445
--- /dev/null
+++ b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/AssemblyInfo.cs
@@ -0,0 +1,58 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+//
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+//
+[assembly: AssemblyTitle("")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+//
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+
+[assembly: AssemblyVersion("1.0.*")]
+
+//
+// In order to sign your assembly you must specify a key to use. Refer to the
+// Microsoft .NET Framework documentation for more information on assembly signing.
+//
+// Use the attributes below to control which key is used for signing.
+//
+// Notes:
+// (*) If no key is specified, the assembly is not signed.
+// (*) KeyName refers to a key that has been installed in the Crypto Service
+// Provider (CSP) on your machine. KeyFile refers to a file which contains
+// a key.
+// (*) If the KeyFile and the KeyName values are both specified, the
+// following processing occurs:
+// (1) If the KeyName can be found in the CSP, that key is used.
+// (2) If the KeyName does not exist and the KeyFile does exist, the key
+// in the KeyFile is installed into the CSP and used.
+// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
+// When specifying the KeyFile, the location of the KeyFile should be
+// relative to the project output directory which is
+// %Project Directory%\obj\. For example, if your KeyFile is
+// located in the project directory, you would specify the AssemblyKeyFile
+// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
+// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
+// documentation for more information on this.
+//
+[assembly: AssemblyDelaySign(false)]
+[assembly: AssemblyKeyFile(@"..\..\..\..\SigningKey.snk")]
+[assembly: AssemblyKeyName("")]
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/Chapter 5 - Zip pipeline sample.suo b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/Chapter 5 - Zip pipeline sample.suo
new file mode 100644
index 0000000..c01dbb8
Binary files /dev/null and b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/Chapter 5 - Zip pipeline sample.suo differ
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/FileStreamReadWrite.cs b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/FileStreamReadWrite.cs
new file mode 100644
index 0000000..5ec36a2
--- /dev/null
+++ b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/FileStreamReadWrite.cs
@@ -0,0 +1,62 @@
+namespace Microsoft.Samples.PipelineUtilities
+{
+ using System;
+ using System.IO;
+
+ ///
+ /// Summary description for FileStreamReadWrite.
+ ///
+ public abstract class FileStreamReadWrite
+ {
+ public static void DumpStreamToFile (Stream fromStream, string toFilename)
+ {
+ FileStream file = null;
+ try
+ {
+ file = new FileStream(toFilename, System.IO.FileMode.Create);
+ byte[] tmpBuff = new byte[4096];
+ int bytesRead = 0;
+
+ while ((bytesRead = fromStream.Read(tmpBuff, 0, tmpBuff.Length)) != 0)
+ {
+ file.Write(tmpBuff, 0, bytesRead);
+ }
+
+ file.Close();
+ file = null;
+ }
+ finally
+ {
+ if (file != null) file.Close();
+ }
+ }
+
+ public static MemoryStream ReadFileToMemoryStream (string fromFilename)
+ {
+ FileStream file = null;
+ try
+ {
+ file = new FileStream(fromFilename, System.IO.FileMode.Open);
+ MemoryStream memStream = new MemoryStream();
+ byte[] tmpBuff = new byte[4096];
+ int bytesRead = 0;
+
+ while ((bytesRead = file.Read(tmpBuff, 0, tmpBuff.Length)) != 0)
+ {
+ memStream.Write(tmpBuff, 0, bytesRead);
+ }
+
+ file.Close();
+ file = null;
+
+ memStream.Position = 0;
+ return memStream;
+ }
+ finally
+ {
+ if (file != null) file.Close();
+ }
+ }
+
+ }
+}
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/Microsoft.Samples.PipelineUtilities.csproj b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/Microsoft.Samples.PipelineUtilities.csproj
new file mode 100644
index 0000000..488f189
--- /dev/null
+++ b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/Microsoft.Samples.PipelineUtilities.csproj
@@ -0,0 +1,109 @@
+
+
+ Local
+ 8.0.50727
+ 2.0
+ {74CE9A86-DF65-4D45-A7AF-1AC351E5B5C3}
+ Debug
+ AnyCPU
+
+
+
+
+ Microsoft.Samples.PipelineUtilities
+
+
+ JScript
+ Grid
+ IE50
+ false
+ Library
+ Microsoft.Samples.PipelineUtilities
+ OnBuildSuccess
+
+
+
+
+
+
+
+
+ bin\Debug\
+ false
+ 285212672
+ false
+
+
+ DEBUG;TRACE
+
+
+ true
+ 4096
+ false
+
+
+ false
+ false
+ false
+ false
+ 4
+ full
+ prompt
+
+
+ bin\Release\
+ false
+ 285212672
+ false
+
+
+ TRACE
+
+
+ false
+ 4096
+ false
+
+
+ true
+ false
+ false
+ false
+ 4
+ none
+ prompt
+
+
+
+ Microsoft.BizTalk.Pipeline
+ ..\..\..\Program Files\Microsoft BizTalk Server 2004\Microsoft.BizTalk.Pipeline.dll
+
+
+ System
+
+
+ System.Data
+
+
+ System.XML
+
+
+
+
+ Code
+
+
+ Code
+
+
+ Code
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/Microsoft.Samples.PipelineUtilities.csproj.user b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/Microsoft.Samples.PipelineUtilities.csproj.user
new file mode 100644
index 0000000..7e53e79
--- /dev/null
+++ b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/Microsoft.Samples.PipelineUtilities.csproj.user
@@ -0,0 +1,57 @@
+
+
+ 7.10.3077
+ Debug
+ AnyCPU
+ C:\Program Files\Microsoft BizTalk Server 2004\
+
+
+
+
+ 0
+ ProjectFiles
+ 0
+
+
+ false
+ false
+ false
+ false
+ false
+
+
+ Project
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+ false
+ false
+ false
+ false
+ false
+
+
+ Project
+
+
+
+
+
+
+
+
+
+
+ true
+
+
\ No newline at end of file
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/PropertyBagReadWrite.cs b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/PropertyBagReadWrite.cs
new file mode 100644
index 0000000..0a43cea
--- /dev/null
+++ b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/PropertyBagReadWrite.cs
@@ -0,0 +1,55 @@
+using System;
+
+namespace Microsoft.Samples.PipelineUtilities
+{
+ ///
+ /// Summary description for PropertyBagReadWrite.
+ ///
+ public abstract class PropertyBagReadWrite
+ {
+ ///
+ /// Reads property value from property bag.
+ ///
+ /// Property bag.
+ /// Name of property.
+ /// Value of the property.
+ public static object ReadPropertyBag(Microsoft.BizTalk.Component.Interop.IPropertyBag pb, string propName)
+ {
+ object val = null;
+
+ try
+ {
+ pb.Read(propName, out val, 0);
+ }
+ catch(ArgumentException)
+ {
+ return val;
+ }
+ catch(Exception ex)
+ {
+ throw new ApplicationException(ex.Message);
+ }
+
+ return val;
+ }
+
+ ///
+ /// Writes property values into a property bag.
+ ///
+ /// Property bag.
+ /// Name of property.
+ /// Value of property.
+ public static void WritePropertyBag(Microsoft.BizTalk.Component.Interop.IPropertyBag pb, string propName, object val)
+ {
+ try
+ {
+ pb.Write(propName, ref val);
+ }
+ catch(Exception ex)
+ {
+ throw new ApplicationException(ex.Message);
+ }
+ }
+
+ }
+}
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/bin/Debug/Microsoft.Samples.PipelineUtilities.dll b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/bin/Debug/Microsoft.Samples.PipelineUtilities.dll
new file mode 100644
index 0000000..ce86d67
Binary files /dev/null and b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/bin/Debug/Microsoft.Samples.PipelineUtilities.dll differ
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/bin/Debug/Microsoft.Samples.PipelineUtilities.pdb b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/bin/Debug/Microsoft.Samples.PipelineUtilities.pdb
new file mode 100644
index 0000000..c5335f3
Binary files /dev/null and b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/bin/Debug/Microsoft.Samples.PipelineUtilities.pdb differ
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/bin/Debug/Microsoft.Utility.PipelinePropertyAttribute.dll b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/bin/Debug/Microsoft.Utility.PipelinePropertyAttribute.dll
new file mode 100644
index 0000000..7cc9402
Binary files /dev/null and b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/bin/Debug/Microsoft.Utility.PipelinePropertyAttribute.dll differ
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/bin/Debug/Microsoft.Utility.PipelinePropertyAttribute.pdb b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/bin/Debug/Microsoft.Utility.PipelinePropertyAttribute.pdb
new file mode 100644
index 0000000..4478349
Binary files /dev/null and b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/bin/Debug/Microsoft.Utility.PipelinePropertyAttribute.pdb differ
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/obj/Debug/Microsoft.Samples.PipelineUtilities.dll b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/obj/Debug/Microsoft.Samples.PipelineUtilities.dll
new file mode 100644
index 0000000..ce86d67
Binary files /dev/null and b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/obj/Debug/Microsoft.Samples.PipelineUtilities.dll differ
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/obj/Debug/Microsoft.Samples.PipelineUtilities.pdb b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/obj/Debug/Microsoft.Samples.PipelineUtilities.pdb
new file mode 100644
index 0000000..c5335f3
Binary files /dev/null and b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/obj/Debug/Microsoft.Samples.PipelineUtilities.pdb differ
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/obj/Debug/Microsoft.Utility.PipelinePropertyAttribute.dll b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/obj/Debug/Microsoft.Utility.PipelinePropertyAttribute.dll
new file mode 100644
index 0000000..7cc9402
Binary files /dev/null and b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/obj/Debug/Microsoft.Utility.PipelinePropertyAttribute.dll differ
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/obj/Debug/Microsoft.Utility.PipelinePropertyAttribute.pdb b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/obj/Debug/Microsoft.Utility.PipelinePropertyAttribute.pdb
new file mode 100644
index 0000000..4478349
Binary files /dev/null and b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/obj/Debug/Microsoft.Utility.PipelinePropertyAttribute.pdb differ
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/obj/Debug/Microsoft.Utility.PipelinePropertyAttribute.projdata b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/obj/Debug/Microsoft.Utility.PipelinePropertyAttribute.projdata
new file mode 100644
index 0000000..dbcaa24
Binary files /dev/null and b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/obj/Debug/Microsoft.Utility.PipelinePropertyAttribute.projdata differ
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/obj/Microsoft.Samples.PipelineUtilities.csproj.FileList.txt b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/obj/Microsoft.Samples.PipelineUtilities.csproj.FileList.txt
new file mode 100644
index 0000000..358d4c7
--- /dev/null
+++ b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/obj/Microsoft.Samples.PipelineUtilities.csproj.FileList.txt
@@ -0,0 +1,5 @@
+bin\Debug\Microsoft.Samples.PipelineUtilities.dll
+bin\Debug\Microsoft.Samples.PipelineUtilities.pdb
+obj\Debug\ResolveAssemblyReference.cache
+obj\Debug\Microsoft.Samples.PipelineUtilities.dll
+obj\Debug\Microsoft.Samples.PipelineUtilities.pdb
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/obj/Microsoft.Utility.PipelinePropertyAttribute.csproj.FileList.txt b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/obj/Microsoft.Utility.PipelinePropertyAttribute.csproj.FileList.txt
new file mode 100644
index 0000000..77536ff
--- /dev/null
+++ b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Samples.Utilities/obj/Microsoft.Utility.PipelinePropertyAttribute.csproj.FileList.txt
@@ -0,0 +1,5 @@
+bin\Debug\Microsoft.Utility.PipelinePropertyAttribute.dll
+bin\Debug\Microsoft.Utility.PipelinePropertyAttribute.pdb
+obj\Debug\ResolveAssemblyReference.cache
+obj\Debug\Microsoft.Utility.PipelinePropertyAttribute.dll
+obj\Debug\Microsoft.Utility.PipelinePropertyAttribute.pdb
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/AssemblyInfo.cs b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/AssemblyInfo.cs
new file mode 100644
index 0000000..f30d972
--- /dev/null
+++ b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/AssemblyInfo.cs
@@ -0,0 +1,58 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+//
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+//
+[assembly: AssemblyTitle("Microsoft.Utility.PipelineZip")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+//
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+
+[assembly: AssemblyVersion("1.0.0.0")]
+
+//
+// In order to sign your assembly you must specify a key to use. Refer to the
+// Microsoft .NET Framework documentation for more information on assembly signing.
+//
+// Use the attributes below to control which key is used for signing.
+//
+// Notes:
+// (*) If no key is specified, the assembly is not signed.
+// (*) KeyName refers to a key that has been installed in the Crypto Service
+// Provider (CSP) on your machine. KeyFile refers to a file which contains
+// a key.
+// (*) If the KeyFile and the KeyName values are both specified, the
+// following processing occurs:
+// (1) If the KeyName can be found in the CSP, that key is used.
+// (2) If the KeyName does not exist and the KeyFile does exist, the key
+// in the KeyFile is installed into the CSP and used.
+// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
+// When specifying the KeyFile, the location of the KeyFile should be
+// relative to the project output directory which is
+// %Project Directory%\obj\. For example, if your KeyFile is
+// located in the project directory, you would specify the AssemblyKeyFile
+// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
+// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
+// documentation for more information on this.
+//
+[assembly: AssemblyDelaySign(false)]
+[assembly: AssemblyKeyFile(@"..\..\..\..\SigningKey.snk")]
+[assembly: AssemblyKeyName("")]
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/Microsoft.Utility.PipelineZip.csproj b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/Microsoft.Utility.PipelineZip.csproj
new file mode 100644
index 0000000..091a119
--- /dev/null
+++ b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/Microsoft.Utility.PipelineZip.csproj
@@ -0,0 +1,128 @@
+
+
+ Local
+ 8.0.50727
+ 2.0
+ {548FA7AD-797A-4437-A5D5-2EBF4F718281}
+ Debug
+ AnyCPU
+
+
+
+
+ Microsoft.Utility.PipelineZip
+
+
+ JScript
+ Grid
+ IE50
+ false
+ Library
+ Microsoft.Utility.PipelineZip
+ OnBuildSuccess
+
+
+
+
+
+
+
+
+ C:\Program Files\Microsoft BizTalk Server 2006\Pipeline Components\
+ false
+ 285212672
+ false
+
+
+ DEBUG;TRACE
+
+
+ true
+ 4096
+ false
+
+
+ false
+ false
+ false
+ false
+ 4
+ full
+ prompt
+
+
+ bin\Release\
+ false
+ 285212672
+ false
+
+
+ TRACE
+
+
+ false
+ 4096
+ false
+
+
+ true
+ false
+ false
+ false
+ 4
+ none
+ prompt
+
+
+
+ Microsoft.BizTalk.Pipeline
+ ..\..\..\Program Files\Microsoft BizTalk Server 2004\Microsoft.BizTalk.Pipeline.dll
+
+
+ System
+
+
+ System.Data
+
+
+ System.Drawing
+
+
+ System.XML
+
+
+ ICSharpCode.SharpZipLib
+ {7F1C5F40-A2C9-4B92-8A23-78E95A74C194}
+ {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+
+
+ {74CE9A86-DF65-4D45-A7AF-1AC351E5B5C3}
+ Microsoft.Samples.PipelineUtilities
+
+
+
+
+ Code
+
+
+ Code
+
+
+ Code
+
+
+
+ ZipDecodeComponent.cs
+
+
+ ZipEncodeComponent.cs
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/Microsoft.Utility.PipelineZip.csproj.user b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/Microsoft.Utility.PipelineZip.csproj.user
new file mode 100644
index 0000000..06d9ca8
--- /dev/null
+++ b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/Microsoft.Utility.PipelineZip.csproj.user
@@ -0,0 +1,55 @@
+
+
+ 7.10.3077
+ Debug
+ AnyCPU
+ C:\Program Files\Microsoft BizTalk Server 2004\
+
+
+
+
+ 0
+ ProjectFiles
+ 0
+
+
+ false
+ false
+ false
+ false
+ false
+
+
+ Program
+ "C:\test\PipelineComponents\BtpTest\ZipDecode.btp" -d "C:\test\PipelineComponents\BtpTest\test.zip" -c
+
+
+ C:\Program Files\Microsoft BizTalk Server 2004\SDK\Utilities\PipelineTools\Pipeline.exe
+
+
+
+
+ true
+
+
+ false
+ false
+ false
+ false
+ false
+
+
+ Project
+
+
+
+
+
+
+
+
+
+
+ true
+
+
\ No newline at end of file
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/PipelineZip.resx b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/PipelineZip.resx
new file mode 100644
index 0000000..17bc7a8
--- /dev/null
+++ b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/PipelineZip.resx
@@ -0,0 +1,116 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 1.0.0.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+
+ Qk02EAAAAAAAADYAAAAoAAAAIAAAACAAAAABACAAAAAAAAAAAADEDgAAxA4AAAAAAAAAAAAA////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AIFoVgBjSTUAY0k1AGNJNQBjSTUAY0k1AGNJNQBjSTUAY0k1AGNJ
+ NQBjSTUAY0k1AGNJNQBjSTUAY0k1AGNJNQBjSTUAY0k1AGNJNQBjSTUAY0k1AGNJNQBjSTUA////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8AhGtZAPTbzgDewLEA3L6uANu8rADbu6oA2bmoANi3
+ pQDYtaMA17OhANaxnwDWsJwA1K2aANSrlwDSqpYA0qiTANCmkQDQpI8Az6ONAM+giwDNn4kAzZ6HAGNJ
+ NQD///8A////AP///wD///8A////AP///wD///8A////AP///wCGblsA9NzRAPru6QD57OYA+erjAPfn
+ 3wD45dwA9+PaAPbg1wD139QA9N3RAPTbzgDz2MsA89bIAPLTxQDx0cIA8c+/APDNvADvy7kA78m2AO7H
+ tADNoIkAY0k1AP///wD///8A////AP///wD///8A////AP///wD///8A////AIlwXgD139MA+vDsAPnu
+ 6AD56+YA+eniAPjn3wD45dwA9uPaAPXh1gD13tQA9d3RAPTazQDz2MsA89XIAPLTxQDx0cEA8M++AO/N
+ vADvyrkA78i3AM+hiwBjSTUA////AP///wD///8A////AP///wD///8A////AP///wD///8Ai3NhAPbg
+ 1gD78u4A+vHrAKyZiwCJcV8A0L6yAM66rgDNuKsAy7aoAMy1qADeyLoA79fLAPTazQD02MoA89XIAPLT
+ xADx0MEA8c6/APDMuwDvy7kA0KKNAGNJNQD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wCNdmQA9uLYAPz08gD88+4Ahm5bALyjlgB6YE0AdVxJAHJYRABuVUAAfGNQALihkgDdxbgA9dzQAPTZ
+ zgDz2MoA89XIAPHTxADx0MEA8M6/APDMvADQpI8AY0k1AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AI94ZwD35NsA/Pb0APz08QCKcmAAzLivAHNaRwB/ZlUAjHNjAI11ZgB/Z1gAblVBAK+X
+ iAD13tMA9NzQAPTazgDz18oA89XHAPLTxADx0cEA8M6+ANGmkQBjSTUA////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8AkntpAPjm3gD9+fYA/PfzAI52ZQDe0coAp4+CANXGvQDEsKQAuqOVAKyQ
+ fgCVemcAfGNQAPXh1gD13tMA9dzQAPTazQDz18oA89XHAPLSwwDx0cEA0qmUAGNJNQD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wCVfWwA+OjhAP76+QD9+PYAk3tqAPHq6ACxmIsA6eLeAOPZ
+ 0wDXyL8AvaaZAJV6ZwBuVUEA9+LZAPXg1QD13tMA9NzQAPTZzQD018oA8tXHAPLSxADTq5YAY0k1AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AJZ/bwD56uMA/vz6AP76+ACWf24A////AI11
+ ZACAaVYArJiKANfIvwDPu7IAl3xpAHJYRQD25NsA9uLYAPXg1gD13tIA9NzQAPTZzQDz18kA89TGANSs
+ mQBjSTUA////AP///wD///8A////AP///wD///8A////AP///wD///8AmIJxAPns5gD//f0A/vz7AL6v
+ ogCum40A/PbzAM3AtgCJcF4A39PNANfIwACcgnAAdl1JAPjn3gD25NsA9uHYAPXg1QD13dMA9dzPAPTa
+ zADz18kA1a6bAGNJNQD///8A////AP///wD///8A////AP///wD///8A////AP///wCbhHMA+u7oAP/+
+ /gD+/f0A/vv6AP35+AD9+PYA/fbyAI10YgB7XksAjHJiAIFmVAB7YU8A+OjgAPfm3QD349sA9uLYAPbf
+ 1gD13dIA9NvPAPPZzADWsZ4AY0k1AP///wD///8A////AP///wD///8A////AP///wD///8A////AJ2H
+ dgD68esA////AP/+/gD+/fwA/vv6APn18gCijX0AqZKDAKuWiQChjYAAmYJ0AJB2ZACJcV8A+OjgAPfm
+ 3QD349oA9uLYAPbg1QD13dMA9NvPANezoABjSTUA////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8An4l5APvy7gD///8A////AP/+/QD+/fwA+/j2AL+soQD9/PsA8evoAOLX0ADUxLsAxrGmAKiU
+ hQD56uMA+OjgAPjm3QD249oA9uHYAPbg1AD13dIA17WjAGNJNQD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wCijHsA+/TxAP///wD///8A////AP/+/gD+/fwA+/j2AKeThADWzcYA49nTALif
+ kQCHcF0A+u/pAPns5wD46uMA+OjgAPjm3QD349oA9uHYAPbf1ADZt6UAY0k1AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AKSOfgD///8A////AP///wD///8A////AP///wD+/PwAqZSHANXM
+ xQDk2dMAvaaYAIx0YgD78ewA+u/pAPns5gD46uMA+OjgAPjl3AD249oA9uHXANq5pwBjSTUA////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8AppGBAP///wD///8A////AP///wD///8A////AP7+
+ /QCsmYoA2M7HAOXa1QDBq58AkHpoAPvz7wD78OwA+u/pAI94ZwCTfGsA+OjgAPjm3QD349oA27qqAGNJ
+ NQD///8A////AP///wD///8A////AP///wD///8A////AP///wCfiXkA+/LuAP///wD///8A////AP//
+ /wD///8A////ALCdjwDe1tAA6uLeAMu4rQCmjHwAknloAItzYQCHblwAr5WHAH1kUQD46uIA+OjgAPjl
+ 3ADbvKwAY0k1AP///wD///8A////AP///wD///8A////AP///wD///8A////AKKMewD79PEA////AP//
+ /wD///8A////AP///wD///8AtaSWAO3o5QDz7+0A283GALqjmACulYcAmYBvAJyDcgC6oZQAgmlWAPrs
+ 5gD56uMA+OffANy+rgBjSTUA////AP///wD///8A////AP///wD///8A////AP///wD///8ApI5+AP//
+ /wD///8A////AP///wD///8A////AP///wDQxbwA5uDbAPLu7ADs5+MA1ca/AMStoAC0m4wArpWGAMey
+ pgCFbVsA+u7pAPrr5gD56eIA3cGxAGNJNQD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wCmkYEA////AP///wD///8A////AP///wD///8A////APTx7wDLvbUA5d3YAO/q5wDo4d0A39XPANvQ
+ yQCwmIkA1MS6AIpyYQD78OsA+u7oAPnr5QDfwrMAY0k1AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AJ+JeQD78u4A////AP///wD///8A////AP///wD///8A////APPw7QDOwrkAu6qeALGe
+ kQCql4gApZKDAKOOfgDh1tAAjndlAPvy7gD78OsA+u7oAN/EtgBjSTUA////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8Aoox7APv08QD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP/+/AD+/PsA+fTxAMS3rAC4p5wA/PXxAPvz7QD68OsA4Me4AGNJNQD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wC4o5QA////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A//7+AP/+/AD++/sA/vr5AP349gDJtKkAvaWXALKZiQCkingAY0k1AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////ALqmmAD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A///+AP79/AD+/PsAnod2AGNJNQBjSTUAY0k1AGNJ
+ NQBjSTUA////AP///wD///8A////AP///wD///8A////AP///wD///8AvKiaAP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP/9/ACgiXkA1cW9AMex
+ pQC5oZIAbFI+AGNJNQD///8A////AP///wD///8A////AP///wD///8A////AP///wC+qpwA////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A///+AKKM
+ fADj2tMA1cW8AHlgTABsUj4A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AMCt
+ nwD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8ApY5+APPv7QCIcF0AeWBMAP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8Awq+hAP///wD///8A////AP///wD//fwA/vv7AP35+AD9+PUA/PXyAPvz7wD78OsA+u3oAPnr
+ 5AD46eIA9+fdAPfk2wCnkYIAln9uAIhwXQD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wDFsaMAw6+hAMKuoADArJ8Av6ucAL2pmwC8p5oAu6aXALiklQC3opQAtqGSALOf
+ kACynY8AsJuNAK6aiwCtmIgAq5aHAKmUhACWf24A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AA==
+
+
+
\ No newline at end of file
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/SharpZipLib.csproj.user b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/SharpZipLib.csproj.user
new file mode 100644
index 0000000..686cccb
--- /dev/null
+++ b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/SharpZipLib.csproj.user
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/ZipDecodeComponent.cs b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/ZipDecodeComponent.cs
new file mode 100644
index 0000000..0b14ff6
--- /dev/null
+++ b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/ZipDecodeComponent.cs
@@ -0,0 +1,181 @@
+namespace Microsoft.Utility.PipelineZip
+{
+ using System;
+ using System.ComponentModel;
+ using System.Collections;
+ using System.Diagnostics;
+ using System.Drawing;
+ using System.IO;
+ using System.Reflection;
+ using Microsoft.BizTalk.Component.Interop;
+ using Microsoft.Samples.PipelineUtilities;
+ using ICSharpCode.SharpZipLib.Zip;
+
+ [ComponentCategory(CategoryTypes.CATID_PipelineComponent)]
+ [ComponentCategory(CategoryTypes.CATID_Decoder)]
+ [System.Runtime.InteropServices.Guid("67C8CFB9-D89A-4415-A112-76187FC294D1")]
+ public class ZipDecodeComponent :
+ IBaseComponent,
+ Microsoft.BizTalk.Component.Interop.IComponent,
+ Microsoft.BizTalk.Component.Interop.IPersistPropertyBag,
+ IComponentUI
+ {
+
+ // Component information
+ #region IBaseComponent
+ [Browsable(false)] public string Name { get { return "ZIP decoder"; } }
+ [Browsable(false)] public string Version { get { return "1.0"; } }
+ [Browsable(false)] public string Description { get { return "Zip Decode Pipeline Component"; } }
+ [Browsable(false)] public System.IntPtr Icon { get { return ((Bitmap)resourceManager.GetObject("IconBitmap")).GetHicon(); } }
+ #endregion
+
+ private System.Resources.ResourceManager resourceManager =
+ new System.Resources.ResourceManager("Microsoft.Utility.PipelineGnuPG.ZipDecodeComponent", Assembly.GetExecutingAssembly());
+
+ // Property: Password
+ private string _password;
+ [
+ DisplayName("Password"),
+ Description("Password used to unzip messages.")
+ ]
+ public string Password
+ {
+ get { return _password; }
+ set { _password = value; }
+ }
+
+ private Stream Decode (Stream inStream)
+ {
+ Stream outStream = inStream;
+ string inFile = Path.GetTempFileName();
+ string outFile = Path.ChangeExtension(inFile, "txt");
+
+ try
+ {
+ ZipInputStream zipStream = new ZipInputStream( inStream );
+
+ // get password, if supplied
+ if ((_password != null) && (_password != ""))
+ zipStream.Password = _password;
+
+ // this algorithm demands that the zip archive contain exactly one file
+ ZipEntry entry = zipStream.GetNextEntry();
+ if (entry == null)
+ throw new ApplicationException( "Input ZIP archive does not contain any files - expecting exactly one file" );
+ if (entry.IsDirectory)
+ throw new ApplicationException( "Input ZIP contains a directory - expecting exactly one file" );
+
+ // copy the compressed stream into the output stream
+ outStream = new MemoryStream();
+ byte[] buffer = new byte[4096];
+ int count = 0;
+ while ((count = zipStream.Read(buffer, 0, buffer.Length)) != 0)
+ outStream.Write( buffer, 0, count );
+
+ // make sure that was the one and only file
+ entry = zipStream.GetNextEntry();
+ if (entry != null)
+ throw new ApplicationException( "Input ZIP archive contains multiple files and/or directories - expecting exactly one file" );
+
+ zipStream.Close();
+
+#if DEBUG
+ outStream.Seek( 0, SeekOrigin.Begin );
+ Microsoft.Samples.PipelineUtilities.FileStreamReadWrite.DumpStreamToFile( outStream, outFile );
+#endif
+
+ outStream.Seek( 0, SeekOrigin.Begin );
+ }
+ catch (Exception ex)
+ {
+ System.Diagnostics.Debug.WriteLine(ex);
+ throw;
+ }
+ finally
+ {
+ if (File.Exists(inFile))
+ {
+ File.Delete(inFile);
+ }
+
+ if (File.Exists(outFile))
+ {
+ File.Delete(outFile);
+ }
+ }
+
+ return outStream;
+ }
+
+ #region IPersistPropertyBag Members
+
+ public void InitNew()
+ {
+ }
+
+ public void GetClassID(out Guid classID)
+ {
+ classID = new Guid ("19800584-283D-44da-B1EE-0968387DA088");
+ }
+
+ public void Load(IPropertyBag propertyBag, int errorLog)
+ {
+ string text;
+ text = (string)PropertyBagReadWrite.ReadPropertyBag( propertyBag, "Password" );
+ if (text != null) _password = text;
+ }
+
+ public void Save(IPropertyBag propertyBag, bool clearDirty, bool saveAllProperties)
+ {
+ object val;
+ val = (object)_password;
+ PropertyBagReadWrite.WritePropertyBag( propertyBag, "Password", val );
+ }
+
+ #endregion
+
+
+ #region IComponent Members
+
+ public Microsoft.BizTalk.Message.Interop.IBaseMessage Execute(IPipelineContext pContext, Microsoft.BizTalk.Message.Interop.IBaseMessage pInMsg)
+ {
+ try
+ {
+ if (pInMsg != null)
+ {
+ Stream originalStream = pInMsg.BodyPart.GetOriginalDataStream();
+ pInMsg.BodyPart.Data = Decode( originalStream );
+ pContext.ResourceTracker.AddResource( pInMsg.BodyPart.Data );
+ }
+ }
+ catch (Exception ex)
+ {
+ System.Diagnostics.Debug.WriteLine( "Exception caught in ZipDecodeComponent::Execute: " + ex.Message );
+ throw new ApplicationException( "ZipDecodeComponent was unable to decompress input stream. This may occur if there is more than one file in the zip archive. See inner exception for more information.", ex );
+ }
+ return pInMsg;
+ }
+
+ #endregion
+
+ #region IComponentUI Members
+
+ ///
+ /// The Validate method is called by the BizTalk Editor during the build
+ /// of a BizTalk project.
+ ///
+ /// An Object containing the configuration properties.
+ /// The IEnumerator enables the caller to enumerate through a collection of strings containing error messages. These error messages appear as compiler error messages. To report successful property validation, the method should return an empty enumerator.
+ public IEnumerator Validate(object projectSystem)
+ {
+ // example implementation:
+ // ArrayList errorList = new ArrayList();
+ // errorList.Add("This is a compiler error");
+ // return errorList.GetEnumerator();
+ return null;
+ }
+
+
+ #endregion
+ }
+}
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/ZipDecodeComponent.resx b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/ZipDecodeComponent.resx
new file mode 100644
index 0000000..3f337e0
--- /dev/null
+++ b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/ZipDecodeComponent.resx
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 1.0.0.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/ZipEncodeComponent.cs b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/ZipEncodeComponent.cs
new file mode 100644
index 0000000..feeb721
--- /dev/null
+++ b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/ZipEncodeComponent.cs
@@ -0,0 +1,209 @@
+namespace Microsoft.Utility.PipelineZip
+{
+ using System;
+ using System.ComponentModel;
+ using System.Collections;
+ using System.Diagnostics;
+ using System.Drawing;
+ using System.IO;
+ using System.Reflection;
+ using Microsoft.BizTalk.Component.Interop;
+ using Microsoft.Samples.PipelineUtilities;
+ using ICSharpCode.SharpZipLib.Zip;
+
+ [ComponentCategory(CategoryTypes.CATID_PipelineComponent)]
+ [ComponentCategory(CategoryTypes.CATID_Encoder)]
+ [System.Runtime.InteropServices.Guid("56C7B68B-F288-4f78-A67F-20043CA4943E")]
+ public class ZipEncodeComponent :
+ IBaseComponent,
+ Microsoft.BizTalk.Component.Interop.IComponent,
+ Microsoft.BizTalk.Component.Interop.IPersistPropertyBag,
+ IComponentUI
+ {
+
+ // Component information
+ #region IBaseComponent
+ [Browsable(false)] public string Name { get { return "ZIP encoder"; } }
+ [Browsable(false)] public string Version { get { return "1.0"; } }
+ [Browsable(false)] public string Description { get { return "Zip Encode Pipeline Component"; } }
+ [Browsable(false)] public System.IntPtr Icon { get { return ((Bitmap)resourceManager.GetObject("IconBitmap")).GetHicon(); } }
+ #endregion
+
+ private System.Resources.ResourceManager resourceManager =
+ new System.Resources.ResourceManager("Microsoft.Utility.PipelineGnuPG.ZipEncodeComponent", Assembly.GetExecutingAssembly());
+
+ // Property: Password
+ private string _password;
+ [
+ DisplayName("Password"),
+ Description("Password used to zip messages.")
+ ]
+ public string Password
+ {
+ get { return _password; }
+ set { _password = value; }
+ }
+
+ // Property: Filename
+ private const string DEFAULT_FILENAME = "file";
+ private string _filename;
+ [
+ DisplayName("Filename"),
+ Description(@"The name of the file that contains the output message. This file will be added to the ZIP compressed output archive. Default is """ + DEFAULT_FILENAME + @""".")
+ ]
+ public string Filename
+ {
+ get { return _filename; }
+ set { _filename = value; }
+ }
+
+ // Property: CompressionLevel
+ const string DEFAULT_COMPRESSIONLEVEL_TEXT = "5";
+ const int DEFAULT_COMPRESSIONLEVEL= 5;
+ private string _compressionlevel;
+ [
+ DisplayName("CompressionLevel"),
+ Description(@"Compression level: 0=Store Only, to 9=Best Compression. Default is '" + DEFAULT_COMPRESSIONLEVEL_TEXT + "'.")
+ ]
+ public string CompressionLevel
+ {
+ get { return _compressionlevel; }
+ set { _compressionlevel = value; }
+ }
+
+ private Stream Encode (Stream inStream)
+ {
+ Stream outStream = inStream;
+ string inFile = Path.GetTempFileName();
+ string outFile = Path.ChangeExtension(inFile, "zip");
+
+ try
+ {
+ ZipOutputStream zipStream = new ZipOutputStream( File.Create( outFile ) );
+
+ // get password, if supplied
+ if ((_password != null) && (_password != ""))
+ zipStream.Password = _password;
+
+ // get compression level, if supplied
+ int compressionlevel = DEFAULT_COMPRESSIONLEVEL;
+ if ((_compressionlevel != null) && (_compressionlevel != ""))
+ compressionlevel = Convert.ToInt32( _compressionlevel );
+ if ((compressionlevel < 0) || (compressionlevel > 9))
+ compressionlevel = DEFAULT_COMPRESSIONLEVEL;
+ zipStream.SetLevel( compressionlevel );
+
+ // get message filename, if supplied
+ string filename = (((_filename != null) && (_filename != "")) ? _filename : DEFAULT_FILENAME );
+ ZipEntry entry = new ZipEntry( filename );
+ zipStream.PutNextEntry( entry );
+
+ // copy the input into the compressed output stream
+ byte[] buffer = new byte[4096];
+ int count = 0;
+ while ((count = inStream.Read(buffer, 0, buffer.Length)) != 0)
+ zipStream.Write( buffer, 0, count );
+ zipStream.Finish();
+ zipStream.Close();
+
+ outStream = Microsoft.Samples.PipelineUtilities.FileStreamReadWrite.ReadFileToMemoryStream(outFile);
+ }
+ catch (Exception ex)
+ {
+ System.Diagnostics.Debug.WriteLine(ex);
+ }
+ finally
+ {
+ if (File.Exists(inFile))
+ {
+ File.Delete(inFile);
+ }
+
+ if (File.Exists(outFile))
+ {
+ File.Delete(outFile);
+ }
+ }
+
+ return outStream;
+ }
+
+ #region IPersistPropertyBag Members
+
+ public void InitNew()
+ {
+ }
+
+ public void GetClassID(out Guid classID)
+ {
+ classID = new Guid ("0F94CF83-0B04-49a6-B73C-70473E0CF96F");
+ }
+
+ public void Load(IPropertyBag propertyBag, int errorLog)
+ {
+ string text;
+ text = (string)PropertyBagReadWrite.ReadPropertyBag( propertyBag, "Password" );
+ if (text != null) _password = text;
+ text = (string)PropertyBagReadWrite.ReadPropertyBag( propertyBag, "Filename" );
+ if (text != null) _filename = text;
+ text = (string)PropertyBagReadWrite.ReadPropertyBag( propertyBag, "CompressionLevel" );
+ if (text != null) _compressionlevel = text;
+ }
+
+ public void Save(IPropertyBag propertyBag, bool clearDirty, bool saveAllProperties)
+ {
+ object val;
+ val = (object)_password;
+ PropertyBagReadWrite.WritePropertyBag( propertyBag, "Password", val );
+ val = (object)_filename;
+ PropertyBagReadWrite.WritePropertyBag( propertyBag, "Filename", val );
+ val = (object)_compressionlevel;
+ PropertyBagReadWrite.WritePropertyBag( propertyBag, "CompressionLevel", val );
+ }
+
+ #endregion
+
+
+ #region IComponent Members
+
+ public Microsoft.BizTalk.Message.Interop.IBaseMessage Execute(IPipelineContext pContext, Microsoft.BizTalk.Message.Interop.IBaseMessage pInMsg)
+ {
+ try
+ {
+ if (pInMsg != null)
+ {
+ Stream originalStream = pInMsg.BodyPart.GetOriginalDataStream();
+ pInMsg.BodyPart.Data = Encode( originalStream );
+ pContext.ResourceTracker.AddResource( pInMsg.BodyPart.Data );
+ }
+ }
+ catch (Exception ex)
+ {
+ System.Diagnostics.Debug.WriteLine( "Exception caught in ZipEncodeComponent::Execute: " + ex.Message );
+ }
+ return pInMsg;
+ }
+
+ #endregion
+
+ #region IComponentUI Members
+
+ ///
+ /// The Validate method is called by the BizTalk Editor during the build
+ /// of a BizTalk project.
+ ///
+ /// An Object containing the configuration properties.
+ /// The IEnumerator enables the caller to enumerate through a collection of strings containing error messages. These error messages appear as compiler error messages. To report successful property validation, the method should return an empty enumerator.
+ public IEnumerator Validate(object projectSystem)
+ {
+ // example implementation:
+ // ArrayList errorList = new ArrayList();
+ // errorList.Add("This is a compiler error");
+ // return errorList.GetEnumerator();
+ return null;
+ }
+
+
+ #endregion
+ }
+}
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/ZipEncodeComponent.resx b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/ZipEncodeComponent.resx
new file mode 100644
index 0000000..3f337e0
--- /dev/null
+++ b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/ZipEncodeComponent.resx
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 1.0.0.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/bin/Debug/ICSharpCode.SharpZipLib.dll b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/bin/Debug/ICSharpCode.SharpZipLib.dll
new file mode 100644
index 0000000..72dfaaf
Binary files /dev/null and b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/bin/Debug/ICSharpCode.SharpZipLib.dll differ
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/bin/Debug/ICSharpCode.SharpZipLib.pdb b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/bin/Debug/ICSharpCode.SharpZipLib.pdb
new file mode 100644
index 0000000..47a8e80
Binary files /dev/null and b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/bin/Debug/ICSharpCode.SharpZipLib.pdb differ
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/bin/Debug/Microsoft.Utility.PipelineZip.dll b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/bin/Debug/Microsoft.Utility.PipelineZip.dll
new file mode 100644
index 0000000..7c0a830
Binary files /dev/null and b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/bin/Debug/Microsoft.Utility.PipelineZip.dll differ
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/bin/Debug/Microsoft.Utility.PipelineZip.pdb b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/bin/Debug/Microsoft.Utility.PipelineZip.pdb
new file mode 100644
index 0000000..a73da33
Binary files /dev/null and b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/bin/Debug/Microsoft.Utility.PipelineZip.pdb differ
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/obj/Debug/Microsoft.Utility.PipelineZip.PipelineZip.resources b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/obj/Debug/Microsoft.Utility.PipelineZip.PipelineZip.resources
new file mode 100644
index 0000000..b354bcb
Binary files /dev/null and b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/obj/Debug/Microsoft.Utility.PipelineZip.PipelineZip.resources differ
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/obj/Debug/Microsoft.Utility.PipelineZip.ZipDecodeComponent.resources b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/obj/Debug/Microsoft.Utility.PipelineZip.ZipDecodeComponent.resources
new file mode 100644
index 0000000..06c24d0
Binary files /dev/null and b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/obj/Debug/Microsoft.Utility.PipelineZip.ZipDecodeComponent.resources differ
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/obj/Debug/Microsoft.Utility.PipelineZip.ZipEncodeComponent.resources b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/obj/Debug/Microsoft.Utility.PipelineZip.ZipEncodeComponent.resources
new file mode 100644
index 0000000..06c24d0
Binary files /dev/null and b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/obj/Debug/Microsoft.Utility.PipelineZip.ZipEncodeComponent.resources differ
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/obj/Debug/Microsoft.Utility.PipelineZip.csproj.GenerateResource.Cache b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/obj/Debug/Microsoft.Utility.PipelineZip.csproj.GenerateResource.Cache
new file mode 100644
index 0000000..7f9f6f3
Binary files /dev/null and b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/obj/Debug/Microsoft.Utility.PipelineZip.csproj.GenerateResource.Cache differ
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/obj/Debug/Microsoft.Utility.PipelineZip.dll b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/obj/Debug/Microsoft.Utility.PipelineZip.dll
new file mode 100644
index 0000000..72a8fb2
Binary files /dev/null and b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/obj/Debug/Microsoft.Utility.PipelineZip.dll differ
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/obj/Debug/Microsoft.Utility.PipelineZip.pdb b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/obj/Debug/Microsoft.Utility.PipelineZip.pdb
new file mode 100644
index 0000000..1ed7ef8
Binary files /dev/null and b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/obj/Debug/Microsoft.Utility.PipelineZip.pdb differ
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/obj/Debug/Microsoft.Utility.PipelineZip.projdata b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/obj/Debug/Microsoft.Utility.PipelineZip.projdata
new file mode 100644
index 0000000..4c28e1e
Binary files /dev/null and b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/obj/Debug/Microsoft.Utility.PipelineZip.projdata differ
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/obj/Debug/ResolveAssemblyReference.cache b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/obj/Debug/ResolveAssemblyReference.cache
new file mode 100644
index 0000000..6040571
Binary files /dev/null and b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/obj/Debug/ResolveAssemblyReference.cache differ
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/obj/Debug/SharpZipLib.projdata b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/obj/Debug/SharpZipLib.projdata
new file mode 100644
index 0000000..e214529
Binary files /dev/null and b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/obj/Debug/SharpZipLib.projdata differ
diff --git a/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/obj/Microsoft.Utility.PipelineZip.csproj.FileList.txt b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/obj/Microsoft.Utility.PipelineZip.csproj.FileList.txt
new file mode 100644
index 0000000..046fa8c
--- /dev/null
+++ b/Samples/Chapter5/Zip Pipeline Component/Microsoft.Utility.PipelineZip/obj/Microsoft.Utility.PipelineZip.csproj.FileList.txt
@@ -0,0 +1,11 @@
+..\..\..\Program Files\Microsoft BizTalk Server 2004\Pipeline Components\Microsoft.Utility.PipelineZip.dll
+..\..\..\Program Files\Microsoft BizTalk Server 2004\Pipeline Components\Microsoft.Utility.PipelineZip.pdb
+obj\Debug\ResolveAssemblyReference.cache
+obj\Debug\Microsoft.Utility.PipelineZip.PipelineZip.resources
+obj\Debug\Microsoft.Utility.PipelineZip.ZipDecodeComponent.resources
+obj\Debug\Microsoft.Utility.PipelineZip.ZipEncodeComponent.resources
+obj\Debug\Microsoft.Utility.PipelineZip.csproj.GenerateResource.Cache
+obj\Debug\Microsoft.Utility.PipelineZip.dll
+obj\Debug\Microsoft.Utility.PipelineZip.pdb
+C:\Program Files\Microsoft BizTalk Server 2006\Pipeline Components\Microsoft.Utility.PipelineZip.dll
+C:\Program Files\Microsoft BizTalk Server 2006\Pipeline Components\Microsoft.Utility.PipelineZip.pdb
diff --git a/Samples/README.txt b/Samples/README.txt
new file mode 100644
index 0000000..3452a79
--- /dev/null
+++ b/Samples/README.txt
@@ -0,0 +1 @@
+This code is provided as is with no guarantees. It may be reused or editied in commercial and non-commercial applications at your own risk.
diff --git a/contributing.md b/contributing.md
new file mode 100644
index 0000000..f6005ad
--- /dev/null
+++ b/contributing.md
@@ -0,0 +1,14 @@
+# Contributing to Apress Source Code
+
+Copyright for Apress source code belongs to the author(s). However, under fair use you are encouraged to fork and contribute minor corrections and updates for the benefit of the author(s) and other readers.
+
+## How to Contribute
+
+1. Make sure you have a GitHub account.
+2. Fork the repository for the relevant book.
+3. Create a new branch on which to make your change, e.g.
+`git checkout -b my_code_contribution`
+4. Commit your change. Include a commit message describing the correction. Please note that if your commit message is not clear, the correction will not be accepted.
+5. Submit a pull request.
+
+Thank you for your contribution!
\ No newline at end of file