示例#1
0
        /// <summary>
        /// Reads the contents of the archive's Central Directory and returns an ArchiveInformation record with the
        /// CompressedSize and UncompressedSize fields populated from the contents of the Central Directory file header
        /// records.
        /// </summary>
        /// <param name="eocdRecord">The End of Central Directory record which gives us information about the Central Directory's location</param>
        /// <returns>The pre-populated ArchiveInformation record</returns>
        /// <exception cref="InvalidArchiveException"></exception>
        private ArchiveInformation ReadCentralDirectoryContents(ZipEndOfCentralDirectoryRecord eocdRecord)
        {
            // -- Get a new info record
            ArchiveInformation info = new ArchiveInformation();

            info.UncompressedSize = 0;
            info.CompressedSize   = 0;

            // -- Open the correct archive part and seek to the first Central Directory record
            Open(eocdRecord.CDDisk + 1);
            InputStream.Seek((long)eocdRecord.CDOffset, SeekOrigin.Begin);

            // -- Loop all entries
            for (int i = 0; i < eocdRecord.NumFilesInCD; i++)
            {
                ZipCentralDirectoryFileHeader cdHeader = new ZipCentralDirectoryFileHeader();

                cdHeader.Signature = ReadULong();

                if (cdHeader.Signature != BitConverter.ToUInt32(new byte[] { 0x50, 0x4b, 0x01, 0x02 }, 0))
                {
                    throw new InvalidArchiveException(String.Format(Language.ResourceManager.GetString("ERR_FORMAT_INVALID_CD_HEADER_AT_POSITION"), CurrentPartNumber, InputStream.Position - 4));
                }

                cdHeader.VersionMadeBy          = ReadUShort();
                cdHeader.VersionToExtract       = ReadUShort();
                cdHeader.Flags                  = ReadUShort();
                cdHeader.CompressionMethod      = ReadUShort();
                cdHeader.LastModTime            = ReadUShort();
                cdHeader.LastModDate            = ReadUShort();
                cdHeader.CRC32                  = ReadULong();
                cdHeader.CompressedSize         = ReadULong();
                cdHeader.UncompressedSize       = ReadULong();
                cdHeader.FileNameLength         = ReadUShort();
                cdHeader.ExtraFieldLength       = ReadUShort();
                cdHeader.FileCommentLength      = ReadUShort();
                cdHeader.DiskNumberStart        = ReadUShort();
                cdHeader.InternalFileAttributes = ReadUShort();
                cdHeader.ExternalFileAttributes = ReadULong();
                cdHeader.RelativeOffset         = ReadULong();
                cdHeader.Filename               = ReadUtf8String(cdHeader.FileNameLength);
                cdHeader.Comment                = "";

                if (cdHeader.FileCommentLength > 0)
                {
                    cdHeader.Comment = ReadUtf8String(cdHeader.FileCommentLength);
                }

                info.CompressedSize   += cdHeader.CompressedSize;
                info.UncompressedSize += cdHeader.UncompressedSize;
            }
            return(info);
        }
        private static void GetStreamingAssetsInfoFromJar(string apkPath, List <string> paths, List <PartInfo> parts)
        {
            using (var stream = File.OpenRead(apkPath))
                using (var reader = new BinaryReader(stream))
                {
                    if (!stream.CanRead)
                    {
                        throw new ArgumentException();
                    }
                    if (!stream.CanSeek)
                    {
                        throw new ArgumentException();
                    }

                    long expectedNumberOfEntries;
                    long centralDirectoryStart;
                    ZipArchiveUtils.ReadEndOfCentralDirectory(stream, reader, out expectedNumberOfEntries, out centralDirectoryStart);

                    try
                    {
                        stream.Seek(centralDirectoryStart, SeekOrigin.Begin);

                        long numberOfEntries = 0;

                        ZipCentralDirectoryFileHeader header;

                        const int    prefixLength = 7;
                        const string prefix       = "assets/";
                        const string assetsPrefix = "assets/bin/";
                        Debug.Assert(prefixLength == prefix.Length);

                        while (ZipCentralDirectoryFileHeader.TryReadBlock(reader, out header))
                        {
                            if (header.CompressedSize != header.UncompressedSize)
                            {
                                // we only want uncompressed files
                            }
                            else
                            {
                                var fileName = Encoding.UTF8.GetString(header.Filename);
                                if (fileName.StartsWith(prefix))
                                {
                                    // ignore normal assets...
                                    if (fileName.StartsWith(assetsPrefix))
                                    {
                                        // Note: if you put bin directory in your StreamingAssets you will get false negative here
                                    }
                                    else
                                    {
                                        var relativePath = fileName.Substring(prefixLength - 1);
                                        var entry        = new PartInfo()
                                        {
                                            crc32  = header.Crc32,
                                            offset = header.RelativeOffsetOfLocalHeader, // this offset will need fixing later on
                                            size   = header.UncompressedSize
                                        };

                                        var index = paths.BinarySearch(relativePath, StringComparer.OrdinalIgnoreCase);
                                        if (index >= 0)
                                        {
                                            throw new System.InvalidOperationException("Paths duplicate! " + fileName);
                                        }

                                        paths.Insert(~index, relativePath);
                                        parts.Insert(~index, entry);
                                    }
                                }
                            }

                            numberOfEntries++;
                        }

                        if (numberOfEntries != expectedNumberOfEntries)
                        {
                            throw new ZipArchiveException("Number of entries does not match");
                        }
                    }
                    catch (EndOfStreamException ex)
                    {
                        throw new ZipArchiveException("CentralDirectoryInvalid", ex);
                    }

                    // now fix offsets
                    for (int i = 0; i < parts.Count; ++i)
                    {
                        var entry = parts[i];
                        stream.Seek(entry.offset, SeekOrigin.Begin);

                        if (!ZipLocalFileHeader.TrySkipBlock(reader))
                        {
                            throw new ZipArchiveException("Local file header corrupt");
                        }

                        entry.offset = stream.Position;

                        parts[i] = entry;
                    }
                }
        }
        private static void GetStreamingAssetsInfoFromJar(string apkPath, List <string> paths, List <PartInfo> parts)
        {
            using (var stream = File.OpenRead(apkPath))
                using (var reader = new BinaryReader(stream))
                {
                    if (!stream.CanRead)
                    {
                        throw new ArgumentException();
                    }
                    if (!stream.CanSeek)
                    {
                        throw new ArgumentException();
                    }

                    long expectedNumberOfEntries;
                    long centralDirectoryStart;
                    ZipArchiveUtils.ReadEndOfCentralDirectory(stream, reader, out expectedNumberOfEntries, out centralDirectoryStart);

                    try
                    {
                        stream.Seek(centralDirectoryStart, SeekOrigin.Begin);

                        long numberOfEntries = 0;

                        ZipCentralDirectoryFileHeader header;

                        const int    prefixLength = 7;
                        const string prefix       = "assets/";
                        const string assetsPrefix = "assets/bin/";
                        Debug.Assert(prefixLength == prefix.Length);

                        while (ZipCentralDirectoryFileHeader.TryReadBlock(reader, out header))
                        {
                            if (header.CompressedSize != header.UncompressedSize)
                            {
#if UNITY_ASSERTIONS
                                var fileName = Encoding.UTF8.GetString(header.Filename);
                                if (fileName.StartsWith(prefix) && !fileName.StartsWith(assetsPrefix))
                                {
                                    bool isStreamingAsset = true;
                                    AndroidIsCompressedFileStreamingAsset(fileName, ref isStreamingAsset);
                                    if (isStreamingAsset)
                                    {
                                        Debug.LogAssertionFormat("BetterStreamingAssets: file {0} is where Streaming Assets are put, but is compressed. " +
                                                                 "If this is a App Bundle build, see README for a possible workaround. " +
                                                                 "If this file is not a Streaming Asset (has been on purpose by hand or by another plug-in), implement " +
                                                                 "BetterStreamingAssets.AndroidIsCompressedFileStreamingAsset partial method to prevent this message from appearing again. ",
                                                                 fileName);
                                    }
                                }
#endif
                                // we only want uncompressed files
                            }
                            else
                            {
                                var fileName = Encoding.UTF8.GetString(header.Filename);

                                if (fileName.EndsWith("/"))
                                {
                                    // there's some strangeness when it comes to OBB: directories are listed as files
                                    // simply ignoring them should be enough
                                    Debug.Assert(header.UncompressedSize == 0);
                                }
                                else if (fileName.StartsWith(prefix))
                                {
                                    // ignore normal assets...
                                    if (fileName.StartsWith(assetsPrefix))
                                    {
                                        // Note: if you put bin directory in your StreamingAssets you will get false negative here
                                    }
                                    else
                                    {
                                        var relativePath = fileName.Substring(prefixLength - 1);
                                        var entry        = new PartInfo()
                                        {
                                            crc32  = header.Crc32,
                                            offset = header.RelativeOffsetOfLocalHeader, // this offset will need fixing later on
                                            size   = header.UncompressedSize
                                        };

                                        var index = paths.BinarySearch(relativePath, StringComparer.OrdinalIgnoreCase);
                                        if (index >= 0)
                                        {
                                            throw new System.InvalidOperationException("Paths duplicate! " + fileName);
                                        }

                                        paths.Insert(~index, relativePath);
                                        parts.Insert(~index, entry);
                                    }
                                }
                            }

                            numberOfEntries++;
                        }

                        if (numberOfEntries != expectedNumberOfEntries)
                        {
                            throw new ZipArchiveException("Number of entries does not match");
                        }
                    }
                    catch (EndOfStreamException ex)
                    {
                        throw new ZipArchiveException("CentralDirectoryInvalid", ex);
                    }

                    // now fix offsets
                    for (int i = 0; i < parts.Count; ++i)
                    {
                        var entry = parts[i];
                        stream.Seek(entry.offset, SeekOrigin.Begin);

                        if (!ZipLocalFileHeader.TrySkipBlock(reader))
                        {
                            throw new ZipArchiveException("Local file header corrupt");
                        }

                        entry.offset = stream.Position;

                        parts[i] = entry;
                    }
                }
        }