nochump.util.zip压缩和好压缩使用方法

nochump.util.zip压缩和解压缩使用方法

/*
2 nochump.util.zip.ZipOutput
3 Copyright (C) 2007 David Chang (dchang@nochump.com)

5 This file is part of nochump.util.zip.

7 nochump.util.zip is free software: you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11 
12 nochump.util.zip is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU Lesser General Public License for more details.
16 
17 You should have received a copy of the GNU Lesser General Public License
18 along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
19 */
20 package nochump.util.zip {
21 
22         import flash.utils.Dictionary;
23         import flash.utils.Endian;
24         import flash.utils.ByteArray;
25       
26         public class ZipOutput {
27               
28                 private var _entry:ZipEntry;
29                 private var _entries:Array = [];
30                 private var _names:Dictionary = new Dictionary();
31                 private var _def:Deflater = new Deflater();
32                 private var _crc:CRC32 = new CRC32();
33                 private var _buf:ByteArray = new ByteArray();
34                 private var _comment:String = "";
35               
36                 public function ZipOutput() {
37                         _buf.endian = Endian.LITTLE_ENDIAN;
38                 }
39               
40                 /**
41                  * Returns the number of entries in this zip file.
42                  */
43                 public function get size():uint {
44                         return _entries.length;
45                 }
46               
47                 /**
48                  * Returns the byte array of the finished zip.
49                  */
50                 public function get byteArray():ByteArray {
51                         _buf.position = 0;
52                         return _buf;
53                 }
54               
55                 /**
56                  *
57                  */
58                 public function set comment(value:String):void {
59                         _comment = value;
60                 }
61               
62                 public function putNextEntry(e:ZipEntry):void {
63                         if(_entry != null) closeEntry();
64                         // TODO:
65                         if(e.dostime == 0) e.time = new Date().time;
66                         if (e.method == -1) e.method = ZipConstants.DEFLATED; // use default method
67                         switch(e.method) {
68                                 case ZipConstants.DEFLATED:
69                                         if (e.size == -1 || e.compressedSize == -1 || e.crc == 0) {
70                                                 // store size, compressed size, and crc-32 in data descriptor
71                                                 // immediately following the compressed entry data
72                                                 e.flag = 8;
73                                         } else if (e.size != -1 && e.compressedSize != -1 && e.crc != 0) {
74                                                 // store size, compressed size, and crc-32 in LOC header
75                                                 e.flag = 0;
76                                         } else {
77                                                 throw new ZipError("DEFLATED entry missing size, compressed size, or crc-32");
78                                         }
79                                         e.version = 20;
80                                         break;
81                                 case ZipConstants.STORED:
82                                         // compressed size, uncompressed size, and crc-32 must all be
83                                         // set for entries using STORED compression method
84                                         if (e.size == -1) {
85                                                 e.size = e.compressedSize;
86                                         } else if (e.compressedSize == -1) {
87                                                 e.compressedSize = e.size;
88                                         } else if (e.size != e.compressedSize) {
89                                                 throw new ZipError("STORED entry where compressed != uncompressed size");
90                                         }
91                                         if (e.size == -1 || e.crc == 0) {
92                                                 throw new ZipError("STORED entry missing size, compressed size, or crc-32");
93                                         }
94                                         e.version = 10;
95                                         e.flag = 0;
96                                         break;
97                                 default:
98                                         throw new ZipError("unsupported compression method");
99                         }
100                         e.offset = _buf.position;
101                         if (_names[e.name] != null) {
102                                 throw new ZipError("duplicate entry: " + e.name);
103                         } else {
104                                 _names[e.name] = e;
105                         }
106                         writeLOC(e);
107                         _entries.push(e);
108                         _entry = e;
109                 }
110               
111                 public function write(b:ByteArray):void {
112                         if (_entry == null) {
113                                 throw new ZipError("no current ZIP entry");
114                         }
115                         //*
116                         switch (_entry.method) {
117                                 case ZipConstants.DEFLATED:
118                                         //super.write(b, off, len);
119                                         var cb:ByteArray = new ByteArray();
120                                         _def.setInput(b);
121                                         _def.deflate(cb);
122                                         _buf.writeBytes(cb);
123                                         // TODO: test if Deflater can deflate to the end of _buf (saves from using variable cb and an extra copy)
124                                         break;
125                                 case ZipConstants.STORED:
126                                         // TODO:
127                                         //if (written - locoff > _entry.size) {
128                                         //      throw new ZipError("attempt to write past end of STORED entry");
129                                         //}
130                                         //out.write(b, off, len);
131                                         _buf.writeBytes(b);
132                                         break;
133                                 default:
134                                         throw new Error("invalid compression method");
135                         }
136                         /**/
137                         _crc.update(b);
138                 }
139               
140                 // check if this method is still necessary since we're not dealing with streams
141                 // seems crc and whether a data descriptor i necessary is determined here
142                 public function closeEntry():void {
143                         var e:ZipEntry = _entry;
144                         if(e != null) {
145                                 switch (e.method) {
146                                         case ZipConstants.DEFLATED:
147                                                 if ((e.flag & 8) == 0) {
148                                                         // verify size, compressed size, and crc-32 settings
149                                                         if (e.size != _def.getBytesRead()) {
150                                                                 throw new ZipError("invalid entry size (expected " + e.size + " but got " + _def.getBytesRead() + " bytes)");
151                                                         }
152                                                         if (e.compressedSize != _def.getBytesWritten()) {
153                                                                 throw new ZipError("invalid entry compressed size (expected " + e.compressedSize + " but got " + _def.getBytesWritten() + " bytes)");
154                                                         }
155                                                         if (e.crc != _crc.getValue()) {
156                                                                 throw new ZipError( "invalid entry CRC-32 (expected 0x" + e.crc + " but got 0x" + _crc.getValue() + ")");
157                                                         }
158                                                 } else {
159                                                         e.size = _def.getBytesRead();
160                                                         e.compressedSize = _def.getBytesWritten();
161                                                         e.crc = _crc.getValue();
162                                                         writeEXT(e);
163                                                 }
164                                                 _def.reset();
165                                                 break;
166                                         case ZipConstants.STORED:
167                                                 // TODO:
168                                                 break;
169                                         default:
170                                                 throw new Error("invalid compression method");
171                                 }
172                                 _crc.reset();
173                                 _entry = null;
174                         }
175                 }
176               
177                 public function finish():void {
178                         if(_entry != null) closeEntry();
179                         if (_entries.length < 1) throw new ZipError("ZIP file must have at least one entry");
180                         var off:uint = _buf.position;
181                         // write central directory
182                         for(var i:uint = 0; i < _entries.length; i++) {
183                                 writeCEN(_entries[i]);
184                         }
185                         writeEND(off, _buf.position - off);
186                 }
187               
188                 private function writeLOC(e:ZipEntry):void {
189                         _buf.writeUnsignedInt(ZipConstants.LOCSIG);
190                         _buf.writeShort(e.version);
191                         _buf.writeShort(e.flag);
192                         _buf.writeShort(e.method);
193                         _buf.writeUnsignedInt(e.dostime); // dostime
194                         if ((e.flag & 8) == 8) {
195                                 // store size, uncompressed size, and crc-32 in data descriptor
196                                 // immediately following compressed entry data
197                                 _buf.writeUnsignedInt(0);
198                                 _buf.writeUnsignedInt(0);
199                                 _buf.writeUnsignedInt(0);
200                         } else {
201                                 _buf.writeUnsignedInt(e.crc); // crc-32
202                                 _buf.writeUnsignedInt(e.compressedSize); // compressed size
203                                 _buf.writeUnsignedInt(e.size); // uncompressed size
204                         }
205                         _buf.writeShort(e.name.length);
206                         _buf.writeShort(e.extra != null ? e.extra.length : 0);
207                         _buf.writeUTFBytes(e.name);
208                         if (e.extra != null) {
209                                 _buf.writeBytes(e.extra);
210                         }
211                 }
212               
213                 /*
214                  * Writes extra data descriptor (EXT) for specified entry.
215                  */
216                 private function writeEXT(e:ZipEntry):void {
217                         _buf.writeUnsignedInt(ZipConstants.EXTSIG); // EXT header signature
218                         _buf.writeUnsignedInt(e.crc); // crc-32
219                         _buf.writeUnsignedInt(e.compressedSize); // compressed size
220                         _buf.writeUnsignedInt(e.size); // uncompressed size
221                 }
222               
223                 /*
224                  * Write central directory (CEN) header for specified entry.
225                  * REMIND: add support for file attributes
226                  */
227                 private function writeCEN(e:ZipEntry):void {
228                         _buf.writeUnsignedInt(ZipConstants.CENSIG); // CEN header signature
229                         _buf.writeShort(e.version); // version made by
230                         _buf.writeShort(e.version); // version needed to extract
231                         _buf.writeShort(e.flag); // general purpose bit flag
232                         _buf.writeShort(e.method); // compression method
233                         _buf.writeUnsignedInt(e.dostime); // last modification time
234                         _buf.writeUnsignedInt(e.crc); // crc-32
235                         _buf.writeUnsignedInt(e.compressedSize); // compressed size
236                         _buf.writeUnsignedInt(e.size); // uncompressed size
237                         _buf.writeShort(e.name.length);
238                         _buf.writeShort(e.extra != null ? e.extra.length : 0);
239                         _buf.writeShort(e.comment != null ? e.comment.length : 0);
240                         _buf.writeShort(0); // starting disk number
241                         _buf.writeShort(0); // internal file attributes (unused)
242                         _buf.writeUnsignedInt(0); // external file attributes (unused)
243                         _buf.writeUnsignedInt(e.offset); // relative offset of local header
244                         _buf.writeUTFBytes(e.name);
245                         if (e.extra != null) {
246                                 _buf.writeBytes(e.extra);
247                         }
248                         if (e.comment != null) {
249                                 _buf.writeUTFBytes(e.comment);
250                         }
251                 }
252               
253                 /*
254                  * Writes end of central directory (END) header.
255                  */
256                 private function writeEND(off:uint, len:uint):void {
257                         _buf.writeUnsignedInt(ZipConstants.ENDSIG); // END record signature
258                         _buf.writeShort(0); // number of this disk
259                         _buf.writeShort(0); // central directory start disk
260                         _buf.writeShort(_entries.length); // number of directory entries on disk
261                         _buf.writeShort(_entries.length); // total number of directory entries
262                         _buf.writeUnsignedInt(len); // length of central directory
263                         _buf.writeUnsignedInt(off); // offset of central directory
264                         _buf.writeUTF(_comment); // zip file comment
265                 }
266               
267         }
268       
269 }