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; } } }