public function addFileHeader(): void
    {
        $name = static::filterFilename($this->name);

        // calculate name length
        $nameLength = strlen($name);

        // create dos timestamp
        $time = static::dosTime($this->opt->getTime()->getTimestamp());

        $comment = $this->opt->getComment();

        if (!mb_check_encoding($name, 'ASCII') ||
            !mb_check_encoding($comment, 'ASCII')) {
            // Sets Bit 11: Language encoding flag (EFS).  If this bit is set,
            // the filename and comment fields for this file
            // MUST be encoded using UTF-8. (see APPENDIX D)
            if (!mb_check_encoding($name, 'UTF-8') ||
                !mb_check_encoding($comment, 'UTF-8')) {
                throw new EncodingException(
                    'File name and comment should use UTF-8 ' .
                    'if one of them does not fit into ASCII range.'
                );
            }
            $this->bits |= self::BIT_EFS_UTF8;
        }

        if ($this->method->equals(Method::DEFLATE())) {
            $this->version = Version::DEFLATE();
        }

        $force = (boolean)($this->bits & self::BIT_ZERO_HEADER) &&
            $this->zip->opt->isEnableZip64();

        $footer = $this->buildZip64ExtraBlock($force);

        // If this file will start over 4GB limit in ZIP file,
        // CDR record will have to use Zip64 extension to describe offset
        // to keep consistency we use the same value here
        if ($this->zip->ofs->isOver32()) {
            $this->version = Version::ZIP64();
        }

        $fields = [
            ['V', ZipStream::FILE_HEADER_SIGNATURE],
            ['v', $this->version->getValue()],      // Version needed to Extract
            ['v', $this->bits],                     // General purpose bit flags - data descriptor flag set
            ['v', $this->method->getValue()],       // Compression method
            ['V', $time],                           // Timestamp (DOS Format)
            ['V', $this->crc],                      // CRC32 of data (0 -> moved to data descriptor footer)
            ['V', $this->zlen->getLowFF($force)],   // Length of compressed data (forced to 0xFFFFFFFF for zero header)
            ['V', $this->len->getLowFF($force)],    // Length of original data (forced to 0xFFFFFFFF for zero header)
            ['v', $nameLength],                     // Length of filename
            ['v', strlen($footer)],                 // Extra data (see above)
        ];

        // pack fields and calculate "total" length
        $header = ZipStream::packFields($fields);

        // print header and filename
        $data = $header . $name . $footer;
        $this->zip->send($data);

        // save header length
        $this->hlen = Bigint::init(strlen($data));
    }