Browse Source

updated zip package : remove "File" to Reader, added CRC32 and Writer

Nicolas Cannasse 17 years ago
parent
commit
ea477462fd

+ 3 - 1
std/haxe/ImportAll.hx

@@ -538,7 +538,9 @@ import neko.io.StringInput;
 import neko.io.StringOutput;
 
 import neko.zip.Compress;
-import neko.zip.File;
+import neko.zip.CRC32;
+import neko.zip.Reader;
+import neko.zip.Writer;
 import neko.zip.Flush;
 import neko.zip.Uncompress;
 

+ 52 - 0
std/neko/zip/CRC32.hx

@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2005-2008, The haXe Project Contributors
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+package neko.zip;
+import neko.Int32;
+
+class CRC32 {
+	private static var INITIAL_VALUE = Int32.make(0xFFFF, 0xFFFF);
+	private static var POLYNOM = Int32.make(0xEDB8, 0x8320);
+
+	/*
+	 *  Function computes CRC32 code of a given string.
+	 *  Warning: returns Int32 as result uses all 32 bits
+	 *  UTF - 8 coding is not supported
+	 */
+	public static function encode(str : String) : Int32 {
+		var crc = INITIAL_VALUE;
+		var s = untyped str.__s;
+		for( i in 0...str.length ) {
+			var tmp = Int32.and( Int32.xor(crc,untyped __dollar__sget(s,i)), cast 0xFF );
+			for( j in 0...8 ) {
+				if( Int32.and(tmp,cast 1) == cast 1 )
+					tmp = Int32.xor(Int32.ushr(tmp,1),POLYNOM);
+				else
+					tmp = Int32.ushr(tmp,1);
+			}
+			crc = Int32.xor(Int32.ushr(crc,8), tmp);
+		}
+		return Int32.xor(crc, INITIAL_VALUE);
+	}
+}

+ 7 - 3
std/neko/zip/File.hx → std/neko/zip/Reader.hx

@@ -31,11 +31,12 @@ typedef ZipEntry = {
 	var compressed : Bool;
 	var compressedSize : Int;
 	var data : String;
+	var crc32 : Null<neko.Int32>;
 }
 
 // see http://www.pkware.com/documents/casestudies/APPNOTE.TXT
 
-class File {
+class Reader {
 
 	public static function unzip( f : ZipEntry ) : String {
 		if( !f.compressed )
@@ -58,7 +59,7 @@ class File {
 		var year = d >> 9;
 		var month = (d >> 5) & 15;
 		var day = d & 31;
-		return new Date(year + 1980, month-1, day, hour, min, sec);
+		return new Date(year + 1980, month-1, day, hour, min, sec << 1);
 	}
 
 	public static function readZipEntry( i : neko.io.Input ) : ZipEntry {
@@ -68,6 +69,7 @@ class File {
 		if( h != 0x04034B50 )
 			throw "Invalid Zip Data";
 		var version = i.readUInt16();
+		trace(version);
 		var flags = i.readUInt16();
 		var extraFields = (flags & 8) != 0;
 		if( (flags & 0xFFF7) != 0 )
@@ -77,7 +79,7 @@ class File {
 		if( compressed && compression != 8 )
 			throw "Unsupported compression "+compression;
 		var mtime = readZipDate(i);
-		var crc32 = i.read(4);
+		var crc32 = neko.Int32.read(i);
 		var csize = i.readInt32();
 		var usize = i.readInt32();
 		var fnamelen = i.readInt16();
@@ -100,6 +102,7 @@ class File {
 			compressed : compressed,
 			compressedSize : csize,
 			data : data,
+			crc32 : crc32,
 		};
 	}
 
@@ -136,6 +139,7 @@ class File {
 				compressed : false,
 				compressedSize : e.fileSize,
 				data : data,
+				crc32 : null,
 			});
 		}
 		return l;

+ 134 - 0
std/neko/zip/Writer.hx

@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2005-2008, The haXe Project Contributors
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+package neko.zip;
+
+class Writer {
+
+	/*
+	* The next constant is required for computing the Central
+	* Directory Record(CDR) size. CDR consists of some fields
+	* of constant size and a filename. Constant represents
+	* total length of all fields with constant size for each
+	* file in archive
+	*/
+	private static var CENTRAL_DIRECTORY_RECORD_FIELDS_SIZE = 46;
+
+	/*
+	* The following constant is the total size of all fields
+	* of Local File Header. It's required for calculating
+	* offset of start of central directory record
+	*/
+	private static var LOCAL_FILE_HEADER_FIELDS_SIZE = 30;
+
+	static function writeZipDate( o : neko.io.Output, date : Date ) {
+		var hour = date.getHours();
+		var min = date.getMinutes();
+		var sec = date.getSeconds() >> 1;
+		o.writeUInt16( (hour << 11) | (min << 5) | sec );
+		var year = date.getFullYear() - 1980;
+		var month = date.getMonth() + 1;
+		var day = date.getDate();
+		o.writeUInt16( (year << 9) | (month << 5) | day );
+	}
+
+	static function writeZipEntry( o : neko.io.Output, level, f : { data : String, fileName : String, fileTime : Date } ) {
+		var fdata = f.data, cdata = null, crc32, compressed = true;
+		o.writeUInt32(0x04034B50);
+		o.writeUInt16(0x0014); // version
+		o.writeUInt16(0); // flags
+		if( fdata == null ) {
+			fdata = "";
+			cdata = "XXXXXX";
+			crc32 = neko.Int32.ofInt(0);
+			compressed = false;
+		} else {
+			crc32 = CRC32.encode(f.data);
+			cdata = Compress.run( f.data, level );
+		}
+		o.writeUInt16(compressed?8:0);
+		writeZipDate(o,f.fileTime);
+		neko.Int32.write(o,crc32);
+		o.writeUInt32(cdata.length - 6);
+		o.writeUInt32(fdata.length);
+		o.writeUInt16(f.fileName.length);
+		o.writeUInt16(0);
+		o.write(f.fileName);
+		if( cdata != null ) o.writeFullBytes(cdata,2,cdata.length-6);
+		return {
+			compressed : compressed,
+			fileName : f.fileName,
+			dlen : fdata.length,
+			clen : cdata.length - 6,
+			date : f.fileTime,
+			crc32 : crc32,
+		};
+	}
+
+	public static function writeZip( o : neko.io.Output, files, compressionLevel : Int ) {
+		var files = Lambda.map(files,callback(writeZipEntry,o,compressionLevel));
+		var cdr_size = 0;
+		var cdr_offset = 0;
+		for( f in files ) {
+			var namelen = f.fileName.length;
+			o.writeUInt32(0x02014B50); // header
+			o.writeUInt16(0x0014); // version made-by
+			o.writeUInt16(0x0014); // version
+			o.writeUInt16(0); // flags
+			o.writeUInt16(f.compressed?8:0);
+			writeZipDate(o,f.date);
+			neko.Int32.write(o,f.crc32);
+			o.writeUInt32(f.clen);
+			o.writeUInt32(f.dlen);
+			o.writeUInt16(namelen);
+			o.writeUInt16(0); //extra field length always 0
+			o.writeUInt16(0); //comment length always 0
+			o.writeUInt16(0); //disk number start
+			o.writeUInt16(0); //internal file attributes
+			o.writeUInt32(0);	//external file attributes
+			o.writeUInt32(0); //relative offset of local header
+			o.write(f.fileName);
+			cdr_size += CENTRAL_DIRECTORY_RECORD_FIELDS_SIZE + namelen;
+			cdr_offset += LOCAL_FILE_HEADER_FIELDS_SIZE + namelen + f.clen;
+		}
+		//end of central dir signature
+		o.writeUInt32(0x06054B50);
+		//number of this disk
+		o.writeUInt16(0);
+		//number of the disk with the start of the central directory
+		o.writeUInt16(0);
+		//total number of entries in the central directory on this disk
+		o.writeUInt16(files.length);
+		//total number of entries in the central directory
+		o.writeUInt16(files.length);
+		//size of the central directory record
+		o.writeUInt32(cdr_size);
+		//offset of start of central directory with respect to the starting disk number
+		o.writeUInt32(cdr_offset);
+		// .ZIP file comment length
+		o.writeUInt16(0);
+	}
+
+
+}

+ 2 - 2
std/tools/haxelib/Datas.hx

@@ -1,6 +1,6 @@
 package tools.haxelib;
 
-import neko.zip.File;
+import neko.zip.Reader;
 import haxe.xml.Check;
 
 typedef UserInfos = {
@@ -83,7 +83,7 @@ class Datas {
 		var xmldata = null;
 		for( f in zip )
 			if( StringTools.endsWith(f.fileName,XML) ) {
-				xmldata = neko.zip.File.unzip(f);
+				xmldata = neko.zip.Reader.unzip(f);
 				break;
 			}
 		if( xmldata == null )

+ 3 - 3
std/tools/haxelib/Main.hx

@@ -269,7 +269,7 @@ class Main {
 	function submit() {
 		var file = param("Package");
 		var data = neko.io.File.getContent(file);
-		var zip = neko.zip.File.readZip(new neko.io.StringInput(data));
+		var zip = neko.zip.Reader.readZip(new neko.io.StringInput(data));
 		var infos = Datas.readInfos(zip);
 		var user = infos.developers.first();
 		var password;
@@ -366,7 +366,7 @@ class Main {
 
 		// read zip content
 		var f = neko.io.File.read(filepath,true);
-		var zip = neko.zip.File.readZip(f);
+		var zip = neko.zip.Reader.readZip(f);
 		f.close();
 		var infos = Datas.readInfos(zip);
 
@@ -411,7 +411,7 @@ class Main {
 				}
 				path += file;
 				print("  Install "+path);
-				var data = neko.zip.File.unzip(zipfile);
+				var data = neko.zip.Reader.unzip(zipfile);
 				var f = neko.io.File.write(target+path,true);
 				f.write(data);
 				f.close();

+ 1 - 1
std/tools/haxelib/SiteApi.hx

@@ -90,7 +90,7 @@ class SiteApi {
 		var path = Site.TMP_DIR+"/"+Std.parseInt(id)+".tmp";
 
 		var file = try neko.io.File.read(path,true) catch( e : Dynamic ) throw "Invalid file id #"+id;
-		var zip = try neko.zip.File.readZip(file) catch( e : Dynamic ) { file.close(); neko.Lib.rethrow(e); };
+		var zip = try neko.zip.Reader.readZip(file) catch( e : Dynamic ) { file.close(); neko.Lib.rethrow(e); };
 		file.close();
 
 		var infos = Datas.readInfos(zip);