1#region README
2
3  //_____________________________________________________________________________
4  //
5  //Sample C# code, .NET Framework 1.1, contributed to the Info-Zip project by
6  //Adrian Maull, April 2005.
7  //
8  //If you have questions or comments, contact me at adrian.maull@sprintpcs.com.  Though
9  //I will try to respond to coments/questions, I do not guarantee such response.
10  //
11  //THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
12  //KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
13  //IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
14  //PARTICULAR PURPOSE.
15  //
16  //_____________________________________________________________________________
17
18
19#endregion
20
21#region KNOWN ISSUES
22
23  //_____________________________________________________________________________
24  //
25  //KNOWN ISSUES:
26  //From my testing I have encountered some issues
27  //
28  //1.  I receive an error code from the Unzip32.dll when I try to retrieve the comment from the
29  //    zip file.  To display a comment you set the nzflag of the DCLIST structure = 1.  In this
30  //    implementation, just set the m_Unzip.ExtractList = ExtractListEnum.ListContents and
31  //    m_Unzip.DisplayComment = DisplayCommentEnum.True
32  //    I provided a work around to this in the GetZipFileComment() method.
33  //
34  //    [CS, 2009-01-10:]
35  //    The DisplayComment option works now. However, the work-around code to
36  //    retrieve the zipfile comment using direct I/O has not yet been replaced
37  //    by code using the UnZip DLL.
38  //
39  //2.  I have not tested any password/encryption logic in this sample
40  //_____________________________________________________________________________
41
42
43#endregion
44
45using System;
46using System.Security.Permissions;
47using System.Runtime.InteropServices;
48using System.Text;
49using System.Windows.Forms;
50using System.IO;
51
52namespace CSharpInfoZip_UnZipSample
53{
54  /// <summary>
55  /// Summary description for Unzip.
56  /// </summary>
57
58  #region Public Enums
59
60  public enum ExtractOnlyNewerEnum {False, True};
61  public enum SpaceToUnderScoreEnum {False, True};
62  public enum PromptToOverWriteEnum {NotRequired, Required};
63  public enum QuietEnum {AllMessages, LessMessages, NoMessages};
64  public enum WriteStdOutEnum {False, True};
65  public enum TestZipEnum {False, True};
66  public enum ExtractOrListEnum {Extract, ListContents};
67  public enum FreshenExistingEnum {False, True};
68  public enum DisplayCommentEnum {False, True};
69  public enum HonorDirectoriesEnum {False, True};
70  public enum OverWriteFilesEnum {False, True};
71  public enum ConvertCR_CRLFEnum {False, True};
72  public enum VerboseZIEnum {False, True};
73  public enum UnixFileBackupEnum { False, True }
74  public enum CaseSensitivityEnum { True, False };
75  public enum RestoreTimeStampsEnum { All, FilesOnly, None };
76  public enum UTF8NameTranslationEnum { Automatic, EscapeNonASCII, Disabled };
77  public enum PrivilegeEnum {Default, ACL, Privilege};
78  public enum ReplaceFileOptionsEnum {ReplaceNo=100, ReplaceYes=102, ReplaceAll=103,
79                                      ReplaceNone=104, ReplaceRename=105};
80
81
82  #endregion
83
84  #region Event Delegates
85
86  public delegate void UnZipDLLPrintMessageEventHandler(object sender, UnZipDLLPrintMessageEventArgs  e);
87  public delegate int UnZipDLLServiceMessageEventHandler(object sender, UnZipDLLServiceMessageEventArgs  e);
88
89  #endregion
90
91  public class Unzip
92  {
93    public Unzip()
94    {
95    }
96
97    #region Constants
98    // Current version of the DCLIST interface structure, must be matched
99    // with the UZ_DCL_STRUCTVER constant as defined in the struct.h header
100    // from the UnZip WinDLL code.
101    private const uint uz_dcl_StructVer = 0x600;
102    #endregion
103
104    #region Private Vars
105
106    private ulong m_ZipFileSize;
107    private ulong m_ZipFileCount;
108    private int m_Stop;
109    private string m_ZipFileName;
110    private string m_ExtractionDirectory;
111    private string m_Password;
112    private string m_Comment;
113    private string [] m_FilesToUnzip = new string[0]; //Default
114    private string [] m_FilesToExclude = new string[0]; //Default
115    private ZipFileEntries m_ZipFileEntries = new ZipFileEntries();
116    private Encoding m_EncodingANSI = Encoding.Default;
117
118    private ExtractOnlyNewerEnum m_ExtractOnlyNewer;
119    private SpaceToUnderScoreEnum m_SpaceToUnderScore;
120    private PromptToOverWriteEnum m_PromptToOverWrite;
121    private QuietEnum m_Quiet;
122    private WriteStdOutEnum m_WriteStdOut;
123    private TestZipEnum m_TestZip;
124    private ExtractOrListEnum m_ExtractOrList;
125    private FreshenExistingEnum m_FreshenExisting;
126    private DisplayCommentEnum m_DisplayComment;
127    private HonorDirectoriesEnum m_HonorDirectories;
128    private OverWriteFilesEnum m_OverWriteFiles;
129    private ConvertCR_CRLFEnum m_ConvertCR_CRLF;
130    private VerboseZIEnum m_VerboseZI;
131    private UnixFileBackupEnum m_UnixFileBackup;
132    private CaseSensitivityEnum m_CaseSensitivity;
133    private RestoreTimeStampsEnum m_RestoreTimeStamps;
134    private UTF8NameTranslationEnum m_UTF8NameTranslation;
135    private PrivilegeEnum m_Privilege;
136
137
138    #endregion
139
140    #region Structures
141
142    // Callback Large String
143    protected struct UNZIPCBChar
144    {
145      [MarshalAs( UnmanagedType.ByValArray, SizeConst= 32000, ArraySubType = UnmanagedType.U1)]
146      public byte [] ch;
147    }
148
149    // Callback Small String (size of a filename buffer)
150    protected struct UNZIPCBCh
151    {
152      [MarshalAs( UnmanagedType.ByValArray, SizeConst= 260, ArraySubType = UnmanagedType.U1)]
153      public byte [] ch;
154    }
155
156    //UNZIP32.DLL DCLIST Structure
157    [ StructLayout( LayoutKind.Sequential )]
158    protected struct DCLIST
159    {
160      public uint StructVersID;       // struct version id (= UZ_DCL_STRUCTVER)
161      public int ExtractOnlyNewer;    //1 = Extract Only Newer/New, Else 0
162      public int SpaceToUnderscore;   //1 = Convert Space To Underscore, Else 0
163      public int PromptToOverwrite;   //1 = Prompt To Overwrite Required, Else 0
164      public int fQuiet;              //2 = No Messages, 1 = Less, 0 = All
165      public int ncflag;              //1 = Write To Stdout, Else 0
166      public int ntflag;              //1 = Test Zip File, Else 0
167      public int nvflag;              //0 = Extract, 1 = List Zip Contents
168      public int nfflag;              //1 = Extract Only Newer Over Existing, Else 0
169      public int nzflag;              //1 = Display Zip File Comment, Else 0
170      public int ndflag;              //1 = Honor Directories, Else 0
171      public int noflag;              //1 = Overwrite Files, Else 0
172      public int naflag;              //1 = Convert CR To CRLF, Else 0
173      public int nZIflag;             //1 = Zip Info Verbose, Else 0
174      public int B_flag;              //1 = backup existing files
175      public int C_flag;              //1 = Case Insensitivity, 0 = Case Sensitivity
176      public int D_flag;              //controls restoration of timestamps
177                                      //0 = restore all timestamps (default)
178                                      //1 = skip restoration of timestamps for folders
179                                      //    created on behalf of directory entries in the
180                                      //    Zip archive
181                                      //2 = no restoration of timestamps; extracted files
182                                      //    and dirs get stamped with current time */
183      public int U_flag;              // controls UTF-8 filename coding support
184                                      //0 = automatic UTF-8 translation enabled (default)
185                                      //1 = recognize UTF-8 coded names, but all non-ASCII
186                                      //    characters are "escaped" into "#Uxxxx"
187                                      //2 = UTF-8 support is disabled, filename handling
188                                      //    works exactly as in previous UnZip versions */
189      public int fPrivilege;          //1 = ACL, 2 = Privileges
190      public string Zip;              //The Zip Filename To Extract Files
191      public string ExtractDir;       //The Extraction Directory, NULL If Extracting To Current Dir
192    }
193
194    //UNZIP32.DLL Userfunctions Structure
195    [ StructLayout( LayoutKind.Sequential )]
196    protected struct USERFUNCTION
197    {
198      public UZDLLPrintCallback UZDLLPrnt;              //Print function callback
199      public int UZDLLSND;                              //Not supported
200      public UZDLLReplaceCallback UZDLLREPLACE;         //Replace function callback
201      public UZDLLPasswordCallback UZDLLPASSWORD;       //Password function callback
202      // 64-bit versions
203      public UZReceiveDLLMessageCallback UZDLLMESSAGE;  //Receive message callback
204      public UZDLLServiceCallback UZDLLSERVICE;         //Service callback
205      // 32-bit versions (not used/needed here)
206      public UZReceiveDLLMsgCBck_32 UZDLLMESSAGE_I32;   //Receive message callback
207      public UZDLLServiceCBck_32 UZDLLSERVICE_I32;      //Service callback
208      public ulong TotalSizeComp;                       //Total Size Of Zip Archive
209      public ulong TotalSize;                           //Total Size Of All Files In Archive
210      public ulong NumMembers;                          //Total Number Of All Files In The Archive
211      public uint CompFactor;                           //Compression Factor
212      public short cchComment;                          //Flag If Archive Has A Comment!
213    }
214
215    #endregion
216
217    #region DLL Function Declares
218
219    //NOTE:
220    //This Assumes UNZIP32.DLL Is In Your \Windows\System Directory!
221    [DllImport("unzip32.dll", SetLastError=true)]
222    private static extern int Wiz_SingleEntryUnzip (int ifnc, string [] ifnv, int xfnc, string [] xfnv,
223      ref DCLIST dcl, ref USERFUNCTION Userf);
224
225
226    #endregion
227
228    #region Properties
229
230    public string Password
231    {
232      get {return m_Password;}
233      set {m_Password = value;}
234    }
235
236    public string Comment
237    {
238      get {return m_Comment;}
239      set {m_Comment = value;}
240    }
241
242    public ExtractOnlyNewerEnum ExtractOnlyNewer
243    {
244      get {return m_ExtractOnlyNewer;}
245      set {m_ExtractOnlyNewer = value;}
246    }
247
248    public SpaceToUnderScoreEnum SpaceToUnderScore
249    {
250      get {return m_SpaceToUnderScore;}
251      set {m_SpaceToUnderScore = value;}
252    }
253
254    public PromptToOverWriteEnum PromptToOverWrite
255    {
256      get {return m_PromptToOverWrite;}
257      set {m_PromptToOverWrite = value;}
258    }
259
260    public QuietEnum Quiet
261    {
262      get {return m_Quiet;}
263      set {m_Quiet = value;}
264    }
265
266    public WriteStdOutEnum WriteStdOut
267    {
268      get {return m_WriteStdOut;}
269      set {m_WriteStdOut = value;}
270    }
271
272    public TestZipEnum TestZip
273    {
274      get {return m_TestZip;}
275      set {m_TestZip = value;}
276    }
277
278    public ExtractOrListEnum ExtractOrList
279    {
280      get {return m_ExtractOrList;}
281      set {m_ExtractOrList = value;}
282    }
283
284    public FreshenExistingEnum FreshenExisting
285    {
286      get {return m_FreshenExisting;}
287      set {m_FreshenExisting = value;}
288    }
289
290    public DisplayCommentEnum DisplayComment
291    {
292      get {return m_DisplayComment;}
293      set {m_DisplayComment = value;}
294    }
295
296    public HonorDirectoriesEnum HonorDirectories
297    {
298      get {return m_HonorDirectories;}
299      set {m_HonorDirectories = value;}
300    }
301
302    public OverWriteFilesEnum OverWriteFiles
303    {
304      get {return m_OverWriteFiles;}
305      set {m_OverWriteFiles = value;}
306    }
307
308    public ConvertCR_CRLFEnum ConvertCR_CRLF
309    {
310      get {return m_ConvertCR_CRLF;}
311      set {m_ConvertCR_CRLF = value;}
312    }
313
314    public VerboseZIEnum VerboseZI
315    {
316      get {return m_VerboseZI;}
317      set {m_VerboseZI = value;}
318    }
319
320    public UnixFileBackupEnum UnixFileBackup
321    {
322      get { return m_UnixFileBackup; }
323      set { m_UnixFileBackup = value; }
324    }
325
326    public CaseSensitivityEnum CaseSensitivity
327    {
328      get {return m_CaseSensitivity;}
329      set {m_CaseSensitivity = value;}
330    }
331
332    public RestoreTimeStampsEnum RestoreTimeStamps
333    {
334      get { return m_RestoreTimeStamps; }
335      set { m_RestoreTimeStamps = value; }
336    }
337
338    public UTF8NameTranslationEnum UTF8NameTranslation
339    {
340      get { return m_UTF8NameTranslation; }
341      set { m_UTF8NameTranslation = value; }
342    }
343
344    public PrivilegeEnum Privilege
345    {
346      get {return m_Privilege;}
347      set {m_Privilege = value;}
348    }
349
350    public string ZipFileName
351    {
352      get {return m_ZipFileName;}
353      set {m_ZipFileName = value;}
354    }
355
356    public string ExtractDirectory
357    {
358      get {return m_ExtractionDirectory;}
359      set {m_ExtractionDirectory = value;}
360    }
361
362    public string [] FilesToUnzip
363    {
364      get {return m_FilesToUnzip;}
365      set {m_FilesToUnzip = value;}
366    }
367
368    public string [] FilesToExclude
369    {
370      get {return m_FilesToExclude;}
371      set {m_FilesToExclude = value;}
372    }
373
374    #endregion
375
376    #region UnZip DLL Delegates
377
378    //Callback For UNZIP32.DLL - Receive Message Function
379    protected delegate void UZReceiveDLLMessageCallback (ulong ucsize, ulong csiz,
380                                ushort cfactor, ushort mo,
381                                ushort dy, ushort yr, ushort hh, ushort mm, byte c,
382                                [MarshalAs(UnmanagedType.LPStr)]String fname,
383                                [MarshalAs(UnmanagedType.LPStr)]String meth,
384                                uint crc, sbyte fCrypt);
385
386    //Callback For UNZIP32.DLL - Receive Message Function (no-Int64 variant, not used here)
387    protected delegate void UZReceiveDLLMsgCBck_32(uint ucsize_lo, uint ucsize_hi, uint csiz_lo, uint csiz_hi,
388                                ushort cfactor, ushort mo,
389                                ushort dy, ushort yr, ushort hh, ushort mm, byte c,
390                                [MarshalAs(UnmanagedType.LPStr)]String fname,
391                                [MarshalAs(UnmanagedType.LPStr)]String meth,
392                                uint crc, sbyte fCrypt);
393
394    //Callback For UNZIP32.DLL - Print Message Function
395    protected delegate int UZDLLPrintCallback ([MarshalAs(UnmanagedType.LPStr)]String fname, uint x);
396
397    //Callback For UNZIP32.DLL - DLL Service Function
398    protected delegate int UZDLLServiceCallback([MarshalAs(UnmanagedType.LPStr)]String fname,
399                                                ulong ucsize);
400
401    //Callback For UNZIP32.DLL - DLL Service Function (no-Int64 variant, not used here)
402    protected delegate int UZDLLServiceCBck_32([MarshalAs(UnmanagedType.LPStr)]String fname,
403                                               uint ucsize_lo, uint ucsize_hi);
404
405    //Callback For UNZIP32.DLL - Password Function
406    protected delegate int UZDLLPasswordCallback(ref UNZIPCBCh pwd, int bufsize,
407                                                 [MarshalAs(UnmanagedType.LPStr)]String msg,
408                                                 [MarshalAs(UnmanagedType.LPStr)]String entryname);
409
410    //Callback For UNZIP32.DLL - Replace Function To Overwrite Files
411    protected delegate int UZDLLReplaceCallback(ref UNZIPCBCh fname, uint fnbufsiz);
412
413    #endregion
414
415    #region Events
416
417    public event UnZipDLLPrintMessageEventHandler ReceivePrintMessage;
418    public event UnZipDLLServiceMessageEventHandler ReceiveServiceMessage;
419
420    #endregion
421
422    #region Protected Functions
423
424    protected virtual void OnReceivePrintMessage (UnZipDLLPrintMessageEventArgs e)
425    {
426      if (ReceivePrintMessage != null)
427      {
428        ReceivePrintMessage(this, e);
429      }
430    }
431
432    protected virtual void OnReceiveServiceMessage (UnZipDLLServiceMessageEventArgs e)
433    {
434      if (ReceiveServiceMessage != null)
435      {
436        ReceiveServiceMessage(this, e);
437      }
438    }
439
440    #endregion
441
442    #region CallBack Functions
443
444    //This function is called when the DCLIST structure's nvflag is ExtractListEnum.ListContents.
445    //It is used to list the zip file contents
446    protected void UZReceiveDLLMessage (ulong ucsize, ulong csiz, ushort cfactor, ushort mo,
447                              ushort dy, ushort yr, ushort hh, ushort mm, byte c,
448                              [MarshalAs(UnmanagedType.LPStr)]String fname,
449                              [MarshalAs(UnmanagedType.LPStr)]String meth,
450                              uint crc, sbyte fCrypt)
451    {
452      //Add up the size of each file in the zip file
453      m_ZipFileSize += ucsize;
454      m_ZipFileCount ++;
455
456      //NOTE:
457      //Build out the ZipFileEntry collection
458      //You can do additional formatting for the month, day, and year properties
459      ZipFileEntry zfe = new ZipFileEntry();
460      zfe.FileName = Path.GetFileName(fname);
461      zfe.FilePath = Path.GetDirectoryName(fname);
462      zfe.IsFolder = (zfe.FileName.Length == 0 ? true : false);
463      zfe.FileSize = unchecked(ucsize);
464      zfe.FileMonth = mo;
465      zfe.FileDay = dy;
466      zfe.FileYear = yr;
467      zfe.FileHour = hh;
468      zfe.FileMinute = mm;
469      zfe.CompressedSize = unchecked(csiz);
470      zfe.CompressionFactor = cfactor;
471      zfe.CompressionMethShort = meth;
472
473      m_ZipFileEntries.Add(zfe);
474
475    }
476
477    protected int UZDLLPrint([MarshalAs(UnmanagedType.LPStr)]String msg, uint x)
478    {
479      UnZipDLLPrintMessageEventArgs e =
480          new UnZipDLLPrintMessageEventArgs(msg.Substring(0, Math.Min(unchecked((int)x),
481                                                                      msg.Length)));
482      OnReceivePrintMessage(e);
483
484      return 0;
485    }
486
487    /*
488    DLLSERVICE *ServCallBk  = Callback function designed to be used for
489                allowing the application to process Windows messages,
490                or canceling the operation, as well as giving the
491                option of a progress indicator. If this function
492                returns a non-zero value, then it will terminate
493                what it is doing. It provides the application with
494                the name of the name of the archive member it has
495                just processed, as well as it's original size.
496
497    fname.ch = the name of the file being zipped
498    ucsize = the size of the file being zipped
499
500     * */
501    protected int UZDLLService([MarshalAs(UnmanagedType.LPStr)]String fname,
502                               ulong ucsize)
503    {
504      //Raise this event
505      UnZipDLLServiceMessageEventArgs e =
506          new UnZipDLLServiceMessageEventArgs(m_ZipFileSize, fname, unchecked(ucsize));
507      OnReceiveServiceMessage (e);
508
509      return m_Stop;
510    }
511
512    protected int UZDLLPassword(ref UNZIPCBCh pwd, int bufsize,
513                        [MarshalAs(UnmanagedType.LPStr)]String msg,
514                        [MarshalAs(UnmanagedType.LPStr)]String entryname)
515    {
516      if (m_Password == null | m_Password == string.Empty) return -1;
517
518      if (m_Password.Length >= bufsize)
519      {
520        MessageBox.Show("Length of supplied password exceeds available pw buffer size "
521                    + bufsize.ToString() + "!", "Password Error",
522                    MessageBoxButtons.OK, MessageBoxIcon.Error);
523        return 5;  // IZ_PW_ERROR
524      }
525
526      //clear the byte array
527      for (int i = 0; i < bufsize; i ++)
528        pwd.ch[i] = 0;
529
530      m_EncodingANSI.GetBytes(m_Password, 0, m_Password.Length, pwd.ch, 0);
531
532      return 0;
533    }
534
535    protected int UZDLLReplace(ref UNZIPCBCh fname, uint fnbufsiz)
536    {
537      ReplaceFileOptionsEnum ReplaceFileOption = ReplaceFileOptionsEnum.ReplaceNo; //Default
538      string s = string.Empty;
539      int i = 0;
540
541      if (fnbufsiz > fname.ch.Length) fnbufsiz = (uint)fname.ch.Length;
542      for (i = 0; i < fnbufsiz; i++)
543        if (fname.ch[i] == 0) break;
544      s = m_EncodingANSI.GetString(fname.ch, 0, i);
545
546      DialogResult rslt = MessageBox.Show("Overwrite [" + s + "]?  Click Cancel to skip all.",
547                                  "Overwrite Confirmation", MessageBoxButtons.YesNoCancel,
548                                  MessageBoxIcon.Question);
549      switch (rslt)
550      {
551        case DialogResult.No:
552          ReplaceFileOption = ReplaceFileOptionsEnum.ReplaceNo;
553          break;
554        case DialogResult.Yes:
555          ReplaceFileOption = ReplaceFileOptionsEnum.ReplaceYes;
556          break;
557        case DialogResult.Cancel:
558          ReplaceFileOption = ReplaceFileOptionsEnum.ReplaceNone;
559          break;
560      }
561      return ConvertEnumToInt(ReplaceFileOption);
562    }
563
564    #endregion
565
566    #region Public Functions
567
568    public int UnZipFiles ()
569    {
570      int ret = -1;
571
572      //check to see if there is enough information to proceed.
573      //Exceptions can be thrown if required data is not passed in
574      if (m_ZipFileName == string.Empty) return -1;
575      if (m_ExtractionDirectory == string.Empty) return -1;
576
577      //The zip file size, in bytes, is stored in the m_ZipFileSize variable.
578      //m_ZipFileCount is the number of files in the zip.  This information
579      //is useful for some sort of progress information during unzipping.
580      if (!GetZipFileSizeAndCount()) return ret;
581
582      DCLIST dclist = new DCLIST();
583      dclist.StructVersID = uz_dcl_StructVer;   // Current version of this structure
584      dclist.ExtractOnlyNewer = ConvertEnumToInt(m_ExtractOnlyNewer);
585      dclist.SpaceToUnderscore = ConvertEnumToInt(m_SpaceToUnderScore);
586      dclist.PromptToOverwrite = ConvertEnumToInt(m_PromptToOverWrite);
587      dclist.fQuiet = ConvertEnumToInt(m_Quiet);
588      dclist.ncflag = ConvertEnumToInt(m_WriteStdOut);
589      dclist.ntflag = ConvertEnumToInt (m_TestZip);
590      dclist.nvflag = ConvertEnumToInt(m_ExtractOrList);
591      dclist.nfflag = ConvertEnumToInt(m_FreshenExisting);
592      dclist.nzflag = ConvertEnumToInt(m_DisplayComment);
593      dclist.ndflag = ConvertEnumToInt(m_HonorDirectories);
594      dclist.noflag = ConvertEnumToInt(m_OverWriteFiles);
595      dclist.naflag = ConvertEnumToInt(m_ConvertCR_CRLF);
596      dclist.nZIflag = ConvertEnumToInt(m_VerboseZI);
597      dclist.B_flag = ConvertEnumToInt(m_UnixFileBackup);
598      dclist.C_flag = ConvertEnumToInt(m_CaseSensitivity);
599      dclist.D_flag = ConvertEnumToInt(m_RestoreTimeStamps);
600      dclist.U_flag = ConvertEnumToInt(m_UTF8NameTranslation);
601      dclist.fPrivilege = ConvertEnumToInt(m_Privilege);
602      dclist.Zip = m_ZipFileName;
603      dclist.ExtractDir = m_ExtractionDirectory;
604
605      USERFUNCTION uf = PrepareUserFunctionCallbackStructure();
606
607      try
608      {
609        ret = Wiz_SingleEntryUnzip(m_FilesToUnzip.Length, m_FilesToUnzip, m_FilesToExclude.Length,
610          m_FilesToExclude, ref dclist, ref uf);
611      }
612      catch (Exception e)
613      {
614        MessageBox.Show (e.ToString() + Environment.NewLine +
615                         "Last Win32ErrorCode: " + Marshal.GetLastWin32Error());
616        //You can check the meaning of return codes here:
617        //http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/system_error_codes__0-499_.asp
618      }
619
620      return ret;
621    }
622
623    public bool GetZipFileSizeAndCount(ref ulong size, ref ulong fileCount)
624    {
625      if (!GetZipFileSizeAndCount()) return false;
626      size = m_ZipFileSize;
627      fileCount = m_ZipFileCount;
628      return true;
629    }
630
631    public ZipFileEntries GetZipFileContents ()
632    {
633      int ret = 0;
634
635      DCLIST dclist = new DCLIST();
636      dclist.StructVersID = uz_dcl_StructVer;
637      dclist.nvflag = ConvertEnumToInt(ExtractOrListEnum.ListContents);
638      dclist.Zip = m_ZipFileName;
639
640      USERFUNCTION uf = PrepareUserFunctionCallbackStructure();
641
642      m_ZipFileSize = 0;
643      m_ZipFileCount = 0;
644      m_ZipFileEntries.Clear();
645
646      //This call will fill the m_ZipFileEntries collection because when the nvflag = ExtractListEnum.ListContents
647      //the UZReceiveDLLMessage callback function is called
648      try
649      {
650        ret = Wiz_SingleEntryUnzip(m_FilesToUnzip.Length, m_FilesToUnzip, m_FilesToExclude.Length,
651          m_FilesToExclude, ref dclist, ref uf);
652      }
653      catch(Exception e)
654      {
655        MessageBox.Show (e.ToString() + Environment.NewLine +
656                         "Last Win32ErrorCode: " + Marshal.GetLastWin32Error());
657        //You can check the meaning of return codes here:
658        //http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/system_error_codes__0-499_.asp
659      }
660
661      return m_ZipFileEntries;
662    }
663
664    public string GetZipFileComment()
665    {
666      //WORK AROUND:
667      //This method provides a work around to setting the nzflag of the DCLIST structure = 1, which instructs
668      //the dll to extract the zip file comment.  See the KNOWN ISSUES region at the beginning of this code
669      //sample.
670
671      //NOTE:
672      //Explanation of Big Endian and Little Endian Architecture
673      //http://support.microsoft.com/default.aspx?scid=kb;en-us;102025
674      //Bytes in the stream are in Big Endian format.  We have to read the bytes and
675      //convert to Little Endian format.  That's what the GetLittleEndianByteOrder function
676      //does.
677
678      const int CENTRALRECORDENDSIGNATURE = 0x06054b50;
679      const int CENTRALRECORDENDSIZE = 22;
680
681      string comment = string.Empty;
682      Encoding ae = Encoding.Default;
683
684      if (m_ZipFileName == null | m_ZipFileName == string.Empty) return string.Empty;
685
686      try
687      {
688        FileStream fs = File.OpenRead(m_ZipFileName);
689        long pos = fs.Length - CENTRALRECORDENDSIZE;
690
691        while (GetLittleEndianByteOrder(fs,4) != CENTRALRECORDENDSIGNATURE)
692          fs.Seek(pos--, SeekOrigin.Begin);
693
694
695        int diskNumber = GetLittleEndianByteOrder(fs,2);              /* number of this disk */
696        int startingDiskNum = GetLittleEndianByteOrder(fs,2);         /* number of the starting disk */
697        int entriesOnrThisDisk = GetLittleEndianByteOrder(fs,2);      /* entries on this disk */
698        int totalEntries = GetLittleEndianByteOrder(fs,2);            /* total number of entries */
699        int centralDirectoryTotalSize = GetLittleEndianByteOrder(fs,4); /* size of entire central directory */
700        int offsetOfCentralDirectory = GetLittleEndianByteOrder(fs,4);  /* offset of central on starting disk */
701        //This is what we really want here
702        int commentSize = GetLittleEndianByteOrder(fs,2);             /* length of zip file comment */
703
704
705        byte[] zipFileComment = new byte[commentSize];
706        fs.Read(zipFileComment, 0, zipFileComment.Length);
707
708        comment =  ae.GetString(zipFileComment, 0, zipFileComment.Length);
709        fs.Close();
710      }
711      catch (Exception e)
712      {
713        throw new Exception(e.Message);
714      }
715      return comment;
716    }
717
718    public void Stop ()
719    {
720      //m_Stop gets returned from the UZDLLService callback.
721      //A value of 1 means abort processing.
722      m_Stop = 1;
723    }
724
725    #endregion
726
727    #region Private Functions
728
729    private int ConvertEnumToInt (System.Enum obj)
730    {
731      return Convert.ToInt32(obj);
732    }
733
734    private bool GetZipFileSizeAndCount()
735    {
736      int ret = 0;
737
738      DCLIST dclist = new DCLIST();
739      dclist.StructVersID = uz_dcl_StructVer;   // Current version of this structure
740      dclist.nvflag = ConvertEnumToInt(ExtractOrListEnum.ListContents);
741      dclist.Zip = m_ZipFileName;
742      dclist.ExtractDir = m_ExtractionDirectory;
743
744      USERFUNCTION uf = PrepareUserFunctionCallbackStructure();
745
746      //Reset these variables
747      m_ZipFileSize = 0;
748      m_ZipFileCount = 0;
749
750      ret = Wiz_SingleEntryUnzip(m_FilesToUnzip.Length, m_FilesToUnzip, m_FilesToExclude.Length,
751                                 m_FilesToExclude, ref dclist, ref uf);
752
753      return (ret == 0);
754    }
755
756
757    private USERFUNCTION PrepareUserFunctionCallbackStructure()
758    {
759      USERFUNCTION uf = new USERFUNCTION();
760      uf.UZDLLPrnt = new UZDLLPrintCallback(UZDLLPrint);
761      uf.UZDLLSND = 0; //Not supported
762      uf.UZDLLREPLACE = new UZDLLReplaceCallback(UZDLLReplace);
763      uf.UZDLLPASSWORD = new UZDLLPasswordCallback(UZDLLPassword);
764      uf.UZDLLMESSAGE = new UZReceiveDLLMessageCallback(UZReceiveDLLMessage);
765      uf.UZDLLSERVICE = new UZDLLServiceCallback(UZDLLService);
766      uf.UZDLLMESSAGE_I32 = null; // not used
767      uf.UZDLLSERVICE_I32 = null; // not used
768
769      return uf;
770    }
771
772    private int GetLittleEndianByteOrder(FileStream fs, int len)
773    {
774      int result = 0;
775      int n = 0;
776      int [] byteArr = new int[len];
777
778      //Pull the bytes from the stream
779      for(n=0;n<len;n++)
780        byteArr[n] = fs.ReadByte();
781
782      //Left shift the bytes to get a resulting number in little endian format
783      for(n=0;n<byteArr.Length;n++)
784        result += (byteArr[n] << (n*8));
785
786      return result;
787    }
788
789    #endregion
790  }
791}
792