ZipFile constructor

ZipFile([
  1. InputStreamBase? input,
  2. ZipFileHeader? header,
  3. String? password
])

Implementation

ZipFile([InputStreamBase? input, this.header, String? password]) {
  if (input != null) {
    signature = input.readUint32();
    if (signature != zipFileSignature) {
      throw ArchiveException('Invalid Zip Signature');
    }

    version = input.readUint16();
    flags = input.readUint16();
    compressionMethod = input.readUint16();
    lastModFileTime = input.readUint16();
    lastModFileDate = input.readUint16();
    crc32 = input.readUint32();
    compressedSize = input.readUint32();
    uncompressedSize = input.readUint32();
    final fnLen = input.readUint16();
    final exLen = input.readUint16();
    filename = input.readString(size: fnLen);
    extraField = input.readBytes(exLen).toUint8List();

    // Use the compressedSize and uncompressedSize from the CFD header.
    // For Zip64, the sizes in the local header will be 0xFFFFFFFF.
    compressedSize = header?.compressedSize ?? compressedSize;
    uncompressedSize = header?.uncompressedSize ?? uncompressedSize;

    _encryptionType =
        (flags & 0x1) != 0 ? encryptionZipCrypto : encryptionNone;
    _password = password;

    // Read compressedSize bytes for the compressed data.
    _rawContent = input.readBytes(header!.compressedSize!);

    if (_encryptionType != 0 && exLen > 2) {
      final extra = InputStream(extraField);
      while (!extra.isEOS) {
        final id = extra.readUint16();
        final size = extra.readUint16();
        final extraBytes = extra.readBytes(size);
        if (id == AesHeader.signature) {
          final vendorVersion = extraBytes.readUint16();
          final vendorId = extraBytes.readString(size: 2);
          final encryptionStrength = extraBytes.readByte();
          final compressionMethod = extraBytes.readUint16();

          _encryptionType = encryptionAes;
          _aesHeader = AesHeader(
              vendorVersion, vendorId, encryptionStrength, compressionMethod);

          // compressionMethod in the file header will be 99 for aes encrypted
          // files. The compressionMethod value in the AES extraField stores
          // the actual compressionMethod.
          this.compressionMethod = _aesHeader!.compressionMethod;
        }
      }
    }

    if (_encryptionType == 1 && password != null) {
      _initKeys(password);
    }

    // If bit 3 (0x08) of the flags field is set, then the CRC-32 and file
    // sizes are not known when the header is written. The fields in the
    // local header are filled with zero, and the CRC-32 and size are
    // appended in a 12-byte structure (optionally preceded by a 4-byte
    // signature) immediately after the compressed data:
    if (flags & 0x08 != 0) {
      final sigOrCrc = input.readUint32();
      if (sigOrCrc == 0x08074b50) {
        crc32 = input.readUint32();
      } else {
        crc32 = sigOrCrc;
      }

      compressedSize = input.readUint32();
      uncompressedSize = input.readUint32();
    }
  }

  // Make sure to use the Central Directory filename to avoid filename
  // spoofing. https://github.com/brendan-duncan/archive/issues/266
  filename = header?.filename ?? filename;
}