[WindowsBase] Fixed string buffer overflow when handling Zip entries.
[mono.git] / mcs / class / WindowsBase / ZipSharp / NativeUnzip.cs
1 // NativeUnzip.cs created with MonoDevelop
2 // User: alan at 13:11 20/10/2008
3 //
4 // To change standard headers go to Edit->Preferences->Coding->Standard Headers
5 //
6
7 using System;
8 using System.Collections.Generic;
9 using System.IO;
10 using System.IO.Packaging;
11 using System.Runtime.InteropServices;
12 using System.Text;
13
14 namespace zipsharp
15 {
16         static class NativeUnzip
17         {
18                 enum ZipStringComparison
19                 {
20                         OSDefault = 0,
21                         CaseSensitive = 1,
22                         CaseInsensitive = 2
23                 }
24                 
25                 public static void CloseArchive (UnzipHandle handle)
26                 {
27                         unzClose (handle);
28                         handle.SetHandleAsInvalid ();
29                 }
30
31                 public static void CloseCurrentFile (UnzipHandle handle)
32                 {
33                         if (unzCloseCurrentFile (handle) != 0)
34                                 throw new Exception ("Could not close the active file");
35                 }
36
37                 static CompressionOption ConvertCompression (int compressionLevel)
38                 {
39                         switch (compressionLevel)
40                         {
41                         case 1:
42                         case 2:
43                                 return CompressionOption.SuperFast;
44                                 
45                         case 3:
46                         case 4:
47                                 return CompressionOption.Fast;
48                                 
49                         case 5:
50                         case 6:
51                                 return CompressionOption.Normal;
52                                 
53                         case 7:
54                         case 8:
55                         case 9:
56                                 return CompressionOption.Maximum;
57
58                         default:
59                                 return CompressionOption.NotCompressed;
60                         }
61                 }
62
63                 public static long CurrentFilePosition (UnzipHandle handle)
64                 {
65                         return unztell(handle).ToInt64 ();
66                 }
67
68                 public static long CurrentFileLength (UnzipHandle handle)
69                 {
70                         UnzipFileInfo info;
71                         StringBuilder sbName = new StringBuilder (128);
72                         int result = unzGetCurrentFileInfo (handle, out info, sbName, new IntPtr (sbName.Capacity), IntPtr.Zero, IntPtr.Zero, null,  IntPtr.Zero);
73                         
74                         if (result != 0)
75                                 return -1;
76                         else
77                                 return (long)info.UncompressedSize;
78                 }
79                 
80                 static string GetCurrentFileName (UnzipHandle handle)
81                 {
82                         UnzipFileInfo info;
83                         int result = unzGetCurrentFileInfo (handle, out info, null, IntPtr.Zero, IntPtr.Zero, new IntPtr (0), null,  IntPtr.Zero);
84
85                         if (result != 0)
86                                 return null;
87                         
88                         StringBuilder sbName = new StringBuilder ((int)info.SizeFilename+1); // +1 to account for extra \0 at the end
89                         result = unzGetCurrentFileInfo (handle, out info, sbName, new IntPtr (sbName.Capacity), IntPtr.Zero, new IntPtr (0), null,  IntPtr.Zero);
90                         
91                         if (result != 0)
92                                 return null;
93                         else
94                                 return sbName.ToString ();
95                 }
96
97                 public static string[] GetFiles (UnzipHandle handle)
98                 {
99                         List<string> files = new List<string> ();
100
101                         GoToFirstFile (handle);
102
103                         string name;
104                         while ((name = GetCurrentFileName(handle)) != null)
105                         {
106                                 files.Add (name);
107                                 if (!NativeUnzip.GoToNextFile (handle))
108                                         break;
109                         }
110                         
111                         return files.ToArray ();
112                 }
113
114                 static void GoToFirstFile (UnzipHandle handle)
115                 {
116                         if (NativeUnzip.unzGoToFirstFile (handle) != 0)
117                                 throw new Exception ("Zip file is invalid");
118                 }
119
120                 static bool GoToNextFile (UnzipHandle handle)
121                 {
122                         return unzGoToNextFile(handle) == 0;
123                 }
124                 
125                 public static UnzipHandle OpenArchive (ZlibFileFuncDef fileFuncs)
126                 {
127                         UnzipHandle handle = unzOpen2 ("", ref fileFuncs);
128                         if (handle.IsInvalid)
129                                 throw new Exception ("Could not open unzip archive");
130                         return handle;
131                 }
132
133                 public static void OpenFile (UnzipHandle handle, string name, out CompressionOption level)
134                 {
135                         if (unzLocateFile (handle, name, (int) ZipStringComparison.CaseInsensitive) != 0)
136                                 throw new Exception ("The file doesn't exist");
137                         
138                         int method, compression;
139                         // '0' means do not open in raw mode (raw == do not decompress)
140                         if (unzOpenCurrentFile2 (handle, out method, out compression, 0) != 0)
141                                 throw new Exception ("The file could not be opened");
142
143                         level = ConvertCompression (method == 0 ? 0 : compression);
144                 }
145
146                 public static unsafe int Read (UnzipHandle handle, byte[] buffer, int offset, int count)
147                 {
148                         if ((buffer.Length - offset) > count)
149                                 throw new ArgumentOutOfRangeException ("count", "Buffer is too small to read that amount of data");
150                         
151                         fixed (byte * b = &buffer[offset])
152                                 return unzReadCurrentFile (handle, b, (uint)count);
153                 }
154
155                 [DllImport ("MonoPosixHelper", CallingConvention=CallingConvention.Cdecl)]
156                 static extern int unzCloseCurrentFile (UnzipHandle handle);
157
158                 [DllImport ("MonoPosixHelper", CallingConvention=CallingConvention.Cdecl)]
159                 static extern IntPtr unztell (UnzipHandle handle);
160                 
161                 [DllImport ("MonoPosixHelper", CallingConvention=CallingConvention.Cdecl)]
162                 static extern int unzGoToFirstFile (UnzipHandle handle);
163
164                 [DllImport ("MonoPosixHelper", CallingConvention=CallingConvention.Cdecl)]
165                 static extern UnzipHandle unzOpen2 (string path,
166                                                             ref ZlibFileFuncDef pzlib_filefunc_def);
167
168                 [DllImport ("MonoPosixHelper", CallingConvention=CallingConvention.Cdecl)]
169                 static extern int unzGoToNextFile (UnzipHandle handle);
170
171                 [DllImport ("MonoPosixHelper", CallingConvention=CallingConvention.Cdecl)]
172                 static extern int unzLocateFile (UnzipHandle handle,
173                                                          string szFileName,
174                                                          int iCaseSensitivity);
175
176                 [DllImport ("MonoPosixHelper", CallingConvention=CallingConvention.Cdecl)]
177                 static extern int unzOpenCurrentFile2 (UnzipHandle handle,
178                                                        out int method,
179                                                        out int level,
180                                                        int raw);
181
182                 [DllImport ("MonoPosixHelper", CallingConvention=CallingConvention.Cdecl)]
183                 static extern int unzGetCurrentFileInfo (UnzipHandle handle,
184                                                                  out UnzipFileInfo pfile_info,
185                                                                  StringBuilder szFileName,
186                                                                  IntPtr fileNameBufferSize,   // uLong
187                                                                  IntPtr extraField,           // void *
188                                                                  IntPtr extraFieldBufferSize, // uLong
189                                                                  StringBuilder szComment,
190                                                                  IntPtr commentBufferSize);   // uLong
191
192                 [DllImport ("MonoPosixHelper", CallingConvention=CallingConvention.Cdecl)]
193                 static unsafe extern int unzReadCurrentFile (UnzipHandle handle,
194                                                               byte* buf, // voidp
195                                                               uint len);
196
197                 //[DllImport ("MonoPosixHelper", CallingConvention=CallingConvention.Cdecl)]
198                 //static extern int unzSetOffset (UnzipHandle handle, IntPtr pos); // uLong
199                 
200                 [DllImport ("MonoPosixHelper", CallingConvention=CallingConvention.Cdecl)]
201                 static extern int unzClose (UnzipHandle handle);
202         }
203 }