/bin/std/neko/zip/Writer.hx

http://github.com/Yoomee/clippy · Haxe · 134 lines · 82 code · 8 blank · 44 comment · 6 complexity · ebdd147c5b1301baac57da23d6dc1b5b MD5 · raw file

  1. /*
  2. * Copyright (c) 2005-2008, The haXe Project Contributors
  3. * All rights reserved.
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions are met:
  6. *
  7. * - Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * - Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. *
  13. * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
  14. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  15. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  16. * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
  17. * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  18. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  19. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  20. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  21. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  22. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  23. * DAMAGE.
  24. */
  25. package neko.zip;
  26. class Writer {
  27. /*
  28. * The next constant is required for computing the Central
  29. * Directory Record(CDR) size. CDR consists of some fields
  30. * of constant size and a filename. Constant represents
  31. * total length of all fields with constant size for each
  32. * file in archive
  33. */
  34. private static var CENTRAL_DIRECTORY_RECORD_FIELDS_SIZE = 46;
  35. /*
  36. * The following constant is the total size of all fields
  37. * of Local File Header. It's required for calculating
  38. * offset of start of central directory record
  39. */
  40. private static var LOCAL_FILE_HEADER_FIELDS_SIZE = 30;
  41. static function writeZipDate( o : haxe.io.Output, date : Date ) {
  42. var hour = date.getHours();
  43. var min = date.getMinutes();
  44. var sec = date.getSeconds() >> 1;
  45. o.writeUInt16( (hour << 11) | (min << 5) | sec );
  46. var year = date.getFullYear() - 1980;
  47. var month = date.getMonth() + 1;
  48. var day = date.getDate();
  49. o.writeUInt16( (year << 9) | (month << 5) | day );
  50. }
  51. static function writeZipEntry( o : haxe.io.Output, level, f : { data : haxe.io.Bytes, fileName : String, fileTime : Date } ) {
  52. var fdata = f.data, cdata = null, crc32, compressed = true;
  53. o.writeUInt30(0x04034B50);
  54. o.writeUInt16(0x0014); // version
  55. o.writeUInt16(0); // flags
  56. if( fdata == null ) {
  57. fdata = haxe.io.Bytes.alloc(0);
  58. cdata = haxe.io.Bytes.ofString("XXXXXX");
  59. crc32 = haxe.Int32.ofInt(0);
  60. compressed = false;
  61. } else {
  62. crc32 = CRC32.encode(f.data);
  63. cdata = Compress.run( f.data, level );
  64. }
  65. o.writeUInt16(compressed?8:0);
  66. writeZipDate(o,f.fileTime);
  67. o.writeInt32(crc32);
  68. o.writeUInt30(cdata.length - 6);
  69. o.writeUInt30(fdata.length);
  70. o.writeUInt16(f.fileName.length);
  71. o.writeUInt16(0);
  72. o.writeString(f.fileName);
  73. if( cdata != null ) o.writeFullBytes(cdata,2,cdata.length-6);
  74. return {
  75. compressed : compressed,
  76. fileName : f.fileName,
  77. dlen : fdata.length,
  78. clen : cdata.length - 6,
  79. date : f.fileTime,
  80. crc32 : crc32,
  81. };
  82. }
  83. public static function writeZip( o : haxe.io.Output, files, compressionLevel : Int ) {
  84. var files = Lambda.map(files,callback(writeZipEntry,o,compressionLevel));
  85. var cdr_size = 0;
  86. var cdr_offset = 0;
  87. for( f in files ) {
  88. var namelen = f.fileName.length;
  89. o.writeUInt30(0x02014B50); // header
  90. o.writeUInt16(0x0014); // version made-by
  91. o.writeUInt16(0x0014); // version
  92. o.writeUInt16(0); // flags
  93. o.writeUInt16(f.compressed?8:0);
  94. writeZipDate(o,f.date);
  95. o.writeInt32(f.crc32);
  96. o.writeUInt30(f.clen);
  97. o.writeUInt30(f.dlen);
  98. o.writeUInt16(namelen);
  99. o.writeUInt16(0); //extra field length always 0
  100. o.writeUInt16(0); //comment length always 0
  101. o.writeUInt16(0); //disk number start
  102. o.writeUInt16(0); //internal file attributes
  103. o.writeUInt30(0); //external file attributes
  104. o.writeUInt30(cdr_offset); //relative offset of local header
  105. o.writeString(f.fileName);
  106. cdr_size += CENTRAL_DIRECTORY_RECORD_FIELDS_SIZE + namelen;
  107. cdr_offset += LOCAL_FILE_HEADER_FIELDS_SIZE + namelen + f.clen;
  108. }
  109. //end of central dir signature
  110. o.writeUInt30(0x06054B50);
  111. //number of this disk
  112. o.writeUInt16(0);
  113. //number of the disk with the start of the central directory
  114. o.writeUInt16(0);
  115. //total number of entries in the central directory on this disk
  116. o.writeUInt16(files.length);
  117. //total number of entries in the central directory
  118. o.writeUInt16(files.length);
  119. //size of the central directory record
  120. o.writeUInt30(cdr_size);
  121. //offset of start of central directory with respect to the starting disk number
  122. o.writeUInt30(cdr_offset);
  123. // .ZIP file comment length
  124. o.writeUInt16(0);
  125. }
  126. }