nochump.util.zip压缩和解压缩使用方法
/*
2?nochump.util.zip.ZipOutput
3?Copyright (C) 2007 David Chang (dchang@nochump.com)
4?
5?This file is part of nochump.util.zip.
6?
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?}