import 'dart:convert'; import 'archive.dart'; import 'archive_file.dart'; import 'util/archive_exception.dart'; import 'util/crc32.dart'; import 'util/input_stream.dart'; import 'zip/zip_directory.dart'; import 'zip/zip_file.dart'; /// Decode a zip formatted buffer into an [Archive] object. class ZipDecoder { late ZipDirectory directory; Archive decodeBytes(List data, {bool verify = false, String? password}) { return decodeBuffer(InputStream(data), verify: verify, password: password); } Archive decodeBuffer( InputStreamBase input, { bool verify = false, String? password, }) { directory = ZipDirectory.read(input, password: password); final archive = Archive(); for (final zfh in directory.fileHeaders) { final zf = zfh.file!; // The attributes are stored in base 8 final mode = zfh.externalFileAttributes!; final compress = zf.compressionMethod != ZipFile.zipCompressionStore; if (verify) { final computedCrc = getCrc32(zf.content); if (computedCrc != zf.crc32) { throw ArchiveException('Invalid CRC for file in archive.'); } } //dynamic content = zf.rawContent; final file = ArchiveFile( zf.filename, zf.uncompressedSize!, zf, zf.compressionMethod); file.mode = mode >> 16; // see https://github.com/brendan-duncan/archive/issues/21 // UNIX systems has a creator version of 3 decimal at 1 byte offset if (zfh.versionMadeBy >> 8 == 3) { file.isFile = false; final fileType = file.mode & 0xF000; switch (fileType) { case 0x8000: case 0x0000: // No determination can be made so we assume it's a file. file.isFile = true; break; case 0xA000: file.isSymbolicLink = true; file.nameOfLinkedFile = utf8.decode(file.content as List); break; default: } } else { file.isFile = !file.name.endsWith('/'); } file.crc32 = zf.crc32; file.compress = compress; file.lastModTime = zf.lastModFileDate << 16 | zf.lastModFileTime; archive.addFile(file); } return archive; } }