static async Task <bool> ReadEntry(HttpClient httpClient, Uri url, CDHeader cdh, BinaryReader br, string destinationDirectory)
    {
        string compressedFilePath = Path.Combine(destinationDirectory, $"{Path.GetFileName (cdh.FileName)}.deflated");

        Console.WriteLine($" {cdh.FileName} (offset: {cdh.RelativeOffsetOfLocalHeader})");

        (bool success, Stream contentStream) = await ReadFileData(httpClient, url, cdh);

        if (!success)
        {
            Console.Error.WriteLine("Failed to read file data");
            return(false);
        }

        using (var destFile = new BinaryWriter(File.OpenWrite(compressedFilePath))) {
            using (var fbr = new BinaryReader(contentStream)) {
                if (!await DownloadAndExtract(fbr, contentStream, destFile, compressedFilePath))
                {
                    return(CleanupAndReturn(false));
                }
            }
        }

        return(CleanupAndReturn(true));

        bool CleanupAndReturn(bool retval)
        {
            if (File.Exists(compressedFilePath))
            {
                File.Delete(compressedFilePath);
            }

            return(retval);
        }
    }
    static (bool success, CDHeader cdh) ReadCDHeader(BinaryReader cdr, long dataLength, ref long nread)
    {
        var cdh = new CDHeader();

        bool   worked;
        string whatFailed = null;

        cdh.Signature = ReadUInt(cdr, dataLength, ref nread, out worked);
        if (!worked || cdh.Signature != CDHeaderSignature)
        {
            whatFailed = "Signature ({cdh.Signature:x} != {CDHeaderSignature:x})";
            goto failed;
        }

        cdh.VersionMadeBy = ReadUShort(cdr, dataLength, ref nread, out worked);
        if (!worked)
        {
            whatFailed = "VersionMadeBy";
            goto failed;
        }

        cdh.VersionNeededToExtract = ReadUShort(cdr, dataLength, ref nread, out worked);
        if (!worked)
        {
            whatFailed = "VersionNeededToExtract";
            goto failed;
        }

        cdh.GeneralPurposeBitFlag = ReadUShort(cdr, dataLength, ref nread, out worked);
        if (!worked)
        {
            whatFailed = "GeneralPurposeBitFlag";
            goto failed;
        }

        cdh.CompressionMethod = ReadUShort(cdr, dataLength, ref nread, out worked);
        if (!worked)
        {
            whatFailed = "CompressionMethod";
            goto failed;
        }

        cdh.LastModFileTime = ReadUShort(cdr, dataLength, ref nread, out worked);
        if (!worked)
        {
            whatFailed = "LastModFileTime";
            goto failed;
        }

        cdh.LastModFileDate = ReadUShort(cdr, dataLength, ref nread, out worked);
        if (!worked)
        {
            whatFailed = "LastModFileDate";
            goto failed;
        }

        cdh.CRC32 = ReadUInt(cdr, dataLength, ref nread, out worked);
        if (!worked)
        {
            whatFailed = "CRC32";
            goto failed;
        }

        cdh.CompressedSize = ReadUInt(cdr, dataLength, ref nread, out worked);
        if (!worked)
        {
            whatFailed = "CompressedSize";
            goto failed;
        }

        cdh.UncompressedSize = ReadUInt(cdr, dataLength, ref nread, out worked);
        if (!worked)
        {
            whatFailed = "UncompressedSize";
            goto failed;
        }

        cdh.FileNameLength = ReadUShort(cdr, dataLength, ref nread, out worked);
        if (!worked)
        {
            whatFailed = "FileNameLength";
            goto failed;
        }

        cdh.ExtraFieldLength = ReadUShort(cdr, dataLength, ref nread, out worked);
        if (!worked)
        {
            whatFailed = "ExtraFieldLength";
            goto failed;
        }

        cdh.FileCommentLength = ReadUShort(cdr, dataLength, ref nread, out worked);
        if (!worked)
        {
            whatFailed = "FileCommentLength";
            goto failed;
        }

        cdh.DiskNumberStart = ReadUShort(cdr, dataLength, ref nread, out worked);
        if (!worked)
        {
            whatFailed = "DiskNumberStart";
            goto failed;
        }

        cdh.InternalFileAttributes = ReadUShort(cdr, dataLength, ref nread, out worked);
        if (!worked)
        {
            whatFailed = "InternalFileAttributes";
            goto failed;
        }

        cdh.ExternalFileAttributes = ReadUInt(cdr, dataLength, ref nread, out worked);
        if (!worked)
        {
            whatFailed = "ExternalFileAttributes";
            goto failed;
        }

        cdh.RelativeOffsetOfLocalHeader = ReadUInt(cdr, dataLength, ref nread, out worked);
        if (!worked)
        {
            whatFailed = "RelativeOffsetOfLocalHeader";
            goto failed;
        }

        byte[] bytes = ReadBytes(cdr, cdh.FileNameLength, dataLength, ref nread, out worked);
        if (!worked)
        {
            whatFailed = "FileName (bytes)";
            goto failed;
        }

        cdh.FileName = Encoding.ASCII.GetString(bytes);
        if (!worked)
        {
            whatFailed = "FileName (ASCII decode)";
            goto failed;
        }

        if (cdh.ExtraFieldLength > 0)
        {
            cdh.ExtraField = ReadBytes(cdr, cdh.ExtraFieldLength, dataLength, ref nread, out worked);
            if (!worked)
            {
                whatFailed = "ExtraField";
                goto failed;
            }
        }

        if (cdh.FileCommentLength > 0)
        {
            bytes = ReadBytes(cdr, cdh.FileCommentLength, dataLength, ref nread, out worked);
            if (!worked)
            {
                whatFailed = "FileComment (bytes)";
                goto failed;
            }
            cdh.FileComment = Encoding.ASCII.GetString(bytes);
        }

        return(true, cdh);

failed:
        if (!String.IsNullOrEmpty(whatFailed))
        {
            Console.Error.WriteLine($"Failed to read a central directory header field: {whatFailed}");
        }

        return(false, null);
    }
    static async Task <(bool success, Stream data)> ReadFileData(HttpClient httpClient, Uri url, CDHeader cdh)
    {
        long fileOffset = cdh.RelativeOffsetOfLocalHeader;
        long dataSize   =
            cdh.CompressedSize +
            30 +                   // local file header size, the static portion
            cdh.FileName.Length +  // They're the same in both haders
            cdh.ExtraFieldLength + // This may differ between headers...
            16384;                 // ...so we add some extra padding

        var req = new HttpRequestMessage(HttpMethod.Get, url);

        req.Headers.ConnectionClose = true;
        req.Headers.Range           = new RangeHeaderValue(fileOffset, fileOffset + dataSize);

        HttpResponseMessage resp = await httpClient.SendAsync(req).ConfigureAwait(false);

        if (!resp.IsSuccessStatusCode)
        {
            Console.Error.WriteLine($"Failed to read file data: HTTP error {resp.StatusCode}");
            return(false, null);
        }

        Stream s = await resp.Content.ReadAsStreamAsync().ConfigureAwait(false);

        if (s.Length < dataSize)
        {
            Console.Error.WriteLine($"Failed to read file data: invalid data length ({s.Length} < {dataSize})");
            s.Dispose();
            return(false, null);
        }

        return(true, s);
    }