root/trunk/Updater/ICSharpCode.SharpZipLib/Zip/FastZip.cs @ 597

Wersja 597, 21.9 KB (wprowadzona przez marek, 17 years temu)

re #165

Line 
1// FastZip.cs
2//
3// Copyright 2005 John Reilly
4//
5// This program is free software; you can redistribute it and/or
6// modify it under the terms of the GNU General Public License
7// as published by the Free Software Foundation; either version 2
8// of the License, or (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program; if not, write to the Free Software
17// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18//
19// Linking this library statically or dynamically with other modules is
20// making a combined work based on this library.  Thus, the terms and
21// conditions of the GNU General Public License cover the whole
22// combination.
23//
24// As a special exception, the copyright holders of this library give you
25// permission to link this library with independent modules to produce an
26// executable, regardless of the license terms of these independent
27// modules, and to copy and distribute the resulting executable under
28// terms of your choice, provided that you also meet, for each linked
29// independent module, the terms and conditions of the license of that
30// module.  An independent module is a module which is not derived from
31// or based on this library.  If you modify this library, you may extend
32// this exception to your version of the library, but you are not
33// obligated to do so.  If you do not wish to do so, delete this
34// exception statement from your version.
35
36using System;
37using System.IO;
38using ICSharpCode.SharpZipLib.Core;
39
40namespace ICSharpCode.SharpZipLib.Zip
41{
42        /// <summary>
43        /// FastZipEvents supports all events applicable to <see cref="FastZip">FastZip</see> operations.
44        /// </summary>
45        public class FastZipEvents
46        {
47                /// <summary>
48                /// Delegate to invoke when processing directories.
49                /// </summary>
50                public ProcessDirectoryHandler ProcessDirectory;
51               
52                /// <summary>
53                /// Delegate to invoke when processing files.
54                /// </summary>
55                public ProcessFileHandler ProcessFile;
56
57                /// <summary>
58                /// Delegate to invoke during processing of files.
59                /// </summary>
60                public ProgressHandler Progress;
61
62                /// <summary>
63                /// Delegate to invoke when processing for a file has been completed.
64                /// </summary>
65                public CompletedFileHandler CompletedFile;
66               
67                /// <summary>
68                /// Delegate to invoke when processing directory failures.
69                /// </summary>
70                public DirectoryFailureHandler DirectoryFailure;
71               
72                /// <summary>
73                /// Delegate to invoke when processing file failures.
74                /// </summary>
75                public FileFailureHandler FileFailure;
76               
77                /// <summary>
78                /// Raise the <see cref="DirectoryFailure">directory failure</see> event.
79                /// </summary>
80                /// <param name="directory">The directory causing the failure.</param>
81                /// <param name="e">The exception for this event.</param>
82                /// <returns>A boolean indicating if execution should continue or not.</returns>
83                public bool OnDirectoryFailure(string directory, Exception e)
84                {
85                        bool result = false;
86                        DirectoryFailureHandler handler = DirectoryFailure;
87
88                        if ( handler != null ) {
89                                ScanFailureEventArgs args = new ScanFailureEventArgs(directory, e);
90                                handler(this, args);
91                                result = args.ContinueRunning;
92                        }
93                        return result;
94                }
95               
96                /// <summary>
97                /// Raises the <see cref="FileFailure">file failure delegate</see>.
98                /// </summary>
99                /// <param name="file">The file causing the failure.</param>
100                /// <param name="e">The exception for this failure.</param>
101                /// <returns>A boolean indicating if execution should continue or not.</returns>
102                public bool OnFileFailure(string file, Exception e)
103                {
104                        FileFailureHandler handler = FileFailure;
105            bool result = (handler != null);
106
107                        if ( result ) {
108                                ScanFailureEventArgs args = new ScanFailureEventArgs(file, e);
109                                handler(this, args);
110                                result = args.ContinueRunning;
111                        }
112                        return result;
113                }
114               
115                /// <summary>
116                /// Fires the <see cref="ProcessFile">Process File delegate</see>.
117                /// </summary>
118                /// <param name="file">The file being processed.</param>
119                /// <returns>A boolean indicating if execution should continue or not.</returns>
120                public bool OnProcessFile(string file)
121                {
122                        bool result = true;
123                        ProcessFileHandler handler = ProcessFile;
124
125                        if ( handler != null ) {
126                                ScanEventArgs args = new ScanEventArgs(file);
127                                ProcessFile(this, args);
128                                result = args.ContinueRunning;
129                        }
130                        return result;
131                }
132
133                /// <summary>
134                /// Fires the CompletedFile delegate
135                /// </summary>
136                /// <param name="file">The file whose processing has been completed.</param>
137                /// <returns>A boolean indicating if execution should continue or not.</returns>
138                public bool OnCompletedFile(string file)
139                {
140                        bool result = true;
141                        CompletedFileHandler handler = CompletedFile;
142                        if ( handler != null ) {
143                                ScanEventArgs args = new ScanEventArgs(file);
144                                handler(this, args);
145                                result = args.ContinueRunning;
146                        }
147                        return result;
148                }
149               
150                /// <summary>
151                /// Fires the <see cref="ProcessDirectory">process directory</see> delegate.
152                /// </summary>
153                /// <param name="directory">The directory being processed.</param>
154                /// <param name="hasMatchingFiles">Flag indicating if the directory has matching files as determined by the current filter.</param>
155                /// <returns>A <see cref="bool"/> of true if the operation should continue; false otherwise.</returns>
156                public bool OnProcessDirectory(string directory, bool hasMatchingFiles)
157                {
158                        bool result = true;
159                        ProcessDirectoryHandler handler = ProcessDirectory;
160                        if ( handler != null ) {
161                                DirectoryEventArgs args = new DirectoryEventArgs(directory, hasMatchingFiles);
162                                handler(this, args);
163                                result = args.ContinueRunning;
164                        }
165                        return result;
166                }
167
168                /// <summary>
169                /// The minimum timespan between <see cref="Progress"/> events.
170                /// </summary>
171                /// <value>The minimum period of time between <see cref="Progress"/> events.</value>
172                /// <seealso cref="Progress"/>
173                public TimeSpan ProgressInterval
174                {
175                        get { return progressInterval_; }
176                        set { progressInterval_ = value; }
177                }
178
179                #region Instance Fields
180                TimeSpan progressInterval_ = TimeSpan.FromSeconds(3);
181                #endregion
182        }
183       
184        /// <summary>
185        /// FastZip provides facilities for creating and extracting zip files.
186        /// </summary>
187        public class FastZip
188        {
189                #region Enumerations
190                /// <summary>
191                /// Defines the desired handling when overwriting files during extraction.
192                /// </summary>
193                public enum Overwrite
194                {
195                        /// <summary>
196                        /// Prompt the user to confirm overwriting
197                        /// </summary>
198                        Prompt,
199                        /// <summary>
200                        /// Never overwrite files.
201                        /// </summary>
202                        Never,
203                        /// <summary>
204                        /// Always overwrite files.
205                        /// </summary>
206                        Always
207                }
208                #endregion
209               
210                #region Constructors
211                /// <summary>
212                /// Initialise a default instance of <see cref="FastZip"/>.
213                /// </summary>
214                public FastZip()
215                {
216                }
217
218                /// <summary>
219                /// Initialise a new instance of <see cref="FastZip"/>
220                /// </summary>
221                /// <param name="events">The <see cref="FastZipEvents">events</see> to use during operations.</param>
222                public FastZip(FastZipEvents events)
223                {
224                        events_ = events;
225                }
226                #endregion
227               
228                #region Properties
229                /// <summary>
230                /// Get/set a value indicating wether empty directories should be created.
231                /// </summary>
232                public bool CreateEmptyDirectories
233                {
234                        get { return createEmptyDirectories_; }
235                        set { createEmptyDirectories_ = value; }
236                }
237
238#if !NETCF_1_0
239                /// <summary>
240                /// Get / set the password value.
241                /// </summary>
242                public string Password
243                {
244                        get { return password_; }
245                        set { password_ = value; }
246                }
247#endif
248
249                /// <summary>
250                /// Get or set the <see cref="INameTransform"></see> active when creating Zip files.
251                /// </summary>
252                /// <seealso cref="EntryFactory"></seealso>
253                public INameTransform NameTransform
254                {
255                        get { return entryFactory_.NameTransform; }
256                        set {
257                                entryFactory_.NameTransform = value;
258                        }
259                }
260
261                /// <summary>
262                /// Get or set the <see cref="IEntryFactory"></see> active when creating Zip files.
263                /// </summary>
264                public IEntryFactory EntryFactory
265                {
266                        get { return entryFactory_; }
267                        set {
268                                if ( value == null ) {
269                                        entryFactory_ = new ZipEntryFactory();
270                                }
271                                else {
272                                        entryFactory_ = value;
273                                }
274                        }
275                }
276               
277                /// <summary>
278                /// Gets or sets the setting for <see cref="UseZip64">Zip64 handling when writing.</see>
279                /// </summary>
280        /// <remarks>
281        /// The default value is dynamic which is not backwards compatible with old
282        /// programs and can cause problems with XP's built in compression which cant
283        /// read Zip64 archives. However it does avoid the situation were a large file
284        /// is added and cannot be completed correctly.
285        /// NOTE: Setting the size for entries before they are added is the best solution!
286        /// By default the EntryFactory used by FastZip will set fhe file size.
287        /// </remarks>
288                public UseZip64 UseZip64
289                {
290                        get { return useZip64_; }
291                        set { useZip64_ = value; }
292                }
293               
294                /// <summary>
295                /// Get/set a value indicating wether file dates and times should
296                /// be restored when extracting files from an archive.
297                /// </summary>
298                /// <remarks>The default value is false.</remarks>
299                public bool RestoreDateTimeOnExtract
300                {
301                        get {
302                                return restoreDateTimeOnExtract_;
303                        }
304                        set {
305                                restoreDateTimeOnExtract_ = value;
306                        }
307                }
308               
309                /// <summary>
310                /// Get/set a value indicating wether file attributes should
311                /// be restored during extract operations
312                /// </summary>
313                public bool RestoreAttributesOnExtract
314                {
315                        get { return restoreAttributesOnExtract_; }
316                        set { restoreAttributesOnExtract_ = value; }
317                }
318                #endregion
319               
320                #region Delegates
321                /// <summary>
322                /// Delegate called when confirming overwriting of files.
323                /// </summary>
324                public delegate bool ConfirmOverwriteDelegate(string fileName);
325                #endregion
326               
327                #region CreateZip
328                /// <summary>
329                /// Create a zip file.
330                /// </summary>
331                /// <param name="zipFileName">The name of the zip file to create.</param>
332                /// <param name="sourceDirectory">The directory to source files from.</param>
333                /// <param name="recurse">True to recurse directories, false for no recursion.</param>
334                /// <param name="fileFilter">The <see cref="PathFilter">file filter</see> to apply.</param>
335                /// <param name="directoryFilter">The <see cref="PathFilter">directory filter</see> to apply.</param>
336                public void CreateZip(string zipFileName, string sourceDirectory,
337                        bool recurse, string fileFilter, string directoryFilter)
338                {
339                        CreateZip(File.Create(zipFileName), sourceDirectory, recurse, fileFilter, directoryFilter);
340                }
341               
342                /// <summary>
343                /// Create a zip file/archive.
344                /// </summary>
345                /// <param name="zipFileName">The name of the zip file to create.</param>
346                /// <param name="sourceDirectory">The directory to obtain files and directories from.</param>
347                /// <param name="recurse">True to recurse directories, false for no recursion.</param>
348                /// <param name="fileFilter">The file filter to apply.</param>
349                public void CreateZip(string zipFileName, string sourceDirectory, bool recurse, string fileFilter)
350                {
351                        CreateZip(File.Create(zipFileName), sourceDirectory, recurse, fileFilter, null);
352                }
353
354                /// <summary>
355                /// Create a zip archive sending output to the <paramref name="outputStream"/> passed.
356                /// </summary>
357                /// <param name="outputStream">The stream to write archive data to.</param>
358                /// <param name="sourceDirectory">The directory to source files from.</param>
359                /// <param name="recurse">True to recurse directories, false for no recursion.</param>
360                /// <param name="fileFilter">The <see cref="PathFilter">file filter</see> to apply.</param>
361                /// <param name="directoryFilter">The <see cref="PathFilter">directory filter</see> to apply.</param>
362                public void CreateZip(Stream outputStream, string sourceDirectory, bool recurse, string fileFilter, string directoryFilter)
363                {
364                        NameTransform = new ZipNameTransform(sourceDirectory);
365                        sourceDirectory_ = sourceDirectory;
366
367                        using ( outputStream_ = new ZipOutputStream(outputStream) ) {
368
369#if !NETCF_1_0
370                                if ( password_ != null ) {
371                                        outputStream_.Password = password_;
372                                }
373#endif
374
375                                outputStream_.UseZip64 = UseZip64;
376                                FileSystemScanner scanner = new FileSystemScanner(fileFilter, directoryFilter);
377                                scanner.ProcessFile += new ProcessFileHandler(ProcessFile);
378                                if ( this.CreateEmptyDirectories ) {
379                                        scanner.ProcessDirectory += new ProcessDirectoryHandler(ProcessDirectory);
380                                }
381                               
382                                if (events_ != null) {
383                                        if ( events_.FileFailure != null ) {
384                                                scanner.FileFailure += events_.FileFailure;
385                                        }
386
387                                        if ( events_.DirectoryFailure != null ) {
388                                                scanner.DirectoryFailure += events_.DirectoryFailure;
389                                        }
390                                }
391
392                                scanner.Scan(sourceDirectory, recurse);
393                        }
394                }
395
396                #endregion
397               
398                #region ExtractZip
399                /// <summary>
400                /// Extract the contents of a zip file.
401                /// </summary>
402                /// <param name="zipFileName">The zip file to extract from.</param>
403                /// <param name="targetDirectory">The directory to save extracted information in.</param>
404                /// <param name="fileFilter">A filter to apply to files.</param>
405                public void ExtractZip(string zipFileName, string targetDirectory, string fileFilter)
406                {
407                        ExtractZip(zipFileName, targetDirectory, Overwrite.Always, null, fileFilter, null, restoreDateTimeOnExtract_);
408                }
409               
410                /// <summary>
411                /// Extract the contents of a zip file.
412                /// </summary>
413                /// <param name="zipFileName">The zip file to extract from.</param>
414                /// <param name="targetDirectory">The directory to save extracted information in.</param>
415                /// <param name="overwrite">The style of <see cref="Overwrite">overwriting</see> to apply.</param>
416                /// <param name="confirmDelegate">A delegate to invoke when confirming overwriting.</param>
417                /// <param name="fileFilter">A filter to apply to files.</param>
418                /// <param name="directoryFilter">A filter to apply to directories.</param>
419                /// <param name="restoreDateTime">Flag indicating wether to restore the date and time for extracted files.</param>
420                public void ExtractZip(string zipFileName, string targetDirectory,
421                                                           Overwrite overwrite, ConfirmOverwriteDelegate confirmDelegate,
422                                                           string fileFilter, string directoryFilter, bool restoreDateTime)
423                {
424                        if ( (overwrite == Overwrite.Prompt) && (confirmDelegate == null) ) {
425                                throw new ArgumentNullException("confirmDelegate");
426                        }
427
428                        continueRunning_ = true;
429                        overwrite_ = overwrite;
430                        confirmDelegate_ = confirmDelegate;
431                        extractNameTransform_ = new WindowsNameTransform(targetDirectory);
432                       
433                        fileFilter_ = new NameFilter(fileFilter);
434                        directoryFilter_ = new NameFilter(directoryFilter);
435                        restoreDateTimeOnExtract_ = restoreDateTime;
436                       
437                        using ( zipFile_ = new ZipFile(zipFileName) ) {
438
439#if !NETCF_1_0
440                                if (password_ != null) {
441                                        zipFile_.Password = password_;
442                                }
443#endif
444
445                                System.Collections.IEnumerator enumerator = zipFile_.GetEnumerator();
446                                while ( continueRunning_ && enumerator.MoveNext()) {
447                                        ZipEntry entry = (ZipEntry) enumerator.Current;
448                                        if ( entry.IsFile )
449                                        {
450                        // TODO Path.GetDirectory can fail here on invalid characters.
451                                                if ( directoryFilter_.IsMatch(Path.GetDirectoryName(entry.Name)) && fileFilter_.IsMatch(entry.Name) ) {
452                                                        ExtractEntry(entry);
453                                                }
454                                        }
455                                        else if ( entry.IsDirectory ) {
456                                                if ( directoryFilter_.IsMatch(entry.Name) && CreateEmptyDirectories ) {
457                                                        ExtractEntry(entry);
458                                                }
459                                        }
460                                        else {
461                                                // Do nothing for volume labels etc...
462                                        }
463                                }
464                        }
465                }
466                #endregion
467               
468                #region Internal Processing
469                void ProcessDirectory(object sender, DirectoryEventArgs e)
470                {
471                        if ( !e.HasMatchingFiles && CreateEmptyDirectories ) {
472                                if ( events_ != null ) {
473                                        events_.OnProcessDirectory(e.Name, e.HasMatchingFiles);
474                                }
475                               
476                                if ( e.ContinueRunning ) {
477                                        if (e.Name != sourceDirectory_) {
478                                                ZipEntry entry = entryFactory_.MakeDirectoryEntry(e.Name);
479                                                outputStream_.PutNextEntry(entry);
480                                        }
481                                }
482                        }
483                }
484               
485                void ProcessFile(object sender, ScanEventArgs e)
486                {
487                        if ( (events_ != null) && (events_.ProcessFile != null) ) {
488                                events_.ProcessFile(sender, e);
489                        }
490                       
491                        if ( e.ContinueRunning ) {
492                                using( FileStream stream=File.OpenRead(e.Name) ) {
493                                        ZipEntry entry=entryFactory_.MakeFileEntry(e.Name);
494                                        outputStream_.PutNextEntry(entry);
495                                        AddFileContents(e.Name, stream);
496                                }
497                        }
498                }
499
500                void AddFileContents(string name, Stream stream)
501                {
502                        if( stream==null ) {
503                                throw new ArgumentNullException("stream");
504                        }
505
506                        if( buffer_==null ) {
507                                buffer_=new byte[4096];
508                        }
509
510                        if( (events_!=null)&&(events_.Progress!=null) ) {
511                                StreamUtils.Copy(stream, outputStream_, buffer_,
512                                        events_.Progress, events_.ProgressInterval, this, name);
513                        }
514                        else {
515                                StreamUtils.Copy(stream, outputStream_, buffer_);
516                        }
517
518                        if( events_!=null ) {
519                                continueRunning_=events_.OnCompletedFile(name);
520                        }
521                }
522
523                void ExtractFileEntry(ZipEntry entry, string targetName)
524                {
525                        bool proceed = true;
526                        if ( overwrite_ != Overwrite.Always ) {
527                                if ( File.Exists(targetName) ) {
528                                        if ( (overwrite_ == Overwrite.Prompt) && (confirmDelegate_ != null) ) {
529                                                proceed = confirmDelegate_(targetName);
530                                        }
531                                        else {
532                                                proceed = false;
533                                        }
534                                }
535                        }
536                       
537                        if ( proceed ) {
538                                if ( events_ != null ) {
539                                        continueRunning_ = events_.OnProcessFile(entry.Name);
540                                }
541                       
542                                if ( continueRunning_ ) {
543                                        try {
544                                                using ( FileStream outputStream = File.Create(targetName) ) {
545                                                        if ( buffer_ == null ) {
546                                                                buffer_ = new byte[4096];
547                                                        }
548                                                        if ((events_ != null) && (events_.Progress != null))
549                                                        {
550                                                                StreamUtils.Copy(zipFile_.GetInputStream(entry), outputStream, buffer_,
551                                                                        events_.Progress, events_.ProgressInterval, this, entry.Name, entry.Size);
552                                                        }
553                                                        else
554                                                        {
555                                                                StreamUtils.Copy(zipFile_.GetInputStream(entry), outputStream, buffer_);
556                                                        }
557                                                       
558                                                        if (events_ != null) {
559                                                                continueRunning_ = events_.OnCompletedFile(entry.Name);
560                                                        }
561                                                }
562
563#if !NETCF_1_0 && !NETCF_2_0
564                                                if ( restoreDateTimeOnExtract_ ) {
565                                                        File.SetLastWriteTime(targetName, entry.DateTime);
566                                                }
567                                               
568                                                if ( RestoreAttributesOnExtract && entry.IsDOSEntry && (entry.ExternalFileAttributes != -1)) {
569                                                        FileAttributes fileAttributes = (FileAttributes) entry.ExternalFileAttributes;
570                                                        // TODO: FastZip - Setting of other file attributes on extraction is a little trickier.
571                                                        fileAttributes &= (FileAttributes.Archive | FileAttributes.Normal | FileAttributes.ReadOnly | FileAttributes.Hidden);
572                                                        File.SetAttributes(targetName, fileAttributes);
573                                                }
574#endif                                         
575                                        }
576                                        catch(Exception ex) {
577                                                if ( events_ != null ) {
578                                                        continueRunning_ = events_.OnFileFailure(targetName, ex);
579                                                }
580                                                else {
581                            continueRunning_ = false;
582                            throw;
583                                                }
584                                        }
585                                }
586                        }
587                }
588
589                void ExtractEntry(ZipEntry entry)
590                {
591                        bool doExtraction = entry.IsCompressionMethodSupported();
592                        string targetName = entry.Name;
593                       
594                        if ( doExtraction ) {
595                                if ( entry.IsFile ) {
596                                        targetName = extractNameTransform_.TransformFile(targetName);
597                                }
598                                else if ( entry.IsDirectory ) {
599                                        targetName = extractNameTransform_.TransformDirectory(targetName);
600                                }
601                               
602                                doExtraction = !((targetName == null) || (targetName.Length == 0));
603                        }
604                       
605                        // TODO: Fire delegate/throw exception were compression method not supported, or name is invalid?
606
607                        string dirName = null;
608                       
609                        if ( doExtraction ) {
610                                        if ( entry.IsDirectory ) {
611                                                dirName = targetName;
612                                        }
613                                        else {
614                                                dirName = Path.GetDirectoryName(Path.GetFullPath(targetName));
615                                        }
616                        }
617                       
618                        if ( doExtraction && !Directory.Exists(dirName) ) {
619                                if ( !entry.IsDirectory || CreateEmptyDirectories ) {
620                                        try {
621                                                Directory.CreateDirectory(dirName);
622                                        }
623                                        catch (Exception ex) {
624                                                doExtraction = false;
625                                                if ( events_ != null ) {
626                                                        if ( entry.IsDirectory ) {
627                                                                continueRunning_ = events_.OnDirectoryFailure(targetName, ex);
628                                                        }
629                                                        else {
630                                                                continueRunning_ = events_.OnFileFailure(targetName, ex);
631                                                        }
632                                                }
633                                                else {
634                                                        continueRunning_ = false;
635                            throw;
636                                                }
637                                        }
638                                }
639                        }
640                       
641                        if ( doExtraction && entry.IsFile ) {
642                                ExtractFileEntry(entry, targetName);
643                        }
644                }
645
646                static int MakeExternalAttributes(FileInfo info)
647                {
648                        return (int)info.Attributes;
649                }
650               
651#if NET_1_0 || NET_1_1 || NETCF_1_0
652                static bool NameIsValid(string name)
653                {
654                        return (name != null) &&
655                                (name.Length > 0) &&
656                                (name.IndexOfAny(Path.InvalidPathChars) < 0);
657                }
658#else
659                static bool NameIsValid(string name)
660                {
661                        return (name != null) &&
662                                (name.Length > 0) &&
663                                (name.IndexOfAny(Path.GetInvalidPathChars()) < 0);
664                }
665#endif
666                #endregion
667               
668                #region Instance Fields
669                bool continueRunning_;
670                byte[] buffer_;
671                ZipOutputStream outputStream_;
672                ZipFile zipFile_;
673                string sourceDirectory_;
674                NameFilter fileFilter_;
675                NameFilter directoryFilter_;
676                Overwrite overwrite_;
677                ConfirmOverwriteDelegate confirmDelegate_;
678               
679                bool restoreDateTimeOnExtract_;
680                bool restoreAttributesOnExtract_;
681                bool createEmptyDirectories_;
682                FastZipEvents events_;
683                IEntryFactory entryFactory_ = new ZipEntryFactory();
684                INameTransform extractNameTransform_;
685                UseZip64 useZip64_=UseZip64.Dynamic;
686               
687#if !NETCF_1_0
688                string password_;
689#endif 
690
691                #endregion
692        }
693}
Notatka: Zobacz TracBrowser aby uzyskać więcej informacji.