Example #1
0
    //construct an instance of the class and parse list of zip entries
    public TinyUnzip(Stream stream, bool needDispose = true)
    {
        if (!stream.CanSeek)
        {
            throw new Exception("Unzip - stream should be able to perform Seek operation!");
        }

        m_needDispose = needDispose;

        m_stream = stream;

        m_eocd = EOCD.ReadEOCD(m_stream);
        m_stream.Seek(m_eocd.offsetToCentralDir, SeekOrigin.Begin);

        m_reader            = new BinaryReader(m_stream);
        m_centralDirEntries = new CentralDirectory[m_eocd.centralDirsTotalNum];
        m_entries           = new List <Entry>(m_eocd.centralDirsTotalNum);

        for (int i = 0; i < m_centralDirEntries.Length; i++)
        {
            m_centralDirEntries[i] = CentralDirectory.Read(m_reader);

            Entry entry = new Entry(m_centralDirEntries[i].fileName,
                                    m_centralDirEntries[i].comment,
                                    m_centralDirEntries[i].compressedSize,
                                    m_centralDirEntries[i].uncompressedSize,
                                    m_centralDirEntries[i].fileLastModificationTime,
                                    m_centralDirEntries[i].fileLastModificationDate,
                                    m_centralDirEntries[i].crc32);
            m_entries.Add(entry);
        }
    }
    static async Task <(bool success, EOCD eocd)> GetEOCD(HttpClient httpClient, Uri url, long fileSize)
    {
        long fileOffset = fileSize - EndFileChunkSize;
        var  req        = new HttpRequestMessage(HttpMethod.Get, url);

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

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

        if (!resp.IsSuccessStatusCode)
        {
            return(false, null);
        }

        using (var eocdStream = await resp.Content.ReadAsStreamAsync().ConfigureAwait(false)) {
            using (var sr = new BinaryReader(eocdStream)) {
                byte[] expected    = { 0x50, 0x4b, 0x05, 0x06 };
                int    expectedPos = 0;

                for (int i = 0; i < eocdStream.Length; i++)
                {
                    byte b = sr.ReadByte();
                    if (b != expected [expectedPos])
                    {
                        expectedPos = 0;
                        continue;
                    }

                    if (expectedPos == expected.Length - 1)
                    {
                        // We've found the signature
                        var eocd = new EOCD();
                        eocd.Signature            = 0x06054b50;
                        eocd.DiskNumber           = sr.ReadUInt16();
                        eocd.CDStartDisk          = sr.ReadUInt16();
                        eocd.TotalEntriesThisDisk = sr.ReadUInt16();
                        eocd.TotalEntries         = sr.ReadUInt16();
                        eocd.CDSize        = sr.ReadUInt32();
                        eocd.CDOffset      = sr.ReadUInt32();
                        eocd.CommentLength = sr.ReadUInt16();

                        return(true, eocd);
                    }

                    expectedPos++;
                    if (expectedPos >= expected.Length)
                    {
                        expectedPos = 0;
                    }
                }
            }
        }

        return(false, null);
    }
    static async Task <bool> ProcessEntries(HttpClient httpClient, Uri url, EOCD eocd, Stream centralDirectory, HashSet <string> neededFiles, string destinationDirectory)
    {
        long foundEntries = 0;

        using (var br = new BinaryReader(centralDirectory)) {
            long nread    = 0;
            long nentries = 1;

            while (nread < centralDirectory.Length && nentries <= eocd.TotalEntries)
            {
                (bool success, CDHeader cdh) = ReadCDHeader(br, centralDirectory.Length, ref nread);
                nentries++;
                if (!success)
                {
                    Console.Error.WriteLine($"Failed to read a Central Directory file header for entry {nentries}");
                    return(false);
                }

                if (!neededFiles.Contains(cdh.FileName))
                {
                    continue;
                }

                if (!await ReadEntry(httpClient, url, cdh, br, destinationDirectory))
                {
                    return(false);
                }
                foundEntries++;
            }
        }

        if (foundEntries < neededFiles.Count)
        {
            Console.WriteLine($"Could not find all required binaries. Found {foundEntries} out of {neededFiles.Count}");
            return(false);
        }

        return(true);
    }
Example #4
0
        static EOCD ReadEOCD(BinaryReader reader)
        {
            EOCD eocd = new EOCD();

            eocd.signature             = reader.ReadUInt32();
            eocd.numberOfDisk          = reader.ReadUInt16();
            eocd.disk                  = reader.ReadUInt16();
            eocd.curDiskCentralDirsNum = reader.ReadUInt16();
            eocd.centralDirsTotalNum   = reader.ReadUInt16();
            eocd.sizeOfCentralDir      = reader.ReadUInt32();
            eocd.offsetToCentralDir    = reader.ReadUInt32();
            ushort commentLength = reader.ReadUInt16();

            eocd.comment = ReadAsString(reader, commentLength);

            if (eocd.signature != 0x06054b50)
            {
                throw new Exception("Broken signature in zip archive");
            }

            return(eocd);
        }