mirror of
https://github.com/Dongyifengs/AssetStudio-Genshin-MoYi.git
synced 2025-04-19 02:59:19 +08:00
Chinese Translated
This commit is contained in:
commit
242a387a79
63
.gitattributes
vendored
Normal file
63
.gitattributes
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
###############################################################################
|
||||
# Set default behavior to automatically normalize line endings.
|
||||
###############################################################################
|
||||
* text=auto
|
||||
|
||||
###############################################################################
|
||||
# Set default behavior for command prompt diff.
|
||||
#
|
||||
# This is need for earlier builds of msysgit that does not have it on by
|
||||
# default for csharp files.
|
||||
# Note: This is only used by command line
|
||||
###############################################################################
|
||||
#*.cs diff=csharp
|
||||
|
||||
###############################################################################
|
||||
# Set the merge driver for project and solution files
|
||||
#
|
||||
# Merging from the command prompt will add diff markers to the files if there
|
||||
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
||||
# the diff markers are never inserted). Diff markers may cause the following
|
||||
# file extensions to fail to load in VS. An alternative would be to treat
|
||||
# these files as binary and thus will always conflict and require user
|
||||
# intervention with every merge. To do so, just uncomment the entries below
|
||||
###############################################################################
|
||||
#*.sln merge=binary
|
||||
#*.csproj merge=binary
|
||||
#*.vbproj merge=binary
|
||||
#*.vcxproj merge=binary
|
||||
#*.vcproj merge=binary
|
||||
#*.dbproj merge=binary
|
||||
#*.fsproj merge=binary
|
||||
#*.lsproj merge=binary
|
||||
#*.wixproj merge=binary
|
||||
#*.modelproj merge=binary
|
||||
#*.sqlproj merge=binary
|
||||
#*.wwaproj merge=binary
|
||||
|
||||
###############################################################################
|
||||
# behavior for image files
|
||||
#
|
||||
# image files are treated as binary by default.
|
||||
###############################################################################
|
||||
#*.jpg binary
|
||||
#*.png binary
|
||||
#*.gif binary
|
||||
|
||||
###############################################################################
|
||||
# diff behavior for common document formats
|
||||
#
|
||||
# Convert binary document formats to text before diffing them. This feature
|
||||
# is only available from the command line. Turn it on by uncommenting the
|
||||
# entries below.
|
||||
###############################################################################
|
||||
#*.doc diff=astextplain
|
||||
#*.DOC diff=astextplain
|
||||
#*.docx diff=astextplain
|
||||
#*.DOCX diff=astextplain
|
||||
#*.dot diff=astextplain
|
||||
#*.DOT diff=astextplain
|
||||
#*.pdf diff=astextplain
|
||||
#*.PDF diff=astextplain
|
||||
#*.rtf diff=astextplain
|
||||
#*.RTF diff=astextplain
|
342
.gitignore
vendored
Normal file
342
.gitignore
vendored
Normal file
@ -0,0 +1,342 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUNIT
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# JustCode is a .NET coding add-in
|
||||
.JustCode
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- Backup*.rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
/AssetStudioCLI/Properties/launchSettings.json
|
||||
/AssetStudioGUI/Properties/launchSettings.json
|
13
AssetStudio.PInvoke/AssetStudio.PInvoke.csproj
Normal file
13
AssetStudio.PInvoke/AssetStudio.PInvoke.csproj
Normal file
@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Version>0.18.60</Version>
|
||||
<AssemblyVersion>0.18.60</AssemblyVersion>
|
||||
<FileVersion>0.18.60</FileVersion>
|
||||
<Copyright>Copyright © Perfare 2020-2022; Copyright © hozuki 2020</Copyright>
|
||||
<DebugType>embedded</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
124
AssetStudio.PInvoke/DllLoader.cs
Normal file
124
AssetStudio.PInvoke/DllLoader.cs
Normal file
@ -0,0 +1,124 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace AssetStudio.PInvoke
|
||||
{
|
||||
public static class DllLoader
|
||||
{
|
||||
|
||||
public static void PreloadDll(string dllName)
|
||||
{
|
||||
var dllDir = GetDirectedDllDirectory();
|
||||
|
||||
// Not using OperatingSystem.Platform.
|
||||
// See: https://www.mono-project.com/docs/faq/technical/#how-to-detect-the-execution-platform
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
Win32.LoadDll(dllDir, dllName);
|
||||
}
|
||||
else
|
||||
{
|
||||
Posix.LoadDll(dllDir, dllName);
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetDirectedDllDirectory()
|
||||
{
|
||||
var localPath = Process.GetCurrentProcess().MainModule.FileName;
|
||||
var localDir = Path.GetDirectoryName(localPath);
|
||||
|
||||
var subDir = Environment.Is64BitProcess ? "x64" : "x86";
|
||||
|
||||
var directedDllDir = Path.Combine(localDir, subDir);
|
||||
|
||||
return directedDllDir;
|
||||
}
|
||||
|
||||
private static class Win32
|
||||
{
|
||||
|
||||
internal static void LoadDll(string dllDir, string dllName)
|
||||
{
|
||||
var dllFileName = $"{dllName}.dll";
|
||||
var directedDllPath = Path.Combine(dllDir, dllFileName);
|
||||
|
||||
// Specify SEARCH_DLL_LOAD_DIR to load dependent libraries located in the same platform-specific directory.
|
||||
var hLibrary = LoadLibraryEx(directedDllPath, IntPtr.Zero, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR);
|
||||
|
||||
if (hLibrary == IntPtr.Zero)
|
||||
{
|
||||
var errorCode = Marshal.GetLastWin32Error();
|
||||
var exception = new Win32Exception(errorCode);
|
||||
|
||||
throw new DllNotFoundException(exception.Message, exception);
|
||||
}
|
||||
}
|
||||
|
||||
// HMODULE LoadLibraryExA(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags);
|
||||
// HMODULE LoadLibraryExW(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags);
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
private static extern IntPtr LoadLibraryEx(string lpLibFileName, IntPtr hFile, uint dwFlags);
|
||||
|
||||
private const uint LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x1000;
|
||||
private const uint LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR = 0x100;
|
||||
|
||||
}
|
||||
|
||||
private static class Posix
|
||||
{
|
||||
|
||||
internal static void LoadDll(string dllDir, string dllName)
|
||||
{
|
||||
string dllExtension;
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
dllExtension = ".so";
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
dllExtension = ".dylib";
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
var dllFileName = $"lib{dllName}{dllExtension}";
|
||||
var directedDllPath = Path.Combine(dllDir, dllFileName);
|
||||
|
||||
const int ldFlags = RTLD_NOW | RTLD_GLOBAL;
|
||||
var hLibrary = DlOpen(directedDllPath, ldFlags);
|
||||
|
||||
if (hLibrary == IntPtr.Zero)
|
||||
{
|
||||
var pErrStr = DlError();
|
||||
// `PtrToStringAnsi` always uses the specific constructor of `String` (see dotnet/core#2325),
|
||||
// which in turn interprets the byte sequence with system default codepage. On OSX and Linux
|
||||
// the codepage is UTF-8 so the error message should be handled correctly.
|
||||
var errorMessage = Marshal.PtrToStringAnsi(pErrStr);
|
||||
|
||||
throw new DllNotFoundException(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
// OSX and most Linux OS use LP64 so `int` is still 32-bit even on 64-bit platforms.
|
||||
// void *dlopen(const char *filename, int flag);
|
||||
[DllImport("libdl", EntryPoint = "dlopen")]
|
||||
private static extern IntPtr DlOpen([MarshalAs(UnmanagedType.LPStr)] string fileName, int flags);
|
||||
|
||||
// char *dlerror(void);
|
||||
[DllImport("libdl", EntryPoint = "dlerror")]
|
||||
private static extern IntPtr DlError();
|
||||
|
||||
private const int RTLD_LAZY = 0x1;
|
||||
private const int RTLD_NOW = 0x2;
|
||||
private const int RTLD_GLOBAL = 0x100;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
100
AssetStudio.PInvoke/Utf8StringHandle.cs
Normal file
100
AssetStudio.PInvoke/Utf8StringHandle.cs
Normal file
@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace AssetStudio.PInvoke
|
||||
{
|
||||
// Generally the technique from Steamworks.NET
|
||||
public class Utf8StringHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
{
|
||||
|
||||
static Utf8StringHandle()
|
||||
{
|
||||
Utf8 = new UTF8Encoding(false);
|
||||
}
|
||||
|
||||
public Utf8StringHandle(string str)
|
||||
: base(true)
|
||||
{
|
||||
IntPtr buffer;
|
||||
|
||||
if (str == null)
|
||||
{
|
||||
buffer = IntPtr.Zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (str.Length == 0)
|
||||
{
|
||||
buffer = Marshal.AllocHGlobal(1);
|
||||
|
||||
unsafe
|
||||
{
|
||||
*(byte*)buffer = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var strlen = Utf8.GetByteCount(str);
|
||||
var strBuffer = new byte[strlen + 1];
|
||||
|
||||
Utf8.GetBytes(str, 0, str.Length, strBuffer, 0);
|
||||
|
||||
buffer = Marshal.AllocHGlobal(strBuffer.Length);
|
||||
|
||||
Marshal.Copy(strBuffer, 0, buffer, strBuffer.Length);
|
||||
}
|
||||
}
|
||||
|
||||
SetHandle(buffer);
|
||||
}
|
||||
|
||||
public static string ReadUtf8StringFromPointer(IntPtr lpstr)
|
||||
{
|
||||
if (lpstr == IntPtr.Zero || lpstr == new IntPtr(-1))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var byteCount = 0;
|
||||
|
||||
unsafe
|
||||
{
|
||||
var p = (byte*)lpstr.ToPointer();
|
||||
|
||||
while (*p != 0)
|
||||
{
|
||||
byteCount += 1;
|
||||
p += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (byteCount == 0)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var strBuffer = new byte[byteCount];
|
||||
|
||||
Marshal.Copy(lpstr, strBuffer, 0, byteCount);
|
||||
|
||||
var str = Utf8.GetString(strBuffer);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
if (!IsInvalid)
|
||||
{
|
||||
Marshal.FreeHGlobal(handle);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static readonly UTF8Encoding Utf8;
|
||||
|
||||
}
|
||||
}
|
155
AssetStudio.sln
Normal file
155
AssetStudio.sln
Normal file
@ -0,0 +1,155 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.32014.148
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssetStudio", "AssetStudio\AssetStudio.csproj", "{422FEC21-EF60-4F29-AA56-95DFDA23C913}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssetStudio.PInvoke", "AssetStudio.PInvoke\AssetStudio.PInvoke.csproj", "{0B2BE613-3049-4021-85D1-21C325F729F4}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssetStudioFBXWrapper", "AssetStudioFBXWrapper\AssetStudioFBXWrapper.csproj", "{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027} = {11EA25A3-ED68-40EE-A9D0-7FDE3B583027}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssetStudioGUI", "AssetStudioGUI\AssetStudioGUI.csproj", "{29EAD018-1C67-497A-AB8E-727D595AD756}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssetStudioUtility", "AssetStudioUtility\AssetStudioUtility.csproj", "{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Texture2DDecoderWrapper", "Texture2DDecoderWrapper\Texture2DDecoderWrapper.csproj", "{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD} = {29356642-C46E-4144-83D8-22DC09D0D7FD}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AssetStudioFBXNative", "AssetStudioFBXNative\AssetStudioFBXNative.vcxproj", "{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Texture2DDecoderNative", "Texture2DDecoderNative\Texture2DDecoderNative.vcxproj", "{29356642-C46E-4144-83D8-22DC09D0D7FD}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssetStudioCLI", "AssetStudioCLI\AssetStudioCLI.csproj", "{5B2D8C81-7DE2-429C-AF90-B7C71D91F3B6}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Release|x64.Build.0 = Release|Any CPU
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{422FEC21-EF60-4F29-AA56-95DFDA23C913}.Release|x86.Build.0 = Release|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Release|x64.Build.0 = Release|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{0B2BE613-3049-4021-85D1-21C325F729F4}.Release|x86.Build.0 = Release|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Release|x64.Build.0 = Release|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{E301AFEA-84E7-4BCE-8D65-A2576D8D105B}.Release|x86.Build.0 = Release|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Release|x64.Build.0 = Release|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{29EAD018-1C67-497A-AB8E-727D595AD756}.Release|x86.Build.0 = Release|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Release|x64.Build.0 = Release|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{65EAFFA3-01D3-4EF5-B092-8B4647E9A1FF}.Release|x86.Build.0 = Release|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Release|x64.Build.0 = Release|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{6438FEC1-56B0-488C-A5E2-FBDB23E9574B}.Release|x86.Build.0 = Release|Any CPU
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Debug|Any CPU.Build.0 = Debug|Win32
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Debug|x64.Build.0 = Debug|x64
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Debug|x86.Build.0 = Debug|Win32
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Release|Any CPU.Build.0 = Release|Win32
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Release|x64.ActiveCfg = Release|x64
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Release|x64.Build.0 = Release|x64
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Release|x86.ActiveCfg = Release|Win32
|
||||
{11EA25A3-ED68-40EE-A9D0-7FDE3B583027}.Release|x86.Build.0 = Release|Win32
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Debug|Any CPU.Build.0 = Debug|Win32
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Debug|x64.Build.0 = Debug|x64
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Debug|x86.Build.0 = Debug|Win32
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Release|Any CPU.Build.0 = Release|Win32
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Release|x64.ActiveCfg = Release|x64
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Release|x64.Build.0 = Release|x64
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Release|x86.ActiveCfg = Release|Win32
|
||||
{29356642-C46E-4144-83D8-22DC09D0D7FD}.Release|x86.Build.0 = Release|Win32
|
||||
{5B2D8C81-7DE2-429C-AF90-B7C71D91F3B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5B2D8C81-7DE2-429C-AF90-B7C71D91F3B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5B2D8C81-7DE2-429C-AF90-B7C71D91F3B6}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{5B2D8C81-7DE2-429C-AF90-B7C71D91F3B6}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{5B2D8C81-7DE2-429C-AF90-B7C71D91F3B6}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{5B2D8C81-7DE2-429C-AF90-B7C71D91F3B6}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{5B2D8C81-7DE2-429C-AF90-B7C71D91F3B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5B2D8C81-7DE2-429C-AF90-B7C71D91F3B6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5B2D8C81-7DE2-429C-AF90-B7C71D91F3B6}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{5B2D8C81-7DE2-429C-AF90-B7C71D91F3B6}.Release|x64.Build.0 = Release|Any CPU
|
||||
{5B2D8C81-7DE2-429C-AF90-B7C71D91F3B6}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{5B2D8C81-7DE2-429C-AF90-B7C71D91F3B6}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {3C074481-9CDD-4780-B9F6-57BBC5092EA2}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
79
AssetStudio/7zip/Common/CRC.cs
Normal file
79
AssetStudio/7zip/Common/CRC.cs
Normal file
@ -0,0 +1,79 @@
|
||||
// Common/CRC.cs
|
||||
|
||||
using System.Text;
|
||||
|
||||
namespace SevenZip
|
||||
{
|
||||
public class CRC
|
||||
{
|
||||
public static readonly uint[] Table;
|
||||
|
||||
static CRC()
|
||||
{
|
||||
Table = new uint[256];
|
||||
const uint kPoly = 0xEDB88320;
|
||||
for (uint i = 0; i < 256; i++)
|
||||
{
|
||||
uint r = i;
|
||||
for (int j = 0; j < 8; j++)
|
||||
if ((r & 1) != 0)
|
||||
r = (r >> 1) ^ kPoly;
|
||||
else
|
||||
r >>= 1;
|
||||
Table[i] = r;
|
||||
}
|
||||
}
|
||||
|
||||
uint _value = 0xFFFFFFFF;
|
||||
|
||||
public void Init() { _value = 0xFFFFFFFF; }
|
||||
|
||||
public void UpdateByte(byte b)
|
||||
{
|
||||
_value = Table[(((byte)(_value)) ^ b)] ^ (_value >> 8);
|
||||
}
|
||||
|
||||
public void Update(byte[] data, uint offset, uint size)
|
||||
{
|
||||
for (uint i = 0; i < size; i++)
|
||||
_value = Table[(((byte)(_value)) ^ data[offset + i])] ^ (_value >> 8);
|
||||
}
|
||||
|
||||
public uint GetDigest() { return _value ^ 0xFFFFFFFF; }
|
||||
|
||||
static uint CalculateDigest(byte[] data, uint offset, uint size)
|
||||
{
|
||||
CRC crc = new CRC();
|
||||
// crc.Init();
|
||||
crc.Update(data, offset, size);
|
||||
return crc.GetDigest();
|
||||
}
|
||||
|
||||
static bool VerifyDigest(uint digest, byte[] data, uint offset, uint size)
|
||||
{
|
||||
return (CalculateDigest(data, offset, size) == digest);
|
||||
}
|
||||
|
||||
public static uint CalculateDigestAscii(string data)
|
||||
{
|
||||
var bytes = Encoding.ASCII.GetBytes(data);
|
||||
return CalculateDigest(bytes, 0, (uint)bytes.Length);
|
||||
}
|
||||
|
||||
public static uint CalculateDigestUTF8(string data)
|
||||
{
|
||||
var bytes = Encoding.UTF8.GetBytes(data);
|
||||
return CalculateDigest(bytes, 0, (uint)bytes.Length);
|
||||
}
|
||||
|
||||
public static bool VerifyDigestUTF8(string data, uint digest)
|
||||
{
|
||||
return CalculateDigestUTF8(data) == digest;
|
||||
}
|
||||
|
||||
public static bool Verify28DigestUTF8(string data, uint digest)
|
||||
{
|
||||
return (CalculateDigestUTF8(data) & 0xFFFFFFF) == digest;
|
||||
}
|
||||
}
|
||||
}
|
274
AssetStudio/7zip/Common/CommandLineParser.cs
Normal file
274
AssetStudio/7zip/Common/CommandLineParser.cs
Normal file
@ -0,0 +1,274 @@
|
||||
// CommandLineParser.cs
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace SevenZip.CommandLineParser
|
||||
{
|
||||
public enum SwitchType
|
||||
{
|
||||
Simple,
|
||||
PostMinus,
|
||||
LimitedPostString,
|
||||
UnLimitedPostString,
|
||||
PostChar
|
||||
}
|
||||
|
||||
public class SwitchForm
|
||||
{
|
||||
public string IDString;
|
||||
public SwitchType Type;
|
||||
public bool Multi;
|
||||
public int MinLen;
|
||||
public int MaxLen;
|
||||
public string PostCharSet;
|
||||
|
||||
public SwitchForm(string idString, SwitchType type, bool multi,
|
||||
int minLen, int maxLen, string postCharSet)
|
||||
{
|
||||
IDString = idString;
|
||||
Type = type;
|
||||
Multi = multi;
|
||||
MinLen = minLen;
|
||||
MaxLen = maxLen;
|
||||
PostCharSet = postCharSet;
|
||||
}
|
||||
public SwitchForm(string idString, SwitchType type, bool multi, int minLen):
|
||||
this(idString, type, multi, minLen, 0, "")
|
||||
{
|
||||
}
|
||||
public SwitchForm(string idString, SwitchType type, bool multi):
|
||||
this(idString, type, multi, 0)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class SwitchResult
|
||||
{
|
||||
public bool ThereIs;
|
||||
public bool WithMinus;
|
||||
public ArrayList PostStrings = new ArrayList();
|
||||
public int PostCharIndex;
|
||||
public SwitchResult()
|
||||
{
|
||||
ThereIs = false;
|
||||
}
|
||||
}
|
||||
|
||||
public class Parser
|
||||
{
|
||||
public ArrayList NonSwitchStrings = new ArrayList();
|
||||
SwitchResult[] _switches;
|
||||
|
||||
public Parser(int numSwitches)
|
||||
{
|
||||
_switches = new SwitchResult[numSwitches];
|
||||
for (int i = 0; i < numSwitches; i++)
|
||||
_switches[i] = new SwitchResult();
|
||||
}
|
||||
|
||||
bool ParseString(string srcString, SwitchForm[] switchForms)
|
||||
{
|
||||
int len = srcString.Length;
|
||||
if (len == 0)
|
||||
return false;
|
||||
int pos = 0;
|
||||
if (!IsItSwitchChar(srcString[pos]))
|
||||
return false;
|
||||
while (pos < len)
|
||||
{
|
||||
if (IsItSwitchChar(srcString[pos]))
|
||||
pos++;
|
||||
const int kNoLen = -1;
|
||||
int matchedSwitchIndex = 0;
|
||||
int maxLen = kNoLen;
|
||||
for (int switchIndex = 0; switchIndex < _switches.Length; switchIndex++)
|
||||
{
|
||||
int switchLen = switchForms[switchIndex].IDString.Length;
|
||||
if (switchLen <= maxLen || pos + switchLen > len)
|
||||
continue;
|
||||
if (String.Compare(switchForms[switchIndex].IDString, 0,
|
||||
srcString, pos, switchLen, true) == 0)
|
||||
{
|
||||
matchedSwitchIndex = switchIndex;
|
||||
maxLen = switchLen;
|
||||
}
|
||||
}
|
||||
if (maxLen == kNoLen)
|
||||
throw new Exception("maxLen == kNoLen");
|
||||
SwitchResult matchedSwitch = _switches[matchedSwitchIndex];
|
||||
SwitchForm switchForm = switchForms[matchedSwitchIndex];
|
||||
if ((!switchForm.Multi) && matchedSwitch.ThereIs)
|
||||
throw new Exception("switch must be single");
|
||||
matchedSwitch.ThereIs = true;
|
||||
pos += maxLen;
|
||||
int tailSize = len - pos;
|
||||
SwitchType type = switchForm.Type;
|
||||
switch (type)
|
||||
{
|
||||
case SwitchType.PostMinus:
|
||||
{
|
||||
if (tailSize == 0)
|
||||
matchedSwitch.WithMinus = false;
|
||||
else
|
||||
{
|
||||
matchedSwitch.WithMinus = (srcString[pos] == kSwitchMinus);
|
||||
if (matchedSwitch.WithMinus)
|
||||
pos++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SwitchType.PostChar:
|
||||
{
|
||||
if (tailSize < switchForm.MinLen)
|
||||
throw new Exception("switch is not full");
|
||||
string charSet = switchForm.PostCharSet;
|
||||
const int kEmptyCharValue = -1;
|
||||
if (tailSize == 0)
|
||||
matchedSwitch.PostCharIndex = kEmptyCharValue;
|
||||
else
|
||||
{
|
||||
int index = charSet.IndexOf(srcString[pos]);
|
||||
if (index < 0)
|
||||
matchedSwitch.PostCharIndex = kEmptyCharValue;
|
||||
else
|
||||
{
|
||||
matchedSwitch.PostCharIndex = index;
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SwitchType.LimitedPostString:
|
||||
case SwitchType.UnLimitedPostString:
|
||||
{
|
||||
int minLen = switchForm.MinLen;
|
||||
if (tailSize < minLen)
|
||||
throw new Exception("switch is not full");
|
||||
if (type == SwitchType.UnLimitedPostString)
|
||||
{
|
||||
matchedSwitch.PostStrings.Add(srcString.Substring(pos));
|
||||
return true;
|
||||
}
|
||||
String stringSwitch = srcString.Substring(pos, minLen);
|
||||
pos += minLen;
|
||||
for (int i = minLen; i < switchForm.MaxLen && pos < len; i++, pos++)
|
||||
{
|
||||
char c = srcString[pos];
|
||||
if (IsItSwitchChar(c))
|
||||
break;
|
||||
stringSwitch += c;
|
||||
}
|
||||
matchedSwitch.PostStrings.Add(stringSwitch);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public void ParseStrings(SwitchForm[] switchForms, string[] commandStrings)
|
||||
{
|
||||
int numCommandStrings = commandStrings.Length;
|
||||
bool stopSwitch = false;
|
||||
for (int i = 0; i < numCommandStrings; i++)
|
||||
{
|
||||
string s = commandStrings[i];
|
||||
if (stopSwitch)
|
||||
NonSwitchStrings.Add(s);
|
||||
else
|
||||
if (s == kStopSwitchParsing)
|
||||
stopSwitch = true;
|
||||
else
|
||||
if (!ParseString(s, switchForms))
|
||||
NonSwitchStrings.Add(s);
|
||||
}
|
||||
}
|
||||
|
||||
public SwitchResult this[int index] { get { return _switches[index]; } }
|
||||
|
||||
public static int ParseCommand(CommandForm[] commandForms, string commandString,
|
||||
out string postString)
|
||||
{
|
||||
for (int i = 0; i < commandForms.Length; i++)
|
||||
{
|
||||
string id = commandForms[i].IDString;
|
||||
if (commandForms[i].PostStringMode)
|
||||
{
|
||||
if (commandString.IndexOf(id) == 0)
|
||||
{
|
||||
postString = commandString.Substring(id.Length);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (commandString == id)
|
||||
{
|
||||
postString = "";
|
||||
return i;
|
||||
}
|
||||
}
|
||||
postString = "";
|
||||
return -1;
|
||||
}
|
||||
|
||||
static bool ParseSubCharsCommand(int numForms, CommandSubCharsSet[] forms,
|
||||
string commandString, ArrayList indices)
|
||||
{
|
||||
indices.Clear();
|
||||
int numUsedChars = 0;
|
||||
for (int i = 0; i < numForms; i++)
|
||||
{
|
||||
CommandSubCharsSet charsSet = forms[i];
|
||||
int currentIndex = -1;
|
||||
int len = charsSet.Chars.Length;
|
||||
for (int j = 0; j < len; j++)
|
||||
{
|
||||
char c = charsSet.Chars[j];
|
||||
int newIndex = commandString.IndexOf(c);
|
||||
if (newIndex >= 0)
|
||||
{
|
||||
if (currentIndex >= 0)
|
||||
return false;
|
||||
if (commandString.IndexOf(c, newIndex + 1) >= 0)
|
||||
return false;
|
||||
currentIndex = j;
|
||||
numUsedChars++;
|
||||
}
|
||||
}
|
||||
if (currentIndex == -1 && !charsSet.EmptyAllowed)
|
||||
return false;
|
||||
indices.Add(currentIndex);
|
||||
}
|
||||
return (numUsedChars == commandString.Length);
|
||||
}
|
||||
const char kSwitchID1 = '-';
|
||||
const char kSwitchID2 = '/';
|
||||
|
||||
const char kSwitchMinus = '-';
|
||||
const string kStopSwitchParsing = "--";
|
||||
|
||||
static bool IsItSwitchChar(char c)
|
||||
{
|
||||
return (c == kSwitchID1 || c == kSwitchID2);
|
||||
}
|
||||
}
|
||||
|
||||
public class CommandForm
|
||||
{
|
||||
public string IDString = "";
|
||||
public bool PostStringMode = false;
|
||||
public CommandForm(string idString, bool postStringMode)
|
||||
{
|
||||
IDString = idString;
|
||||
PostStringMode = postStringMode;
|
||||
}
|
||||
}
|
||||
|
||||
class CommandSubCharsSet
|
||||
{
|
||||
public string Chars = "";
|
||||
public bool EmptyAllowed = false;
|
||||
}
|
||||
}
|
72
AssetStudio/7zip/Common/InBuffer.cs
Normal file
72
AssetStudio/7zip/Common/InBuffer.cs
Normal file
@ -0,0 +1,72 @@
|
||||
// InBuffer.cs
|
||||
|
||||
namespace SevenZip.Buffer
|
||||
{
|
||||
public class InBuffer
|
||||
{
|
||||
byte[] m_Buffer;
|
||||
uint m_Pos;
|
||||
uint m_Limit;
|
||||
uint m_BufferSize;
|
||||
System.IO.Stream m_Stream;
|
||||
bool m_StreamWasExhausted;
|
||||
ulong m_ProcessedSize;
|
||||
|
||||
public InBuffer(uint bufferSize)
|
||||
{
|
||||
m_Buffer = new byte[bufferSize];
|
||||
m_BufferSize = bufferSize;
|
||||
}
|
||||
|
||||
public void Init(System.IO.Stream stream)
|
||||
{
|
||||
m_Stream = stream;
|
||||
m_ProcessedSize = 0;
|
||||
m_Limit = 0;
|
||||
m_Pos = 0;
|
||||
m_StreamWasExhausted = false;
|
||||
}
|
||||
|
||||
public bool ReadBlock()
|
||||
{
|
||||
if (m_StreamWasExhausted)
|
||||
return false;
|
||||
m_ProcessedSize += m_Pos;
|
||||
int aNumProcessedBytes = m_Stream.Read(m_Buffer, 0, (int)m_BufferSize);
|
||||
m_Pos = 0;
|
||||
m_Limit = (uint)aNumProcessedBytes;
|
||||
m_StreamWasExhausted = (aNumProcessedBytes == 0);
|
||||
return (!m_StreamWasExhausted);
|
||||
}
|
||||
|
||||
|
||||
public void ReleaseStream()
|
||||
{
|
||||
// m_Stream.Close();
|
||||
m_Stream = null;
|
||||
}
|
||||
|
||||
public bool ReadByte(byte b) // check it
|
||||
{
|
||||
if (m_Pos >= m_Limit)
|
||||
if (!ReadBlock())
|
||||
return false;
|
||||
b = m_Buffer[m_Pos++];
|
||||
return true;
|
||||
}
|
||||
|
||||
public byte ReadByte()
|
||||
{
|
||||
// return (byte)m_Stream.ReadByte();
|
||||
if (m_Pos >= m_Limit)
|
||||
if (!ReadBlock())
|
||||
return 0xFF;
|
||||
return m_Buffer[m_Pos++];
|
||||
}
|
||||
|
||||
public ulong GetProcessedSize()
|
||||
{
|
||||
return m_ProcessedSize + m_Pos;
|
||||
}
|
||||
}
|
||||
}
|
47
AssetStudio/7zip/Common/OutBuffer.cs
Normal file
47
AssetStudio/7zip/Common/OutBuffer.cs
Normal file
@ -0,0 +1,47 @@
|
||||
// OutBuffer.cs
|
||||
|
||||
namespace SevenZip.Buffer
|
||||
{
|
||||
public class OutBuffer
|
||||
{
|
||||
byte[] m_Buffer;
|
||||
uint m_Pos;
|
||||
uint m_BufferSize;
|
||||
System.IO.Stream m_Stream;
|
||||
ulong m_ProcessedSize;
|
||||
|
||||
public OutBuffer(uint bufferSize)
|
||||
{
|
||||
m_Buffer = new byte[bufferSize];
|
||||
m_BufferSize = bufferSize;
|
||||
}
|
||||
|
||||
public void SetStream(System.IO.Stream stream) { m_Stream = stream; }
|
||||
public void FlushStream() { m_Stream.Flush(); }
|
||||
public void CloseStream() { m_Stream.Close(); }
|
||||
public void ReleaseStream() { m_Stream = null; }
|
||||
|
||||
public void Init()
|
||||
{
|
||||
m_ProcessedSize = 0;
|
||||
m_Pos = 0;
|
||||
}
|
||||
|
||||
public void WriteByte(byte b)
|
||||
{
|
||||
m_Buffer[m_Pos++] = b;
|
||||
if (m_Pos >= m_BufferSize)
|
||||
FlushData();
|
||||
}
|
||||
|
||||
public void FlushData()
|
||||
{
|
||||
if (m_Pos == 0)
|
||||
return;
|
||||
m_Stream.Write(m_Buffer, 0, (int)m_Pos);
|
||||
m_Pos = 0;
|
||||
}
|
||||
|
||||
public ulong GetProcessedSize() { return m_ProcessedSize + m_Pos; }
|
||||
}
|
||||
}
|
24
AssetStudio/7zip/Compress/LZ/IMatchFinder.cs
Normal file
24
AssetStudio/7zip/Compress/LZ/IMatchFinder.cs
Normal file
@ -0,0 +1,24 @@
|
||||
// IMatchFinder.cs
|
||||
|
||||
using System;
|
||||
|
||||
namespace SevenZip.Compression.LZ
|
||||
{
|
||||
interface IInWindowStream
|
||||
{
|
||||
void SetStream(System.IO.Stream inStream);
|
||||
void Init();
|
||||
void ReleaseStream();
|
||||
Byte GetIndexByte(Int32 index);
|
||||
UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit);
|
||||
UInt32 GetNumAvailableBytes();
|
||||
}
|
||||
|
||||
interface IMatchFinder : IInWindowStream
|
||||
{
|
||||
void Create(UInt32 historySize, UInt32 keepAddBufferBefore,
|
||||
UInt32 matchMaxLen, UInt32 keepAddBufferAfter);
|
||||
UInt32 GetMatches(UInt32[] distances);
|
||||
void Skip(UInt32 num);
|
||||
}
|
||||
}
|
367
AssetStudio/7zip/Compress/LZ/LzBinTree.cs
Normal file
367
AssetStudio/7zip/Compress/LZ/LzBinTree.cs
Normal file
@ -0,0 +1,367 @@
|
||||
// LzBinTree.cs
|
||||
|
||||
using System;
|
||||
|
||||
namespace SevenZip.Compression.LZ
|
||||
{
|
||||
public class BinTree : InWindow, IMatchFinder
|
||||
{
|
||||
UInt32 _cyclicBufferPos;
|
||||
UInt32 _cyclicBufferSize = 0;
|
||||
UInt32 _matchMaxLen;
|
||||
|
||||
UInt32[] _son;
|
||||
UInt32[] _hash;
|
||||
|
||||
UInt32 _cutValue = 0xFF;
|
||||
UInt32 _hashMask;
|
||||
UInt32 _hashSizeSum = 0;
|
||||
|
||||
bool HASH_ARRAY = true;
|
||||
|
||||
const UInt32 kHash2Size = 1 << 10;
|
||||
const UInt32 kHash3Size = 1 << 16;
|
||||
const UInt32 kBT2HashSize = 1 << 16;
|
||||
const UInt32 kStartMaxLen = 1;
|
||||
const UInt32 kHash3Offset = kHash2Size;
|
||||
const UInt32 kEmptyHashValue = 0;
|
||||
const UInt32 kMaxValForNormalize = ((UInt32)1 << 31) - 1;
|
||||
|
||||
UInt32 kNumHashDirectBytes = 0;
|
||||
UInt32 kMinMatchCheck = 4;
|
||||
UInt32 kFixHashSize = kHash2Size + kHash3Size;
|
||||
|
||||
public void SetType(int numHashBytes)
|
||||
{
|
||||
HASH_ARRAY = (numHashBytes > 2);
|
||||
if (HASH_ARRAY)
|
||||
{
|
||||
kNumHashDirectBytes = 0;
|
||||
kMinMatchCheck = 4;
|
||||
kFixHashSize = kHash2Size + kHash3Size;
|
||||
}
|
||||
else
|
||||
{
|
||||
kNumHashDirectBytes = 2;
|
||||
kMinMatchCheck = 2 + 1;
|
||||
kFixHashSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public new void SetStream(System.IO.Stream stream) { base.SetStream(stream); }
|
||||
public new void ReleaseStream() { base.ReleaseStream(); }
|
||||
|
||||
public new void Init()
|
||||
{
|
||||
base.Init();
|
||||
for (UInt32 i = 0; i < _hashSizeSum; i++)
|
||||
_hash[i] = kEmptyHashValue;
|
||||
_cyclicBufferPos = 0;
|
||||
ReduceOffsets(-1);
|
||||
}
|
||||
|
||||
public new void MovePos()
|
||||
{
|
||||
if (++_cyclicBufferPos >= _cyclicBufferSize)
|
||||
_cyclicBufferPos = 0;
|
||||
base.MovePos();
|
||||
if (_pos == kMaxValForNormalize)
|
||||
Normalize();
|
||||
}
|
||||
|
||||
public new Byte GetIndexByte(Int32 index) { return base.GetIndexByte(index); }
|
||||
|
||||
public new UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit)
|
||||
{ return base.GetMatchLen(index, distance, limit); }
|
||||
|
||||
public new UInt32 GetNumAvailableBytes() { return base.GetNumAvailableBytes(); }
|
||||
|
||||
public void Create(UInt32 historySize, UInt32 keepAddBufferBefore,
|
||||
UInt32 matchMaxLen, UInt32 keepAddBufferAfter)
|
||||
{
|
||||
if (historySize > kMaxValForNormalize - 256)
|
||||
throw new Exception();
|
||||
_cutValue = 16 + (matchMaxLen >> 1);
|
||||
|
||||
UInt32 windowReservSize = (historySize + keepAddBufferBefore +
|
||||
matchMaxLen + keepAddBufferAfter) / 2 + 256;
|
||||
|
||||
base.Create(historySize + keepAddBufferBefore, matchMaxLen + keepAddBufferAfter, windowReservSize);
|
||||
|
||||
_matchMaxLen = matchMaxLen;
|
||||
|
||||
UInt32 cyclicBufferSize = historySize + 1;
|
||||
if (_cyclicBufferSize != cyclicBufferSize)
|
||||
_son = new UInt32[(_cyclicBufferSize = cyclicBufferSize) * 2];
|
||||
|
||||
UInt32 hs = kBT2HashSize;
|
||||
|
||||
if (HASH_ARRAY)
|
||||
{
|
||||
hs = historySize - 1;
|
||||
hs |= (hs >> 1);
|
||||
hs |= (hs >> 2);
|
||||
hs |= (hs >> 4);
|
||||
hs |= (hs >> 8);
|
||||
hs >>= 1;
|
||||
hs |= 0xFFFF;
|
||||
if (hs > (1 << 24))
|
||||
hs >>= 1;
|
||||
_hashMask = hs;
|
||||
hs++;
|
||||
hs += kFixHashSize;
|
||||
}
|
||||
if (hs != _hashSizeSum)
|
||||
_hash = new UInt32[_hashSizeSum = hs];
|
||||
}
|
||||
|
||||
public UInt32 GetMatches(UInt32[] distances)
|
||||
{
|
||||
UInt32 lenLimit;
|
||||
if (_pos + _matchMaxLen <= _streamPos)
|
||||
lenLimit = _matchMaxLen;
|
||||
else
|
||||
{
|
||||
lenLimit = _streamPos - _pos;
|
||||
if (lenLimit < kMinMatchCheck)
|
||||
{
|
||||
MovePos();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 offset = 0;
|
||||
UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;
|
||||
UInt32 cur = _bufferOffset + _pos;
|
||||
UInt32 maxLen = kStartMaxLen; // to avoid items for len < hashSize;
|
||||
UInt32 hashValue, hash2Value = 0, hash3Value = 0;
|
||||
|
||||
if (HASH_ARRAY)
|
||||
{
|
||||
UInt32 temp = CRC.Table[_bufferBase[cur]] ^ _bufferBase[cur + 1];
|
||||
hash2Value = temp & (kHash2Size - 1);
|
||||
temp ^= ((UInt32)(_bufferBase[cur + 2]) << 8);
|
||||
hash3Value = temp & (kHash3Size - 1);
|
||||
hashValue = (temp ^ (CRC.Table[_bufferBase[cur + 3]] << 5)) & _hashMask;
|
||||
}
|
||||
else
|
||||
hashValue = _bufferBase[cur] ^ ((UInt32)(_bufferBase[cur + 1]) << 8);
|
||||
|
||||
UInt32 curMatch = _hash[kFixHashSize + hashValue];
|
||||
if (HASH_ARRAY)
|
||||
{
|
||||
UInt32 curMatch2 = _hash[hash2Value];
|
||||
UInt32 curMatch3 = _hash[kHash3Offset + hash3Value];
|
||||
_hash[hash2Value] = _pos;
|
||||
_hash[kHash3Offset + hash3Value] = _pos;
|
||||
if (curMatch2 > matchMinPos)
|
||||
if (_bufferBase[_bufferOffset + curMatch2] == _bufferBase[cur])
|
||||
{
|
||||
distances[offset++] = maxLen = 2;
|
||||
distances[offset++] = _pos - curMatch2 - 1;
|
||||
}
|
||||
if (curMatch3 > matchMinPos)
|
||||
if (_bufferBase[_bufferOffset + curMatch3] == _bufferBase[cur])
|
||||
{
|
||||
if (curMatch3 == curMatch2)
|
||||
offset -= 2;
|
||||
distances[offset++] = maxLen = 3;
|
||||
distances[offset++] = _pos - curMatch3 - 1;
|
||||
curMatch2 = curMatch3;
|
||||
}
|
||||
if (offset != 0 && curMatch2 == curMatch)
|
||||
{
|
||||
offset -= 2;
|
||||
maxLen = kStartMaxLen;
|
||||
}
|
||||
}
|
||||
|
||||
_hash[kFixHashSize + hashValue] = _pos;
|
||||
|
||||
UInt32 ptr0 = (_cyclicBufferPos << 1) + 1;
|
||||
UInt32 ptr1 = (_cyclicBufferPos << 1);
|
||||
|
||||
UInt32 len0, len1;
|
||||
len0 = len1 = kNumHashDirectBytes;
|
||||
|
||||
if (kNumHashDirectBytes != 0)
|
||||
{
|
||||
if (curMatch > matchMinPos)
|
||||
{
|
||||
if (_bufferBase[_bufferOffset + curMatch + kNumHashDirectBytes] !=
|
||||
_bufferBase[cur + kNumHashDirectBytes])
|
||||
{
|
||||
distances[offset++] = maxLen = kNumHashDirectBytes;
|
||||
distances[offset++] = _pos - curMatch - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 count = _cutValue;
|
||||
|
||||
while(true)
|
||||
{
|
||||
if(curMatch <= matchMinPos || count-- == 0)
|
||||
{
|
||||
_son[ptr0] = _son[ptr1] = kEmptyHashValue;
|
||||
break;
|
||||
}
|
||||
UInt32 delta = _pos - curMatch;
|
||||
UInt32 cyclicPos = ((delta <= _cyclicBufferPos) ?
|
||||
(_cyclicBufferPos - delta) :
|
||||
(_cyclicBufferPos - delta + _cyclicBufferSize)) << 1;
|
||||
|
||||
UInt32 pby1 = _bufferOffset + curMatch;
|
||||
UInt32 len = Math.Min(len0, len1);
|
||||
if (_bufferBase[pby1 + len] == _bufferBase[cur + len])
|
||||
{
|
||||
while(++len != lenLimit)
|
||||
if (_bufferBase[pby1 + len] != _bufferBase[cur + len])
|
||||
break;
|
||||
if (maxLen < len)
|
||||
{
|
||||
distances[offset++] = maxLen = len;
|
||||
distances[offset++] = delta - 1;
|
||||
if (len == lenLimit)
|
||||
{
|
||||
_son[ptr1] = _son[cyclicPos];
|
||||
_son[ptr0] = _son[cyclicPos + 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_bufferBase[pby1 + len] < _bufferBase[cur + len])
|
||||
{
|
||||
_son[ptr1] = curMatch;
|
||||
ptr1 = cyclicPos + 1;
|
||||
curMatch = _son[ptr1];
|
||||
len1 = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
_son[ptr0] = curMatch;
|
||||
ptr0 = cyclicPos;
|
||||
curMatch = _son[ptr0];
|
||||
len0 = len;
|
||||
}
|
||||
}
|
||||
MovePos();
|
||||
return offset;
|
||||
}
|
||||
|
||||
public void Skip(UInt32 num)
|
||||
{
|
||||
do
|
||||
{
|
||||
UInt32 lenLimit;
|
||||
if (_pos + _matchMaxLen <= _streamPos)
|
||||
lenLimit = _matchMaxLen;
|
||||
else
|
||||
{
|
||||
lenLimit = _streamPos - _pos;
|
||||
if (lenLimit < kMinMatchCheck)
|
||||
{
|
||||
MovePos();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;
|
||||
UInt32 cur = _bufferOffset + _pos;
|
||||
|
||||
UInt32 hashValue;
|
||||
|
||||
if (HASH_ARRAY)
|
||||
{
|
||||
UInt32 temp = CRC.Table[_bufferBase[cur]] ^ _bufferBase[cur + 1];
|
||||
UInt32 hash2Value = temp & (kHash2Size - 1);
|
||||
_hash[hash2Value] = _pos;
|
||||
temp ^= ((UInt32)(_bufferBase[cur + 2]) << 8);
|
||||
UInt32 hash3Value = temp & (kHash3Size - 1);
|
||||
_hash[kHash3Offset + hash3Value] = _pos;
|
||||
hashValue = (temp ^ (CRC.Table[_bufferBase[cur + 3]] << 5)) & _hashMask;
|
||||
}
|
||||
else
|
||||
hashValue = _bufferBase[cur] ^ ((UInt32)(_bufferBase[cur + 1]) << 8);
|
||||
|
||||
UInt32 curMatch = _hash[kFixHashSize + hashValue];
|
||||
_hash[kFixHashSize + hashValue] = _pos;
|
||||
|
||||
UInt32 ptr0 = (_cyclicBufferPos << 1) + 1;
|
||||
UInt32 ptr1 = (_cyclicBufferPos << 1);
|
||||
|
||||
UInt32 len0, len1;
|
||||
len0 = len1 = kNumHashDirectBytes;
|
||||
|
||||
UInt32 count = _cutValue;
|
||||
while (true)
|
||||
{
|
||||
if (curMatch <= matchMinPos || count-- == 0)
|
||||
{
|
||||
_son[ptr0] = _son[ptr1] = kEmptyHashValue;
|
||||
break;
|
||||
}
|
||||
|
||||
UInt32 delta = _pos - curMatch;
|
||||
UInt32 cyclicPos = ((delta <= _cyclicBufferPos) ?
|
||||
(_cyclicBufferPos - delta) :
|
||||
(_cyclicBufferPos - delta + _cyclicBufferSize)) << 1;
|
||||
|
||||
UInt32 pby1 = _bufferOffset + curMatch;
|
||||
UInt32 len = Math.Min(len0, len1);
|
||||
if (_bufferBase[pby1 + len] == _bufferBase[cur + len])
|
||||
{
|
||||
while (++len != lenLimit)
|
||||
if (_bufferBase[pby1 + len] != _bufferBase[cur + len])
|
||||
break;
|
||||
if (len == lenLimit)
|
||||
{
|
||||
_son[ptr1] = _son[cyclicPos];
|
||||
_son[ptr0] = _son[cyclicPos + 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_bufferBase[pby1 + len] < _bufferBase[cur + len])
|
||||
{
|
||||
_son[ptr1] = curMatch;
|
||||
ptr1 = cyclicPos + 1;
|
||||
curMatch = _son[ptr1];
|
||||
len1 = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
_son[ptr0] = curMatch;
|
||||
ptr0 = cyclicPos;
|
||||
curMatch = _son[ptr0];
|
||||
len0 = len;
|
||||
}
|
||||
}
|
||||
MovePos();
|
||||
}
|
||||
while (--num != 0);
|
||||
}
|
||||
|
||||
void NormalizeLinks(UInt32[] items, UInt32 numItems, UInt32 subValue)
|
||||
{
|
||||
for (UInt32 i = 0; i < numItems; i++)
|
||||
{
|
||||
UInt32 value = items[i];
|
||||
if (value <= subValue)
|
||||
value = kEmptyHashValue;
|
||||
else
|
||||
value -= subValue;
|
||||
items[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void Normalize()
|
||||
{
|
||||
UInt32 subValue = _pos - _cyclicBufferSize;
|
||||
NormalizeLinks(_son, _cyclicBufferSize * 2, subValue);
|
||||
NormalizeLinks(_hash, _hashSizeSum, subValue);
|
||||
ReduceOffsets((Int32)subValue);
|
||||
}
|
||||
|
||||
public void SetCutValue(UInt32 cutValue) { _cutValue = cutValue; }
|
||||
}
|
||||
}
|
132
AssetStudio/7zip/Compress/LZ/LzInWindow.cs
Normal file
132
AssetStudio/7zip/Compress/LZ/LzInWindow.cs
Normal file
@ -0,0 +1,132 @@
|
||||
// LzInWindow.cs
|
||||
|
||||
using System;
|
||||
|
||||
namespace SevenZip.Compression.LZ
|
||||
{
|
||||
public class InWindow
|
||||
{
|
||||
public Byte[] _bufferBase = null; // pointer to buffer with data
|
||||
System.IO.Stream _stream;
|
||||
UInt32 _posLimit; // offset (from _buffer) of first byte when new block reading must be done
|
||||
bool _streamEndWasReached; // if (true) then _streamPos shows real end of stream
|
||||
|
||||
UInt32 _pointerToLastSafePosition;
|
||||
|
||||
public UInt32 _bufferOffset;
|
||||
|
||||
public UInt32 _blockSize; // Size of Allocated memory block
|
||||
public UInt32 _pos; // offset (from _buffer) of curent byte
|
||||
UInt32 _keepSizeBefore; // how many BYTEs must be kept in buffer before _pos
|
||||
UInt32 _keepSizeAfter; // how many BYTEs must be kept buffer after _pos
|
||||
public UInt32 _streamPos; // offset (from _buffer) of first not read byte from Stream
|
||||
|
||||
public void MoveBlock()
|
||||
{
|
||||
UInt32 offset = (UInt32)(_bufferOffset) + _pos - _keepSizeBefore;
|
||||
// we need one additional byte, since MovePos moves on 1 byte.
|
||||
if (offset > 0)
|
||||
offset--;
|
||||
|
||||
UInt32 numBytes = (UInt32)(_bufferOffset) + _streamPos - offset;
|
||||
|
||||
// check negative offset ????
|
||||
for (UInt32 i = 0; i < numBytes; i++)
|
||||
_bufferBase[i] = _bufferBase[offset + i];
|
||||
_bufferOffset -= offset;
|
||||
}
|
||||
|
||||
public virtual void ReadBlock()
|
||||
{
|
||||
if (_streamEndWasReached)
|
||||
return;
|
||||
while (true)
|
||||
{
|
||||
int size = (int)((0 - _bufferOffset) + _blockSize - _streamPos);
|
||||
if (size == 0)
|
||||
return;
|
||||
int numReadBytes = _stream.Read(_bufferBase, (int)(_bufferOffset + _streamPos), size);
|
||||
if (numReadBytes == 0)
|
||||
{
|
||||
_posLimit = _streamPos;
|
||||
UInt32 pointerToPostion = _bufferOffset + _posLimit;
|
||||
if (pointerToPostion > _pointerToLastSafePosition)
|
||||
_posLimit = (UInt32)(_pointerToLastSafePosition - _bufferOffset);
|
||||
|
||||
_streamEndWasReached = true;
|
||||
return;
|
||||
}
|
||||
_streamPos += (UInt32)numReadBytes;
|
||||
if (_streamPos >= _pos + _keepSizeAfter)
|
||||
_posLimit = _streamPos - _keepSizeAfter;
|
||||
}
|
||||
}
|
||||
|
||||
void Free() { _bufferBase = null; }
|
||||
|
||||
public void Create(UInt32 keepSizeBefore, UInt32 keepSizeAfter, UInt32 keepSizeReserv)
|
||||
{
|
||||
_keepSizeBefore = keepSizeBefore;
|
||||
_keepSizeAfter = keepSizeAfter;
|
||||
UInt32 blockSize = keepSizeBefore + keepSizeAfter + keepSizeReserv;
|
||||
if (_bufferBase == null || _blockSize != blockSize)
|
||||
{
|
||||
Free();
|
||||
_blockSize = blockSize;
|
||||
_bufferBase = new Byte[_blockSize];
|
||||
}
|
||||
_pointerToLastSafePosition = _blockSize - keepSizeAfter;
|
||||
}
|
||||
|
||||
public void SetStream(System.IO.Stream stream) { _stream = stream; }
|
||||
public void ReleaseStream() { _stream = null; }
|
||||
|
||||
public void Init()
|
||||
{
|
||||
_bufferOffset = 0;
|
||||
_pos = 0;
|
||||
_streamPos = 0;
|
||||
_streamEndWasReached = false;
|
||||
ReadBlock();
|
||||
}
|
||||
|
||||
public void MovePos()
|
||||
{
|
||||
_pos++;
|
||||
if (_pos > _posLimit)
|
||||
{
|
||||
UInt32 pointerToPostion = _bufferOffset + _pos;
|
||||
if (pointerToPostion > _pointerToLastSafePosition)
|
||||
MoveBlock();
|
||||
ReadBlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Byte GetIndexByte(Int32 index) { return _bufferBase[_bufferOffset + _pos + index]; }
|
||||
|
||||
// index + limit have not to exceed _keepSizeAfter;
|
||||
public UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit)
|
||||
{
|
||||
if (_streamEndWasReached)
|
||||
if ((_pos + index) + limit > _streamPos)
|
||||
limit = _streamPos - (UInt32)(_pos + index);
|
||||
distance++;
|
||||
// Byte *pby = _buffer + (size_t)_pos + index;
|
||||
UInt32 pby = _bufferOffset + _pos + (UInt32)index;
|
||||
|
||||
UInt32 i;
|
||||
for (i = 0; i < limit && _bufferBase[pby + i] == _bufferBase[pby + i - distance]; i++);
|
||||
return i;
|
||||
}
|
||||
|
||||
public UInt32 GetNumAvailableBytes() { return _streamPos - _pos; }
|
||||
|
||||
public void ReduceOffsets(Int32 subValue)
|
||||
{
|
||||
_bufferOffset += (UInt32)subValue;
|
||||
_posLimit -= (UInt32)subValue;
|
||||
_pos -= (UInt32)subValue;
|
||||
_streamPos -= (UInt32)subValue;
|
||||
}
|
||||
}
|
||||
}
|
110
AssetStudio/7zip/Compress/LZ/LzOutWindow.cs
Normal file
110
AssetStudio/7zip/Compress/LZ/LzOutWindow.cs
Normal file
@ -0,0 +1,110 @@
|
||||
// LzOutWindow.cs
|
||||
|
||||
namespace SevenZip.Compression.LZ
|
||||
{
|
||||
public class OutWindow
|
||||
{
|
||||
byte[] _buffer = null;
|
||||
uint _pos;
|
||||
uint _windowSize = 0;
|
||||
uint _streamPos;
|
||||
System.IO.Stream _stream;
|
||||
|
||||
public uint TrainSize = 0;
|
||||
|
||||
public void Create(uint windowSize)
|
||||
{
|
||||
if (_windowSize != windowSize)
|
||||
{
|
||||
// System.GC.Collect();
|
||||
_buffer = new byte[windowSize];
|
||||
}
|
||||
_windowSize = windowSize;
|
||||
_pos = 0;
|
||||
_streamPos = 0;
|
||||
}
|
||||
|
||||
public void Init(System.IO.Stream stream, bool solid)
|
||||
{
|
||||
ReleaseStream();
|
||||
_stream = stream;
|
||||
if (!solid)
|
||||
{
|
||||
_streamPos = 0;
|
||||
_pos = 0;
|
||||
TrainSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Train(System.IO.Stream stream)
|
||||
{
|
||||
long len = stream.Length;
|
||||
uint size = (len < _windowSize) ? (uint)len : _windowSize;
|
||||
TrainSize = size;
|
||||
stream.Position = len - size;
|
||||
_streamPos = _pos = 0;
|
||||
while (size > 0)
|
||||
{
|
||||
uint curSize = _windowSize - _pos;
|
||||
if (size < curSize)
|
||||
curSize = size;
|
||||
int numReadBytes = stream.Read(_buffer, (int)_pos, (int)curSize);
|
||||
if (numReadBytes == 0)
|
||||
return false;
|
||||
size -= (uint)numReadBytes;
|
||||
_pos += (uint)numReadBytes;
|
||||
_streamPos += (uint)numReadBytes;
|
||||
if (_pos == _windowSize)
|
||||
_streamPos = _pos = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ReleaseStream()
|
||||
{
|
||||
Flush();
|
||||
_stream = null;
|
||||
}
|
||||
|
||||
public void Flush()
|
||||
{
|
||||
uint size = _pos - _streamPos;
|
||||
if (size == 0)
|
||||
return;
|
||||
_stream.Write(_buffer, (int)_streamPos, (int)size);
|
||||
if (_pos >= _windowSize)
|
||||
_pos = 0;
|
||||
_streamPos = _pos;
|
||||
}
|
||||
|
||||
public void CopyBlock(uint distance, uint len)
|
||||
{
|
||||
uint pos = _pos - distance - 1;
|
||||
if (pos >= _windowSize)
|
||||
pos += _windowSize;
|
||||
for (; len > 0; len--)
|
||||
{
|
||||
if (pos >= _windowSize)
|
||||
pos = 0;
|
||||
_buffer[_pos++] = _buffer[pos++];
|
||||
if (_pos >= _windowSize)
|
||||
Flush();
|
||||
}
|
||||
}
|
||||
|
||||
public void PutByte(byte b)
|
||||
{
|
||||
_buffer[_pos++] = b;
|
||||
if (_pos >= _windowSize)
|
||||
Flush();
|
||||
}
|
||||
|
||||
public byte GetByte(uint distance)
|
||||
{
|
||||
uint pos = _pos - distance - 1;
|
||||
if (pos >= _windowSize)
|
||||
pos += _windowSize;
|
||||
return _buffer[pos];
|
||||
}
|
||||
}
|
||||
}
|
76
AssetStudio/7zip/Compress/LZMA/LzmaBase.cs
Normal file
76
AssetStudio/7zip/Compress/LZMA/LzmaBase.cs
Normal file
@ -0,0 +1,76 @@
|
||||
// LzmaBase.cs
|
||||
|
||||
namespace SevenZip.Compression.LZMA
|
||||
{
|
||||
internal abstract class Base
|
||||
{
|
||||
public const uint kNumRepDistances = 4;
|
||||
public const uint kNumStates = 12;
|
||||
|
||||
// static byte []kLiteralNextStates = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5};
|
||||
// static byte []kMatchNextStates = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10};
|
||||
// static byte []kRepNextStates = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11};
|
||||
// static byte []kShortRepNextStates = {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11};
|
||||
|
||||
public struct State
|
||||
{
|
||||
public uint Index;
|
||||
public void Init() { Index = 0; }
|
||||
public void UpdateChar()
|
||||
{
|
||||
if (Index < 4) Index = 0;
|
||||
else if (Index < 10) Index -= 3;
|
||||
else Index -= 6;
|
||||
}
|
||||
public void UpdateMatch() { Index = (uint)(Index < 7 ? 7 : 10); }
|
||||
public void UpdateRep() { Index = (uint)(Index < 7 ? 8 : 11); }
|
||||
public void UpdateShortRep() { Index = (uint)(Index < 7 ? 9 : 11); }
|
||||
public bool IsCharState() { return Index < 7; }
|
||||
}
|
||||
|
||||
public const int kNumPosSlotBits = 6;
|
||||
public const int kDicLogSizeMin = 0;
|
||||
// public const int kDicLogSizeMax = 30;
|
||||
// public const uint kDistTableSizeMax = kDicLogSizeMax * 2;
|
||||
|
||||
public const int kNumLenToPosStatesBits = 2; // it's for speed optimization
|
||||
public const uint kNumLenToPosStates = 1 << kNumLenToPosStatesBits;
|
||||
|
||||
public const uint kMatchMinLen = 2;
|
||||
|
||||
public static uint GetLenToPosState(uint len)
|
||||
{
|
||||
len -= kMatchMinLen;
|
||||
if (len < kNumLenToPosStates)
|
||||
return len;
|
||||
return (uint)(kNumLenToPosStates - 1);
|
||||
}
|
||||
|
||||
public const int kNumAlignBits = 4;
|
||||
public const uint kAlignTableSize = 1 << kNumAlignBits;
|
||||
public const uint kAlignMask = (kAlignTableSize - 1);
|
||||
|
||||
public const uint kStartPosModelIndex = 4;
|
||||
public const uint kEndPosModelIndex = 14;
|
||||
public const uint kNumPosModels = kEndPosModelIndex - kStartPosModelIndex;
|
||||
|
||||
public const uint kNumFullDistances = 1 << ((int)kEndPosModelIndex / 2);
|
||||
|
||||
public const uint kNumLitPosStatesBitsEncodingMax = 4;
|
||||
public const uint kNumLitContextBitsMax = 8;
|
||||
|
||||
public const int kNumPosStatesBitsMax = 4;
|
||||
public const uint kNumPosStatesMax = (1 << kNumPosStatesBitsMax);
|
||||
public const int kNumPosStatesBitsEncodingMax = 4;
|
||||
public const uint kNumPosStatesEncodingMax = (1 << kNumPosStatesBitsEncodingMax);
|
||||
|
||||
public const int kNumLowLenBits = 3;
|
||||
public const int kNumMidLenBits = 3;
|
||||
public const int kNumHighLenBits = 8;
|
||||
public const uint kNumLowLenSymbols = 1 << kNumLowLenBits;
|
||||
public const uint kNumMidLenSymbols = 1 << kNumMidLenBits;
|
||||
public const uint kNumLenSymbols = kNumLowLenSymbols + kNumMidLenSymbols +
|
||||
(1 << kNumHighLenBits);
|
||||
public const uint kMatchMaxLen = kMatchMinLen + kNumLenSymbols - 1;
|
||||
}
|
||||
}
|
398
AssetStudio/7zip/Compress/LZMA/LzmaDecoder.cs
Normal file
398
AssetStudio/7zip/Compress/LZMA/LzmaDecoder.cs
Normal file
@ -0,0 +1,398 @@
|
||||
// LzmaDecoder.cs
|
||||
|
||||
using System;
|
||||
|
||||
namespace SevenZip.Compression.LZMA
|
||||
{
|
||||
using RangeCoder;
|
||||
|
||||
public class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream
|
||||
{
|
||||
class LenDecoder
|
||||
{
|
||||
BitDecoder m_Choice = new BitDecoder();
|
||||
BitDecoder m_Choice2 = new BitDecoder();
|
||||
BitTreeDecoder[] m_LowCoder = new BitTreeDecoder[Base.kNumPosStatesMax];
|
||||
BitTreeDecoder[] m_MidCoder = new BitTreeDecoder[Base.kNumPosStatesMax];
|
||||
BitTreeDecoder m_HighCoder = new BitTreeDecoder(Base.kNumHighLenBits);
|
||||
uint m_NumPosStates = 0;
|
||||
|
||||
public void Create(uint numPosStates)
|
||||
{
|
||||
for (uint posState = m_NumPosStates; posState < numPosStates; posState++)
|
||||
{
|
||||
m_LowCoder[posState] = new BitTreeDecoder(Base.kNumLowLenBits);
|
||||
m_MidCoder[posState] = new BitTreeDecoder(Base.kNumMidLenBits);
|
||||
}
|
||||
m_NumPosStates = numPosStates;
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
m_Choice.Init();
|
||||
for (uint posState = 0; posState < m_NumPosStates; posState++)
|
||||
{
|
||||
m_LowCoder[posState].Init();
|
||||
m_MidCoder[posState].Init();
|
||||
}
|
||||
m_Choice2.Init();
|
||||
m_HighCoder.Init();
|
||||
}
|
||||
|
||||
public uint Decode(RangeCoder.Decoder rangeDecoder, uint posState)
|
||||
{
|
||||
if (m_Choice.Decode(rangeDecoder) == 0)
|
||||
return m_LowCoder[posState].Decode(rangeDecoder);
|
||||
else
|
||||
{
|
||||
uint symbol = Base.kNumLowLenSymbols;
|
||||
if (m_Choice2.Decode(rangeDecoder) == 0)
|
||||
symbol += m_MidCoder[posState].Decode(rangeDecoder);
|
||||
else
|
||||
{
|
||||
symbol += Base.kNumMidLenSymbols;
|
||||
symbol += m_HighCoder.Decode(rangeDecoder);
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class LiteralDecoder
|
||||
{
|
||||
struct Decoder2
|
||||
{
|
||||
BitDecoder[] m_Decoders;
|
||||
public void Create() { m_Decoders = new BitDecoder[0x300]; }
|
||||
public void Init() { for (int i = 0; i < 0x300; i++) m_Decoders[i].Init(); }
|
||||
|
||||
public byte DecodeNormal(RangeCoder.Decoder rangeDecoder)
|
||||
{
|
||||
uint symbol = 1;
|
||||
do
|
||||
symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder);
|
||||
while (symbol < 0x100);
|
||||
return (byte)symbol;
|
||||
}
|
||||
|
||||
public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, byte matchByte)
|
||||
{
|
||||
uint symbol = 1;
|
||||
do
|
||||
{
|
||||
uint matchBit = (uint)(matchByte >> 7) & 1;
|
||||
matchByte <<= 1;
|
||||
uint bit = m_Decoders[((1 + matchBit) << 8) + symbol].Decode(rangeDecoder);
|
||||
symbol = (symbol << 1) | bit;
|
||||
if (matchBit != bit)
|
||||
{
|
||||
while (symbol < 0x100)
|
||||
symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder);
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (symbol < 0x100);
|
||||
return (byte)symbol;
|
||||
}
|
||||
}
|
||||
|
||||
Decoder2[] m_Coders;
|
||||
int m_NumPrevBits;
|
||||
int m_NumPosBits;
|
||||
uint m_PosMask;
|
||||
|
||||
public void Create(int numPosBits, int numPrevBits)
|
||||
{
|
||||
if (m_Coders != null && m_NumPrevBits == numPrevBits &&
|
||||
m_NumPosBits == numPosBits)
|
||||
return;
|
||||
m_NumPosBits = numPosBits;
|
||||
m_PosMask = ((uint)1 << numPosBits) - 1;
|
||||
m_NumPrevBits = numPrevBits;
|
||||
uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);
|
||||
m_Coders = new Decoder2[numStates];
|
||||
for (uint i = 0; i < numStates; i++)
|
||||
m_Coders[i].Create();
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);
|
||||
for (uint i = 0; i < numStates; i++)
|
||||
m_Coders[i].Init();
|
||||
}
|
||||
|
||||
uint GetState(uint pos, byte prevByte)
|
||||
{ return ((pos & m_PosMask) << m_NumPrevBits) + (uint)(prevByte >> (8 - m_NumPrevBits)); }
|
||||
|
||||
public byte DecodeNormal(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte)
|
||||
{ return m_Coders[GetState(pos, prevByte)].DecodeNormal(rangeDecoder); }
|
||||
|
||||
public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte, byte matchByte)
|
||||
{ return m_Coders[GetState(pos, prevByte)].DecodeWithMatchByte(rangeDecoder, matchByte); }
|
||||
};
|
||||
|
||||
LZ.OutWindow m_OutWindow = new LZ.OutWindow();
|
||||
RangeCoder.Decoder m_RangeDecoder = new RangeCoder.Decoder();
|
||||
|
||||
BitDecoder[] m_IsMatchDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax];
|
||||
BitDecoder[] m_IsRepDecoders = new BitDecoder[Base.kNumStates];
|
||||
BitDecoder[] m_IsRepG0Decoders = new BitDecoder[Base.kNumStates];
|
||||
BitDecoder[] m_IsRepG1Decoders = new BitDecoder[Base.kNumStates];
|
||||
BitDecoder[] m_IsRepG2Decoders = new BitDecoder[Base.kNumStates];
|
||||
BitDecoder[] m_IsRep0LongDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax];
|
||||
|
||||
BitTreeDecoder[] m_PosSlotDecoder = new BitTreeDecoder[Base.kNumLenToPosStates];
|
||||
BitDecoder[] m_PosDecoders = new BitDecoder[Base.kNumFullDistances - Base.kEndPosModelIndex];
|
||||
|
||||
BitTreeDecoder m_PosAlignDecoder = new BitTreeDecoder(Base.kNumAlignBits);
|
||||
|
||||
LenDecoder m_LenDecoder = new LenDecoder();
|
||||
LenDecoder m_RepLenDecoder = new LenDecoder();
|
||||
|
||||
LiteralDecoder m_LiteralDecoder = new LiteralDecoder();
|
||||
|
||||
uint m_DictionarySize;
|
||||
uint m_DictionarySizeCheck;
|
||||
|
||||
uint m_PosStateMask;
|
||||
|
||||
public Decoder()
|
||||
{
|
||||
m_DictionarySize = 0xFFFFFFFF;
|
||||
for (int i = 0; i < Base.kNumLenToPosStates; i++)
|
||||
m_PosSlotDecoder[i] = new BitTreeDecoder(Base.kNumPosSlotBits);
|
||||
}
|
||||
|
||||
void SetDictionarySize(uint dictionarySize)
|
||||
{
|
||||
if (m_DictionarySize != dictionarySize)
|
||||
{
|
||||
m_DictionarySize = dictionarySize;
|
||||
m_DictionarySizeCheck = Math.Max(m_DictionarySize, 1);
|
||||
uint blockSize = Math.Max(m_DictionarySizeCheck, (1 << 12));
|
||||
m_OutWindow.Create(blockSize);
|
||||
}
|
||||
}
|
||||
|
||||
void SetLiteralProperties(int lp, int lc)
|
||||
{
|
||||
if (lp > 8)
|
||||
throw new InvalidParamException();
|
||||
if (lc > 8)
|
||||
throw new InvalidParamException();
|
||||
m_LiteralDecoder.Create(lp, lc);
|
||||
}
|
||||
|
||||
void SetPosBitsProperties(int pb)
|
||||
{
|
||||
if (pb > Base.kNumPosStatesBitsMax)
|
||||
throw new InvalidParamException();
|
||||
uint numPosStates = (uint)1 << pb;
|
||||
m_LenDecoder.Create(numPosStates);
|
||||
m_RepLenDecoder.Create(numPosStates);
|
||||
m_PosStateMask = numPosStates - 1;
|
||||
}
|
||||
|
||||
bool _solid = false;
|
||||
void Init(System.IO.Stream inStream, System.IO.Stream outStream)
|
||||
{
|
||||
m_RangeDecoder.Init(inStream);
|
||||
m_OutWindow.Init(outStream, _solid);
|
||||
|
||||
uint i;
|
||||
for (i = 0; i < Base.kNumStates; i++)
|
||||
{
|
||||
for (uint j = 0; j <= m_PosStateMask; j++)
|
||||
{
|
||||
uint index = (i << Base.kNumPosStatesBitsMax) + j;
|
||||
m_IsMatchDecoders[index].Init();
|
||||
m_IsRep0LongDecoders[index].Init();
|
||||
}
|
||||
m_IsRepDecoders[i].Init();
|
||||
m_IsRepG0Decoders[i].Init();
|
||||
m_IsRepG1Decoders[i].Init();
|
||||
m_IsRepG2Decoders[i].Init();
|
||||
}
|
||||
|
||||
m_LiteralDecoder.Init();
|
||||
for (i = 0; i < Base.kNumLenToPosStates; i++)
|
||||
m_PosSlotDecoder[i].Init();
|
||||
// m_PosSpecDecoder.Init();
|
||||
for (i = 0; i < Base.kNumFullDistances - Base.kEndPosModelIndex; i++)
|
||||
m_PosDecoders[i].Init();
|
||||
|
||||
m_LenDecoder.Init();
|
||||
m_RepLenDecoder.Init();
|
||||
m_PosAlignDecoder.Init();
|
||||
}
|
||||
|
||||
public void Code(System.IO.Stream inStream, System.IO.Stream outStream,
|
||||
Int64 inSize, Int64 outSize, ICodeProgress progress)
|
||||
{
|
||||
Init(inStream, outStream);
|
||||
|
||||
Base.State state = new Base.State();
|
||||
state.Init();
|
||||
uint rep0 = 0, rep1 = 0, rep2 = 0, rep3 = 0;
|
||||
|
||||
UInt64 nowPos64 = 0;
|
||||
UInt64 outSize64 = (UInt64)outSize;
|
||||
if (nowPos64 < outSize64)
|
||||
{
|
||||
if (m_IsMatchDecoders[state.Index << Base.kNumPosStatesBitsMax].Decode(m_RangeDecoder) != 0)
|
||||
throw new DataErrorException();
|
||||
state.UpdateChar();
|
||||
byte b = m_LiteralDecoder.DecodeNormal(m_RangeDecoder, 0, 0);
|
||||
m_OutWindow.PutByte(b);
|
||||
nowPos64++;
|
||||
}
|
||||
while (nowPos64 < outSize64)
|
||||
{
|
||||
// UInt64 next = Math.Min(nowPos64 + (1 << 18), outSize64);
|
||||
// while(nowPos64 < next)
|
||||
{
|
||||
uint posState = (uint)nowPos64 & m_PosStateMask;
|
||||
if (m_IsMatchDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode(m_RangeDecoder) == 0)
|
||||
{
|
||||
byte b;
|
||||
byte prevByte = m_OutWindow.GetByte(0);
|
||||
if (!state.IsCharState())
|
||||
b = m_LiteralDecoder.DecodeWithMatchByte(m_RangeDecoder,
|
||||
(uint)nowPos64, prevByte, m_OutWindow.GetByte(rep0));
|
||||
else
|
||||
b = m_LiteralDecoder.DecodeNormal(m_RangeDecoder, (uint)nowPos64, prevByte);
|
||||
m_OutWindow.PutByte(b);
|
||||
state.UpdateChar();
|
||||
nowPos64++;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint len;
|
||||
if (m_IsRepDecoders[state.Index].Decode(m_RangeDecoder) == 1)
|
||||
{
|
||||
if (m_IsRepG0Decoders[state.Index].Decode(m_RangeDecoder) == 0)
|
||||
{
|
||||
if (m_IsRep0LongDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode(m_RangeDecoder) == 0)
|
||||
{
|
||||
state.UpdateShortRep();
|
||||
m_OutWindow.PutByte(m_OutWindow.GetByte(rep0));
|
||||
nowPos64++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt32 distance;
|
||||
if (m_IsRepG1Decoders[state.Index].Decode(m_RangeDecoder) == 0)
|
||||
{
|
||||
distance = rep1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_IsRepG2Decoders[state.Index].Decode(m_RangeDecoder) == 0)
|
||||
distance = rep2;
|
||||
else
|
||||
{
|
||||
distance = rep3;
|
||||
rep3 = rep2;
|
||||
}
|
||||
rep2 = rep1;
|
||||
}
|
||||
rep1 = rep0;
|
||||
rep0 = distance;
|
||||
}
|
||||
len = m_RepLenDecoder.Decode(m_RangeDecoder, posState) + Base.kMatchMinLen;
|
||||
state.UpdateRep();
|
||||
}
|
||||
else
|
||||
{
|
||||
rep3 = rep2;
|
||||
rep2 = rep1;
|
||||
rep1 = rep0;
|
||||
len = Base.kMatchMinLen + m_LenDecoder.Decode(m_RangeDecoder, posState);
|
||||
state.UpdateMatch();
|
||||
uint posSlot = m_PosSlotDecoder[Base.GetLenToPosState(len)].Decode(m_RangeDecoder);
|
||||
if (posSlot >= Base.kStartPosModelIndex)
|
||||
{
|
||||
int numDirectBits = (int)((posSlot >> 1) - 1);
|
||||
rep0 = ((2 | (posSlot & 1)) << numDirectBits);
|
||||
if (posSlot < Base.kEndPosModelIndex)
|
||||
rep0 += BitTreeDecoder.ReverseDecode(m_PosDecoders,
|
||||
rep0 - posSlot - 1, m_RangeDecoder, numDirectBits);
|
||||
else
|
||||
{
|
||||
rep0 += (m_RangeDecoder.DecodeDirectBits(
|
||||
numDirectBits - Base.kNumAlignBits) << Base.kNumAlignBits);
|
||||
rep0 += m_PosAlignDecoder.ReverseDecode(m_RangeDecoder);
|
||||
}
|
||||
}
|
||||
else
|
||||
rep0 = posSlot;
|
||||
}
|
||||
if (rep0 >= m_OutWindow.TrainSize + nowPos64 || rep0 >= m_DictionarySizeCheck)
|
||||
{
|
||||
if (rep0 == 0xFFFFFFFF)
|
||||
break;
|
||||
throw new DataErrorException();
|
||||
}
|
||||
m_OutWindow.CopyBlock(rep0, len);
|
||||
nowPos64 += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_OutWindow.Flush();
|
||||
m_OutWindow.ReleaseStream();
|
||||
m_RangeDecoder.ReleaseStream();
|
||||
}
|
||||
|
||||
public void SetDecoderProperties(byte[] properties)
|
||||
{
|
||||
if (properties.Length < 5)
|
||||
throw new InvalidParamException();
|
||||
int lc = properties[0] % 9;
|
||||
int remainder = properties[0] / 9;
|
||||
int lp = remainder % 5;
|
||||
int pb = remainder / 5;
|
||||
if (pb > Base.kNumPosStatesBitsMax)
|
||||
throw new InvalidParamException();
|
||||
UInt32 dictionarySize = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
dictionarySize += ((UInt32)(properties[1 + i])) << (i * 8);
|
||||
SetDictionarySize(dictionarySize);
|
||||
SetLiteralProperties(lp, lc);
|
||||
SetPosBitsProperties(pb);
|
||||
}
|
||||
|
||||
public bool Train(System.IO.Stream stream)
|
||||
{
|
||||
_solid = true;
|
||||
return m_OutWindow.Train(stream);
|
||||
}
|
||||
|
||||
/*
|
||||
public override bool CanRead { get { return true; }}
|
||||
public override bool CanWrite { get { return true; }}
|
||||
public override bool CanSeek { get { return true; }}
|
||||
public override long Length { get { return 0; }}
|
||||
public override long Position
|
||||
{
|
||||
get { return 0; }
|
||||
set { }
|
||||
}
|
||||
public override void Flush() { }
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
}
|
||||
public override long Seek(long offset, System.IO.SeekOrigin origin)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
public override void SetLength(long value) {}
|
||||
*/
|
||||
}
|
||||
}
|
1480
AssetStudio/7zip/Compress/LZMA/LzmaEncoder.cs
Normal file
1480
AssetStudio/7zip/Compress/LZMA/LzmaEncoder.cs
Normal file
File diff suppressed because it is too large
Load Diff
234
AssetStudio/7zip/Compress/RangeCoder/RangeCoder.cs
Normal file
234
AssetStudio/7zip/Compress/RangeCoder/RangeCoder.cs
Normal file
@ -0,0 +1,234 @@
|
||||
using System;
|
||||
|
||||
namespace SevenZip.Compression.RangeCoder
|
||||
{
|
||||
class Encoder
|
||||
{
|
||||
public const uint kTopValue = (1 << 24);
|
||||
|
||||
System.IO.Stream Stream;
|
||||
|
||||
public UInt64 Low;
|
||||
public uint Range;
|
||||
uint _cacheSize;
|
||||
byte _cache;
|
||||
|
||||
long StartPosition;
|
||||
|
||||
public void SetStream(System.IO.Stream stream)
|
||||
{
|
||||
Stream = stream;
|
||||
}
|
||||
|
||||
public void ReleaseStream()
|
||||
{
|
||||
Stream = null;
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
StartPosition = Stream.Position;
|
||||
|
||||
Low = 0;
|
||||
Range = 0xFFFFFFFF;
|
||||
_cacheSize = 1;
|
||||
_cache = 0;
|
||||
}
|
||||
|
||||
public void FlushData()
|
||||
{
|
||||
for (int i = 0; i < 5; i++)
|
||||
ShiftLow();
|
||||
}
|
||||
|
||||
public void FlushStream()
|
||||
{
|
||||
Stream.Flush();
|
||||
}
|
||||
|
||||
public void CloseStream()
|
||||
{
|
||||
Stream.Close();
|
||||
}
|
||||
|
||||
public void Encode(uint start, uint size, uint total)
|
||||
{
|
||||
Low += start * (Range /= total);
|
||||
Range *= size;
|
||||
while (Range < kTopValue)
|
||||
{
|
||||
Range <<= 8;
|
||||
ShiftLow();
|
||||
}
|
||||
}
|
||||
|
||||
public void ShiftLow()
|
||||
{
|
||||
if ((uint)Low < (uint)0xFF000000 || (uint)(Low >> 32) == 1)
|
||||
{
|
||||
byte temp = _cache;
|
||||
do
|
||||
{
|
||||
Stream.WriteByte((byte)(temp + (Low >> 32)));
|
||||
temp = 0xFF;
|
||||
}
|
||||
while (--_cacheSize != 0);
|
||||
_cache = (byte)(((uint)Low) >> 24);
|
||||
}
|
||||
_cacheSize++;
|
||||
Low = ((uint)Low) << 8;
|
||||
}
|
||||
|
||||
public void EncodeDirectBits(uint v, int numTotalBits)
|
||||
{
|
||||
for (int i = numTotalBits - 1; i >= 0; i--)
|
||||
{
|
||||
Range >>= 1;
|
||||
if (((v >> i) & 1) == 1)
|
||||
Low += Range;
|
||||
if (Range < kTopValue)
|
||||
{
|
||||
Range <<= 8;
|
||||
ShiftLow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void EncodeBit(uint size0, int numTotalBits, uint symbol)
|
||||
{
|
||||
uint newBound = (Range >> numTotalBits) * size0;
|
||||
if (symbol == 0)
|
||||
Range = newBound;
|
||||
else
|
||||
{
|
||||
Low += newBound;
|
||||
Range -= newBound;
|
||||
}
|
||||
while (Range < kTopValue)
|
||||
{
|
||||
Range <<= 8;
|
||||
ShiftLow();
|
||||
}
|
||||
}
|
||||
|
||||
public long GetProcessedSizeAdd()
|
||||
{
|
||||
return _cacheSize +
|
||||
Stream.Position - StartPosition + 4;
|
||||
// (long)Stream.GetProcessedSize();
|
||||
}
|
||||
}
|
||||
|
||||
class Decoder
|
||||
{
|
||||
public const uint kTopValue = (1 << 24);
|
||||
public uint Range;
|
||||
public uint Code;
|
||||
// public Buffer.InBuffer Stream = new Buffer.InBuffer(1 << 16);
|
||||
public System.IO.Stream Stream;
|
||||
|
||||
public void Init(System.IO.Stream stream)
|
||||
{
|
||||
// Stream.Init(stream);
|
||||
Stream = stream;
|
||||
|
||||
Code = 0;
|
||||
Range = 0xFFFFFFFF;
|
||||
for (int i = 0; i < 5; i++)
|
||||
Code = (Code << 8) | (byte)Stream.ReadByte();
|
||||
}
|
||||
|
||||
public void ReleaseStream()
|
||||
{
|
||||
// Stream.ReleaseStream();
|
||||
Stream = null;
|
||||
}
|
||||
|
||||
public void CloseStream()
|
||||
{
|
||||
Stream.Close();
|
||||
}
|
||||
|
||||
public void Normalize()
|
||||
{
|
||||
while (Range < kTopValue)
|
||||
{
|
||||
Code = (Code << 8) | (byte)Stream.ReadByte();
|
||||
Range <<= 8;
|
||||
}
|
||||
}
|
||||
|
||||
public void Normalize2()
|
||||
{
|
||||
if (Range < kTopValue)
|
||||
{
|
||||
Code = (Code << 8) | (byte)Stream.ReadByte();
|
||||
Range <<= 8;
|
||||
}
|
||||
}
|
||||
|
||||
public uint GetThreshold(uint total)
|
||||
{
|
||||
return Code / (Range /= total);
|
||||
}
|
||||
|
||||
public void Decode(uint start, uint size, uint total)
|
||||
{
|
||||
Code -= start * Range;
|
||||
Range *= size;
|
||||
Normalize();
|
||||
}
|
||||
|
||||
public uint DecodeDirectBits(int numTotalBits)
|
||||
{
|
||||
uint range = Range;
|
||||
uint code = Code;
|
||||
uint result = 0;
|
||||
for (int i = numTotalBits; i > 0; i--)
|
||||
{
|
||||
range >>= 1;
|
||||
/*
|
||||
result <<= 1;
|
||||
if (code >= range)
|
||||
{
|
||||
code -= range;
|
||||
result |= 1;
|
||||
}
|
||||
*/
|
||||
uint t = (code - range) >> 31;
|
||||
code -= range & (t - 1);
|
||||
result = (result << 1) | (1 - t);
|
||||
|
||||
if (range < kTopValue)
|
||||
{
|
||||
code = (code << 8) | (byte)Stream.ReadByte();
|
||||
range <<= 8;
|
||||
}
|
||||
}
|
||||
Range = range;
|
||||
Code = code;
|
||||
return result;
|
||||
}
|
||||
|
||||
public uint DecodeBit(uint size0, int numTotalBits)
|
||||
{
|
||||
uint newBound = (Range >> numTotalBits) * size0;
|
||||
uint symbol;
|
||||
if (Code < newBound)
|
||||
{
|
||||
symbol = 0;
|
||||
Range = newBound;
|
||||
}
|
||||
else
|
||||
{
|
||||
symbol = 1;
|
||||
Code -= newBound;
|
||||
Range -= newBound;
|
||||
}
|
||||
Normalize();
|
||||
return symbol;
|
||||
}
|
||||
|
||||
// ulong GetProcessedSize() {return Stream.GetProcessedSize(); }
|
||||
}
|
||||
}
|
117
AssetStudio/7zip/Compress/RangeCoder/RangeCoderBit.cs
Normal file
117
AssetStudio/7zip/Compress/RangeCoder/RangeCoderBit.cs
Normal file
@ -0,0 +1,117 @@
|
||||
using System;
|
||||
|
||||
namespace SevenZip.Compression.RangeCoder
|
||||
{
|
||||
struct BitEncoder
|
||||
{
|
||||
public const int kNumBitModelTotalBits = 11;
|
||||
public const uint kBitModelTotal = (1 << kNumBitModelTotalBits);
|
||||
const int kNumMoveBits = 5;
|
||||
const int kNumMoveReducingBits = 2;
|
||||
public const int kNumBitPriceShiftBits = 6;
|
||||
|
||||
uint Prob;
|
||||
|
||||
public void Init() { Prob = kBitModelTotal >> 1; }
|
||||
|
||||
public void UpdateModel(uint symbol)
|
||||
{
|
||||
if (symbol == 0)
|
||||
Prob += (kBitModelTotal - Prob) >> kNumMoveBits;
|
||||
else
|
||||
Prob -= (Prob) >> kNumMoveBits;
|
||||
}
|
||||
|
||||
public void Encode(Encoder encoder, uint symbol)
|
||||
{
|
||||
// encoder.EncodeBit(Prob, kNumBitModelTotalBits, symbol);
|
||||
// UpdateModel(symbol);
|
||||
uint newBound = (encoder.Range >> kNumBitModelTotalBits) * Prob;
|
||||
if (symbol == 0)
|
||||
{
|
||||
encoder.Range = newBound;
|
||||
Prob += (kBitModelTotal - Prob) >> kNumMoveBits;
|
||||
}
|
||||
else
|
||||
{
|
||||
encoder.Low += newBound;
|
||||
encoder.Range -= newBound;
|
||||
Prob -= (Prob) >> kNumMoveBits;
|
||||
}
|
||||
if (encoder.Range < Encoder.kTopValue)
|
||||
{
|
||||
encoder.Range <<= 8;
|
||||
encoder.ShiftLow();
|
||||
}
|
||||
}
|
||||
|
||||
private static UInt32[] ProbPrices = new UInt32[kBitModelTotal >> kNumMoveReducingBits];
|
||||
|
||||
static BitEncoder()
|
||||
{
|
||||
const int kNumBits = (kNumBitModelTotalBits - kNumMoveReducingBits);
|
||||
for (int i = kNumBits - 1; i >= 0; i--)
|
||||
{
|
||||
UInt32 start = (UInt32)1 << (kNumBits - i - 1);
|
||||
UInt32 end = (UInt32)1 << (kNumBits - i);
|
||||
for (UInt32 j = start; j < end; j++)
|
||||
ProbPrices[j] = ((UInt32)i << kNumBitPriceShiftBits) +
|
||||
(((end - j) << kNumBitPriceShiftBits) >> (kNumBits - i - 1));
|
||||
}
|
||||
}
|
||||
|
||||
public uint GetPrice(uint symbol)
|
||||
{
|
||||
return ProbPrices[(((Prob - symbol) ^ ((-(int)symbol))) & (kBitModelTotal - 1)) >> kNumMoveReducingBits];
|
||||
}
|
||||
public uint GetPrice0() { return ProbPrices[Prob >> kNumMoveReducingBits]; }
|
||||
public uint GetPrice1() { return ProbPrices[(kBitModelTotal - Prob) >> kNumMoveReducingBits]; }
|
||||
}
|
||||
|
||||
struct BitDecoder
|
||||
{
|
||||
public const int kNumBitModelTotalBits = 11;
|
||||
public const uint kBitModelTotal = (1 << kNumBitModelTotalBits);
|
||||
const int kNumMoveBits = 5;
|
||||
|
||||
uint Prob;
|
||||
|
||||
public void UpdateModel(int numMoveBits, uint symbol)
|
||||
{
|
||||
if (symbol == 0)
|
||||
Prob += (kBitModelTotal - Prob) >> numMoveBits;
|
||||
else
|
||||
Prob -= (Prob) >> numMoveBits;
|
||||
}
|
||||
|
||||
public void Init() { Prob = kBitModelTotal >> 1; }
|
||||
|
||||
public uint Decode(RangeCoder.Decoder rangeDecoder)
|
||||
{
|
||||
uint newBound = (uint)(rangeDecoder.Range >> kNumBitModelTotalBits) * (uint)Prob;
|
||||
if (rangeDecoder.Code < newBound)
|
||||
{
|
||||
rangeDecoder.Range = newBound;
|
||||
Prob += (kBitModelTotal - Prob) >> kNumMoveBits;
|
||||
if (rangeDecoder.Range < Decoder.kTopValue)
|
||||
{
|
||||
rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte();
|
||||
rangeDecoder.Range <<= 8;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
rangeDecoder.Range -= newBound;
|
||||
rangeDecoder.Code -= newBound;
|
||||
Prob -= (Prob) >> kNumMoveBits;
|
||||
if (rangeDecoder.Range < Decoder.kTopValue)
|
||||
{
|
||||
rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte();
|
||||
rangeDecoder.Range <<= 8;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
157
AssetStudio/7zip/Compress/RangeCoder/RangeCoderBitTree.cs
Normal file
157
AssetStudio/7zip/Compress/RangeCoder/RangeCoderBitTree.cs
Normal file
@ -0,0 +1,157 @@
|
||||
using System;
|
||||
|
||||
namespace SevenZip.Compression.RangeCoder
|
||||
{
|
||||
struct BitTreeEncoder
|
||||
{
|
||||
BitEncoder[] Models;
|
||||
int NumBitLevels;
|
||||
|
||||
public BitTreeEncoder(int numBitLevels)
|
||||
{
|
||||
NumBitLevels = numBitLevels;
|
||||
Models = new BitEncoder[1 << numBitLevels];
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
for (uint i = 1; i < (1 << NumBitLevels); i++)
|
||||
Models[i].Init();
|
||||
}
|
||||
|
||||
public void Encode(Encoder rangeEncoder, UInt32 symbol)
|
||||
{
|
||||
UInt32 m = 1;
|
||||
for (int bitIndex = NumBitLevels; bitIndex > 0; )
|
||||
{
|
||||
bitIndex--;
|
||||
UInt32 bit = (symbol >> bitIndex) & 1;
|
||||
Models[m].Encode(rangeEncoder, bit);
|
||||
m = (m << 1) | bit;
|
||||
}
|
||||
}
|
||||
|
||||
public void ReverseEncode(Encoder rangeEncoder, UInt32 symbol)
|
||||
{
|
||||
UInt32 m = 1;
|
||||
for (UInt32 i = 0; i < NumBitLevels; i++)
|
||||
{
|
||||
UInt32 bit = symbol & 1;
|
||||
Models[m].Encode(rangeEncoder, bit);
|
||||
m = (m << 1) | bit;
|
||||
symbol >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
public UInt32 GetPrice(UInt32 symbol)
|
||||
{
|
||||
UInt32 price = 0;
|
||||
UInt32 m = 1;
|
||||
for (int bitIndex = NumBitLevels; bitIndex > 0; )
|
||||
{
|
||||
bitIndex--;
|
||||
UInt32 bit = (symbol >> bitIndex) & 1;
|
||||
price += Models[m].GetPrice(bit);
|
||||
m = (m << 1) + bit;
|
||||
}
|
||||
return price;
|
||||
}
|
||||
|
||||
public UInt32 ReverseGetPrice(UInt32 symbol)
|
||||
{
|
||||
UInt32 price = 0;
|
||||
UInt32 m = 1;
|
||||
for (int i = NumBitLevels; i > 0; i--)
|
||||
{
|
||||
UInt32 bit = symbol & 1;
|
||||
symbol >>= 1;
|
||||
price += Models[m].GetPrice(bit);
|
||||
m = (m << 1) | bit;
|
||||
}
|
||||
return price;
|
||||
}
|
||||
|
||||
public static UInt32 ReverseGetPrice(BitEncoder[] Models, UInt32 startIndex,
|
||||
int NumBitLevels, UInt32 symbol)
|
||||
{
|
||||
UInt32 price = 0;
|
||||
UInt32 m = 1;
|
||||
for (int i = NumBitLevels; i > 0; i--)
|
||||
{
|
||||
UInt32 bit = symbol & 1;
|
||||
symbol >>= 1;
|
||||
price += Models[startIndex + m].GetPrice(bit);
|
||||
m = (m << 1) | bit;
|
||||
}
|
||||
return price;
|
||||
}
|
||||
|
||||
public static void ReverseEncode(BitEncoder[] Models, UInt32 startIndex,
|
||||
Encoder rangeEncoder, int NumBitLevels, UInt32 symbol)
|
||||
{
|
||||
UInt32 m = 1;
|
||||
for (int i = 0; i < NumBitLevels; i++)
|
||||
{
|
||||
UInt32 bit = symbol & 1;
|
||||
Models[startIndex + m].Encode(rangeEncoder, bit);
|
||||
m = (m << 1) | bit;
|
||||
symbol >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct BitTreeDecoder
|
||||
{
|
||||
BitDecoder[] Models;
|
||||
int NumBitLevels;
|
||||
|
||||
public BitTreeDecoder(int numBitLevels)
|
||||
{
|
||||
NumBitLevels = numBitLevels;
|
||||
Models = new BitDecoder[1 << numBitLevels];
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
for (uint i = 1; i < (1 << NumBitLevels); i++)
|
||||
Models[i].Init();
|
||||
}
|
||||
|
||||
public uint Decode(RangeCoder.Decoder rangeDecoder)
|
||||
{
|
||||
uint m = 1;
|
||||
for (int bitIndex = NumBitLevels; bitIndex > 0; bitIndex--)
|
||||
m = (m << 1) + Models[m].Decode(rangeDecoder);
|
||||
return m - ((uint)1 << NumBitLevels);
|
||||
}
|
||||
|
||||
public uint ReverseDecode(RangeCoder.Decoder rangeDecoder)
|
||||
{
|
||||
uint m = 1;
|
||||
uint symbol = 0;
|
||||
for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
|
||||
{
|
||||
uint bit = Models[m].Decode(rangeDecoder);
|
||||
m <<= 1;
|
||||
m += bit;
|
||||
symbol |= (bit << bitIndex);
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
|
||||
public static uint ReverseDecode(BitDecoder[] Models, UInt32 startIndex,
|
||||
RangeCoder.Decoder rangeDecoder, int NumBitLevels)
|
||||
{
|
||||
uint m = 1;
|
||||
uint symbol = 0;
|
||||
for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
|
||||
{
|
||||
uint bit = Models[startIndex + m].Decode(rangeDecoder);
|
||||
m <<= 1;
|
||||
m += bit;
|
||||
symbol |= (bit << bitIndex);
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
}
|
157
AssetStudio/7zip/ICoder.cs
Normal file
157
AssetStudio/7zip/ICoder.cs
Normal file
@ -0,0 +1,157 @@
|
||||
// ICoder.h
|
||||
|
||||
using System;
|
||||
|
||||
namespace SevenZip
|
||||
{
|
||||
/// <summary>
|
||||
/// The exception that is thrown when an error in input stream occurs during decoding.
|
||||
/// </summary>
|
||||
class DataErrorException : ApplicationException
|
||||
{
|
||||
public DataErrorException(): base("Data Error") { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The exception that is thrown when the value of an argument is outside the allowable range.
|
||||
/// </summary>
|
||||
class InvalidParamException : ApplicationException
|
||||
{
|
||||
public InvalidParamException(): base("Invalid Parameter") { }
|
||||
}
|
||||
|
||||
public interface ICodeProgress
|
||||
{
|
||||
/// <summary>
|
||||
/// Callback progress.
|
||||
/// </summary>
|
||||
/// <param name="inSize">
|
||||
/// input size. -1 if unknown.
|
||||
/// </param>
|
||||
/// <param name="outSize">
|
||||
/// output size. -1 if unknown.
|
||||
/// </param>
|
||||
void SetProgress(Int64 inSize, Int64 outSize);
|
||||
};
|
||||
|
||||
public interface ICoder
|
||||
{
|
||||
/// <summary>
|
||||
/// Codes streams.
|
||||
/// </summary>
|
||||
/// <param name="inStream">
|
||||
/// input Stream.
|
||||
/// </param>
|
||||
/// <param name="outStream">
|
||||
/// output Stream.
|
||||
/// </param>
|
||||
/// <param name="inSize">
|
||||
/// input Size. -1 if unknown.
|
||||
/// </param>
|
||||
/// <param name="outSize">
|
||||
/// output Size. -1 if unknown.
|
||||
/// </param>
|
||||
/// <param name="progress">
|
||||
/// callback progress reference.
|
||||
/// </param>
|
||||
/// <exception cref="SevenZip.DataErrorException">
|
||||
/// if input stream is not valid
|
||||
/// </exception>
|
||||
void Code(System.IO.Stream inStream, System.IO.Stream outStream,
|
||||
Int64 inSize, Int64 outSize, ICodeProgress progress);
|
||||
};
|
||||
|
||||
/*
|
||||
public interface ICoder2
|
||||
{
|
||||
void Code(ISequentialInStream []inStreams,
|
||||
const UInt64 []inSizes,
|
||||
ISequentialOutStream []outStreams,
|
||||
UInt64 []outSizes,
|
||||
ICodeProgress progress);
|
||||
};
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// Provides the fields that represent properties idenitifiers for compressing.
|
||||
/// </summary>
|
||||
public enum CoderPropID
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies default property.
|
||||
/// </summary>
|
||||
DefaultProp = 0,
|
||||
/// <summary>
|
||||
/// Specifies size of dictionary.
|
||||
/// </summary>
|
||||
DictionarySize,
|
||||
/// <summary>
|
||||
/// Specifies size of memory for PPM*.
|
||||
/// </summary>
|
||||
UsedMemorySize,
|
||||
/// <summary>
|
||||
/// Specifies order for PPM methods.
|
||||
/// </summary>
|
||||
Order,
|
||||
/// <summary>
|
||||
/// Specifies Block Size.
|
||||
/// </summary>
|
||||
BlockSize,
|
||||
/// <summary>
|
||||
/// Specifies number of postion state bits for LZMA (0 <= x <= 4).
|
||||
/// </summary>
|
||||
PosStateBits,
|
||||
/// <summary>
|
||||
/// Specifies number of literal context bits for LZMA (0 <= x <= 8).
|
||||
/// </summary>
|
||||
LitContextBits,
|
||||
/// <summary>
|
||||
/// Specifies number of literal position bits for LZMA (0 <= x <= 4).
|
||||
/// </summary>
|
||||
LitPosBits,
|
||||
/// <summary>
|
||||
/// Specifies number of fast bytes for LZ*.
|
||||
/// </summary>
|
||||
NumFastBytes,
|
||||
/// <summary>
|
||||
/// Specifies match finder. LZMA: "BT2", "BT4" or "BT4B".
|
||||
/// </summary>
|
||||
MatchFinder,
|
||||
/// <summary>
|
||||
/// Specifies the number of match finder cyckes.
|
||||
/// </summary>
|
||||
MatchFinderCycles,
|
||||
/// <summary>
|
||||
/// Specifies number of passes.
|
||||
/// </summary>
|
||||
NumPasses,
|
||||
/// <summary>
|
||||
/// Specifies number of algorithm.
|
||||
/// </summary>
|
||||
Algorithm,
|
||||
/// <summary>
|
||||
/// Specifies the number of threads.
|
||||
/// </summary>
|
||||
NumThreads,
|
||||
/// <summary>
|
||||
/// Specifies mode with end marker.
|
||||
/// </summary>
|
||||
EndMarker
|
||||
};
|
||||
|
||||
|
||||
public interface ISetCoderProperties
|
||||
{
|
||||
void SetCoderProperties(CoderPropID[] propIDs, object[] properties);
|
||||
};
|
||||
|
||||
public interface IWriteCoderProperties
|
||||
{
|
||||
void WriteCoderProperties(System.IO.Stream outStream);
|
||||
}
|
||||
|
||||
public interface ISetDecoderProperties
|
||||
{
|
||||
void SetDecoderProperties(byte[] properties);
|
||||
}
|
||||
}
|
231
AssetStudio/AIVersionManager.cs
Normal file
231
AssetStudio/AIVersionManager.cs
Normal file
@ -0,0 +1,231 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using System.Net.Http;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public static class AIVersionManager
|
||||
{
|
||||
private const string BaseUrl = "https://raw.githubusercontent.com/14eyes/gi-asset-indexes/master/";
|
||||
private const string CommitsUrl = "https://api.github.com/repos/14eyes/gi-asset-indexes/commits?path=";
|
||||
private const string VersionIndexName = "version-index.json";
|
||||
private const string VersionIndexKey = "index";
|
||||
|
||||
private static readonly string BaseAIFolder = Path.Combine(Environment.CurrentDirectory, "AI");
|
||||
private static readonly string VersionsPath = Path.Combine(BaseAIFolder, "versions.json");
|
||||
|
||||
private static readonly HttpClient Client;
|
||||
|
||||
private static Dictionary<string, VersionIndex> Versions;
|
||||
|
||||
static AIVersionManager()
|
||||
{
|
||||
Client = new HttpClient();
|
||||
Client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (compatible; MSIE 6.0; Windows 98; Trident/5.1)");
|
||||
Versions = new Dictionary<string, VersionIndex>();
|
||||
}
|
||||
|
||||
public static List<(string, bool)> GetVersions()
|
||||
{
|
||||
var versions = new List<(string, bool)>();
|
||||
var cachedVersions = LoadVersions();
|
||||
foreach (var version in Versions)
|
||||
{
|
||||
versions.Add((version.Key, cachedVersions.ContainsKey(version.Key)));
|
||||
}
|
||||
return versions;
|
||||
}
|
||||
public static async Task<bool> FetchVersions()
|
||||
{
|
||||
var versions = "";
|
||||
var url = Path.Combine(BaseUrl, VersionIndexName);
|
||||
var path = GetPath(VersionIndexKey);
|
||||
if (await NeedDownload(VersionIndexKey, VersionIndexName))
|
||||
{
|
||||
versions = await DownloadString(url, TimeSpan.FromSeconds(2));
|
||||
if (string.IsNullOrEmpty(versions))
|
||||
{
|
||||
Logger.Warning("Could not load AI versions !!");
|
||||
return false;
|
||||
}
|
||||
if (!await StoreCommit(VersionIndexKey, VersionIndexName))
|
||||
{
|
||||
throw new Exception("Failed to store version list !!");
|
||||
}
|
||||
File.WriteAllText(path, versions);
|
||||
}
|
||||
else
|
||||
{
|
||||
versions = File.ReadAllText(path);
|
||||
}
|
||||
Versions = JsonConvert.DeserializeObject<List<VersionIndex>>(versions).ToDictionary(x => x.Version, x => x);
|
||||
return Versions.Count > 0;
|
||||
}
|
||||
|
||||
public static async Task<string> FetchAI(string version)
|
||||
{
|
||||
var path = "";
|
||||
if (Versions.TryGetValue(version, out var versionIndex))
|
||||
{
|
||||
var url = Path.Combine(BaseUrl, versionIndex.MappedPath);
|
||||
path = GetPath(version);
|
||||
if (await NeedDownload(version, versionIndex.MappedPath))
|
||||
{
|
||||
Logger.Info("Downloading...");
|
||||
var json = await DownloadString(url, TimeSpan.FromMinutes(1));
|
||||
if (string.IsNullOrEmpty(json))
|
||||
{
|
||||
Logger.Warning("Could not load AI !!");
|
||||
return "";
|
||||
}
|
||||
if (!await StoreCommit(version, versionIndex.MappedPath))
|
||||
{
|
||||
throw new Exception("Failed to store AI !!");
|
||||
}
|
||||
File.WriteAllText(path, json);
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
private static bool CreateUri(string source, out Uri result) => Uri.TryCreate(source, UriKind.Absolute, out result) && result.Scheme == Uri.UriSchemeHttps;
|
||||
|
||||
private static async Task<string> DownloadString(string url, TimeSpan timeout)
|
||||
{
|
||||
var content = "";
|
||||
if (CreateUri(url, out var uri))
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var cts = new CancellationTokenSource())
|
||||
{
|
||||
cts.CancelAfter(timeout);
|
||||
var response = await Client.GetAsync(uri, cts.Token);
|
||||
content = await response.Content.ReadAsStringAsync();
|
||||
}
|
||||
}
|
||||
catch (TaskCanceledException ex)
|
||||
{
|
||||
Logger.Warning($"Timeout occured while trying to download {Path.GetFileName(url)}, {ex.Message}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Warning($"Failed to download {Path.GetFileName(url)}, {ex.Message}");
|
||||
}
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
private static async Task<bool> NeedDownload(string key, string path)
|
||||
{
|
||||
if (!File.Exists(GetPath(key)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
var latestCommit = await GetLatestCommit(path);
|
||||
if (string.IsNullOrEmpty(latestCommit))
|
||||
{
|
||||
return !File.Exists(GetPath(key));
|
||||
}
|
||||
var dict = LoadVersions();
|
||||
if (dict.TryGetValue(key, out var commit))
|
||||
{
|
||||
if (commit == latestCommit)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static async Task<bool> StoreCommit(string key, string path)
|
||||
{
|
||||
var latestCommit = await GetLatestCommit(path);
|
||||
if (string.IsNullOrEmpty(latestCommit))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var dict = LoadVersions();
|
||||
if (dict.TryGetValue(key, out var commit))
|
||||
{
|
||||
if (commit != latestCommit)
|
||||
{
|
||||
dict[key] = latestCommit;
|
||||
}
|
||||
}
|
||||
else dict.Add(key, latestCommit);
|
||||
StoreVersions(dict);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static Dictionary<string, string> CreateVersions()
|
||||
{
|
||||
var dict = new Dictionary<string, string>();
|
||||
var dir = Path.GetDirectoryName(VersionsPath);
|
||||
Directory.CreateDirectory(dir);
|
||||
var json = JsonConvert.SerializeObject(dict);
|
||||
File.WriteAllText(VersionsPath, json);
|
||||
return dict;
|
||||
}
|
||||
|
||||
private static Dictionary<string, string> LoadVersions()
|
||||
{
|
||||
if (!File.Exists(VersionsPath))
|
||||
{
|
||||
return CreateVersions();
|
||||
}
|
||||
|
||||
var file = File.ReadAllText(VersionsPath);
|
||||
return JsonConvert.DeserializeObject<Dictionary<string, string>>(file);
|
||||
}
|
||||
|
||||
private static void StoreVersions(Dictionary<string, string> dict)
|
||||
{
|
||||
var json = JsonConvert.SerializeObject(dict, Formatting.Indented);
|
||||
File.WriteAllText(VersionsPath, json);
|
||||
}
|
||||
|
||||
private static string GetPath(string version)
|
||||
{
|
||||
string path = "";
|
||||
if (Versions.TryGetValue(version, out var versionIndex))
|
||||
{
|
||||
path = Path.Combine(BaseAIFolder, Path.GetFileName(versionIndex.MappedPath));
|
||||
}
|
||||
else if (version == VersionIndexKey)
|
||||
{
|
||||
path = Path.Combine(BaseAIFolder, VersionIndexName);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
private static async Task<string> GetLatestCommit(string path)
|
||||
{
|
||||
string commit = "";
|
||||
var json = await DownloadString($"{CommitsUrl}{path}", TimeSpan.FromSeconds(2));
|
||||
try
|
||||
{
|
||||
JArray data = JArray.Parse(json);
|
||||
commit = data[0]["sha"].ToString();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Logger.Warning($"Failed to parse latest commit {Path.GetFileName(path)}");
|
||||
}
|
||||
return commit;
|
||||
}
|
||||
|
||||
internal record VersionIndex
|
||||
{
|
||||
public string MappedPath = "";
|
||||
public string RawPath = "";
|
||||
public string Version = "";
|
||||
public double Coverage = 0;
|
||||
}
|
||||
}
|
||||
}
|
11
AssetStudio/AssetEntry.cs
Normal file
11
AssetStudio/AssetEntry.cs
Normal file
@ -0,0 +1,11 @@
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class AssetEntry
|
||||
{
|
||||
public string Name;
|
||||
public string Container;
|
||||
public string Source;
|
||||
public long PathID;
|
||||
public ClassIDType Type;
|
||||
}
|
||||
}
|
22
AssetStudio/AssetStudio.csproj
Normal file
22
AssetStudio/AssetStudio.csproj
Normal file
@ -0,0 +1,22 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Version>1.18.60</Version>
|
||||
<AssemblyVersion>1.18.60</AssemblyVersion>
|
||||
<FileVersion>1.18.60</FileVersion>
|
||||
<Copyright>Copyright © Razmoth 2022; Copyright © Perfare 2018-2022</Copyright>
|
||||
<DebugType>embedded</DebugType>
|
||||
<ApplicationIcon>as.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="as.ico" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="K4os.Compression.LZ4" Version="1.2.16" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.2-beta2" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
586
AssetStudio/AssetsManager.cs
Normal file
586
AssetStudio/AssetsManager.cs
Normal file
@ -0,0 +1,586 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using static AssetStudio.ImportHelper;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class AssetsManager
|
||||
{
|
||||
public Game Game;
|
||||
public bool ResolveDependancies;
|
||||
public string SpecifyUnityVersion;
|
||||
public List<SerializedFile> assetsFileList = new List<SerializedFile>();
|
||||
|
||||
internal Dictionary<string, int> assetsFileIndexCache = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
|
||||
internal Dictionary<string, BinaryReader> resourceFileReaders = new Dictionary<string, BinaryReader>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
private List<string> importFiles = new List<string>();
|
||||
private HashSet<string> importFilesHash = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
private HashSet<string> assetsFileListHash = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public void LoadFiles(params string[] files)
|
||||
{
|
||||
if (ResolveDependancies)
|
||||
files = CABManager.ProcessDependencies(files);
|
||||
Load(files);
|
||||
}
|
||||
|
||||
public void LoadFolder(string path)
|
||||
{
|
||||
var files = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories).ToArray();
|
||||
Load(files);
|
||||
}
|
||||
|
||||
private void Load(string[] files)
|
||||
{
|
||||
foreach (var file in files)
|
||||
{
|
||||
importFiles.Add(file);
|
||||
importFilesHash.Add(Path.GetFileName(file));
|
||||
}
|
||||
|
||||
Progress.Reset();
|
||||
//use a for loop because list size can change
|
||||
for (var i = 0; i < importFiles.Count; i++)
|
||||
{
|
||||
LoadFile(importFiles[i]);
|
||||
Progress.Report(i + 1, importFiles.Count);
|
||||
}
|
||||
|
||||
importFiles.Clear();
|
||||
importFilesHash.Clear();
|
||||
assetsFileListHash.Clear();
|
||||
CABManager.offsets.Clear();
|
||||
|
||||
ReadAssets();
|
||||
ProcessAssets();
|
||||
}
|
||||
|
||||
private void LoadFile(string fullName)
|
||||
{
|
||||
var reader = new FileReader(fullName, Game);
|
||||
LoadFile(reader);
|
||||
}
|
||||
|
||||
private void LoadFile(FileReader reader)
|
||||
{
|
||||
switch (reader.FileType)
|
||||
{
|
||||
case FileType.AssetsFile:
|
||||
LoadAssetsFile(reader);
|
||||
break;
|
||||
case FileType.BundleFile:
|
||||
LoadBundleFile(reader);
|
||||
break;
|
||||
case FileType.GameFile:
|
||||
LoadGameFile(reader);
|
||||
break;
|
||||
case FileType.WebFile:
|
||||
LoadWebFile(reader);
|
||||
break;
|
||||
case FileType.GZipFile:
|
||||
LoadFile(DecompressGZip(reader));
|
||||
break;
|
||||
case FileType.BrotliFile:
|
||||
LoadFile(DecompressBrotli(reader));
|
||||
break;
|
||||
case FileType.ZipFile:
|
||||
LoadZipFile(reader);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadAssetsFile(FileReader reader)
|
||||
{
|
||||
if (!assetsFileListHash.Contains(reader.FileName))
|
||||
{
|
||||
Logger.Info($"Loading {reader.FileName}");
|
||||
try
|
||||
{
|
||||
var assetsFile = new SerializedFile(reader, this, reader.FullPath);
|
||||
CheckStrippedVersion(assetsFile);
|
||||
assetsFileList.Add(assetsFile);
|
||||
assetsFileListHash.Add(assetsFile.fileName);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error($"Error while reading assets file {reader.FullPath}", e);
|
||||
reader.Dispose();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Info($"Skipping {reader.FullPath}");
|
||||
reader.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadAssetsFromMemory(FileReader reader, string originalPath, string unityVersion = null)
|
||||
{
|
||||
if (!assetsFileListHash.Contains(reader.FileName))
|
||||
{
|
||||
try
|
||||
{
|
||||
var assetsFile = new SerializedFile(reader, this);
|
||||
assetsFile.originalPath = originalPath;
|
||||
if (!string.IsNullOrEmpty(unityVersion) && assetsFile.header.m_Version < SerializedFileFormatVersion.Unknown_7)
|
||||
{
|
||||
assetsFile.SetVersion(unityVersion);
|
||||
}
|
||||
CheckStrippedVersion(assetsFile);
|
||||
assetsFileList.Add(assetsFile);
|
||||
assetsFileListHash.Add(assetsFile.fileName);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error($"Error while reading assets file {reader.FullPath} from {Path.GetFileName(originalPath)}", e);
|
||||
resourceFileReaders.Add(reader.FileName, reader);
|
||||
}
|
||||
}
|
||||
else
|
||||
Logger.Info($"Skipping {originalPath} ({reader.FileName})");
|
||||
}
|
||||
|
||||
private void LoadBundleFile(FileReader reader, string originalPath = null)
|
||||
{
|
||||
Logger.Info("Loading " + reader.FullPath);
|
||||
try
|
||||
{
|
||||
var bundleFile = new BundleFile(reader);
|
||||
foreach (var file in bundleFile.FileList)
|
||||
{
|
||||
var dummyPath = Path.Combine(Path.GetDirectoryName(reader.FullPath), file.fileName);
|
||||
var subReader = new FileReader(dummyPath, file.stream);
|
||||
if (subReader.FileType == FileType.AssetsFile)
|
||||
{
|
||||
LoadAssetsFromMemory(subReader, originalPath ?? reader.FullPath, bundleFile.m_Header.unityRevision);
|
||||
}
|
||||
else
|
||||
{
|
||||
resourceFileReaders[file.fileName] = subReader; //TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var str = $"Error while reading bundle file {reader.FullPath}";
|
||||
if (originalPath != null)
|
||||
{
|
||||
str += $" from {Path.GetFileName(originalPath)}";
|
||||
}
|
||||
Logger.Error(str, e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
reader.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadWebFile(FileReader reader)
|
||||
{
|
||||
Logger.Info("Loading " + reader.FullPath);
|
||||
try
|
||||
{
|
||||
var webFile = new WebFile(reader);
|
||||
foreach (var file in webFile.fileList)
|
||||
{
|
||||
var dummyPath = Path.Combine(Path.GetDirectoryName(reader.FullPath), file.fileName);
|
||||
var subReader = new FileReader(dummyPath, file.stream);
|
||||
switch (subReader.FileType)
|
||||
{
|
||||
case FileType.AssetsFile:
|
||||
LoadAssetsFromMemory(subReader, reader.FullPath);
|
||||
break;
|
||||
case FileType.BundleFile:
|
||||
LoadBundleFile(subReader, reader.FullPath);
|
||||
break;
|
||||
case FileType.WebFile:
|
||||
LoadWebFile(subReader);
|
||||
break;
|
||||
case FileType.ResourceFile:
|
||||
resourceFileReaders[file.fileName] = subReader; //TODO
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error($"Error while reading web file {reader.FullPath}", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
reader.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadZipFile(FileReader reader)
|
||||
{
|
||||
Logger.Info("Loading " + reader.FileName);
|
||||
try
|
||||
{
|
||||
using (ZipArchive archive = new ZipArchive(reader.BaseStream, ZipArchiveMode.Read))
|
||||
{
|
||||
List<string> splitFiles = new List<string>();
|
||||
// register all files before parsing the assets so that the external references can be found
|
||||
// and find split files
|
||||
foreach (ZipArchiveEntry entry in archive.Entries)
|
||||
{
|
||||
if (entry.Name.Contains(".split"))
|
||||
{
|
||||
string baseName = Path.GetFileNameWithoutExtension(entry.Name);
|
||||
string basePath = Path.Combine(Path.GetDirectoryName(entry.FullName), baseName);
|
||||
if (!splitFiles.Contains(basePath))
|
||||
{
|
||||
splitFiles.Add(basePath);
|
||||
importFilesHash.Add(baseName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
importFilesHash.Add(entry.Name);
|
||||
}
|
||||
}
|
||||
|
||||
// merge split files and load the result
|
||||
foreach (string basePath in splitFiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
Stream splitStream = new MemoryStream();
|
||||
int i = 0;
|
||||
while (true)
|
||||
{
|
||||
string path = $"{basePath}.split{i++}";
|
||||
ZipArchiveEntry entry = archive.GetEntry(path);
|
||||
if (entry == null)
|
||||
break;
|
||||
using (Stream entryStream = entry.Open())
|
||||
{
|
||||
entryStream.CopyTo(splitStream);
|
||||
}
|
||||
}
|
||||
splitStream.Seek(0, SeekOrigin.Begin);
|
||||
FileReader entryReader = new FileReader(basePath, splitStream);
|
||||
LoadFile(entryReader);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error($"Error while reading zip split file {basePath}", e);
|
||||
}
|
||||
}
|
||||
|
||||
// load all entries
|
||||
foreach (ZipArchiveEntry entry in archive.Entries)
|
||||
{
|
||||
try
|
||||
{
|
||||
string dummyPath = Path.Combine(Path.GetDirectoryName(reader.FullPath), reader.FileName, entry.FullName);
|
||||
// create a new stream
|
||||
// - to store the deflated stream in
|
||||
// - to keep the data for later extraction
|
||||
Stream streamReader = new MemoryStream();
|
||||
using (Stream entryStream = entry.Open())
|
||||
{
|
||||
entryStream.CopyTo(streamReader);
|
||||
}
|
||||
streamReader.Position = 0;
|
||||
|
||||
FileReader entryReader = new FileReader(dummyPath, streamReader);
|
||||
LoadFile(entryReader);
|
||||
if (entryReader.FileType == FileType.ResourceFile)
|
||||
{
|
||||
entryReader.Position = 0;
|
||||
if (!resourceFileReaders.ContainsKey(entry.Name))
|
||||
{
|
||||
resourceFileReaders.Add(entry.Name, entryReader);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error($"Error while reading zip entry {entry.FullName}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error($"Error while reading zip file {reader.FileName}", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
reader.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadGameFile(FileReader reader)
|
||||
{
|
||||
Logger.Info("Loading " + reader.FileName);
|
||||
try
|
||||
{
|
||||
reader.BundlePos = CABManager.offsets.TryGetValue(reader.FullPath, out var list) ? list.ToArray() : Array.Empty<long>();
|
||||
var gameFile = new GameFile(reader);
|
||||
foreach (var bundle in gameFile.Bundles)
|
||||
{
|
||||
foreach (var file in bundle.Value)
|
||||
{
|
||||
var dummyPath = Path.Combine(Path.GetDirectoryName(reader.FullPath), file.fileName);
|
||||
var cabReader = new FileReader(dummyPath, file.stream, Game);
|
||||
if (cabReader.FileType == FileType.AssetsFile)
|
||||
{
|
||||
var assetsFile = new SerializedFile(cabReader, this, reader.FullPath);
|
||||
CheckStrippedVersion(assetsFile);
|
||||
assetsFileList.Add(assetsFile);
|
||||
assetsFileListHash.Add(assetsFile.fileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
resourceFileReaders[file.fileName] = cabReader; //TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error($"Error while reading file {reader.FileName}", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
reader.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void CheckStrippedVersion(SerializedFile assetsFile)
|
||||
{
|
||||
if (assetsFile.IsVersionStripped && string.IsNullOrEmpty(SpecifyUnityVersion))
|
||||
{
|
||||
throw new Exception("The Unity version has been stripped, please set the version in the options");
|
||||
}
|
||||
if (!string.IsNullOrEmpty(SpecifyUnityVersion))
|
||||
{
|
||||
assetsFile.SetVersion(SpecifyUnityVersion);
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
foreach (var assetsFile in assetsFileList)
|
||||
{
|
||||
assetsFile.Objects.Clear();
|
||||
assetsFile.reader.Close();
|
||||
}
|
||||
assetsFileList.Clear();
|
||||
|
||||
foreach (var resourceFileReader in resourceFileReaders)
|
||||
{
|
||||
resourceFileReader.Value.Close();
|
||||
}
|
||||
resourceFileReaders.Clear();
|
||||
|
||||
assetsFileIndexCache.Clear();
|
||||
}
|
||||
|
||||
private void ReadAssets()
|
||||
{
|
||||
Logger.Info("Read assets...");
|
||||
|
||||
var progressCount = assetsFileList.Sum(x => x.m_Objects.Count);
|
||||
int i = 0;
|
||||
Progress.Reset();
|
||||
foreach (var assetsFile in assetsFileList)
|
||||
{
|
||||
foreach (var objectInfo in assetsFile.m_Objects)
|
||||
{
|
||||
var objectReader = new ObjectReader(assetsFile.reader, assetsFile, objectInfo);
|
||||
try
|
||||
{
|
||||
Object obj;
|
||||
switch (objectReader.type)
|
||||
{
|
||||
case ClassIDType.Animation:
|
||||
obj = new Animation(objectReader);
|
||||
break;
|
||||
case ClassIDType.AnimationClip:
|
||||
obj = new AnimationClip(objectReader);
|
||||
break;
|
||||
case ClassIDType.Animator:
|
||||
obj = new Animator(objectReader);
|
||||
break;
|
||||
case ClassIDType.AnimatorController:
|
||||
obj = new AnimatorController(objectReader);
|
||||
break;
|
||||
case ClassIDType.AnimatorOverrideController:
|
||||
obj = new AnimatorOverrideController(objectReader);
|
||||
break;
|
||||
case ClassIDType.AssetBundle:
|
||||
obj = new AssetBundle(objectReader);
|
||||
break;
|
||||
case ClassIDType.AudioClip:
|
||||
obj = new AudioClip(objectReader);
|
||||
break;
|
||||
case ClassIDType.Avatar:
|
||||
obj = new Avatar(objectReader);
|
||||
break;
|
||||
case ClassIDType.Font:
|
||||
obj = new Font(objectReader);
|
||||
break;
|
||||
case ClassIDType.GameObject:
|
||||
obj = new GameObject(objectReader);
|
||||
break;
|
||||
case ClassIDType.IndexObject:
|
||||
obj = new IndexObject(objectReader);
|
||||
break;
|
||||
case ClassIDType.Material:
|
||||
obj = new Material(objectReader);
|
||||
break;
|
||||
case ClassIDType.Mesh:
|
||||
obj = new Mesh(objectReader);
|
||||
break;
|
||||
case ClassIDType.MeshFilter:
|
||||
obj = new MeshFilter(objectReader);
|
||||
break;
|
||||
case ClassIDType.MeshRenderer:
|
||||
if (!Renderer.Parsable) continue;
|
||||
obj = new MeshRenderer(objectReader);
|
||||
break;
|
||||
case ClassIDType.MiHoYoBinData:
|
||||
obj = new MiHoYoBinData(objectReader);
|
||||
break;
|
||||
case ClassIDType.MonoBehaviour:
|
||||
obj = new MonoBehaviour(objectReader);
|
||||
break;
|
||||
case ClassIDType.MonoScript:
|
||||
obj = new MonoScript(objectReader);
|
||||
break;
|
||||
case ClassIDType.MovieTexture:
|
||||
obj = new MovieTexture(objectReader);
|
||||
break;
|
||||
case ClassIDType.PlayerSettings:
|
||||
obj = new PlayerSettings(objectReader);
|
||||
break;
|
||||
case ClassIDType.RectTransform:
|
||||
obj = new RectTransform(objectReader);
|
||||
break;
|
||||
case ClassIDType.Shader:
|
||||
if (!Shader.Parsable) continue;
|
||||
obj = new Shader(objectReader);
|
||||
break;
|
||||
case ClassIDType.SkinnedMeshRenderer:
|
||||
if (!Renderer.Parsable) continue;
|
||||
obj = new SkinnedMeshRenderer(objectReader);
|
||||
break;
|
||||
case ClassIDType.Sprite:
|
||||
obj = new Sprite(objectReader);
|
||||
break;
|
||||
case ClassIDType.SpriteAtlas:
|
||||
obj = new SpriteAtlas(objectReader);
|
||||
break;
|
||||
case ClassIDType.TextAsset:
|
||||
obj = new TextAsset(objectReader);
|
||||
break;
|
||||
case ClassIDType.Texture2D:
|
||||
obj = new Texture2D(objectReader);
|
||||
break;
|
||||
case ClassIDType.Transform:
|
||||
obj = new Transform(objectReader);
|
||||
break;
|
||||
case ClassIDType.VideoClip:
|
||||
obj = new VideoClip(objectReader);
|
||||
break;
|
||||
case ClassIDType.ResourceManager:
|
||||
obj = new ResourceManager(objectReader);
|
||||
break;
|
||||
default:
|
||||
obj = new Object(objectReader);
|
||||
break;
|
||||
}
|
||||
assetsFile.AddObject(obj);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("Unable to load object")
|
||||
.AppendLine($"Assets {assetsFile.fileName}")
|
||||
.AppendLine($"Path {assetsFile.originalPath}")
|
||||
.AppendLine($"Type {objectReader.type}")
|
||||
.AppendLine($"PathID {objectInfo.m_PathID}")
|
||||
.Append(e);
|
||||
Logger.Error(sb.ToString());
|
||||
}
|
||||
|
||||
Progress.Report(++i, progressCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessAssets()
|
||||
{
|
||||
Logger.Info("Process Assets...");
|
||||
|
||||
foreach (var assetsFile in assetsFileList)
|
||||
{
|
||||
foreach (var obj in assetsFile.Objects)
|
||||
{
|
||||
if (obj is GameObject m_GameObject)
|
||||
{
|
||||
foreach (var pptr in m_GameObject.m_Components)
|
||||
{
|
||||
if (pptr.TryGet(out var m_Component))
|
||||
{
|
||||
switch (m_Component)
|
||||
{
|
||||
case Transform m_Transform:
|
||||
m_GameObject.m_Transform = m_Transform;
|
||||
break;
|
||||
case MeshRenderer m_MeshRenderer:
|
||||
m_GameObject.m_MeshRenderer = m_MeshRenderer;
|
||||
break;
|
||||
case MeshFilter m_MeshFilter:
|
||||
m_GameObject.m_MeshFilter = m_MeshFilter;
|
||||
break;
|
||||
case SkinnedMeshRenderer m_SkinnedMeshRenderer:
|
||||
m_GameObject.m_SkinnedMeshRenderer = m_SkinnedMeshRenderer;
|
||||
break;
|
||||
case Animator m_Animator:
|
||||
m_GameObject.m_Animator = m_Animator;
|
||||
break;
|
||||
case Animation m_Animation:
|
||||
m_GameObject.m_Animation = m_Animation;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (obj is SpriteAtlas m_SpriteAtlas)
|
||||
{
|
||||
if (m_SpriteAtlas.m_RenderDataMap.Count > 0)
|
||||
{
|
||||
foreach (var m_PackedSprite in m_SpriteAtlas.m_PackedSprites)
|
||||
{
|
||||
if (m_PackedSprite.TryGet(out var m_Sprite))
|
||||
{
|
||||
if (m_Sprite.m_SpriteAtlas.IsNull)
|
||||
{
|
||||
m_Sprite.m_SpriteAtlas.Set(m_SpriteAtlas);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Sprite.m_SpriteAtlas.TryGet(out var m_SpriteAtlaOld);
|
||||
if (m_SpriteAtlaOld.m_IsVariant)
|
||||
{
|
||||
m_Sprite.m_SpriteAtlas.Set(m_SpriteAtlas);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
10
AssetStudio/BigArrayPool.cs
Normal file
10
AssetStudio/BigArrayPool.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System.Buffers;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public static class BigArrayPool<T>
|
||||
{
|
||||
private static readonly ArrayPool<T> s_shared = ArrayPool<T>.Create(64 * 1024 * 1024, 3);
|
||||
public static ArrayPool<T> Shared => s_shared;
|
||||
}
|
||||
}
|
271
AssetStudio/Brotli/BitReader.cs
Normal file
271
AssetStudio/Brotli/BitReader.cs
Normal file
@ -0,0 +1,271 @@
|
||||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>Bit reading helpers.</summary>
|
||||
internal sealed class BitReader
|
||||
{
|
||||
/// <summary>
|
||||
/// Input byte buffer, consist of a ring-buffer and a "slack" region where bytes from the start of
|
||||
/// the ring-buffer are copied.
|
||||
/// </summary>
|
||||
private const int Capacity = 1024;
|
||||
|
||||
private const int Slack = 16;
|
||||
|
||||
private const int IntBufferSize = Capacity + Slack;
|
||||
|
||||
private const int ByteReadSize = Capacity << 2;
|
||||
|
||||
private const int ByteBufferSize = IntBufferSize << 2;
|
||||
|
||||
private readonly byte[] byteBuffer = new byte[ByteBufferSize];
|
||||
|
||||
private readonly int[] intBuffer = new int[IntBufferSize];
|
||||
|
||||
private readonly Org.Brotli.Dec.IntReader intReader = new Org.Brotli.Dec.IntReader();
|
||||
|
||||
private System.IO.Stream input;
|
||||
|
||||
/// <summary>Input stream is finished.</summary>
|
||||
private bool endOfStreamReached;
|
||||
|
||||
/// <summary>Pre-fetched bits.</summary>
|
||||
internal long accumulator;
|
||||
|
||||
/// <summary>Current bit-reading position in accumulator.</summary>
|
||||
internal int bitOffset;
|
||||
|
||||
/// <summary>Offset of next item in intBuffer.</summary>
|
||||
private int intOffset;
|
||||
|
||||
private int tailBytes = 0;
|
||||
|
||||
/* Number of bytes in unfinished "int" item. */
|
||||
/// <summary>Fills up the input buffer.</summary>
|
||||
/// <remarks>
|
||||
/// Fills up the input buffer.
|
||||
/// <p> No-op if there are at least 36 bytes present after current position.
|
||||
/// <p> After encountering the end of the input stream, 64 additional zero bytes are copied to the
|
||||
/// buffer.
|
||||
/// </remarks>
|
||||
internal static void ReadMoreInput(Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
// TODO: Split to check and read; move read outside of decoding loop.
|
||||
if (br.intOffset <= Capacity - 9)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (br.endOfStreamReached)
|
||||
{
|
||||
if (IntAvailable(br) >= -2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("No more input");
|
||||
}
|
||||
int readOffset = br.intOffset << 2;
|
||||
int bytesRead = ByteReadSize - readOffset;
|
||||
System.Array.Copy(br.byteBuffer, readOffset, br.byteBuffer, 0, bytesRead);
|
||||
br.intOffset = 0;
|
||||
try
|
||||
{
|
||||
while (bytesRead < ByteReadSize)
|
||||
{
|
||||
int len = br.input.Read(br.byteBuffer, bytesRead, ByteReadSize - bytesRead);
|
||||
// EOF is -1 in Java, but 0 in C#.
|
||||
if (len <= 0)
|
||||
{
|
||||
br.endOfStreamReached = true;
|
||||
br.tailBytes = bytesRead;
|
||||
bytesRead += 3;
|
||||
break;
|
||||
}
|
||||
bytesRead += len;
|
||||
}
|
||||
}
|
||||
catch (System.IO.IOException e)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Failed to read input", e);
|
||||
}
|
||||
Org.Brotli.Dec.IntReader.Convert(br.intReader, bytesRead >> 2);
|
||||
}
|
||||
|
||||
internal static void CheckHealth(Org.Brotli.Dec.BitReader br, bool endOfStream)
|
||||
{
|
||||
if (!br.endOfStreamReached)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int byteOffset = (br.intOffset << 2) + ((br.bitOffset + 7) >> 3) - 8;
|
||||
if (byteOffset > br.tailBytes)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Read after end");
|
||||
}
|
||||
if (endOfStream && (byteOffset != br.tailBytes))
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Unused bytes after end");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Advances the Read buffer by 5 bytes to make room for reading next 24 bits.</summary>
|
||||
internal static void FillBitWindow(Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
if (br.bitOffset >= 32)
|
||||
{
|
||||
br.accumulator = ((long)br.intBuffer[br.intOffset++] << 32) | ((long)(((ulong)br.accumulator) >> 32));
|
||||
br.bitOffset -= 32;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Reads the specified number of bits from Read Buffer.</summary>
|
||||
internal static int ReadBits(Org.Brotli.Dec.BitReader br, int n)
|
||||
{
|
||||
FillBitWindow(br);
|
||||
int val = (int)((long)(((ulong)br.accumulator) >> br.bitOffset)) & ((1 << n) - 1);
|
||||
br.bitOffset += n;
|
||||
return val;
|
||||
}
|
||||
|
||||
/// <summary>Initialize bit reader.</summary>
|
||||
/// <remarks>
|
||||
/// Initialize bit reader.
|
||||
/// <p> Initialisation turns bit reader to a ready state. Also a number of bytes is prefetched to
|
||||
/// accumulator. Because of that this method may block until enough data could be read from input.
|
||||
/// </remarks>
|
||||
/// <param name="br">BitReader POJO</param>
|
||||
/// <param name="input">data source</param>
|
||||
internal static void Init(Org.Brotli.Dec.BitReader br, System.IO.Stream input)
|
||||
{
|
||||
if (br.input != null)
|
||||
{
|
||||
throw new System.InvalidOperationException("Bit reader already has associated input stream");
|
||||
}
|
||||
Org.Brotli.Dec.IntReader.Init(br.intReader, br.byteBuffer, br.intBuffer);
|
||||
br.input = input;
|
||||
br.accumulator = 0;
|
||||
br.bitOffset = 64;
|
||||
br.intOffset = Capacity;
|
||||
br.endOfStreamReached = false;
|
||||
Prepare(br);
|
||||
}
|
||||
|
||||
private static void Prepare(Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
ReadMoreInput(br);
|
||||
CheckHealth(br, false);
|
||||
FillBitWindow(br);
|
||||
FillBitWindow(br);
|
||||
}
|
||||
|
||||
internal static void Reload(Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
if (br.bitOffset == 64)
|
||||
{
|
||||
Prepare(br);
|
||||
}
|
||||
}
|
||||
|
||||
/// <exception cref="System.IO.IOException"/>
|
||||
internal static void Close(Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
System.IO.Stream @is = br.input;
|
||||
br.input = null;
|
||||
if (@is != null)
|
||||
{
|
||||
@is.Close();
|
||||
}
|
||||
}
|
||||
|
||||
internal static void JumpToByteBoundary(Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
int padding = (64 - br.bitOffset) & 7;
|
||||
if (padding != 0)
|
||||
{
|
||||
int paddingBits = Org.Brotli.Dec.BitReader.ReadBits(br, padding);
|
||||
if (paddingBits != 0)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Corrupted padding bits");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static int IntAvailable(Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
int limit = Capacity;
|
||||
if (br.endOfStreamReached)
|
||||
{
|
||||
limit = (br.tailBytes + 3) >> 2;
|
||||
}
|
||||
return limit - br.intOffset;
|
||||
}
|
||||
|
||||
internal static void CopyBytes(Org.Brotli.Dec.BitReader br, byte[] data, int offset, int length)
|
||||
{
|
||||
if ((br.bitOffset & 7) != 0)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Unaligned copyBytes");
|
||||
}
|
||||
// Drain accumulator.
|
||||
while ((br.bitOffset != 64) && (length != 0))
|
||||
{
|
||||
data[offset++] = unchecked((byte)((long)(((ulong)br.accumulator) >> br.bitOffset)));
|
||||
br.bitOffset += 8;
|
||||
length--;
|
||||
}
|
||||
if (length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Get data from shadow buffer with "sizeof(int)" granularity.
|
||||
int copyInts = System.Math.Min(IntAvailable(br), length >> 2);
|
||||
if (copyInts > 0)
|
||||
{
|
||||
int readOffset = br.intOffset << 2;
|
||||
System.Array.Copy(br.byteBuffer, readOffset, data, offset, copyInts << 2);
|
||||
offset += copyInts << 2;
|
||||
length -= copyInts << 2;
|
||||
br.intOffset += copyInts;
|
||||
}
|
||||
if (length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Read tail bytes.
|
||||
if (IntAvailable(br) > 0)
|
||||
{
|
||||
// length = 1..3
|
||||
FillBitWindow(br);
|
||||
while (length != 0)
|
||||
{
|
||||
data[offset++] = unchecked((byte)((long)(((ulong)br.accumulator) >> br.bitOffset)));
|
||||
br.bitOffset += 8;
|
||||
length--;
|
||||
}
|
||||
CheckHealth(br, false);
|
||||
return;
|
||||
}
|
||||
// Now it is possible to copy bytes directly.
|
||||
try
|
||||
{
|
||||
while (length > 0)
|
||||
{
|
||||
int len = br.input.Read(data, offset, length);
|
||||
if (len == -1)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Unexpected end of input");
|
||||
}
|
||||
offset += len;
|
||||
length -= len;
|
||||
}
|
||||
}
|
||||
catch (System.IO.IOException e)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Failed to read input", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
223
AssetStudio/Brotli/BrotliInputStream.cs
Normal file
223
AssetStudio/Brotli/BrotliInputStream.cs
Normal file
@ -0,0 +1,223 @@
|
||||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="System.IO.Stream"/>
|
||||
/// decorator that decompresses brotli data.
|
||||
/// <p> Not thread-safe.
|
||||
/// </summary>
|
||||
public class BrotliInputStream : System.IO.Stream
|
||||
{
|
||||
public const int DefaultInternalBufferSize = 16384;
|
||||
|
||||
/// <summary>Internal buffer used for efficient byte-by-byte reading.</summary>
|
||||
private byte[] buffer;
|
||||
|
||||
/// <summary>Number of decoded but still unused bytes in internal buffer.</summary>
|
||||
private int remainingBufferBytes;
|
||||
|
||||
/// <summary>Next unused byte offset.</summary>
|
||||
private int bufferOffset;
|
||||
|
||||
/// <summary>Decoder state.</summary>
|
||||
private readonly Org.Brotli.Dec.State state = new Org.Brotli.Dec.State();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a
|
||||
/// <see cref="System.IO.Stream"/>
|
||||
/// wrapper that decompresses brotli data.
|
||||
/// <p> For byte-by-byte reading (
|
||||
/// <see cref="ReadByte()"/>
|
||||
/// ) internal buffer with
|
||||
/// <see cref="DefaultInternalBufferSize"/>
|
||||
/// size is allocated and used.
|
||||
/// <p> Will block the thread until first kilobyte of data of source is available.
|
||||
/// </summary>
|
||||
/// <param name="source">underlying data source</param>
|
||||
/// <exception cref="System.IO.IOException">in case of corrupted data or source stream problems</exception>
|
||||
public BrotliInputStream(System.IO.Stream source)
|
||||
: this(source, DefaultInternalBufferSize, null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a
|
||||
/// <see cref="System.IO.Stream"/>
|
||||
/// wrapper that decompresses brotli data.
|
||||
/// <p> For byte-by-byte reading (
|
||||
/// <see cref="ReadByte()"/>
|
||||
/// ) internal buffer of specified size is
|
||||
/// allocated and used.
|
||||
/// <p> Will block the thread until first kilobyte of data of source is available.
|
||||
/// </summary>
|
||||
/// <param name="source">compressed data source</param>
|
||||
/// <param name="byteReadBufferSize">
|
||||
/// size of internal buffer used in case of
|
||||
/// byte-by-byte reading
|
||||
/// </param>
|
||||
/// <exception cref="System.IO.IOException">in case of corrupted data or source stream problems</exception>
|
||||
public BrotliInputStream(System.IO.Stream source, int byteReadBufferSize)
|
||||
: this(source, byteReadBufferSize, null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a
|
||||
/// <see cref="System.IO.Stream"/>
|
||||
/// wrapper that decompresses brotli data.
|
||||
/// <p> For byte-by-byte reading (
|
||||
/// <see cref="ReadByte()"/>
|
||||
/// ) internal buffer of specified size is
|
||||
/// allocated and used.
|
||||
/// <p> Will block the thread until first kilobyte of data of source is available.
|
||||
/// </summary>
|
||||
/// <param name="source">compressed data source</param>
|
||||
/// <param name="byteReadBufferSize">
|
||||
/// size of internal buffer used in case of
|
||||
/// byte-by-byte reading
|
||||
/// </param>
|
||||
/// <param name="customDictionary">
|
||||
/// custom dictionary data;
|
||||
/// <see langword="null"/>
|
||||
/// if not used
|
||||
/// </param>
|
||||
/// <exception cref="System.IO.IOException">in case of corrupted data or source stream problems</exception>
|
||||
public BrotliInputStream(System.IO.Stream source, int byteReadBufferSize, byte[] customDictionary)
|
||||
{
|
||||
if (byteReadBufferSize <= 0)
|
||||
{
|
||||
throw new System.ArgumentException("Bad buffer size:" + byteReadBufferSize);
|
||||
}
|
||||
else if (source == null)
|
||||
{
|
||||
throw new System.ArgumentException("source is null");
|
||||
}
|
||||
this.buffer = new byte[byteReadBufferSize];
|
||||
this.remainingBufferBytes = 0;
|
||||
this.bufferOffset = 0;
|
||||
try
|
||||
{
|
||||
Org.Brotli.Dec.State.SetInput(state, source);
|
||||
}
|
||||
catch (Org.Brotli.Dec.BrotliRuntimeException ex)
|
||||
{
|
||||
throw new System.IO.IOException("Brotli decoder initialization failed", ex);
|
||||
}
|
||||
if (customDictionary != null)
|
||||
{
|
||||
Org.Brotli.Dec.Decode.SetCustomDictionary(state, customDictionary);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary><inheritDoc/></summary>
|
||||
/// <exception cref="System.IO.IOException"/>
|
||||
public override void Close()
|
||||
{
|
||||
Org.Brotli.Dec.State.Close(state);
|
||||
}
|
||||
|
||||
/// <summary><inheritDoc/></summary>
|
||||
/// <exception cref="System.IO.IOException"/>
|
||||
public override int ReadByte()
|
||||
{
|
||||
if (bufferOffset >= remainingBufferBytes)
|
||||
{
|
||||
remainingBufferBytes = Read(buffer, 0, buffer.Length);
|
||||
bufferOffset = 0;
|
||||
if (remainingBufferBytes == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return buffer[bufferOffset++] & unchecked((int)(0xFF));
|
||||
}
|
||||
|
||||
/// <summary><inheritDoc/></summary>
|
||||
/// <exception cref="System.IO.IOException"/>
|
||||
public override int Read(byte[] destBuffer, int destOffset, int destLen)
|
||||
{
|
||||
if (destOffset < 0)
|
||||
{
|
||||
throw new System.ArgumentException("Bad offset: " + destOffset);
|
||||
}
|
||||
else if (destLen < 0)
|
||||
{
|
||||
throw new System.ArgumentException("Bad length: " + destLen);
|
||||
}
|
||||
else if (destOffset + destLen > destBuffer.Length)
|
||||
{
|
||||
throw new System.ArgumentException("Buffer overflow: " + (destOffset + destLen) + " > " + destBuffer.Length);
|
||||
}
|
||||
else if (destLen == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int copyLen = System.Math.Max(remainingBufferBytes - bufferOffset, 0);
|
||||
if (copyLen != 0)
|
||||
{
|
||||
copyLen = System.Math.Min(copyLen, destLen);
|
||||
System.Array.Copy(buffer, bufferOffset, destBuffer, destOffset, copyLen);
|
||||
bufferOffset += copyLen;
|
||||
destOffset += copyLen;
|
||||
destLen -= copyLen;
|
||||
if (destLen == 0)
|
||||
{
|
||||
return copyLen;
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
state.output = destBuffer;
|
||||
state.outputOffset = destOffset;
|
||||
state.outputLength = destLen;
|
||||
state.outputUsed = 0;
|
||||
Org.Brotli.Dec.Decode.Decompress(state);
|
||||
if (state.outputUsed == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return state.outputUsed + copyLen;
|
||||
}
|
||||
catch (Org.Brotli.Dec.BrotliRuntimeException ex)
|
||||
{
|
||||
throw new System.IO.IOException("Brotli stream decoding failed", ex);
|
||||
}
|
||||
}
|
||||
// <{[INJECTED CODE]}>
|
||||
public override bool CanRead {
|
||||
get {return true;}
|
||||
}
|
||||
|
||||
public override bool CanSeek {
|
||||
get {return false;}
|
||||
}
|
||||
public override long Length {
|
||||
get {throw new System.NotSupportedException();}
|
||||
}
|
||||
public override long Position {
|
||||
get {throw new System.NotSupportedException();}
|
||||
set {throw new System.NotSupportedException();}
|
||||
}
|
||||
public override long Seek(long offset, System.IO.SeekOrigin origin) {
|
||||
throw new System.NotSupportedException();
|
||||
}
|
||||
public override void SetLength(long value){
|
||||
throw new System.NotSupportedException();
|
||||
}
|
||||
|
||||
public override bool CanWrite{get{return false;}}
|
||||
public override System.IAsyncResult BeginWrite(byte[] buffer, int offset,
|
||||
int count, System.AsyncCallback callback, object state) {
|
||||
throw new System.NotSupportedException();
|
||||
}
|
||||
public override void Write(byte[] buffer, int offset, int count) {
|
||||
throw new System.NotSupportedException();
|
||||
}
|
||||
|
||||
public override void Flush() {}
|
||||
}
|
||||
}
|
22
AssetStudio/Brotli/BrotliRuntimeException.cs
Normal file
22
AssetStudio/Brotli/BrotliRuntimeException.cs
Normal file
@ -0,0 +1,22 @@
|
||||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>Unchecked exception used internally.</summary>
|
||||
[System.Serializable]
|
||||
internal class BrotliRuntimeException : System.Exception
|
||||
{
|
||||
internal BrotliRuntimeException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
|
||||
internal BrotliRuntimeException(string message, System.Exception cause)
|
||||
: base(message, cause)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
57
AssetStudio/Brotli/Context.cs
Normal file
57
AssetStudio/Brotli/Context.cs
Normal file
@ -0,0 +1,57 @@
|
||||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>Common context lookup table for all context modes.</summary>
|
||||
internal sealed class Context
|
||||
{
|
||||
internal static readonly int[] Lookup = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 12, 16, 12, 12, 20, 12, 16, 24, 28, 12, 12, 32, 12, 36, 12, 44, 44, 44, 44, 44, 44, 44, 44
|
||||
, 44, 44, 32, 32, 24, 40, 28, 12, 12, 48, 52, 52, 52, 48, 52, 52, 52, 48, 52, 52, 52, 52, 52, 48, 52, 52, 52, 52, 52, 48, 52, 52, 52, 52, 52, 24, 12, 28, 12, 12, 12, 56, 60, 60, 60, 56, 60, 60, 60, 56, 60, 60, 60, 60, 60, 56, 60, 60, 60, 60
|
||||
, 60, 56, 60, 60, 60, 60, 60, 24, 12, 28, 12, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,
|
||||
1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
|
||||
40, 40, 40, 40, 40, 40, 40, 40, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 56, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38
|
||||
, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
|
||||
37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35
|
||||
, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
|
||||
34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9,
|
||||
10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24,
|
||||
25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31, 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39,
|
||||
40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51, 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54,
|
||||
55, 55, 55, 55, 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59, 60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
internal static readonly int[] LookupOffsets = new int[] { 1024, 1536, 1280, 1536, 0, 256, 768, 512 };
|
||||
// CONTEXT_UTF8, last byte.
|
||||
// ASCII range.
|
||||
// UTF8 continuation byte range.
|
||||
// UTF8 lead byte range.
|
||||
// CONTEXT_UTF8 second last byte.
|
||||
// ASCII range.
|
||||
// UTF8 continuation byte range.
|
||||
// UTF8 lead byte range.
|
||||
// CONTEXT_SIGNED, second last byte.
|
||||
// CONTEXT_SIGNED, last byte, same as the above values shifted by 3 bits.
|
||||
// CONTEXT_LSB6, last byte.
|
||||
// CONTEXT_MSB6, last byte.
|
||||
// CONTEXT_{M,L}SB6, second last byte,
|
||||
// CONTEXT_LSB6
|
||||
// CONTEXT_MSB6
|
||||
// CONTEXT_UTF8
|
||||
// CONTEXT_SIGNED
|
||||
}
|
||||
}
|
992
AssetStudio/Brotli/Decode.cs
Normal file
992
AssetStudio/Brotli/Decode.cs
Normal file
@ -0,0 +1,992 @@
|
||||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>API for Brotli decompression.</summary>
|
||||
internal sealed class Decode
|
||||
{
|
||||
private const int DefaultCodeLength = 8;
|
||||
|
||||
private const int CodeLengthRepeatCode = 16;
|
||||
|
||||
private const int NumLiteralCodes = 256;
|
||||
|
||||
private const int NumInsertAndCopyCodes = 704;
|
||||
|
||||
private const int NumBlockLengthCodes = 26;
|
||||
|
||||
private const int LiteralContextBits = 6;
|
||||
|
||||
private const int DistanceContextBits = 2;
|
||||
|
||||
private const int HuffmanTableBits = 8;
|
||||
|
||||
private const int HuffmanTableMask = unchecked((int)(0xFF));
|
||||
|
||||
private const int CodeLengthCodes = 18;
|
||||
|
||||
private static readonly int[] CodeLengthCodeOrder = new int[] { 1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
|
||||
|
||||
private const int NumDistanceShortCodes = 16;
|
||||
|
||||
private static readonly int[] DistanceShortCodeIndexOffset = new int[] { 3, 2, 1, 0, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 };
|
||||
|
||||
private static readonly int[] DistanceShortCodeValueOffset = new int[] { 0, 0, 0, 0, -1, 1, -2, 2, -3, 3, -1, 1, -2, 2, -3, 3 };
|
||||
|
||||
/// <summary>Static Huffman code for the code length code lengths.</summary>
|
||||
private static readonly int[] FixedTable = new int[] { unchecked((int)(0x020000)), unchecked((int)(0x020004)), unchecked((int)(0x020003)), unchecked((int)(0x030002)), unchecked((int)(0x020000)), unchecked((int)(0x020004)), unchecked((int)(0x020003
|
||||
)), unchecked((int)(0x040001)), unchecked((int)(0x020000)), unchecked((int)(0x020004)), unchecked((int)(0x020003)), unchecked((int)(0x030002)), unchecked((int)(0x020000)), unchecked((int)(0x020004)), unchecked((int)(0x020003)), unchecked((int
|
||||
)(0x040005)) };
|
||||
|
||||
/// <summary>Decodes a number in the range [0..255], by reading 1 - 11 bits.</summary>
|
||||
private static int DecodeVarLenUnsignedByte(Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
if (Org.Brotli.Dec.BitReader.ReadBits(br, 1) != 0)
|
||||
{
|
||||
int n = Org.Brotli.Dec.BitReader.ReadBits(br, 3);
|
||||
if (n == 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Org.Brotli.Dec.BitReader.ReadBits(br, n) + (1 << n);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static void DecodeMetaBlockLength(Org.Brotli.Dec.BitReader br, Org.Brotli.Dec.State state)
|
||||
{
|
||||
state.inputEnd = Org.Brotli.Dec.BitReader.ReadBits(br, 1) == 1;
|
||||
state.metaBlockLength = 0;
|
||||
state.isUncompressed = false;
|
||||
state.isMetadata = false;
|
||||
if (state.inputEnd && Org.Brotli.Dec.BitReader.ReadBits(br, 1) != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int sizeNibbles = Org.Brotli.Dec.BitReader.ReadBits(br, 2) + 4;
|
||||
if (sizeNibbles == 7)
|
||||
{
|
||||
state.isMetadata = true;
|
||||
if (Org.Brotli.Dec.BitReader.ReadBits(br, 1) != 0)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Corrupted reserved bit");
|
||||
}
|
||||
int sizeBytes = Org.Brotli.Dec.BitReader.ReadBits(br, 2);
|
||||
if (sizeBytes == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < sizeBytes; i++)
|
||||
{
|
||||
int bits = Org.Brotli.Dec.BitReader.ReadBits(br, 8);
|
||||
if (bits == 0 && i + 1 == sizeBytes && sizeBytes > 1)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Exuberant nibble");
|
||||
}
|
||||
state.metaBlockLength |= bits << (i * 8);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < sizeNibbles; i++)
|
||||
{
|
||||
int bits = Org.Brotli.Dec.BitReader.ReadBits(br, 4);
|
||||
if (bits == 0 && i + 1 == sizeNibbles && sizeNibbles > 4)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Exuberant nibble");
|
||||
}
|
||||
state.metaBlockLength |= bits << (i * 4);
|
||||
}
|
||||
}
|
||||
state.metaBlockLength++;
|
||||
if (!state.inputEnd)
|
||||
{
|
||||
state.isUncompressed = Org.Brotli.Dec.BitReader.ReadBits(br, 1) == 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Decodes the next Huffman code from bit-stream.</summary>
|
||||
private static int ReadSymbol(int[] table, int offset, Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
int val = (int)((long)(((ulong)br.accumulator) >> br.bitOffset));
|
||||
offset += val & HuffmanTableMask;
|
||||
int bits = table[offset] >> 16;
|
||||
int sym = table[offset] & unchecked((int)(0xFFFF));
|
||||
if (bits <= HuffmanTableBits)
|
||||
{
|
||||
br.bitOffset += bits;
|
||||
return sym;
|
||||
}
|
||||
offset += sym;
|
||||
int mask = (1 << bits) - 1;
|
||||
offset += (int)(((uint)(val & mask)) >> HuffmanTableBits);
|
||||
br.bitOffset += ((table[offset] >> 16) + HuffmanTableBits);
|
||||
return table[offset] & unchecked((int)(0xFFFF));
|
||||
}
|
||||
|
||||
private static int ReadBlockLength(int[] table, int offset, Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader.FillBitWindow(br);
|
||||
int code = ReadSymbol(table, offset, br);
|
||||
int n = Org.Brotli.Dec.Prefix.BlockLengthNBits[code];
|
||||
return Org.Brotli.Dec.Prefix.BlockLengthOffset[code] + Org.Brotli.Dec.BitReader.ReadBits(br, n);
|
||||
}
|
||||
|
||||
private static int TranslateShortCodes(int code, int[] ringBuffer, int index)
|
||||
{
|
||||
if (code < NumDistanceShortCodes)
|
||||
{
|
||||
index += DistanceShortCodeIndexOffset[code];
|
||||
index &= 3;
|
||||
return ringBuffer[index] + DistanceShortCodeValueOffset[code];
|
||||
}
|
||||
return code - NumDistanceShortCodes + 1;
|
||||
}
|
||||
|
||||
private static void MoveToFront(int[] v, int index)
|
||||
{
|
||||
int value = v[index];
|
||||
for (; index > 0; index--)
|
||||
{
|
||||
v[index] = v[index - 1];
|
||||
}
|
||||
v[0] = value;
|
||||
}
|
||||
|
||||
private static void InverseMoveToFrontTransform(byte[] v, int vLen)
|
||||
{
|
||||
int[] mtf = new int[256];
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
mtf[i] = i;
|
||||
}
|
||||
for (int i = 0; i < vLen; i++)
|
||||
{
|
||||
int index = v[i] & unchecked((int)(0xFF));
|
||||
v[i] = unchecked((byte)mtf[index]);
|
||||
if (index != 0)
|
||||
{
|
||||
MoveToFront(mtf, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ReadHuffmanCodeLengths(int[] codeLengthCodeLengths, int numSymbols, int[] codeLengths, Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
int symbol = 0;
|
||||
int prevCodeLen = DefaultCodeLength;
|
||||
int repeat = 0;
|
||||
int repeatCodeLen = 0;
|
||||
int space = 32768;
|
||||
int[] table = new int[32];
|
||||
Org.Brotli.Dec.Huffman.BuildHuffmanTable(table, 0, 5, codeLengthCodeLengths, CodeLengthCodes);
|
||||
while (symbol < numSymbols && space > 0)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
Org.Brotli.Dec.BitReader.FillBitWindow(br);
|
||||
int p = (int)(((long)(((ulong)br.accumulator) >> br.bitOffset))) & 31;
|
||||
br.bitOffset += table[p] >> 16;
|
||||
int codeLen = table[p] & unchecked((int)(0xFFFF));
|
||||
if (codeLen < CodeLengthRepeatCode)
|
||||
{
|
||||
repeat = 0;
|
||||
codeLengths[symbol++] = codeLen;
|
||||
if (codeLen != 0)
|
||||
{
|
||||
prevCodeLen = codeLen;
|
||||
space -= 32768 >> codeLen;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int extraBits = codeLen - 14;
|
||||
int newLen = 0;
|
||||
if (codeLen == CodeLengthRepeatCode)
|
||||
{
|
||||
newLen = prevCodeLen;
|
||||
}
|
||||
if (repeatCodeLen != newLen)
|
||||
{
|
||||
repeat = 0;
|
||||
repeatCodeLen = newLen;
|
||||
}
|
||||
int oldRepeat = repeat;
|
||||
if (repeat > 0)
|
||||
{
|
||||
repeat -= 2;
|
||||
repeat <<= extraBits;
|
||||
}
|
||||
repeat += Org.Brotli.Dec.BitReader.ReadBits(br, extraBits) + 3;
|
||||
int repeatDelta = repeat - oldRepeat;
|
||||
if (symbol + repeatDelta > numSymbols)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("symbol + repeatDelta > numSymbols");
|
||||
}
|
||||
// COV_NF_LINE
|
||||
for (int i = 0; i < repeatDelta; i++)
|
||||
{
|
||||
codeLengths[symbol++] = repeatCodeLen;
|
||||
}
|
||||
if (repeatCodeLen != 0)
|
||||
{
|
||||
space -= repeatDelta << (15 - repeatCodeLen);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (space != 0)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Unused space");
|
||||
}
|
||||
// COV_NF_LINE
|
||||
// TODO: Pass max_symbol to Huffman table builder instead?
|
||||
Org.Brotli.Dec.Utils.FillWithZeroes(codeLengths, symbol, numSymbols - symbol);
|
||||
}
|
||||
|
||||
// TODO: Use specialized versions for smaller tables.
|
||||
internal static void ReadHuffmanCode(int alphabetSize, int[] table, int offset, Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
bool ok = true;
|
||||
int simpleCodeOrSkip;
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
// TODO: Avoid allocation.
|
||||
int[] codeLengths = new int[alphabetSize];
|
||||
simpleCodeOrSkip = Org.Brotli.Dec.BitReader.ReadBits(br, 2);
|
||||
if (simpleCodeOrSkip == 1)
|
||||
{
|
||||
// Read symbols, codes & code lengths directly.
|
||||
int maxBitsCounter = alphabetSize - 1;
|
||||
int maxBits = 0;
|
||||
int[] symbols = new int[4];
|
||||
int numSymbols = Org.Brotli.Dec.BitReader.ReadBits(br, 2) + 1;
|
||||
while (maxBitsCounter != 0)
|
||||
{
|
||||
maxBitsCounter >>= 1;
|
||||
maxBits++;
|
||||
}
|
||||
// TODO: uncomment when codeLengths is reused.
|
||||
// Utils.fillWithZeroes(codeLengths, 0, alphabetSize);
|
||||
for (int i = 0; i < numSymbols; i++)
|
||||
{
|
||||
symbols[i] = Org.Brotli.Dec.BitReader.ReadBits(br, maxBits) % alphabetSize;
|
||||
codeLengths[symbols[i]] = 2;
|
||||
}
|
||||
codeLengths[symbols[0]] = 1;
|
||||
switch (numSymbols)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
ok = symbols[0] != symbols[1];
|
||||
codeLengths[symbols[1]] = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
case 3:
|
||||
{
|
||||
ok = symbols[0] != symbols[1] && symbols[0] != symbols[2] && symbols[1] != symbols[2];
|
||||
break;
|
||||
}
|
||||
|
||||
case 4:
|
||||
default:
|
||||
{
|
||||
ok = symbols[0] != symbols[1] && symbols[0] != symbols[2] && symbols[0] != symbols[3] && symbols[1] != symbols[2] && symbols[1] != symbols[3] && symbols[2] != symbols[3];
|
||||
if (Org.Brotli.Dec.BitReader.ReadBits(br, 1) == 1)
|
||||
{
|
||||
codeLengths[symbols[2]] = 3;
|
||||
codeLengths[symbols[3]] = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
codeLengths[symbols[0]] = 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Decode Huffman-coded code lengths.
|
||||
int[] codeLengthCodeLengths = new int[CodeLengthCodes];
|
||||
int space = 32;
|
||||
int numCodes = 0;
|
||||
for (int i = simpleCodeOrSkip; i < CodeLengthCodes && space > 0; i++)
|
||||
{
|
||||
int codeLenIdx = CodeLengthCodeOrder[i];
|
||||
Org.Brotli.Dec.BitReader.FillBitWindow(br);
|
||||
int p = (int)((long)(((ulong)br.accumulator) >> br.bitOffset)) & 15;
|
||||
// TODO: Demultiplex FIXED_TABLE.
|
||||
br.bitOffset += FixedTable[p] >> 16;
|
||||
int v = FixedTable[p] & unchecked((int)(0xFFFF));
|
||||
codeLengthCodeLengths[codeLenIdx] = v;
|
||||
if (v != 0)
|
||||
{
|
||||
space -= (32 >> v);
|
||||
numCodes++;
|
||||
}
|
||||
}
|
||||
ok = (numCodes == 1 || space == 0);
|
||||
ReadHuffmanCodeLengths(codeLengthCodeLengths, alphabetSize, codeLengths, br);
|
||||
}
|
||||
if (!ok)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Can't readHuffmanCode");
|
||||
}
|
||||
// COV_NF_LINE
|
||||
Org.Brotli.Dec.Huffman.BuildHuffmanTable(table, offset, HuffmanTableBits, codeLengths, alphabetSize);
|
||||
}
|
||||
|
||||
private static int DecodeContextMap(int contextMapSize, byte[] contextMap, Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
int numTrees = DecodeVarLenUnsignedByte(br) + 1;
|
||||
if (numTrees == 1)
|
||||
{
|
||||
Org.Brotli.Dec.Utils.FillWithZeroes(contextMap, 0, contextMapSize);
|
||||
return numTrees;
|
||||
}
|
||||
bool useRleForZeros = Org.Brotli.Dec.BitReader.ReadBits(br, 1) == 1;
|
||||
int maxRunLengthPrefix = 0;
|
||||
if (useRleForZeros)
|
||||
{
|
||||
maxRunLengthPrefix = Org.Brotli.Dec.BitReader.ReadBits(br, 4) + 1;
|
||||
}
|
||||
int[] table = new int[Org.Brotli.Dec.Huffman.HuffmanMaxTableSize];
|
||||
ReadHuffmanCode(numTrees + maxRunLengthPrefix, table, 0, br);
|
||||
for (int i = 0; i < contextMapSize; )
|
||||
{
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
Org.Brotli.Dec.BitReader.FillBitWindow(br);
|
||||
int code = ReadSymbol(table, 0, br);
|
||||
if (code == 0)
|
||||
{
|
||||
contextMap[i] = 0;
|
||||
i++;
|
||||
}
|
||||
else if (code <= maxRunLengthPrefix)
|
||||
{
|
||||
int reps = (1 << code) + Org.Brotli.Dec.BitReader.ReadBits(br, code);
|
||||
while (reps != 0)
|
||||
{
|
||||
if (i >= contextMapSize)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Corrupted context map");
|
||||
}
|
||||
// COV_NF_LINE
|
||||
contextMap[i] = 0;
|
||||
i++;
|
||||
reps--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
contextMap[i] = unchecked((byte)(code - maxRunLengthPrefix));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (Org.Brotli.Dec.BitReader.ReadBits(br, 1) == 1)
|
||||
{
|
||||
InverseMoveToFrontTransform(contextMap, contextMapSize);
|
||||
}
|
||||
return numTrees;
|
||||
}
|
||||
|
||||
private static void DecodeBlockTypeAndLength(Org.Brotli.Dec.State state, int treeType)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader br = state.br;
|
||||
int[] ringBuffers = state.blockTypeRb;
|
||||
int offset = treeType * 2;
|
||||
Org.Brotli.Dec.BitReader.FillBitWindow(br);
|
||||
int blockType = ReadSymbol(state.blockTypeTrees, treeType * Org.Brotli.Dec.Huffman.HuffmanMaxTableSize, br);
|
||||
state.blockLength[treeType] = ReadBlockLength(state.blockLenTrees, treeType * Org.Brotli.Dec.Huffman.HuffmanMaxTableSize, br);
|
||||
if (blockType == 1)
|
||||
{
|
||||
blockType = ringBuffers[offset + 1] + 1;
|
||||
}
|
||||
else if (blockType == 0)
|
||||
{
|
||||
blockType = ringBuffers[offset];
|
||||
}
|
||||
else
|
||||
{
|
||||
blockType -= 2;
|
||||
}
|
||||
if (blockType >= state.numBlockTypes[treeType])
|
||||
{
|
||||
blockType -= state.numBlockTypes[treeType];
|
||||
}
|
||||
ringBuffers[offset] = ringBuffers[offset + 1];
|
||||
ringBuffers[offset + 1] = blockType;
|
||||
}
|
||||
|
||||
private static void DecodeLiteralBlockSwitch(Org.Brotli.Dec.State state)
|
||||
{
|
||||
DecodeBlockTypeAndLength(state, 0);
|
||||
int literalBlockType = state.blockTypeRb[1];
|
||||
state.contextMapSlice = literalBlockType << LiteralContextBits;
|
||||
state.literalTreeIndex = state.contextMap[state.contextMapSlice] & unchecked((int)(0xFF));
|
||||
state.literalTree = state.hGroup0.trees[state.literalTreeIndex];
|
||||
int contextMode = state.contextModes[literalBlockType];
|
||||
state.contextLookupOffset1 = Org.Brotli.Dec.Context.LookupOffsets[contextMode];
|
||||
state.contextLookupOffset2 = Org.Brotli.Dec.Context.LookupOffsets[contextMode + 1];
|
||||
}
|
||||
|
||||
private static void DecodeCommandBlockSwitch(Org.Brotli.Dec.State state)
|
||||
{
|
||||
DecodeBlockTypeAndLength(state, 1);
|
||||
state.treeCommandOffset = state.hGroup1.trees[state.blockTypeRb[3]];
|
||||
}
|
||||
|
||||
private static void DecodeDistanceBlockSwitch(Org.Brotli.Dec.State state)
|
||||
{
|
||||
DecodeBlockTypeAndLength(state, 2);
|
||||
state.distContextMapSlice = state.blockTypeRb[5] << DistanceContextBits;
|
||||
}
|
||||
|
||||
private static void MaybeReallocateRingBuffer(Org.Brotli.Dec.State state)
|
||||
{
|
||||
int newSize = state.maxRingBufferSize;
|
||||
if ((long)newSize > state.expectedTotalSize)
|
||||
{
|
||||
/* TODO: Handle 2GB+ cases more gracefully. */
|
||||
int minimalNewSize = (int)state.expectedTotalSize + state.customDictionary.Length;
|
||||
while ((newSize >> 1) > minimalNewSize)
|
||||
{
|
||||
newSize >>= 1;
|
||||
}
|
||||
if (!state.inputEnd && newSize < 16384 && state.maxRingBufferSize >= 16384)
|
||||
{
|
||||
newSize = 16384;
|
||||
}
|
||||
}
|
||||
if (newSize <= state.ringBufferSize)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int ringBufferSizeWithSlack = newSize + Org.Brotli.Dec.Dictionary.MaxTransformedWordLength;
|
||||
byte[] newBuffer = new byte[ringBufferSizeWithSlack];
|
||||
if (state.ringBuffer != null)
|
||||
{
|
||||
System.Array.Copy(state.ringBuffer, 0, newBuffer, 0, state.ringBufferSize);
|
||||
}
|
||||
else if (state.customDictionary.Length != 0)
|
||||
{
|
||||
/* Prepend custom dictionary, if any. */
|
||||
int length = state.customDictionary.Length;
|
||||
int offset = 0;
|
||||
if (length > state.maxBackwardDistance)
|
||||
{
|
||||
offset = length - state.maxBackwardDistance;
|
||||
length = state.maxBackwardDistance;
|
||||
}
|
||||
System.Array.Copy(state.customDictionary, offset, newBuffer, 0, length);
|
||||
state.pos = length;
|
||||
state.bytesToIgnore = length;
|
||||
}
|
||||
state.ringBuffer = newBuffer;
|
||||
state.ringBufferSize = newSize;
|
||||
}
|
||||
|
||||
/// <summary>Reads next metablock header.</summary>
|
||||
/// <param name="state">decoding state</param>
|
||||
private static void ReadMetablockInfo(Org.Brotli.Dec.State state)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader br = state.br;
|
||||
if (state.inputEnd)
|
||||
{
|
||||
state.nextRunningState = Org.Brotli.Dec.RunningState.Finished;
|
||||
state.bytesToWrite = state.pos;
|
||||
state.bytesWritten = 0;
|
||||
state.runningState = Org.Brotli.Dec.RunningState.Write;
|
||||
return;
|
||||
}
|
||||
// TODO: Reset? Do we need this?
|
||||
state.hGroup0.codes = null;
|
||||
state.hGroup0.trees = null;
|
||||
state.hGroup1.codes = null;
|
||||
state.hGroup1.trees = null;
|
||||
state.hGroup2.codes = null;
|
||||
state.hGroup2.trees = null;
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
DecodeMetaBlockLength(br, state);
|
||||
if (state.metaBlockLength == 0 && !state.isMetadata)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (state.isUncompressed || state.isMetadata)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader.JumpToByteBoundary(br);
|
||||
state.runningState = state.isMetadata ? Org.Brotli.Dec.RunningState.ReadMetadata : Org.Brotli.Dec.RunningState.CopyUncompressed;
|
||||
}
|
||||
else
|
||||
{
|
||||
state.runningState = Org.Brotli.Dec.RunningState.CompressedBlockStart;
|
||||
}
|
||||
if (state.isMetadata)
|
||||
{
|
||||
return;
|
||||
}
|
||||
state.expectedTotalSize += state.metaBlockLength;
|
||||
if (state.ringBufferSize < state.maxRingBufferSize)
|
||||
{
|
||||
MaybeReallocateRingBuffer(state);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ReadMetablockHuffmanCodesAndContextMaps(Org.Brotli.Dec.State state)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader br = state.br;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
state.numBlockTypes[i] = DecodeVarLenUnsignedByte(br) + 1;
|
||||
state.blockLength[i] = 1 << 28;
|
||||
if (state.numBlockTypes[i] > 1)
|
||||
{
|
||||
ReadHuffmanCode(state.numBlockTypes[i] + 2, state.blockTypeTrees, i * Org.Brotli.Dec.Huffman.HuffmanMaxTableSize, br);
|
||||
ReadHuffmanCode(NumBlockLengthCodes, state.blockLenTrees, i * Org.Brotli.Dec.Huffman.HuffmanMaxTableSize, br);
|
||||
state.blockLength[i] = ReadBlockLength(state.blockLenTrees, i * Org.Brotli.Dec.Huffman.HuffmanMaxTableSize, br);
|
||||
}
|
||||
}
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
state.distancePostfixBits = Org.Brotli.Dec.BitReader.ReadBits(br, 2);
|
||||
state.numDirectDistanceCodes = NumDistanceShortCodes + (Org.Brotli.Dec.BitReader.ReadBits(br, 4) << state.distancePostfixBits);
|
||||
state.distancePostfixMask = (1 << state.distancePostfixBits) - 1;
|
||||
int numDistanceCodes = state.numDirectDistanceCodes + (48 << state.distancePostfixBits);
|
||||
// TODO: Reuse?
|
||||
state.contextModes = new byte[state.numBlockTypes[0]];
|
||||
for (int i = 0; i < state.numBlockTypes[0]; )
|
||||
{
|
||||
/* Ensure that less than 256 bits read between readMoreInput. */
|
||||
int limit = System.Math.Min(i + 96, state.numBlockTypes[0]);
|
||||
for (; i < limit; ++i)
|
||||
{
|
||||
state.contextModes[i] = unchecked((byte)(Org.Brotli.Dec.BitReader.ReadBits(br, 2) << 1));
|
||||
}
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
}
|
||||
// TODO: Reuse?
|
||||
state.contextMap = new byte[state.numBlockTypes[0] << LiteralContextBits];
|
||||
int numLiteralTrees = DecodeContextMap(state.numBlockTypes[0] << LiteralContextBits, state.contextMap, br);
|
||||
state.trivialLiteralContext = true;
|
||||
for (int j = 0; j < state.numBlockTypes[0] << LiteralContextBits; j++)
|
||||
{
|
||||
if (state.contextMap[j] != j >> LiteralContextBits)
|
||||
{
|
||||
state.trivialLiteralContext = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// TODO: Reuse?
|
||||
state.distContextMap = new byte[state.numBlockTypes[2] << DistanceContextBits];
|
||||
int numDistTrees = DecodeContextMap(state.numBlockTypes[2] << DistanceContextBits, state.distContextMap, br);
|
||||
Org.Brotli.Dec.HuffmanTreeGroup.Init(state.hGroup0, NumLiteralCodes, numLiteralTrees);
|
||||
Org.Brotli.Dec.HuffmanTreeGroup.Init(state.hGroup1, NumInsertAndCopyCodes, state.numBlockTypes[1]);
|
||||
Org.Brotli.Dec.HuffmanTreeGroup.Init(state.hGroup2, numDistanceCodes, numDistTrees);
|
||||
Org.Brotli.Dec.HuffmanTreeGroup.Decode(state.hGroup0, br);
|
||||
Org.Brotli.Dec.HuffmanTreeGroup.Decode(state.hGroup1, br);
|
||||
Org.Brotli.Dec.HuffmanTreeGroup.Decode(state.hGroup2, br);
|
||||
state.contextMapSlice = 0;
|
||||
state.distContextMapSlice = 0;
|
||||
state.contextLookupOffset1 = Org.Brotli.Dec.Context.LookupOffsets[state.contextModes[0]];
|
||||
state.contextLookupOffset2 = Org.Brotli.Dec.Context.LookupOffsets[state.contextModes[0] + 1];
|
||||
state.literalTreeIndex = 0;
|
||||
state.literalTree = state.hGroup0.trees[0];
|
||||
state.treeCommandOffset = state.hGroup1.trees[0];
|
||||
// TODO: == 0?
|
||||
state.blockTypeRb[0] = state.blockTypeRb[2] = state.blockTypeRb[4] = 1;
|
||||
state.blockTypeRb[1] = state.blockTypeRb[3] = state.blockTypeRb[5] = 0;
|
||||
}
|
||||
|
||||
private static void CopyUncompressedData(Org.Brotli.Dec.State state)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader br = state.br;
|
||||
byte[] ringBuffer = state.ringBuffer;
|
||||
// Could happen if block ends at ring buffer end.
|
||||
if (state.metaBlockLength <= 0)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader.Reload(br);
|
||||
state.runningState = Org.Brotli.Dec.RunningState.BlockStart;
|
||||
return;
|
||||
}
|
||||
int chunkLength = System.Math.Min(state.ringBufferSize - state.pos, state.metaBlockLength);
|
||||
Org.Brotli.Dec.BitReader.CopyBytes(br, ringBuffer, state.pos, chunkLength);
|
||||
state.metaBlockLength -= chunkLength;
|
||||
state.pos += chunkLength;
|
||||
if (state.pos == state.ringBufferSize)
|
||||
{
|
||||
state.nextRunningState = Org.Brotli.Dec.RunningState.CopyUncompressed;
|
||||
state.bytesToWrite = state.ringBufferSize;
|
||||
state.bytesWritten = 0;
|
||||
state.runningState = Org.Brotli.Dec.RunningState.Write;
|
||||
return;
|
||||
}
|
||||
Org.Brotli.Dec.BitReader.Reload(br);
|
||||
state.runningState = Org.Brotli.Dec.RunningState.BlockStart;
|
||||
}
|
||||
|
||||
private static bool WriteRingBuffer(Org.Brotli.Dec.State state)
|
||||
{
|
||||
/* Ignore custom dictionary bytes. */
|
||||
if (state.bytesToIgnore != 0)
|
||||
{
|
||||
state.bytesWritten += state.bytesToIgnore;
|
||||
state.bytesToIgnore = 0;
|
||||
}
|
||||
int toWrite = System.Math.Min(state.outputLength - state.outputUsed, state.bytesToWrite - state.bytesWritten);
|
||||
if (toWrite != 0)
|
||||
{
|
||||
System.Array.Copy(state.ringBuffer, state.bytesWritten, state.output, state.outputOffset + state.outputUsed, toWrite);
|
||||
state.outputUsed += toWrite;
|
||||
state.bytesWritten += toWrite;
|
||||
}
|
||||
return state.outputUsed < state.outputLength;
|
||||
}
|
||||
|
||||
internal static void SetCustomDictionary(Org.Brotli.Dec.State state, byte[] data)
|
||||
{
|
||||
state.customDictionary = (data == null) ? new byte[0] : data;
|
||||
}
|
||||
|
||||
/// <summary>Actual decompress implementation.</summary>
|
||||
internal static void Decompress(Org.Brotli.Dec.State state)
|
||||
{
|
||||
if (state.runningState == Org.Brotli.Dec.RunningState.Uninitialized)
|
||||
{
|
||||
throw new System.InvalidOperationException("Can't decompress until initialized");
|
||||
}
|
||||
if (state.runningState == Org.Brotli.Dec.RunningState.Closed)
|
||||
{
|
||||
throw new System.InvalidOperationException("Can't decompress after close");
|
||||
}
|
||||
Org.Brotli.Dec.BitReader br = state.br;
|
||||
int ringBufferMask = state.ringBufferSize - 1;
|
||||
byte[] ringBuffer = state.ringBuffer;
|
||||
while (state.runningState != Org.Brotli.Dec.RunningState.Finished)
|
||||
{
|
||||
switch (state.runningState)
|
||||
{
|
||||
case Org.Brotli.Dec.RunningState.BlockStart:
|
||||
{
|
||||
// TODO: extract cases to methods for the better readability.
|
||||
if (state.metaBlockLength < 0)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Invalid metablock length");
|
||||
}
|
||||
ReadMetablockInfo(state);
|
||||
/* Ring-buffer would be reallocated here. */
|
||||
ringBufferMask = state.ringBufferSize - 1;
|
||||
ringBuffer = state.ringBuffer;
|
||||
continue;
|
||||
}
|
||||
|
||||
case Org.Brotli.Dec.RunningState.CompressedBlockStart:
|
||||
{
|
||||
ReadMetablockHuffmanCodesAndContextMaps(state);
|
||||
state.runningState = Org.Brotli.Dec.RunningState.MainLoop;
|
||||
goto case Org.Brotli.Dec.RunningState.MainLoop;
|
||||
}
|
||||
|
||||
case Org.Brotli.Dec.RunningState.MainLoop:
|
||||
{
|
||||
// Fall through
|
||||
if (state.metaBlockLength <= 0)
|
||||
{
|
||||
state.runningState = Org.Brotli.Dec.RunningState.BlockStart;
|
||||
continue;
|
||||
}
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
if (state.blockLength[1] == 0)
|
||||
{
|
||||
DecodeCommandBlockSwitch(state);
|
||||
}
|
||||
state.blockLength[1]--;
|
||||
Org.Brotli.Dec.BitReader.FillBitWindow(br);
|
||||
int cmdCode = ReadSymbol(state.hGroup1.codes, state.treeCommandOffset, br);
|
||||
int rangeIdx = (int)(((uint)cmdCode) >> 6);
|
||||
state.distanceCode = 0;
|
||||
if (rangeIdx >= 2)
|
||||
{
|
||||
rangeIdx -= 2;
|
||||
state.distanceCode = -1;
|
||||
}
|
||||
int insertCode = Org.Brotli.Dec.Prefix.InsertRangeLut[rangeIdx] + (((int)(((uint)cmdCode) >> 3)) & 7);
|
||||
int copyCode = Org.Brotli.Dec.Prefix.CopyRangeLut[rangeIdx] + (cmdCode & 7);
|
||||
state.insertLength = Org.Brotli.Dec.Prefix.InsertLengthOffset[insertCode] + Org.Brotli.Dec.BitReader.ReadBits(br, Org.Brotli.Dec.Prefix.InsertLengthNBits[insertCode]);
|
||||
state.copyLength = Org.Brotli.Dec.Prefix.CopyLengthOffset[copyCode] + Org.Brotli.Dec.BitReader.ReadBits(br, Org.Brotli.Dec.Prefix.CopyLengthNBits[copyCode]);
|
||||
state.j = 0;
|
||||
state.runningState = Org.Brotli.Dec.RunningState.InsertLoop;
|
||||
goto case Org.Brotli.Dec.RunningState.InsertLoop;
|
||||
}
|
||||
|
||||
case Org.Brotli.Dec.RunningState.InsertLoop:
|
||||
{
|
||||
// Fall through
|
||||
if (state.trivialLiteralContext)
|
||||
{
|
||||
while (state.j < state.insertLength)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
if (state.blockLength[0] == 0)
|
||||
{
|
||||
DecodeLiteralBlockSwitch(state);
|
||||
}
|
||||
state.blockLength[0]--;
|
||||
Org.Brotli.Dec.BitReader.FillBitWindow(br);
|
||||
ringBuffer[state.pos] = unchecked((byte)ReadSymbol(state.hGroup0.codes, state.literalTree, br));
|
||||
state.j++;
|
||||
if (state.pos++ == ringBufferMask)
|
||||
{
|
||||
state.nextRunningState = Org.Brotli.Dec.RunningState.InsertLoop;
|
||||
state.bytesToWrite = state.ringBufferSize;
|
||||
state.bytesWritten = 0;
|
||||
state.runningState = Org.Brotli.Dec.RunningState.Write;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int prevByte1 = ringBuffer[(state.pos - 1) & ringBufferMask] & unchecked((int)(0xFF));
|
||||
int prevByte2 = ringBuffer[(state.pos - 2) & ringBufferMask] & unchecked((int)(0xFF));
|
||||
while (state.j < state.insertLength)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
if (state.blockLength[0] == 0)
|
||||
{
|
||||
DecodeLiteralBlockSwitch(state);
|
||||
}
|
||||
int literalTreeIndex = state.contextMap[state.contextMapSlice + (Org.Brotli.Dec.Context.Lookup[state.contextLookupOffset1 + prevByte1] | Org.Brotli.Dec.Context.Lookup[state.contextLookupOffset2 + prevByte2])] & unchecked((int)(0xFF));
|
||||
state.blockLength[0]--;
|
||||
prevByte2 = prevByte1;
|
||||
Org.Brotli.Dec.BitReader.FillBitWindow(br);
|
||||
prevByte1 = ReadSymbol(state.hGroup0.codes, state.hGroup0.trees[literalTreeIndex], br);
|
||||
ringBuffer[state.pos] = unchecked((byte)prevByte1);
|
||||
state.j++;
|
||||
if (state.pos++ == ringBufferMask)
|
||||
{
|
||||
state.nextRunningState = Org.Brotli.Dec.RunningState.InsertLoop;
|
||||
state.bytesToWrite = state.ringBufferSize;
|
||||
state.bytesWritten = 0;
|
||||
state.runningState = Org.Brotli.Dec.RunningState.Write;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (state.runningState != Org.Brotli.Dec.RunningState.InsertLoop)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
state.metaBlockLength -= state.insertLength;
|
||||
if (state.metaBlockLength <= 0)
|
||||
{
|
||||
state.runningState = Org.Brotli.Dec.RunningState.MainLoop;
|
||||
continue;
|
||||
}
|
||||
if (state.distanceCode < 0)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
if (state.blockLength[2] == 0)
|
||||
{
|
||||
DecodeDistanceBlockSwitch(state);
|
||||
}
|
||||
state.blockLength[2]--;
|
||||
Org.Brotli.Dec.BitReader.FillBitWindow(br);
|
||||
state.distanceCode = ReadSymbol(state.hGroup2.codes, state.hGroup2.trees[state.distContextMap[state.distContextMapSlice + (state.copyLength > 4 ? 3 : state.copyLength - 2)] & unchecked((int)(0xFF))], br);
|
||||
if (state.distanceCode >= state.numDirectDistanceCodes)
|
||||
{
|
||||
state.distanceCode -= state.numDirectDistanceCodes;
|
||||
int postfix = state.distanceCode & state.distancePostfixMask;
|
||||
state.distanceCode = (int)(((uint)state.distanceCode) >> state.distancePostfixBits);
|
||||
int n = ((int)(((uint)state.distanceCode) >> 1)) + 1;
|
||||
int offset = ((2 + (state.distanceCode & 1)) << n) - 4;
|
||||
state.distanceCode = state.numDirectDistanceCodes + postfix + ((offset + Org.Brotli.Dec.BitReader.ReadBits(br, n)) << state.distancePostfixBits);
|
||||
}
|
||||
}
|
||||
// Convert the distance code to the actual distance by possibly looking up past distances
|
||||
// from the ringBuffer.
|
||||
state.distance = TranslateShortCodes(state.distanceCode, state.distRb, state.distRbIdx);
|
||||
if (state.distance < 0)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Negative distance");
|
||||
}
|
||||
// COV_NF_LINE
|
||||
if (state.maxDistance != state.maxBackwardDistance && state.pos < state.maxBackwardDistance)
|
||||
{
|
||||
state.maxDistance = state.pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
state.maxDistance = state.maxBackwardDistance;
|
||||
}
|
||||
state.copyDst = state.pos;
|
||||
if (state.distance > state.maxDistance)
|
||||
{
|
||||
state.runningState = Org.Brotli.Dec.RunningState.Transform;
|
||||
continue;
|
||||
}
|
||||
if (state.distanceCode > 0)
|
||||
{
|
||||
state.distRb[state.distRbIdx & 3] = state.distance;
|
||||
state.distRbIdx++;
|
||||
}
|
||||
if (state.copyLength > state.metaBlockLength)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Invalid backward reference");
|
||||
}
|
||||
// COV_NF_LINE
|
||||
state.j = 0;
|
||||
state.runningState = Org.Brotli.Dec.RunningState.CopyLoop;
|
||||
goto case Org.Brotli.Dec.RunningState.CopyLoop;
|
||||
}
|
||||
|
||||
case Org.Brotli.Dec.RunningState.CopyLoop:
|
||||
{
|
||||
// fall through
|
||||
int src = (state.pos - state.distance) & ringBufferMask;
|
||||
int dst = state.pos;
|
||||
int copyLength = state.copyLength - state.j;
|
||||
if ((src + copyLength < ringBufferMask) && (dst + copyLength < ringBufferMask))
|
||||
{
|
||||
for (int k = 0; k < copyLength; ++k)
|
||||
{
|
||||
ringBuffer[dst++] = ringBuffer[src++];
|
||||
}
|
||||
state.j += copyLength;
|
||||
state.metaBlockLength -= copyLength;
|
||||
state.pos += copyLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; state.j < state.copyLength; )
|
||||
{
|
||||
ringBuffer[state.pos] = ringBuffer[(state.pos - state.distance) & ringBufferMask];
|
||||
state.metaBlockLength--;
|
||||
state.j++;
|
||||
if (state.pos++ == ringBufferMask)
|
||||
{
|
||||
state.nextRunningState = Org.Brotli.Dec.RunningState.CopyLoop;
|
||||
state.bytesToWrite = state.ringBufferSize;
|
||||
state.bytesWritten = 0;
|
||||
state.runningState = Org.Brotli.Dec.RunningState.Write;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (state.runningState == Org.Brotli.Dec.RunningState.CopyLoop)
|
||||
{
|
||||
state.runningState = Org.Brotli.Dec.RunningState.MainLoop;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
case Org.Brotli.Dec.RunningState.Transform:
|
||||
{
|
||||
if (state.copyLength >= Org.Brotli.Dec.Dictionary.MinWordLength && state.copyLength <= Org.Brotli.Dec.Dictionary.MaxWordLength)
|
||||
{
|
||||
int offset = Org.Brotli.Dec.Dictionary.OffsetsByLength[state.copyLength];
|
||||
int wordId = state.distance - state.maxDistance - 1;
|
||||
int shift = Org.Brotli.Dec.Dictionary.SizeBitsByLength[state.copyLength];
|
||||
int mask = (1 << shift) - 1;
|
||||
int wordIdx = wordId & mask;
|
||||
int transformIdx = (int)(((uint)wordId) >> shift);
|
||||
offset += wordIdx * state.copyLength;
|
||||
if (transformIdx < Org.Brotli.Dec.Transform.Transforms.Length)
|
||||
{
|
||||
int len = Org.Brotli.Dec.Transform.TransformDictionaryWord(ringBuffer, state.copyDst, Org.Brotli.Dec.Dictionary.GetData(), offset, state.copyLength, Org.Brotli.Dec.Transform.Transforms[transformIdx]);
|
||||
state.copyDst += len;
|
||||
state.pos += len;
|
||||
state.metaBlockLength -= len;
|
||||
if (state.copyDst >= state.ringBufferSize)
|
||||
{
|
||||
state.nextRunningState = Org.Brotli.Dec.RunningState.CopyWrapBuffer;
|
||||
state.bytesToWrite = state.ringBufferSize;
|
||||
state.bytesWritten = 0;
|
||||
state.runningState = Org.Brotli.Dec.RunningState.Write;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Invalid backward reference");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// COV_NF_LINE
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Invalid backward reference");
|
||||
}
|
||||
// COV_NF_LINE
|
||||
state.runningState = Org.Brotli.Dec.RunningState.MainLoop;
|
||||
continue;
|
||||
}
|
||||
|
||||
case Org.Brotli.Dec.RunningState.CopyWrapBuffer:
|
||||
{
|
||||
System.Array.Copy(ringBuffer, state.ringBufferSize, ringBuffer, 0, state.copyDst - state.ringBufferSize);
|
||||
state.runningState = Org.Brotli.Dec.RunningState.MainLoop;
|
||||
continue;
|
||||
}
|
||||
|
||||
case Org.Brotli.Dec.RunningState.ReadMetadata:
|
||||
{
|
||||
while (state.metaBlockLength > 0)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
// Optimize
|
||||
Org.Brotli.Dec.BitReader.ReadBits(br, 8);
|
||||
state.metaBlockLength--;
|
||||
}
|
||||
state.runningState = Org.Brotli.Dec.RunningState.BlockStart;
|
||||
continue;
|
||||
}
|
||||
|
||||
case Org.Brotli.Dec.RunningState.CopyUncompressed:
|
||||
{
|
||||
CopyUncompressedData(state);
|
||||
continue;
|
||||
}
|
||||
|
||||
case Org.Brotli.Dec.RunningState.Write:
|
||||
{
|
||||
if (!WriteRingBuffer(state))
|
||||
{
|
||||
// Output buffer is full.
|
||||
return;
|
||||
}
|
||||
if (state.pos >= state.maxBackwardDistance)
|
||||
{
|
||||
state.maxDistance = state.maxBackwardDistance;
|
||||
}
|
||||
state.pos &= ringBufferMask;
|
||||
state.runningState = state.nextRunningState;
|
||||
continue;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Unexpected state " + state.runningState);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (state.runningState == Org.Brotli.Dec.RunningState.Finished)
|
||||
{
|
||||
if (state.metaBlockLength < 0)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Invalid metablock length");
|
||||
}
|
||||
Org.Brotli.Dec.BitReader.JumpToByteBoundary(br);
|
||||
Org.Brotli.Dec.BitReader.CheckHealth(state.br, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
97
AssetStudio/Brotli/Dictionary.cs
Normal file
97
AssetStudio/Brotli/Dictionary.cs
Normal file
File diff suppressed because one or more lines are too long
149
AssetStudio/Brotli/Huffman.cs
Normal file
149
AssetStudio/Brotli/Huffman.cs
Normal file
@ -0,0 +1,149 @@
|
||||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>Utilities for building Huffman decoding tables.</summary>
|
||||
internal sealed class Huffman
|
||||
{
|
||||
/// <summary>
|
||||
/// Maximum possible Huffman table size for an alphabet size of 704, max code length 15 and root
|
||||
/// table bits 8.
|
||||
/// </summary>
|
||||
internal const int HuffmanMaxTableSize = 1080;
|
||||
|
||||
private const int MaxLength = 15;
|
||||
|
||||
/// <summary>Returns reverse(reverse(key, len) + 1, len).</summary>
|
||||
/// <remarks>
|
||||
/// Returns reverse(reverse(key, len) + 1, len).
|
||||
/// <p> reverse(key, len) is the bit-wise reversal of the len least significant bits of key.
|
||||
/// </remarks>
|
||||
private static int GetNextKey(int key, int len)
|
||||
{
|
||||
int step = 1 << (len - 1);
|
||||
while ((key & step) != 0)
|
||||
{
|
||||
step >>= 1;
|
||||
}
|
||||
return (key & (step - 1)) + step;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores
|
||||
/// <paramref name="item"/>
|
||||
/// in
|
||||
/// <c>table[0], table[step], table[2 * step] .., table[end]</c>
|
||||
/// .
|
||||
/// <p> Assumes that end is an integer multiple of step.
|
||||
/// </summary>
|
||||
private static void ReplicateValue(int[] table, int offset, int step, int end, int item)
|
||||
{
|
||||
do
|
||||
{
|
||||
end -= step;
|
||||
table[offset + end] = item;
|
||||
}
|
||||
while (end > 0);
|
||||
}
|
||||
|
||||
/// <param name="count">histogram of bit lengths for the remaining symbols,</param>
|
||||
/// <param name="len">code length of the next processed symbol.</param>
|
||||
/// <returns>table width of the next 2nd level table.</returns>
|
||||
private static int NextTableBitSize(int[] count, int len, int rootBits)
|
||||
{
|
||||
int left = 1 << (len - rootBits);
|
||||
while (len < MaxLength)
|
||||
{
|
||||
left -= count[len];
|
||||
if (left <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
len++;
|
||||
left <<= 1;
|
||||
}
|
||||
return len - rootBits;
|
||||
}
|
||||
|
||||
/// <summary>Builds Huffman lookup table assuming code lengths are in symbol order.</summary>
|
||||
internal static void BuildHuffmanTable(int[] rootTable, int tableOffset, int rootBits, int[] codeLengths, int codeLengthsSize)
|
||||
{
|
||||
int key;
|
||||
// Reversed prefix code.
|
||||
int[] sorted = new int[codeLengthsSize];
|
||||
// Symbols sorted by code length.
|
||||
// TODO: fill with zeroes?
|
||||
int[] count = new int[MaxLength + 1];
|
||||
// Number of codes of each length.
|
||||
int[] offset = new int[MaxLength + 1];
|
||||
// Offsets in sorted table for each length.
|
||||
int symbol;
|
||||
// Build histogram of code lengths.
|
||||
for (symbol = 0; symbol < codeLengthsSize; symbol++)
|
||||
{
|
||||
count[codeLengths[symbol]]++;
|
||||
}
|
||||
// Generate offsets into sorted symbol table by code length.
|
||||
offset[1] = 0;
|
||||
for (int len = 1; len < MaxLength; len++)
|
||||
{
|
||||
offset[len + 1] = offset[len] + count[len];
|
||||
}
|
||||
// Sort symbols by length, by symbol order within each length.
|
||||
for (symbol = 0; symbol < codeLengthsSize; symbol++)
|
||||
{
|
||||
if (codeLengths[symbol] != 0)
|
||||
{
|
||||
sorted[offset[codeLengths[symbol]]++] = symbol;
|
||||
}
|
||||
}
|
||||
int tableBits = rootBits;
|
||||
int tableSize = 1 << tableBits;
|
||||
int totalSize = tableSize;
|
||||
// Special case code with only one value.
|
||||
if (offset[MaxLength] == 1)
|
||||
{
|
||||
for (key = 0; key < totalSize; key++)
|
||||
{
|
||||
rootTable[tableOffset + key] = sorted[0];
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Fill in root table.
|
||||
key = 0;
|
||||
symbol = 0;
|
||||
for (int len = 1, step = 2; len <= rootBits; len++, step <<= 1)
|
||||
{
|
||||
for (; count[len] > 0; count[len]--)
|
||||
{
|
||||
ReplicateValue(rootTable, tableOffset + key, step, tableSize, len << 16 | sorted[symbol++]);
|
||||
key = GetNextKey(key, len);
|
||||
}
|
||||
}
|
||||
// Fill in 2nd level tables and add pointers to root table.
|
||||
int mask = totalSize - 1;
|
||||
int low = -1;
|
||||
int currentOffset = tableOffset;
|
||||
for (int len = rootBits + 1, step = 2; len <= MaxLength; len++, step <<= 1)
|
||||
{
|
||||
for (; count[len] > 0; count[len]--)
|
||||
{
|
||||
if ((key & mask) != low)
|
||||
{
|
||||
currentOffset += tableSize;
|
||||
tableBits = NextTableBitSize(count, len, rootBits);
|
||||
tableSize = 1 << tableBits;
|
||||
totalSize += tableSize;
|
||||
low = key & mask;
|
||||
rootTable[tableOffset + low] = (tableBits + rootBits) << 16 | (currentOffset - tableOffset - low);
|
||||
}
|
||||
ReplicateValue(rootTable, currentOffset + (key >> rootBits), step, tableSize, (len - rootBits) << 16 | sorted[symbol++]);
|
||||
key = GetNextKey(key, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
50
AssetStudio/Brotli/HuffmanTreeGroup.cs
Normal file
50
AssetStudio/Brotli/HuffmanTreeGroup.cs
Normal file
@ -0,0 +1,50 @@
|
||||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>Contains a collection of huffman trees with the same alphabet size.</summary>
|
||||
internal sealed class HuffmanTreeGroup
|
||||
{
|
||||
/// <summary>The maximal alphabet size in this group.</summary>
|
||||
private int alphabetSize;
|
||||
|
||||
/// <summary>Storage for Huffman lookup tables.</summary>
|
||||
internal int[] codes;
|
||||
|
||||
/// <summary>
|
||||
/// Offsets of distinct lookup tables in
|
||||
/// <see cref="codes"/>
|
||||
/// storage.
|
||||
/// </summary>
|
||||
internal int[] trees;
|
||||
|
||||
/// <summary>Initializes the Huffman tree group.</summary>
|
||||
/// <param name="group">POJO to be initialised</param>
|
||||
/// <param name="alphabetSize">the maximal alphabet size in this group</param>
|
||||
/// <param name="n">number of Huffman codes</param>
|
||||
internal static void Init(Org.Brotli.Dec.HuffmanTreeGroup group, int alphabetSize, int n)
|
||||
{
|
||||
group.alphabetSize = alphabetSize;
|
||||
group.codes = new int[n * Org.Brotli.Dec.Huffman.HuffmanMaxTableSize];
|
||||
group.trees = new int[n];
|
||||
}
|
||||
|
||||
/// <summary>Decodes Huffman trees from input stream and constructs lookup tables.</summary>
|
||||
/// <param name="group">target POJO</param>
|
||||
/// <param name="br">data source</param>
|
||||
internal static void Decode(Org.Brotli.Dec.HuffmanTreeGroup group, Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
int next = 0;
|
||||
int n = group.trees.Length;
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
group.trees[i] = next;
|
||||
Org.Brotli.Dec.Decode.ReadHuffmanCode(group.alphabetSize, group.codes, next, br);
|
||||
next += Org.Brotli.Dec.Huffman.HuffmanMaxTableSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
36
AssetStudio/Brotli/IntReader.cs
Normal file
36
AssetStudio/Brotli/IntReader.cs
Normal file
@ -0,0 +1,36 @@
|
||||
/* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>Byte-to-int conversion magic.</summary>
|
||||
internal sealed class IntReader
|
||||
{
|
||||
private byte[] byteBuffer;
|
||||
|
||||
private int[] intBuffer;
|
||||
|
||||
internal static void Init(Org.Brotli.Dec.IntReader ir, byte[] byteBuffer, int[] intBuffer)
|
||||
{
|
||||
ir.byteBuffer = byteBuffer;
|
||||
ir.intBuffer = intBuffer;
|
||||
}
|
||||
|
||||
/// <summary>Translates bytes to ints.</summary>
|
||||
/// <remarks>
|
||||
/// Translates bytes to ints.
|
||||
/// NB: intLen == 4 * byteSize!
|
||||
/// NB: intLen should be less or equal to intBuffer length.
|
||||
/// </remarks>
|
||||
internal static void Convert(Org.Brotli.Dec.IntReader ir, int intLen)
|
||||
{
|
||||
for (int i = 0; i < intLen; ++i)
|
||||
{
|
||||
ir.intBuffer[i] = ((ir.byteBuffer[i * 4] & unchecked((int)(0xFF)))) | ((ir.byteBuffer[(i * 4) + 1] & unchecked((int)(0xFF))) << 8) | ((ir.byteBuffer[(i * 4) + 2] & unchecked((int)(0xFF))) << 16) | ((ir.byteBuffer[(i * 4) + 3] & unchecked((int
|
||||
)(0xFF))) << 24);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
33
AssetStudio/Brotli/Prefix.cs
Normal file
33
AssetStudio/Brotli/Prefix.cs
Normal file
@ -0,0 +1,33 @@
|
||||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>Lookup tables to map prefix codes to value ranges.</summary>
|
||||
/// <remarks>
|
||||
/// Lookup tables to map prefix codes to value ranges.
|
||||
/// <p> This is used during decoding of the block lengths, literal insertion lengths and copy
|
||||
/// lengths.
|
||||
/// <p> Range represents values: [offset, offset + 2 ^ n_bits)
|
||||
/// </remarks>
|
||||
internal sealed class Prefix
|
||||
{
|
||||
internal static readonly int[] BlockLengthOffset = new int[] { 1, 5, 9, 13, 17, 25, 33, 41, 49, 65, 81, 97, 113, 145, 177, 209, 241, 305, 369, 497, 753, 1265, 2289, 4337, 8433, 16625 };
|
||||
|
||||
internal static readonly int[] BlockLengthNBits = new int[] { 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8, 9, 10, 11, 12, 13, 24 };
|
||||
|
||||
internal static readonly int[] InsertLengthOffset = new int[] { 0, 1, 2, 3, 4, 5, 6, 8, 10, 14, 18, 26, 34, 50, 66, 98, 130, 194, 322, 578, 1090, 2114, 6210, 22594 };
|
||||
|
||||
internal static readonly int[] InsertLengthNBits = new int[] { 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 12, 14, 24 };
|
||||
|
||||
internal static readonly int[] CopyLengthOffset = new int[] { 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 18, 22, 30, 38, 54, 70, 102, 134, 198, 326, 582, 1094, 2118 };
|
||||
|
||||
internal static readonly int[] CopyLengthNBits = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 24 };
|
||||
|
||||
internal static readonly int[] InsertRangeLut = new int[] { 0, 0, 8, 8, 0, 16, 8, 16, 16 };
|
||||
|
||||
internal static readonly int[] CopyRangeLut = new int[] { 0, 8, 0, 8, 16, 0, 16, 8, 16 };
|
||||
}
|
||||
}
|
37
AssetStudio/Brotli/RunningState.cs
Normal file
37
AssetStudio/Brotli/RunningState.cs
Normal file
@ -0,0 +1,37 @@
|
||||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>Enumeration of decoding state-machine.</summary>
|
||||
internal sealed class RunningState
|
||||
{
|
||||
internal const int Uninitialized = 0;
|
||||
|
||||
internal const int BlockStart = 1;
|
||||
|
||||
internal const int CompressedBlockStart = 2;
|
||||
|
||||
internal const int MainLoop = 3;
|
||||
|
||||
internal const int ReadMetadata = 4;
|
||||
|
||||
internal const int CopyUncompressed = 5;
|
||||
|
||||
internal const int InsertLoop = 6;
|
||||
|
||||
internal const int CopyLoop = 7;
|
||||
|
||||
internal const int CopyWrapBuffer = 8;
|
||||
|
||||
internal const int Transform = 9;
|
||||
|
||||
internal const int Finished = 10;
|
||||
|
||||
internal const int Closed = 11;
|
||||
|
||||
internal const int Write = 12;
|
||||
}
|
||||
}
|
171
AssetStudio/Brotli/State.cs
Normal file
171
AssetStudio/Brotli/State.cs
Normal file
@ -0,0 +1,171 @@
|
||||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
internal sealed class State
|
||||
{
|
||||
internal int runningState = Org.Brotli.Dec.RunningState.Uninitialized;
|
||||
|
||||
internal int nextRunningState;
|
||||
|
||||
internal readonly Org.Brotli.Dec.BitReader br = new Org.Brotli.Dec.BitReader();
|
||||
|
||||
internal byte[] ringBuffer;
|
||||
|
||||
internal readonly int[] blockTypeTrees = new int[3 * Org.Brotli.Dec.Huffman.HuffmanMaxTableSize];
|
||||
|
||||
internal readonly int[] blockLenTrees = new int[3 * Org.Brotli.Dec.Huffman.HuffmanMaxTableSize];
|
||||
|
||||
internal int metaBlockLength;
|
||||
|
||||
internal bool inputEnd;
|
||||
|
||||
internal bool isUncompressed;
|
||||
|
||||
internal bool isMetadata;
|
||||
|
||||
internal readonly Org.Brotli.Dec.HuffmanTreeGroup hGroup0 = new Org.Brotli.Dec.HuffmanTreeGroup();
|
||||
|
||||
internal readonly Org.Brotli.Dec.HuffmanTreeGroup hGroup1 = new Org.Brotli.Dec.HuffmanTreeGroup();
|
||||
|
||||
internal readonly Org.Brotli.Dec.HuffmanTreeGroup hGroup2 = new Org.Brotli.Dec.HuffmanTreeGroup();
|
||||
|
||||
internal readonly int[] blockLength = new int[3];
|
||||
|
||||
internal readonly int[] numBlockTypes = new int[3];
|
||||
|
||||
internal readonly int[] blockTypeRb = new int[6];
|
||||
|
||||
internal readonly int[] distRb = new int[] { 16, 15, 11, 4 };
|
||||
|
||||
internal int pos = 0;
|
||||
|
||||
internal int maxDistance = 0;
|
||||
|
||||
internal int distRbIdx = 0;
|
||||
|
||||
internal bool trivialLiteralContext = false;
|
||||
|
||||
internal int literalTreeIndex = 0;
|
||||
|
||||
internal int literalTree;
|
||||
|
||||
internal int j;
|
||||
|
||||
internal int insertLength;
|
||||
|
||||
internal byte[] contextModes;
|
||||
|
||||
internal byte[] contextMap;
|
||||
|
||||
internal int contextMapSlice;
|
||||
|
||||
internal int distContextMapSlice;
|
||||
|
||||
internal int contextLookupOffset1;
|
||||
|
||||
internal int contextLookupOffset2;
|
||||
|
||||
internal int treeCommandOffset;
|
||||
|
||||
internal int distanceCode;
|
||||
|
||||
internal byte[] distContextMap;
|
||||
|
||||
internal int numDirectDistanceCodes;
|
||||
|
||||
internal int distancePostfixMask;
|
||||
|
||||
internal int distancePostfixBits;
|
||||
|
||||
internal int distance;
|
||||
|
||||
internal int copyLength;
|
||||
|
||||
internal int copyDst;
|
||||
|
||||
internal int maxBackwardDistance;
|
||||
|
||||
internal int maxRingBufferSize;
|
||||
|
||||
internal int ringBufferSize = 0;
|
||||
|
||||
internal long expectedTotalSize = 0;
|
||||
|
||||
internal byte[] customDictionary = new byte[0];
|
||||
|
||||
internal int bytesToIgnore = 0;
|
||||
|
||||
internal int outputOffset;
|
||||
|
||||
internal int outputLength;
|
||||
|
||||
internal int outputUsed;
|
||||
|
||||
internal int bytesWritten;
|
||||
|
||||
internal int bytesToWrite;
|
||||
|
||||
internal byte[] output;
|
||||
|
||||
// Current meta-block header information.
|
||||
// TODO: Update to current spec.
|
||||
private static int DecodeWindowBits(Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
if (Org.Brotli.Dec.BitReader.ReadBits(br, 1) == 0)
|
||||
{
|
||||
return 16;
|
||||
}
|
||||
int n = Org.Brotli.Dec.BitReader.ReadBits(br, 3);
|
||||
if (n != 0)
|
||||
{
|
||||
return 17 + n;
|
||||
}
|
||||
n = Org.Brotli.Dec.BitReader.ReadBits(br, 3);
|
||||
if (n != 0)
|
||||
{
|
||||
return 8 + n;
|
||||
}
|
||||
return 17;
|
||||
}
|
||||
|
||||
/// <summary>Associate input with decoder state.</summary>
|
||||
/// <param name="state">uninitialized state without associated input</param>
|
||||
/// <param name="input">compressed data source</param>
|
||||
internal static void SetInput(Org.Brotli.Dec.State state, System.IO.Stream input)
|
||||
{
|
||||
if (state.runningState != Org.Brotli.Dec.RunningState.Uninitialized)
|
||||
{
|
||||
throw new System.InvalidOperationException("State MUST be uninitialized");
|
||||
}
|
||||
Org.Brotli.Dec.BitReader.Init(state.br, input);
|
||||
int windowBits = DecodeWindowBits(state.br);
|
||||
if (windowBits == 9)
|
||||
{
|
||||
/* Reserved case for future expansion. */
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Invalid 'windowBits' code");
|
||||
}
|
||||
state.maxRingBufferSize = 1 << windowBits;
|
||||
state.maxBackwardDistance = state.maxRingBufferSize - 16;
|
||||
state.runningState = Org.Brotli.Dec.RunningState.BlockStart;
|
||||
}
|
||||
|
||||
/// <exception cref="System.IO.IOException"/>
|
||||
internal static void Close(Org.Brotli.Dec.State state)
|
||||
{
|
||||
if (state.runningState == Org.Brotli.Dec.RunningState.Uninitialized)
|
||||
{
|
||||
throw new System.InvalidOperationException("State MUST be initialized");
|
||||
}
|
||||
if (state.runningState == Org.Brotli.Dec.RunningState.Closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
state.runningState = Org.Brotli.Dec.RunningState.Closed;
|
||||
Org.Brotli.Dec.BitReader.Close(state.br);
|
||||
}
|
||||
}
|
||||
}
|
154
AssetStudio/Brotli/Transform.cs
Normal file
154
AssetStudio/Brotli/Transform.cs
Normal file
@ -0,0 +1,154 @@
|
||||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>Transformations on dictionary words.</summary>
|
||||
internal sealed class Transform
|
||||
{
|
||||
private readonly byte[] prefix;
|
||||
|
||||
private readonly int type;
|
||||
|
||||
private readonly byte[] suffix;
|
||||
|
||||
internal Transform(string prefix, int type, string suffix)
|
||||
{
|
||||
this.prefix = ReadUniBytes(prefix);
|
||||
this.type = type;
|
||||
this.suffix = ReadUniBytes(suffix);
|
||||
}
|
||||
|
||||
internal static byte[] ReadUniBytes(string uniBytes)
|
||||
{
|
||||
byte[] result = new byte[uniBytes.Length];
|
||||
for (int i = 0; i < result.Length; ++i)
|
||||
{
|
||||
result[i] = unchecked((byte)uniBytes[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static readonly Org.Brotli.Dec.Transform[] Transforms = new Org.Brotli.Dec.Transform[] { new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, string.Empty), new Org.Brotli.Dec.Transform(string.Empty,
|
||||
Org.Brotli.Dec.WordTransformType.Identity, " "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.Identity, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitFirst1, string.Empty), new Org.Brotli.Dec.Transform
|
||||
(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " the "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.Identity
|
||||
, string.Empty), new Org.Brotli.Dec.Transform("s ", Org.Brotli.Dec.WordTransformType.Identity, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " of "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
|
||||
.UppercaseFirst, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " and "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitFirst2, string.Empty), new Org.Brotli.Dec.Transform
|
||||
(string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast1, string.Empty), new Org.Brotli.Dec.Transform(", ", Org.Brotli.Dec.WordTransformType.Identity, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity
|
||||
, ", "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseFirst, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " in "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
|
||||
.Identity, " to "), new Org.Brotli.Dec.Transform("e ", Org.Brotli.Dec.WordTransformType.Identity, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "\""), new Org.Brotli.Dec.Transform(string.Empty,
|
||||
Org.Brotli.Dec.WordTransformType.Identity, "."), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "\">"), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "\n"), new
|
||||
Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast3, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "]"), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
|
||||
.Identity, " for "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitFirst3, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast2, string.Empty), new Org.Brotli.Dec.Transform
|
||||
(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " a "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " that "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseFirst
|
||||
, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, ". "), new Org.Brotli.Dec.Transform(".", Org.Brotli.Dec.WordTransformType.Identity, string.Empty), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType
|
||||
.Identity, ", "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitFirst4, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " with "), new Org.Brotli.Dec.Transform
|
||||
(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "'"), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " from "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity
|
||||
, " by "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitFirst5, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitFirst6, string.Empty), new Org.Brotli.Dec.Transform
|
||||
(" the ", Org.Brotli.Dec.WordTransformType.Identity, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast4, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
|
||||
.Identity, ". The "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " on "), new Org.Brotli.Dec.Transform
|
||||
(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " as "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " is "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast7
|
||||
, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast1, "ing "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "\n\t"), new Org.Brotli.Dec.Transform(string.Empty
|
||||
, Org.Brotli.Dec.WordTransformType.Identity, ":"), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.Identity, ". "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "ed "), new Org.Brotli.Dec.Transform
|
||||
(string.Empty, Org.Brotli.Dec.WordTransformType.OmitFirst9, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitFirst7, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
|
||||
.OmitLast6, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "("), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst, ", "), new Org.Brotli.Dec.Transform
|
||||
(string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast8, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " at "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
|
||||
.Identity, "ly "), new Org.Brotli.Dec.Transform(" the ", Org.Brotli.Dec.WordTransformType.Identity, " of "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast5, string.Empty), new Org.Brotli.Dec.Transform(
|
||||
string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast9, string.Empty), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseFirst, ", "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst
|
||||
, "\""), new Org.Brotli.Dec.Transform(".", Org.Brotli.Dec.WordTransformType.Identity, "("), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
|
||||
.UppercaseFirst, "\">"), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "=\""), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.Identity, "."), new Org.Brotli.Dec.Transform(".com/",
|
||||
Org.Brotli.Dec.WordTransformType.Identity, string.Empty), new Org.Brotli.Dec.Transform(" the ", Org.Brotli.Dec.WordTransformType.Identity, " of the "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst
|
||||
, "'"), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, ". This "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, ","), new Org.Brotli.Dec.Transform(".", Org.Brotli.Dec.WordTransformType
|
||||
.Identity, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst, "("), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst, "."), new Org.Brotli.Dec.Transform
|
||||
(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " not "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.Identity, "=\""), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "er "
|
||||
), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseAll, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "al "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType
|
||||
.UppercaseAll, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "='"), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, "\""), new Org.Brotli.Dec.Transform
|
||||
(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst, ". "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.Identity, "("), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity,
|
||||
"ful "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseFirst, ". "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "ive "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
|
||||
.Identity, "less "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, "'"), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "est "), new Org.Brotli.Dec.Transform
|
||||
(" ", Org.Brotli.Dec.WordTransformType.UppercaseFirst, "."), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, "\">"), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.Identity, "='"
|
||||
), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst, ","), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "ize "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
|
||||
.UppercaseAll, "."), new Org.Brotli.Dec.Transform("\u00c2\u00a0", Org.Brotli.Dec.WordTransformType.Identity, string.Empty), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.Identity, ","), new Org.Brotli.Dec.Transform(string.Empty
|
||||
, Org.Brotli.Dec.WordTransformType.UppercaseFirst, "=\""), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, "=\""), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity
|
||||
, "ous "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, ", "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst, "='"), new Org.Brotli.Dec.Transform(" ",
|
||||
Org.Brotli.Dec.WordTransformType.UppercaseFirst, ","), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseAll, "=\""), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseAll, ", "), new Org.Brotli.Dec.Transform
|
||||
(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, ","), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, "("), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.
|
||||
UppercaseAll, ". "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseAll, "."), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, "='"), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType
|
||||
.UppercaseAll, ". "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseFirst, "=\""), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseAll, "='"), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType
|
||||
.UppercaseFirst, "='") };
|
||||
|
||||
internal static int TransformDictionaryWord(byte[] dst, int dstOffset, byte[] word, int wordOffset, int len, Org.Brotli.Dec.Transform transform)
|
||||
{
|
||||
int offset = dstOffset;
|
||||
// Copy prefix.
|
||||
byte[] @string = transform.prefix;
|
||||
int tmp = @string.Length;
|
||||
int i = 0;
|
||||
// In most cases tmp < 10 -> no benefits from System.arrayCopy
|
||||
while (i < tmp)
|
||||
{
|
||||
dst[offset++] = @string[i++];
|
||||
}
|
||||
// Copy trimmed word.
|
||||
int op = transform.type;
|
||||
tmp = Org.Brotli.Dec.WordTransformType.GetOmitFirst(op);
|
||||
if (tmp > len)
|
||||
{
|
||||
tmp = len;
|
||||
}
|
||||
wordOffset += tmp;
|
||||
len -= tmp;
|
||||
len -= Org.Brotli.Dec.WordTransformType.GetOmitLast(op);
|
||||
i = len;
|
||||
while (i > 0)
|
||||
{
|
||||
dst[offset++] = word[wordOffset++];
|
||||
i--;
|
||||
}
|
||||
if (op == Org.Brotli.Dec.WordTransformType.UppercaseAll || op == Org.Brotli.Dec.WordTransformType.UppercaseFirst)
|
||||
{
|
||||
int uppercaseOffset = offset - len;
|
||||
if (op == Org.Brotli.Dec.WordTransformType.UppercaseFirst)
|
||||
{
|
||||
len = 1;
|
||||
}
|
||||
while (len > 0)
|
||||
{
|
||||
tmp = dst[uppercaseOffset] & unchecked((int)(0xFF));
|
||||
if (tmp < unchecked((int)(0xc0)))
|
||||
{
|
||||
if (tmp >= 'a' && tmp <= 'z')
|
||||
{
|
||||
dst[uppercaseOffset] ^= unchecked((byte)32);
|
||||
}
|
||||
uppercaseOffset += 1;
|
||||
len -= 1;
|
||||
}
|
||||
else if (tmp < unchecked((int)(0xe0)))
|
||||
{
|
||||
dst[uppercaseOffset + 1] ^= unchecked((byte)32);
|
||||
uppercaseOffset += 2;
|
||||
len -= 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[uppercaseOffset + 2] ^= unchecked((byte)5);
|
||||
uppercaseOffset += 3;
|
||||
len -= 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Copy suffix.
|
||||
@string = transform.suffix;
|
||||
tmp = @string.Length;
|
||||
i = 0;
|
||||
while (i < tmp)
|
||||
{
|
||||
dst[offset++] = @string[i++];
|
||||
}
|
||||
return offset - dstOffset;
|
||||
}
|
||||
}
|
||||
}
|
59
AssetStudio/Brotli/Utils.cs
Normal file
59
AssetStudio/Brotli/Utils.cs
Normal file
@ -0,0 +1,59 @@
|
||||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>A set of utility methods.</summary>
|
||||
internal sealed class Utils
|
||||
{
|
||||
private static readonly byte[] ByteZeroes = new byte[1024];
|
||||
|
||||
private static readonly int[] IntZeroes = new int[1024];
|
||||
|
||||
/// <summary>Fills byte array with zeroes.</summary>
|
||||
/// <remarks>
|
||||
/// Fills byte array with zeroes.
|
||||
/// <p> Current implementation uses
|
||||
/// <see cref="System.Array.Copy(object, int, object, int, int)"/>
|
||||
/// , so it should be used for length not
|
||||
/// less than 16.
|
||||
/// </remarks>
|
||||
/// <param name="dest">array to fill with zeroes</param>
|
||||
/// <param name="offset">the first byte to fill</param>
|
||||
/// <param name="length">number of bytes to change</param>
|
||||
internal static void FillWithZeroes(byte[] dest, int offset, int length)
|
||||
{
|
||||
int cursor = 0;
|
||||
while (cursor < length)
|
||||
{
|
||||
int step = System.Math.Min(cursor + 1024, length) - cursor;
|
||||
System.Array.Copy(ByteZeroes, 0, dest, offset + cursor, step);
|
||||
cursor += step;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Fills int array with zeroes.</summary>
|
||||
/// <remarks>
|
||||
/// Fills int array with zeroes.
|
||||
/// <p> Current implementation uses
|
||||
/// <see cref="System.Array.Copy(object, int, object, int, int)"/>
|
||||
/// , so it should be used for length not
|
||||
/// less than 16.
|
||||
/// </remarks>
|
||||
/// <param name="dest">array to fill with zeroes</param>
|
||||
/// <param name="offset">the first item to fill</param>
|
||||
/// <param name="length">number of item to change</param>
|
||||
internal static void FillWithZeroes(int[] dest, int offset, int length)
|
||||
{
|
||||
int cursor = 0;
|
||||
while (cursor < length)
|
||||
{
|
||||
int step = System.Math.Min(cursor + 1024, length) - cursor;
|
||||
System.Array.Copy(IntZeroes, 0, dest, offset + cursor, step);
|
||||
cursor += step;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
68
AssetStudio/Brotli/WordTransformType.cs
Normal file
68
AssetStudio/Brotli/WordTransformType.cs
Normal file
@ -0,0 +1,68 @@
|
||||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>Enumeration of all possible word transformations.</summary>
|
||||
/// <remarks>
|
||||
/// Enumeration of all possible word transformations.
|
||||
/// <p>There are two simple types of transforms: omit X first/last symbols, two character-case
|
||||
/// transforms and the identity transform.
|
||||
/// </remarks>
|
||||
internal sealed class WordTransformType
|
||||
{
|
||||
internal const int Identity = 0;
|
||||
|
||||
internal const int OmitLast1 = 1;
|
||||
|
||||
internal const int OmitLast2 = 2;
|
||||
|
||||
internal const int OmitLast3 = 3;
|
||||
|
||||
internal const int OmitLast4 = 4;
|
||||
|
||||
internal const int OmitLast5 = 5;
|
||||
|
||||
internal const int OmitLast6 = 6;
|
||||
|
||||
internal const int OmitLast7 = 7;
|
||||
|
||||
internal const int OmitLast8 = 8;
|
||||
|
||||
internal const int OmitLast9 = 9;
|
||||
|
||||
internal const int UppercaseFirst = 10;
|
||||
|
||||
internal const int UppercaseAll = 11;
|
||||
|
||||
internal const int OmitFirst1 = 12;
|
||||
|
||||
internal const int OmitFirst2 = 13;
|
||||
|
||||
internal const int OmitFirst3 = 14;
|
||||
|
||||
internal const int OmitFirst4 = 15;
|
||||
|
||||
internal const int OmitFirst5 = 16;
|
||||
|
||||
internal const int OmitFirst6 = 17;
|
||||
|
||||
internal const int OmitFirst7 = 18;
|
||||
|
||||
internal const int OmitFirst8 = 19;
|
||||
|
||||
internal const int OmitFirst9 = 20;
|
||||
|
||||
internal static int GetOmitFirst(int type)
|
||||
{
|
||||
return type >= OmitFirst1 ? (type - OmitFirst1 + 1) : 0;
|
||||
}
|
||||
|
||||
internal static int GetOmitLast(int type)
|
||||
{
|
||||
return type <= OmitLast9 ? (type - OmitLast1 + 1) : 0;
|
||||
}
|
||||
}
|
||||
}
|
58
AssetStudio/BuildTarget.cs
Normal file
58
AssetStudio/BuildTarget.cs
Normal file
@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public enum BuildTarget
|
||||
{
|
||||
NoTarget = -2,
|
||||
AnyPlayer = -1,
|
||||
ValidPlayer = 1,
|
||||
StandaloneOSX = 2,
|
||||
StandaloneOSXPPC = 3,
|
||||
StandaloneOSXIntel = 4,
|
||||
StandaloneWindows,
|
||||
WebPlayer,
|
||||
WebPlayerStreamed,
|
||||
Wii = 8,
|
||||
iOS = 9,
|
||||
PS3,
|
||||
XBOX360,
|
||||
Broadcom = 12,
|
||||
Android = 13,
|
||||
StandaloneGLESEmu = 14,
|
||||
StandaloneGLES20Emu = 15,
|
||||
NaCl = 16,
|
||||
StandaloneLinux = 17,
|
||||
FlashPlayer = 18,
|
||||
StandaloneWindows64 = 19,
|
||||
WebGL,
|
||||
WSAPlayer,
|
||||
StandaloneLinux64 = 24,
|
||||
StandaloneLinuxUniversal,
|
||||
WP8Player,
|
||||
StandaloneOSXIntel64,
|
||||
BlackBerry,
|
||||
Tizen,
|
||||
PSP2,
|
||||
PS4,
|
||||
PSM,
|
||||
XboxOne,
|
||||
SamsungTV,
|
||||
N3DS,
|
||||
WiiU,
|
||||
tvOS,
|
||||
Switch,
|
||||
Lumin,
|
||||
Stadia,
|
||||
CloudRendering,
|
||||
GameCoreXboxSeries,
|
||||
GameCoreXboxOne,
|
||||
PS5,
|
||||
EmbeddedLinux,
|
||||
QNX,
|
||||
UnknownPlatform = 9999
|
||||
}
|
||||
}
|
20
AssetStudio/BuildType.cs
Normal file
20
AssetStudio/BuildType.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class BuildType
|
||||
{
|
||||
private string buildType;
|
||||
|
||||
public BuildType(string type)
|
||||
{
|
||||
buildType = type;
|
||||
}
|
||||
|
||||
public bool IsAlpha => buildType == "a";
|
||||
public bool IsPatch => buildType == "p";
|
||||
}
|
||||
}
|
420
AssetStudio/BundleFile.cs
Normal file
420
AssetStudio/BundleFile.cs
Normal file
@ -0,0 +1,420 @@
|
||||
using K4os.Compression.LZ4;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
[Flags]
|
||||
public enum ArchiveFlags
|
||||
{
|
||||
CompressionTypeMask = 0x3f,
|
||||
BlocksAndDirectoryInfoCombined = 0x40,
|
||||
BlocksInfoAtTheEnd = 0x80,
|
||||
OldWebPluginCompatibility = 0x100,
|
||||
BlockInfoNeedPaddingAtStart = 0x200
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum StorageBlockFlags
|
||||
{
|
||||
CompressionTypeMask = 0x3f,
|
||||
Streamed = 0x40
|
||||
}
|
||||
|
||||
public enum CompressionType
|
||||
{
|
||||
None,
|
||||
Lzma,
|
||||
Lz4,
|
||||
Lz4HC,
|
||||
Lzham,
|
||||
Lz4Mr0k
|
||||
}
|
||||
public class BundleFile
|
||||
{
|
||||
public class Header
|
||||
{
|
||||
public string signature;
|
||||
public uint version;
|
||||
public string unityVersion;
|
||||
public string unityRevision;
|
||||
public long size;
|
||||
public uint compressedBlocksInfoSize;
|
||||
public uint uncompressedBlocksInfoSize;
|
||||
public ArchiveFlags flags;
|
||||
}
|
||||
|
||||
public class StorageBlock
|
||||
{
|
||||
public uint compressedSize;
|
||||
public uint uncompressedSize;
|
||||
public StorageBlockFlags flags;
|
||||
}
|
||||
|
||||
public class Node
|
||||
{
|
||||
public long offset;
|
||||
public long size;
|
||||
public uint flags;
|
||||
public string path;
|
||||
}
|
||||
|
||||
public Header m_Header;
|
||||
private StorageBlock[] m_BlocksInfo;
|
||||
private Node[] m_DirectoryInfo;
|
||||
|
||||
public StreamFile[] FileList;
|
||||
|
||||
public BundleFile(FileReader reader)
|
||||
{
|
||||
m_Header = new Header();
|
||||
m_Header.signature = reader.ReadStringToNull();
|
||||
|
||||
if (reader.Game.Name == "BH3")
|
||||
{
|
||||
m_Header.version = 6;
|
||||
m_Header.unityVersion = "5.x.x";
|
||||
m_Header.unityRevision = "2017.4.18f1";
|
||||
}
|
||||
else if (reader.Game.Name == "SR_CB2" || reader.Game.Name == "SR_CB3")
|
||||
{
|
||||
var readHeader = m_Header.signature != "ENCR";
|
||||
|
||||
if (!readHeader)
|
||||
{
|
||||
m_Header.version = 7;
|
||||
m_Header.unityVersion = "5.x.x";
|
||||
m_Header.unityRevision = "2019.4.32f1";
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Header.version = reader.ReadUInt32();
|
||||
m_Header.unityVersion = reader.ReadStringToNull();
|
||||
m_Header.unityRevision = reader.ReadStringToNull();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Header.version = reader.ReadUInt32();
|
||||
m_Header.unityVersion = reader.ReadStringToNull();
|
||||
m_Header.unityRevision = reader.ReadStringToNull();
|
||||
}
|
||||
switch (m_Header.signature)
|
||||
{
|
||||
case "UnityArchive":
|
||||
break; //TODO
|
||||
case "UnityWeb":
|
||||
case "UnityRaw":
|
||||
if (m_Header.version == 6)
|
||||
{
|
||||
goto case "UnityFS";
|
||||
}
|
||||
ReadHeaderAndBlocksInfo(reader);
|
||||
using (var blocksStream = CreateBlocksStream(reader.FullPath))
|
||||
{
|
||||
ReadBlocksAndDirectory(reader, blocksStream);
|
||||
ReadFiles(blocksStream, reader.FullPath);
|
||||
}
|
||||
break;
|
||||
case "UnityFS":
|
||||
case "ENCR":
|
||||
ReadHeader(reader);
|
||||
if (reader.Game.Name == "ZZZ_CB1")
|
||||
{
|
||||
reader.AlignStream(0x10);
|
||||
}
|
||||
ReadBlocksInfoAndDirectory(reader);
|
||||
using (var blocksStream = CreateBlocksStream(reader.FullPath))
|
||||
{
|
||||
ReadBlocks(reader, blocksStream);
|
||||
ReadFiles(blocksStream, reader.FullPath);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadHeaderAndBlocksInfo(EndianBinaryReader reader)
|
||||
{
|
||||
if (m_Header.version >= 4)
|
||||
{
|
||||
var hash = reader.ReadBytes(16);
|
||||
var crc = reader.ReadUInt32();
|
||||
}
|
||||
var minimumStreamedBytes = reader.ReadUInt32();
|
||||
m_Header.size = reader.ReadUInt32();
|
||||
var numberOfLevelsToDownloadBeforeStreaming = reader.ReadUInt32();
|
||||
var levelCount = reader.ReadInt32();
|
||||
m_BlocksInfo = new StorageBlock[1];
|
||||
for (int i = 0; i < levelCount; i++)
|
||||
{
|
||||
var storageBlock = new StorageBlock()
|
||||
{
|
||||
compressedSize = reader.ReadUInt32(),
|
||||
uncompressedSize = reader.ReadUInt32(),
|
||||
};
|
||||
if (i == levelCount - 1)
|
||||
{
|
||||
m_BlocksInfo[0] = storageBlock;
|
||||
}
|
||||
}
|
||||
if (m_Header.version >= 2)
|
||||
{
|
||||
var completeFileSize = reader.ReadUInt32();
|
||||
}
|
||||
if (m_Header.version >= 3)
|
||||
{
|
||||
var fileInfoHeaderSize = reader.ReadUInt32();
|
||||
}
|
||||
reader.Position = m_Header.size;
|
||||
}
|
||||
|
||||
private Stream CreateBlocksStream(string path)
|
||||
{
|
||||
Stream blocksStream;
|
||||
var uncompressedSizeSum = m_BlocksInfo.Sum(x => x.uncompressedSize);
|
||||
if (uncompressedSizeSum >= int.MaxValue)
|
||||
{
|
||||
/*var memoryMappedFile = MemoryMappedFile.CreateNew(null, uncompressedSizeSum);
|
||||
assetsDataStream = memoryMappedFile.CreateViewStream();*/
|
||||
blocksStream = new FileStream(path + ".temp", FileMode.Create, FileAccess.ReadWrite, FileShare.None, 4096, FileOptions.DeleteOnClose);
|
||||
}
|
||||
else
|
||||
{
|
||||
blocksStream = new MemoryStream((int)uncompressedSizeSum);
|
||||
}
|
||||
return blocksStream;
|
||||
}
|
||||
|
||||
private void ReadBlocksAndDirectory(EndianBinaryReader reader, Stream blocksStream)
|
||||
{
|
||||
var isCompressed = m_Header.signature == "UnityWeb";
|
||||
foreach (var blockInfo in m_BlocksInfo)
|
||||
{
|
||||
var uncompressedBytes = reader.ReadBytes((int)blockInfo.compressedSize);
|
||||
if (isCompressed)
|
||||
{
|
||||
using (var memoryStream = new MemoryStream(uncompressedBytes))
|
||||
{
|
||||
using (var decompressStream = SevenZipHelper.StreamDecompress(memoryStream))
|
||||
{
|
||||
uncompressedBytes = decompressStream.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
blocksStream.Write(uncompressedBytes, 0, uncompressedBytes.Length);
|
||||
}
|
||||
blocksStream.Position = 0;
|
||||
var blocksReader = new EndianBinaryReader(blocksStream);
|
||||
var nodesCount = blocksReader.ReadInt32();
|
||||
m_DirectoryInfo = new Node[nodesCount];
|
||||
for (int i = 0; i < nodesCount; i++)
|
||||
{
|
||||
m_DirectoryInfo[i] = new Node
|
||||
{
|
||||
path = blocksReader.ReadStringToNull(),
|
||||
offset = blocksReader.ReadUInt32(),
|
||||
size = blocksReader.ReadUInt32()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public void ReadFiles(Stream blocksStream, string path)
|
||||
{
|
||||
FileList = new StreamFile[m_DirectoryInfo.Length];
|
||||
for (int i = 0; i < m_DirectoryInfo.Length; i++)
|
||||
{
|
||||
var node = m_DirectoryInfo[i];
|
||||
var file = new StreamFile();
|
||||
FileList[i] = file;
|
||||
file.path = node.path;
|
||||
file.fileName = Path.GetFileName(node.path);
|
||||
if (node.size >= int.MaxValue)
|
||||
{
|
||||
/*var memoryMappedFile = MemoryMappedFile.CreateNew(null, entryinfo_size);
|
||||
file.stream = memoryMappedFile.CreateViewStream();*/
|
||||
var extractPath = path + "_unpacked" + Path.DirectorySeparatorChar;
|
||||
Directory.CreateDirectory(extractPath);
|
||||
file.stream = new FileStream(extractPath + file.fileName, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);
|
||||
}
|
||||
else
|
||||
{
|
||||
file.stream = new MemoryStream((int)node.size);
|
||||
}
|
||||
blocksStream.Position = node.offset;
|
||||
blocksStream.CopyTo(file.stream, node.size);
|
||||
file.stream.Position = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void DecryptHeader(int key)
|
||||
{
|
||||
var rand = new XORShift128();
|
||||
rand.InitSeed(key);
|
||||
m_Header.flags ^= (ArchiveFlags)rand.NextDecryptInt();
|
||||
m_Header.size ^= rand.NextDecryptLong();
|
||||
m_Header.uncompressedBlocksInfoSize ^= rand.NextDecryptUInt();
|
||||
m_Header.compressedBlocksInfoSize ^= rand.NextDecryptUInt();
|
||||
}
|
||||
|
||||
private void ReadHeader(EndianBinaryReader reader)
|
||||
{
|
||||
if (reader.Game.Name == "BH3")
|
||||
{
|
||||
var key = reader.ReadInt32();
|
||||
m_Header.flags = (ArchiveFlags)reader.ReadUInt32();
|
||||
m_Header.size = reader.ReadInt64();
|
||||
m_Header.uncompressedBlocksInfoSize = reader.ReadUInt32();
|
||||
m_Header.compressedBlocksInfoSize = reader.ReadUInt32();
|
||||
DecryptHeader(key);
|
||||
var encUnityVersion = reader.ReadStringToNull();
|
||||
var encUnityRevision = reader.ReadStringToNull();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Header.size = reader.ReadInt64();
|
||||
m_Header.compressedBlocksInfoSize = reader.ReadUInt32();
|
||||
m_Header.uncompressedBlocksInfoSize = reader.ReadUInt32();
|
||||
m_Header.flags = (ArchiveFlags)reader.ReadUInt32();
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadBlocksInfoAndDirectory(EndianBinaryReader reader)
|
||||
{
|
||||
byte[] blocksInfoBytes;
|
||||
if (m_Header.version >= 7 && reader.Game.Name != "SR_CB2" && reader.Game.Name != "SR_CB3")
|
||||
{
|
||||
reader.AlignStream(16);
|
||||
}
|
||||
if ((m_Header.flags & ArchiveFlags.BlocksInfoAtTheEnd) != 0) //kArchiveBlocksInfoAtTheEnd
|
||||
{
|
||||
var position = reader.Position;
|
||||
reader.Position = reader.BaseStream.Length - m_Header.compressedBlocksInfoSize;
|
||||
blocksInfoBytes = reader.ReadBytes((int)m_Header.compressedBlocksInfoSize);
|
||||
reader.Position = position;
|
||||
}
|
||||
else //0x40 BlocksAndDirectoryInfoCombined
|
||||
{
|
||||
blocksInfoBytes = reader.ReadBytes((int)m_Header.compressedBlocksInfoSize);
|
||||
}
|
||||
MemoryStream blocksInfoUncompresseddStream;
|
||||
var uncompressedSize = m_Header.uncompressedBlocksInfoSize;
|
||||
var compressionType = (CompressionType)(m_Header.flags & ArchiveFlags.CompressionTypeMask);
|
||||
switch (compressionType) //kArchiveCompressionTypeMask
|
||||
{
|
||||
case CompressionType.None: //None
|
||||
{
|
||||
blocksInfoUncompresseddStream = new MemoryStream(blocksInfoBytes);
|
||||
break;
|
||||
}
|
||||
case CompressionType.Lzma: //LZMA
|
||||
{
|
||||
blocksInfoUncompresseddStream = new MemoryStream((int)(uncompressedSize));
|
||||
using (var blocksInfoCompressedStream = new MemoryStream(blocksInfoBytes))
|
||||
{
|
||||
SevenZipHelper.StreamDecompress(blocksInfoCompressedStream, blocksInfoUncompresseddStream, m_Header.compressedBlocksInfoSize, m_Header.uncompressedBlocksInfoSize);
|
||||
}
|
||||
blocksInfoUncompresseddStream.Position = 0;
|
||||
break;
|
||||
}
|
||||
case CompressionType.Lz4: //LZ4
|
||||
case CompressionType.Lz4HC: //LZ4HC
|
||||
{
|
||||
var uncompressedBytes = new byte[uncompressedSize];
|
||||
var numWrite = LZ4Codec.Decode(blocksInfoBytes, uncompressedBytes);
|
||||
if (numWrite != uncompressedSize)
|
||||
{
|
||||
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
|
||||
}
|
||||
blocksInfoUncompresseddStream = new MemoryStream(uncompressedBytes);
|
||||
break;
|
||||
}
|
||||
case CompressionType.Lz4Mr0k: //Lz4Mr0k
|
||||
var blocksInfoSize = blocksInfoBytes.Length;
|
||||
if (Mr0k.IsMr0k(blocksInfoBytes))
|
||||
{
|
||||
Mr0k.Decrypt(ref blocksInfoBytes, ref blocksInfoSize);
|
||||
}
|
||||
goto case CompressionType.Lz4HC;
|
||||
default:
|
||||
throw new IOException($"Unsupported compression type {compressionType}");
|
||||
}
|
||||
using (var blocksInfoReader = new EndianBinaryReader(blocksInfoUncompresseddStream))
|
||||
{
|
||||
if ((reader.Game.Name != "SR_CB2" && reader.Game.Name != "SR_CB3") || m_Header.signature != "ENCR")
|
||||
{
|
||||
var uncompressedDataHash = blocksInfoReader.ReadBytes(16);
|
||||
}
|
||||
var blocksInfoCount = blocksInfoReader.ReadInt32();
|
||||
m_BlocksInfo = new StorageBlock[blocksInfoCount];
|
||||
for (int i = 0; i < blocksInfoCount; i++)
|
||||
{
|
||||
m_BlocksInfo[i] = new StorageBlock
|
||||
{
|
||||
uncompressedSize = blocksInfoReader.ReadUInt32(),
|
||||
compressedSize = blocksInfoReader.ReadUInt32(),
|
||||
flags = (StorageBlockFlags)blocksInfoReader.ReadUInt16()
|
||||
};
|
||||
}
|
||||
|
||||
var nodesCount = blocksInfoReader.ReadInt32();
|
||||
m_DirectoryInfo = new Node[nodesCount];
|
||||
for (int i = 0; i < nodesCount; i++)
|
||||
{
|
||||
m_DirectoryInfo[i] = new Node
|
||||
{
|
||||
offset = blocksInfoReader.ReadInt64(),
|
||||
size = blocksInfoReader.ReadInt64(),
|
||||
flags = blocksInfoReader.ReadUInt32(),
|
||||
path = blocksInfoReader.ReadStringToNull(),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadBlocks(EndianBinaryReader reader, Stream blocksStream)
|
||||
{
|
||||
foreach (var blockInfo in m_BlocksInfo)
|
||||
{
|
||||
var compressionType = (CompressionType)(blockInfo.flags & StorageBlockFlags.CompressionTypeMask);
|
||||
switch (compressionType) //kStorageBlockCompressionTypeMask
|
||||
{
|
||||
case CompressionType.None: //None
|
||||
{
|
||||
reader.BaseStream.CopyTo(blocksStream, blockInfo.compressedSize);
|
||||
break;
|
||||
}
|
||||
case CompressionType.Lzma: //LZMA
|
||||
{
|
||||
SevenZipHelper.StreamDecompress(reader.BaseStream, blocksStream, blockInfo.compressedSize, blockInfo.uncompressedSize);
|
||||
break;
|
||||
}
|
||||
case CompressionType.Lz4: //LZ4
|
||||
case CompressionType.Lz4HC: //LZ4HC
|
||||
case CompressionType.Lz4Mr0k: //Lz4Mr0k
|
||||
{
|
||||
var compressedSize = (int)blockInfo.compressedSize;
|
||||
var compressedBytes = new byte[compressedSize];
|
||||
reader.Read(compressedBytes, 0, compressedSize);
|
||||
if (compressionType == CompressionType.Lz4Mr0k && Mr0k.IsMr0k(compressedBytes))
|
||||
{
|
||||
Mr0k.Decrypt(ref compressedBytes, ref compressedSize);
|
||||
}
|
||||
var uncompressedSize = (int)blockInfo.uncompressedSize;
|
||||
var uncompressedBytes = new byte[uncompressedSize];
|
||||
var numWrite = LZ4Codec.Decode(compressedBytes, 0, compressedSize, uncompressedBytes, 0, uncompressedSize);
|
||||
if (numWrite != uncompressedSize)
|
||||
{
|
||||
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
|
||||
}
|
||||
blocksStream.Write(uncompressedBytes, 0, uncompressedSize);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new IOException($"Unsupported compression type {compressionType}");
|
||||
}
|
||||
}
|
||||
blocksStream.Position = 0;
|
||||
}
|
||||
}
|
||||
}
|
207
AssetStudio/CABManager.cs
Normal file
207
AssetStudio/CABManager.cs
Normal file
@ -0,0 +1,207 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public static class CABManager
|
||||
{
|
||||
public static Dictionary<string, Entry> CABMap = new Dictionary<string, Entry>(StringComparer.OrdinalIgnoreCase);
|
||||
public static Dictionary<string, HashSet<long>> offsets = new Dictionary<string, HashSet<long>>();
|
||||
|
||||
public static void BuildMap(List<string> files, Game game)
|
||||
{
|
||||
Logger.Info($"Building {game.Name}Map");
|
||||
try
|
||||
{
|
||||
int collisions = 0;
|
||||
CABMap.Clear();
|
||||
Progress.Reset();
|
||||
for (int i = 0; i < files.Count; i++)
|
||||
{
|
||||
var file = files[i];
|
||||
var reader = new FileReader(file, game);
|
||||
var gameFile = new GameFile(reader);
|
||||
reader.Dispose();
|
||||
foreach (var bundle in gameFile.Bundles)
|
||||
{
|
||||
foreach (var cab in bundle.Value)
|
||||
{
|
||||
var dummyPath = Path.Combine(Path.GetDirectoryName(reader.FullPath), cab.fileName);
|
||||
using (var cabReader = new FileReader(dummyPath, cab.stream))
|
||||
{
|
||||
if (cabReader.FileType == FileType.AssetsFile)
|
||||
{
|
||||
if (CABMap.ContainsKey(cab.path))
|
||||
{
|
||||
collisions++;
|
||||
continue;
|
||||
}
|
||||
var assetsFile = new SerializedFile(cabReader, null, reader.FullPath);
|
||||
var dependencies = assetsFile.m_Externals.Select(x => x.fileName).ToList();
|
||||
CABMap.Add(cab.path, new Entry(file, bundle.Key, dependencies));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Logger.Info($"[{i + 1}/{files.Count}] Processed {Path.GetFileName(file)}");
|
||||
Progress.Report(i + 1, files.Count);
|
||||
}
|
||||
|
||||
CABMap = CABMap.OrderBy(pair => pair.Key).ToDictionary(pair => pair.Key, pair => pair.Value);
|
||||
var outputFile = new FileInfo($"Maps/{game.Name}Map.bin");
|
||||
|
||||
if (!outputFile.Directory.Exists)
|
||||
outputFile.Directory.Create();
|
||||
|
||||
using (var binaryFile = outputFile.Create())
|
||||
using (var writer = new BinaryWriter(binaryFile))
|
||||
{
|
||||
writer.Write(CABMap.Count);
|
||||
foreach (var cab in CABMap)
|
||||
{
|
||||
writer.Write(cab.Key);
|
||||
writer.Write(cab.Value.Path);
|
||||
writer.Write(cab.Value.Offset);
|
||||
writer.Write(cab.Value.Dependencies.Count);
|
||||
foreach (var dependancy in cab.Value.Dependencies)
|
||||
{
|
||||
writer.Write(dependancy);
|
||||
}
|
||||
}
|
||||
}
|
||||
Logger.Info($"{game.Name}Map build successfully, {collisions} collisions found !!");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Warning($"{game.Name}Map was not build, {e.Message}");
|
||||
}
|
||||
}
|
||||
public static void LoadMap(Game game)
|
||||
{
|
||||
Logger.Info($"Loading {game.Name}Map");
|
||||
try
|
||||
{
|
||||
CABMap.Clear();
|
||||
using (var binaryFile = File.OpenRead($"Maps/{game.Name}Map.bin"))
|
||||
using (var reader = new BinaryReader(binaryFile))
|
||||
{
|
||||
var count = reader.ReadInt32();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var cab = reader.ReadString();
|
||||
var path = reader.ReadString();
|
||||
var offset = reader.ReadInt64();
|
||||
var depCount = reader.ReadInt32();
|
||||
var dependencies = new List<string>();
|
||||
for (int j = 0; j < depCount; j++)
|
||||
{
|
||||
var dependancy = reader.ReadString();
|
||||
dependencies.Add(dependancy);
|
||||
}
|
||||
CABMap.Add(cab, new Entry(path, offset, dependencies));
|
||||
}
|
||||
}
|
||||
Logger.Info($"Loaded {game.Name}Map !!");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Warning($"{game.Name}Map was not loaded, {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddCABOffsets(string[] path, List<string> cabs)
|
||||
{
|
||||
for (int i = 0; i < cabs.Count; i++)
|
||||
{
|
||||
var cab = cabs[i];
|
||||
if (CABMap.TryGetValue(cab, out var entry))
|
||||
{
|
||||
if (!path.Contains(entry.Path))
|
||||
{
|
||||
if (!offsets.ContainsKey(entry.Path))
|
||||
{
|
||||
offsets.Add(entry.Path, new HashSet<long>());
|
||||
}
|
||||
offsets[entry.Path].Add(entry.Offset);
|
||||
}
|
||||
foreach (var dep in entry.Dependencies)
|
||||
{
|
||||
if (!cabs.Contains(dep))
|
||||
cabs.Add(dep);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool FindCAB(string path, out List<string> cabs)
|
||||
{
|
||||
cabs = CABMap.Where(x => x.Value.Path.Contains(path)).Select(x => x.Key).ToList();
|
||||
return cabs.Count != 0;
|
||||
}
|
||||
|
||||
public static string[] ProcessFiles(string[] files)
|
||||
{
|
||||
foreach (var file in files)
|
||||
{
|
||||
if (!offsets.ContainsKey(file))
|
||||
{
|
||||
offsets.Add(file, new HashSet<long>());
|
||||
}
|
||||
if (FindCAB(file, out var cabs))
|
||||
{
|
||||
AddCABOffsets(files, cabs);
|
||||
}
|
||||
}
|
||||
return offsets.Keys.ToArray();
|
||||
}
|
||||
|
||||
public static string[] ProcessDependencies(string[] files)
|
||||
{
|
||||
if (CABMap.Count == 0)
|
||||
{
|
||||
Logger.Warning("CABMap is not build, skip resolving dependencies...");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Info("Resolving Dependencies...");
|
||||
var file = files.FirstOrDefault();
|
||||
var supportedExtensions = GameManager.GetGames().Select(x => x.Extension).ToList();
|
||||
if (supportedExtensions.Contains(Path.GetExtension(file)))
|
||||
{
|
||||
files = ProcessFiles(files);
|
||||
}
|
||||
}
|
||||
return files;
|
||||
}
|
||||
}
|
||||
|
||||
public class Entry : IComparable<Entry>
|
||||
{
|
||||
public string Path;
|
||||
public long Offset;
|
||||
public List<string> Dependencies;
|
||||
public Entry(string path, long offset, List<string> dependencies)
|
||||
{
|
||||
Path = path;
|
||||
Offset = offset;
|
||||
Dependencies = dependencies;
|
||||
}
|
||||
public int CompareTo(Entry other)
|
||||
{
|
||||
if (other == null) return 1;
|
||||
|
||||
int result;
|
||||
if (other == null)
|
||||
throw new ArgumentException("Object is not an Entry");
|
||||
|
||||
result = Path.CompareTo(other.Path);
|
||||
|
||||
if (result == 0)
|
||||
result = Offset.CompareTo(other.Offset);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
395
AssetStudio/ClassIDType.cs
Normal file
395
AssetStudio/ClassIDType.cs
Normal file
@ -0,0 +1,395 @@
|
||||
// official Class ID Reference: https://docs.unity3d.com/Manual/ClassIDReference.html
|
||||
namespace AssetStudio
|
||||
{
|
||||
public enum ClassIDType
|
||||
{
|
||||
UnknownType = -1,
|
||||
Object = 0,
|
||||
GameObject = 1,
|
||||
Component = 2,
|
||||
LevelGameManager = 3,
|
||||
Transform = 4,
|
||||
TimeManager = 5,
|
||||
GlobalGameManager = 6,
|
||||
Behaviour = 8,
|
||||
GameManager = 9,
|
||||
AudioManager = 11,
|
||||
ParticleAnimator = 12,
|
||||
InputManager = 13,
|
||||
EllipsoidParticleEmitter = 15,
|
||||
Pipeline = 17,
|
||||
EditorExtension = 18,
|
||||
Physics2DSettings = 19,
|
||||
Camera = 20,
|
||||
Material = 21,
|
||||
MeshRenderer = 23,
|
||||
Renderer = 25,
|
||||
ParticleRenderer = 26,
|
||||
Texture = 27,
|
||||
Texture2D = 28,
|
||||
OcclusionCullingSettings = 29,
|
||||
GraphicsSettings = 30,
|
||||
MeshFilter = 33,
|
||||
OcclusionPortal = 41,
|
||||
Mesh = 43,
|
||||
Skybox = 45,
|
||||
QualitySettings = 47,
|
||||
Shader = 48,
|
||||
TextAsset = 49,
|
||||
Rigidbody2D = 50,
|
||||
Physics2DManager = 51,
|
||||
Collider2D = 53,
|
||||
Rigidbody = 54,
|
||||
PhysicsManager = 55,
|
||||
Collider = 56,
|
||||
Joint = 57,
|
||||
CircleCollider2D = 58,
|
||||
HingeJoint = 59,
|
||||
PolygonCollider2D = 60,
|
||||
BoxCollider2D = 61,
|
||||
PhysicsMaterial2D = 62,
|
||||
MeshCollider = 64,
|
||||
BoxCollider = 65,
|
||||
CompositeCollider2D = 66,
|
||||
EdgeCollider2D = 68,
|
||||
CapsuleCollider2D = 70,
|
||||
ComputeShader = 72,
|
||||
AnimationClip = 74,
|
||||
ConstantForce = 75,
|
||||
WorldParticleCollider = 76,
|
||||
TagManager = 78,
|
||||
AudioListener = 81,
|
||||
AudioSource = 82,
|
||||
AudioClip = 83,
|
||||
RenderTexture = 84,
|
||||
CustomRenderTexture = 86,
|
||||
MeshParticleEmitter = 87,
|
||||
ParticleEmitter = 88,
|
||||
Cubemap = 89,
|
||||
Avatar = 90,
|
||||
AnimatorController = 91,
|
||||
GUILayer = 92,
|
||||
RuntimeAnimatorController = 93,
|
||||
ScriptMapper = 94,
|
||||
Animator = 95,
|
||||
TrailRenderer = 96,
|
||||
DelayedCallManager = 98,
|
||||
TextMesh = 102,
|
||||
RenderSettings = 104,
|
||||
Light = 108,
|
||||
CGProgram = 109,
|
||||
BaseAnimationTrack = 110,
|
||||
Animation = 111,
|
||||
MonoBehaviour = 114,
|
||||
MonoScript = 115,
|
||||
MonoManager = 116,
|
||||
Texture3D = 117,
|
||||
NewAnimationTrack = 118,
|
||||
Projector = 119,
|
||||
LineRenderer = 120,
|
||||
Flare = 121,
|
||||
Halo = 122,
|
||||
LensFlare = 123,
|
||||
FlareLayer = 124,
|
||||
HaloLayer = 125,
|
||||
NavMeshAreas = 126,
|
||||
NavMeshProjectSettings = 126,
|
||||
HaloManager = 127,
|
||||
Font = 128,
|
||||
PlayerSettings = 129,
|
||||
NamedObject = 130,
|
||||
GUITexture = 131,
|
||||
GUIText = 132,
|
||||
GUIElement = 133,
|
||||
PhysicMaterial = 134,
|
||||
SphereCollider = 135,
|
||||
CapsuleCollider = 136,
|
||||
SkinnedMeshRenderer = 137,
|
||||
FixedJoint = 138,
|
||||
RaycastCollider = 140,
|
||||
BuildSettings = 141,
|
||||
AssetBundle = 142,
|
||||
CharacterController = 143,
|
||||
CharacterJoint = 144,
|
||||
SpringJoint = 145,
|
||||
WheelCollider = 146,
|
||||
ResourceManager = 147,
|
||||
NetworkView = 148,
|
||||
NetworkManager = 149,
|
||||
PreloadData = 150,
|
||||
MovieTexture = 152,
|
||||
ConfigurableJoint = 153,
|
||||
TerrainCollider = 154,
|
||||
MasterServerInterface = 155,
|
||||
TerrainData = 156,
|
||||
LightmapSettings = 157,
|
||||
WebCamTexture = 158,
|
||||
EditorSettings = 159,
|
||||
InteractiveCloth = 160,
|
||||
ClothRenderer = 161,
|
||||
EditorUserSettings = 162,
|
||||
SkinnedCloth = 163,
|
||||
AudioReverbFilter = 164,
|
||||
AudioHighPassFilter = 165,
|
||||
AudioChorusFilter = 166,
|
||||
AudioReverbZone = 167,
|
||||
AudioEchoFilter = 168,
|
||||
AudioLowPassFilter = 169,
|
||||
AudioDistortionFilter = 170,
|
||||
SparseTexture = 171,
|
||||
AudioBehaviour = 180,
|
||||
AudioFilter = 181,
|
||||
WindZone = 182,
|
||||
Cloth = 183,
|
||||
SubstanceArchive = 184,
|
||||
ProceduralMaterial = 185,
|
||||
ProceduralTexture = 186,
|
||||
Texture2DArray = 187,
|
||||
CubemapArray = 188,
|
||||
OffMeshLink = 191,
|
||||
OcclusionArea = 192,
|
||||
Tree = 193,
|
||||
NavMeshObsolete = 194,
|
||||
NavMeshAgent = 195,
|
||||
NavMeshSettings = 196,
|
||||
LightProbesLegacy = 197,
|
||||
ParticleSystem = 198,
|
||||
ParticleSystemRenderer = 199,
|
||||
ShaderVariantCollection = 200,
|
||||
LODGroup = 205,
|
||||
BlendTree = 206,
|
||||
Motion = 207,
|
||||
NavMeshObstacle = 208,
|
||||
SortingGroup = 210,
|
||||
SpriteRenderer = 212,
|
||||
Sprite = 213,
|
||||
CachedSpriteAtlas = 214,
|
||||
ReflectionProbe = 215,
|
||||
ReflectionProbes = 216,
|
||||
Terrain = 218,
|
||||
LightProbeGroup = 220,
|
||||
AnimatorOverrideController = 221,
|
||||
CanvasRenderer = 222,
|
||||
Canvas = 223,
|
||||
RectTransform = 224,
|
||||
CanvasGroup = 225,
|
||||
BillboardAsset = 226,
|
||||
BillboardRenderer = 227,
|
||||
SpeedTreeWindAsset = 228,
|
||||
AnchoredJoint2D = 229,
|
||||
Joint2D = 230,
|
||||
SpringJoint2D = 231,
|
||||
DistanceJoint2D = 232,
|
||||
HingeJoint2D = 233,
|
||||
SliderJoint2D = 234,
|
||||
WheelJoint2D = 235,
|
||||
ClusterInputManager = 236,
|
||||
BaseVideoTexture = 237,
|
||||
NavMeshData = 238,
|
||||
AudioMixer = 240,
|
||||
AudioMixerController = 241,
|
||||
AudioMixerGroupController = 243,
|
||||
AudioMixerEffectController = 244,
|
||||
AudioMixerSnapshotController = 245,
|
||||
PhysicsUpdateBehaviour2D = 246,
|
||||
ConstantForce2D = 247,
|
||||
Effector2D = 248,
|
||||
AreaEffector2D = 249,
|
||||
PointEffector2D = 250,
|
||||
PlatformEffector2D = 251,
|
||||
SurfaceEffector2D = 252,
|
||||
BuoyancyEffector2D = 253,
|
||||
RelativeJoint2D = 254,
|
||||
FixedJoint2D = 255,
|
||||
FrictionJoint2D = 256,
|
||||
TargetJoint2D = 257,
|
||||
LightProbes = 258,
|
||||
LightProbeProxyVolume = 259,
|
||||
SampleClip = 271,
|
||||
AudioMixerSnapshot = 272,
|
||||
AudioMixerGroup = 273,
|
||||
NScreenBridge = 280,
|
||||
AssetBundleManifest = 290,
|
||||
UnityAdsManager = 292,
|
||||
RuntimeInitializeOnLoadManager = 300,
|
||||
CloudWebServicesManager = 301,
|
||||
UnityAnalyticsManager = 303,
|
||||
CrashReportManager = 304,
|
||||
PerformanceReportingManager = 305,
|
||||
UnityConnectSettings = 310,
|
||||
AvatarMask = 319,
|
||||
PlayableDirector = 320,
|
||||
VideoPlayer = 328,
|
||||
VideoClip = 329,
|
||||
ParticleSystemForceField = 330,
|
||||
SpriteMask = 331,
|
||||
WorldAnchor = 362,
|
||||
OcclusionCullingData = 363,
|
||||
MiHoYoGrassData = 601,
|
||||
MiHoYoGrassBlock = 603,
|
||||
MiHoYoGrassLand = 602,
|
||||
MiHoYoVegetationInteractor = 604,
|
||||
MiHoYoWindParameterConfigurator = 605,
|
||||
MiHoYoGrassGlobalConfigurator = 606,
|
||||
//kLargestRuntimeClassID = 364
|
||||
SmallestEditorClassID = 1000,
|
||||
PrefabInstance = 1001,
|
||||
EditorExtensionImpl = 1002,
|
||||
AssetImporter = 1003,
|
||||
AssetDatabaseV1 = 1004,
|
||||
Mesh3DSImporter = 1005,
|
||||
TextureImporter = 1006,
|
||||
ShaderImporter = 1007,
|
||||
ComputeShaderImporter = 1008,
|
||||
AudioImporter = 1020,
|
||||
HierarchyState = 1026,
|
||||
GUIDSerializer = 1027,
|
||||
AssetMetaData = 1028,
|
||||
DefaultAsset = 1029,
|
||||
DefaultImporter = 1030,
|
||||
TextScriptImporter = 1031,
|
||||
SceneAsset = 1032,
|
||||
NativeFormatImporter = 1034,
|
||||
MonoImporter = 1035,
|
||||
AssetServerCache = 1037,
|
||||
LibraryAssetImporter = 1038,
|
||||
ModelImporter = 1040,
|
||||
FBXImporter = 1041,
|
||||
TrueTypeFontImporter = 1042,
|
||||
MovieImporter = 1044,
|
||||
EditorBuildSettings = 1045,
|
||||
DDSImporter = 1046,
|
||||
InspectorExpandedState = 1048,
|
||||
AnnotationManager = 1049,
|
||||
PluginImporter = 1050,
|
||||
EditorUserBuildSettings = 1051,
|
||||
PVRImporter = 1052,
|
||||
ASTCImporter = 1053,
|
||||
KTXImporter = 1054,
|
||||
IHVImageFormatImporter = 1055,
|
||||
AnimatorStateTransition = 1101,
|
||||
AnimatorState = 1102,
|
||||
HumanTemplate = 1105,
|
||||
AnimatorStateMachine = 1107,
|
||||
PreviewAnimationClip = 1108,
|
||||
AnimatorTransition = 1109,
|
||||
SpeedTreeImporter = 1110,
|
||||
AnimatorTransitionBase = 1111,
|
||||
SubstanceImporter = 1112,
|
||||
LightmapParameters = 1113,
|
||||
LightingDataAsset = 1120,
|
||||
GISRaster = 1121,
|
||||
GISRasterImporter = 1122,
|
||||
CadImporter = 1123,
|
||||
SketchUpImporter = 1124,
|
||||
BuildReport = 1125,
|
||||
PackedAssets = 1126,
|
||||
VideoClipImporter = 1127,
|
||||
PlaneCullingOccluder = 1201,
|
||||
BakedCollisionData = 1202,
|
||||
ObjectInstanceCache = 1203,
|
||||
MiHoYoLodLoader = 1204,
|
||||
LODLevel = 1205,
|
||||
MiHoYoLodMeshGroup = 1206,
|
||||
MiHoYoInstanceColor = 1207,
|
||||
MiHoYoBinData = 1208,
|
||||
IndexObject = 1210,
|
||||
MiHoYoTextureStreamingPreloader = 1211,
|
||||
ActivationLogComponent = 2000,
|
||||
//kLargestEditorClassID = 2001
|
||||
//kClassIdOutOfHierarchy = 100000
|
||||
//int = 100000,
|
||||
//bool = 100001,
|
||||
//float = 100002,
|
||||
MonoObject = 100003,
|
||||
Collision = 100004,
|
||||
Vector3f = 100005,
|
||||
RootMotionData = 100006,
|
||||
Collision2D = 100007,
|
||||
AudioMixerLiveUpdateFloat = 100008,
|
||||
AudioMixerLiveUpdateBool = 100009,
|
||||
Polygon2D = 100010,
|
||||
//void = 100011,
|
||||
TilemapCollider2D = 19719996,
|
||||
AssetImporterLog = 41386430,
|
||||
VFXRenderer = 73398921,
|
||||
SerializableManagedRefTestClass = 76251197,
|
||||
Grid = 156049354,
|
||||
ScenesUsingAssets = 156483287,
|
||||
ArticulationBody = 171741748,
|
||||
Preset = 181963792,
|
||||
EmptyObject = 277625683,
|
||||
IConstraint = 285090594,
|
||||
TestObjectWithSpecialLayoutOne = 293259124,
|
||||
AssemblyDefinitionReferenceImporter = 294290339,
|
||||
SiblingDerived = 334799969,
|
||||
TestObjectWithSerializedMapStringNonAlignedStruct = 342846651,
|
||||
SubDerived = 367388927,
|
||||
AssetImportInProgressProxy = 369655926,
|
||||
PluginBuildInfo = 382020655,
|
||||
EditorProjectAccess = 426301858,
|
||||
PrefabImporter = 468431735,
|
||||
TestObjectWithSerializedArray = 478637458,
|
||||
TestObjectWithSerializedAnimationCurve = 478637459,
|
||||
TilemapRenderer = 483693784,
|
||||
ScriptableCamera = 488575907,
|
||||
SpriteAtlasAsset = 612988286,
|
||||
SpriteAtlasDatabase = 638013454,
|
||||
AudioBuildInfo = 641289076,
|
||||
CachedSpriteAtlasRuntimeData = 644342135,
|
||||
RendererFake = 646504946,
|
||||
AssemblyDefinitionReferenceAsset = 662584278,
|
||||
BuiltAssetBundleInfoSet = 668709126,
|
||||
SpriteAtlas = 687078895,
|
||||
RayTracingShaderImporter = 747330370,
|
||||
RayTracingShader = 825902497,
|
||||
LightingSettings = 850595691,
|
||||
PlatformModuleSetup = 877146078,
|
||||
VersionControlSettings = 890905787,
|
||||
AimConstraint = 895512359,
|
||||
VFXManager = 937362698,
|
||||
VisualEffectSubgraph = 994735392,
|
||||
VisualEffectSubgraphOperator = 994735403,
|
||||
VisualEffectSubgraphBlock = 994735404,
|
||||
LocalizationImporter = 1027052791,
|
||||
Derived = 1091556383,
|
||||
PropertyModificationsTargetTestObject = 1111377672,
|
||||
ReferencesArtifactGenerator = 1114811875,
|
||||
AssemblyDefinitionAsset = 1152215463,
|
||||
SceneVisibilityState = 1154873562,
|
||||
LookAtConstraint = 1183024399,
|
||||
SpriteAtlasImporter = 1210832254,
|
||||
MultiArtifactTestImporter = 1223240404,
|
||||
GameObjectRecorder = 1268269756,
|
||||
LightingDataAssetParent = 1325145578,
|
||||
PresetManager = 1386491679,
|
||||
TestObjectWithSpecialLayoutTwo = 1392443030,
|
||||
StreamingManager = 1403656975,
|
||||
LowerResBlitTexture = 1480428607,
|
||||
StreamingController = 1542919678,
|
||||
RenderPassAttachment = 1571458007,
|
||||
TestObjectVectorPairStringBool = 1628831178,
|
||||
GridLayout = 1742807556,
|
||||
AssemblyDefinitionImporter = 1766753193,
|
||||
ParentConstraint = 1773428102,
|
||||
FakeComponent = 1803986026,
|
||||
PositionConstraint = 1818360608,
|
||||
RotationConstraint = 1818360609,
|
||||
ScaleConstraint = 1818360610,
|
||||
Tilemap = 1839735485,
|
||||
PackageManifest = 1896753125,
|
||||
PackageManifestImporter = 1896753126,
|
||||
TerrainLayer = 1953259897,
|
||||
SpriteShapeRenderer = 1971053207,
|
||||
NativeObjectType = 1977754360,
|
||||
TestObjectWithSerializedMapStringBool = 1981279845,
|
||||
SerializableManagedHost = 1995898324,
|
||||
VisualEffectAsset = 2058629509,
|
||||
VisualEffectImporter = 2058629510,
|
||||
VisualEffectResource = 2058629511,
|
||||
VisualEffectObject = 2059678085,
|
||||
VisualEffect = 2083052967,
|
||||
LocalizationAsset = 2083778819,
|
||||
ScriptedImporter = 2089858483
|
||||
}
|
||||
}
|
35
AssetStudio/Classes/Animation.cs
Normal file
35
AssetStudio/Classes/Animation.cs
Normal file
@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public sealed class Animation : Behaviour
|
||||
{
|
||||
public PPtr<AnimationClip>[] m_Animations;
|
||||
|
||||
public Animation(ObjectReader reader) : base(reader)
|
||||
{
|
||||
var m_Animation = new PPtr<AnimationClip>(reader);
|
||||
int numAnimations = reader.ReadInt32();
|
||||
m_Animations = new PPtr<AnimationClip>[numAnimations];
|
||||
for (int i = 0; i < numAnimations; i++)
|
||||
{
|
||||
m_Animations[i] = new PPtr<AnimationClip>(reader);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsContainsAnimationClip(AnimationClip clip)
|
||||
{
|
||||
foreach (PPtr<AnimationClip> ptr in m_Animations)
|
||||
{
|
||||
if (ptr.TryGet(out var animationClip) && animationClip.Equals(clip))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
1627
AssetStudio/Classes/AnimationClip.cs
Normal file
1627
AssetStudio/Classes/AnimationClip.cs
Normal file
File diff suppressed because it is too large
Load Diff
97
AssetStudio/Classes/Animator.cs
Normal file
97
AssetStudio/Classes/Animator.cs
Normal file
@ -0,0 +1,97 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public sealed class Animator : Behaviour
|
||||
{
|
||||
public PPtr<Avatar> m_Avatar;
|
||||
public PPtr<RuntimeAnimatorController> m_Controller;
|
||||
public bool m_HasTransformHierarchy = true;
|
||||
|
||||
public Animator(ObjectReader reader) : base(reader)
|
||||
{
|
||||
m_Avatar = new PPtr<Avatar>(reader);
|
||||
m_Controller = new PPtr<RuntimeAnimatorController>(reader);
|
||||
if (reader.Game.Name == "GI" || reader.Game.Name == "GI_CB2" || reader.Game.Name == "GI_CB3")
|
||||
{
|
||||
var m_FBIKAvatar = new PPtr<Object>(reader); //FBIKAvatar placeholder
|
||||
}
|
||||
var m_CullingMode = reader.ReadInt32();
|
||||
|
||||
if (version[0] > 4 || (version[0] == 4 && version[1] >= 5)) //4.5 and up
|
||||
{
|
||||
var m_UpdateMode = reader.ReadInt32();
|
||||
}
|
||||
|
||||
var m_ApplyRootMotion = reader.ReadBoolean();
|
||||
if (version[0] == 4 && version[1] >= 5) //4.5 and up - 5.0 down
|
||||
{
|
||||
reader.AlignStream();
|
||||
}
|
||||
|
||||
if (version[0] >= 5) //5.0 and up
|
||||
{
|
||||
var m_LinearVelocityBlending = reader.ReadBoolean();
|
||||
if (version[0] > 2021 || (version[0] == 2021 && version[1] >= 2)) //2021.2 and up
|
||||
{
|
||||
var m_StabilizeFeet = reader.ReadBoolean();
|
||||
}
|
||||
reader.AlignStream();
|
||||
}
|
||||
|
||||
if (version[0] < 4 || (version[0] == 4 && version[1] < 5)) //4.5 down
|
||||
{
|
||||
var m_AnimatePhysics = reader.ReadBoolean();
|
||||
}
|
||||
|
||||
if (version[0] > 4 || (version[0] == 4 && version[1] >= 3)) //4.3 and up
|
||||
{
|
||||
m_HasTransformHierarchy = reader.ReadBoolean();
|
||||
}
|
||||
|
||||
if (version[0] > 4 || (version[0] == 4 && version[1] >= 5)) //4.5 and up
|
||||
{
|
||||
var m_AllowConstantClipSamplingOptimization = reader.ReadBoolean();
|
||||
}
|
||||
if (version[0] >= 5 && version[0] < 2018) //5.0 and up - 2018 down
|
||||
{
|
||||
reader.AlignStream();
|
||||
}
|
||||
|
||||
if (version[0] >= 2018) //2018 and up
|
||||
{
|
||||
var m_KeepAnimatorControllerStateOnDisable = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<uint, string> BuildTOS()
|
||||
{
|
||||
if (version[0] > 4 || (version[0] == 4 && version[1] >= 3))
|
||||
{
|
||||
if (m_HasTransformHierarchy)
|
||||
{
|
||||
if (m_GameObject.TryGet(out var go))
|
||||
{
|
||||
return go.BuildTOS();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Dictionary<uint, string>() { { 0, string.Empty } };
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_GameObject.TryGet(out var go))
|
||||
{
|
||||
return go.BuildTOS();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
617
AssetStudio/Classes/AnimatorController.cs
Normal file
617
AssetStudio/Classes/AnimatorController.cs
Normal file
@ -0,0 +1,617 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class HumanPoseMask
|
||||
{
|
||||
public uint word0;
|
||||
public uint word1;
|
||||
public uint word2;
|
||||
|
||||
public HumanPoseMask(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
|
||||
word0 = reader.ReadUInt32();
|
||||
word1 = reader.ReadUInt32();
|
||||
if (version[0] > 5 || (version[0] == 5 && version[1] >= 2)) //5.2 and up
|
||||
{
|
||||
word2 = reader.ReadUInt32();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class SkeletonMaskElement
|
||||
{
|
||||
public uint m_PathHash;
|
||||
public float m_Weight;
|
||||
|
||||
public SkeletonMaskElement(ObjectReader reader)
|
||||
{
|
||||
m_PathHash = reader.ReadUInt32();
|
||||
m_Weight = reader.ReadSingle();
|
||||
}
|
||||
}
|
||||
|
||||
public class SkeletonMask
|
||||
{
|
||||
public SkeletonMaskElement[] m_Data;
|
||||
|
||||
public SkeletonMask(ObjectReader reader)
|
||||
{
|
||||
int numElements = reader.ReadInt32();
|
||||
m_Data = new SkeletonMaskElement[numElements];
|
||||
for (int i = 0; i < numElements; i++)
|
||||
{
|
||||
m_Data[i] = new SkeletonMaskElement(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class LayerConstant
|
||||
{
|
||||
public uint m_StateMachineIndex;
|
||||
public uint m_StateMachineMotionSetIndex;
|
||||
public HumanPoseMask m_BodyMask;
|
||||
public SkeletonMask m_SkeletonMask;
|
||||
public uint m_Binding;
|
||||
public int m_LayerBlendingMode;
|
||||
public float m_DefaultWeight;
|
||||
public bool m_IKPass;
|
||||
public bool m_SyncedLayerAffectsTiming;
|
||||
|
||||
public LayerConstant(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
|
||||
m_StateMachineIndex = reader.ReadUInt32();
|
||||
m_StateMachineMotionSetIndex = reader.ReadUInt32();
|
||||
m_BodyMask = new HumanPoseMask(reader);
|
||||
m_SkeletonMask = new SkeletonMask(reader);
|
||||
m_Binding = reader.ReadUInt32();
|
||||
m_LayerBlendingMode = reader.ReadInt32();
|
||||
if (version[0] > 4 || (version[0] == 4 && version[1] >= 2)) //4.2 and up
|
||||
{
|
||||
m_DefaultWeight = reader.ReadSingle();
|
||||
}
|
||||
m_IKPass = reader.ReadBoolean();
|
||||
if (version[0] > 4 || (version[0] == 4 && version[1] >= 2)) //4.2 and up
|
||||
{
|
||||
m_SyncedLayerAffectsTiming = reader.ReadBoolean();
|
||||
}
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
|
||||
public class ConditionConstant
|
||||
{
|
||||
public uint m_ConditionMode;
|
||||
public uint m_EventID;
|
||||
public float m_EventThreshold;
|
||||
public float m_ExitTime;
|
||||
|
||||
public ConditionConstant(ObjectReader reader)
|
||||
{
|
||||
m_ConditionMode = reader.ReadUInt32();
|
||||
m_EventID = reader.ReadUInt32();
|
||||
m_EventThreshold = reader.ReadSingle();
|
||||
m_ExitTime = reader.ReadSingle();
|
||||
}
|
||||
}
|
||||
|
||||
public class TransitionConstant
|
||||
{
|
||||
public ConditionConstant[] m_ConditionConstantArray;
|
||||
public uint m_DestinationState;
|
||||
public uint m_FullPathID;
|
||||
public uint m_ID;
|
||||
public uint m_UserID;
|
||||
public float m_TransitionDuration;
|
||||
public float m_TransitionOffset;
|
||||
public float m_ExitTime;
|
||||
public bool m_HasExitTime;
|
||||
public bool m_HasFixedDuration;
|
||||
public int m_InterruptionSource;
|
||||
public bool m_OrderedInterruption;
|
||||
public bool m_Atomic;
|
||||
public bool m_CanTransitionToSelf;
|
||||
|
||||
public TransitionConstant(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
|
||||
int numConditions = reader.ReadInt32();
|
||||
m_ConditionConstantArray = new ConditionConstant[numConditions];
|
||||
for (int i = 0; i < numConditions; i++)
|
||||
{
|
||||
m_ConditionConstantArray[i] = new ConditionConstant(reader);
|
||||
}
|
||||
|
||||
m_DestinationState = reader.ReadUInt32();
|
||||
if (version[0] >= 5) //5.0 and up
|
||||
{
|
||||
m_FullPathID = reader.ReadUInt32();
|
||||
}
|
||||
|
||||
m_ID = reader.ReadUInt32();
|
||||
m_UserID = reader.ReadUInt32();
|
||||
m_TransitionDuration = reader.ReadSingle();
|
||||
m_TransitionOffset = reader.ReadSingle();
|
||||
if (version[0] >= 5) //5.0 and up
|
||||
{
|
||||
m_ExitTime = reader.ReadSingle();
|
||||
m_HasExitTime = reader.ReadBoolean();
|
||||
m_HasFixedDuration = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
m_InterruptionSource = reader.ReadInt32();
|
||||
m_OrderedInterruption = reader.ReadBoolean();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Atomic = reader.ReadBoolean();
|
||||
}
|
||||
|
||||
if (version[0] > 4 || (version[0] == 4 && version[1] >= 5)) //4.5 and up
|
||||
{
|
||||
m_CanTransitionToSelf = reader.ReadBoolean();
|
||||
}
|
||||
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
|
||||
public class LeafInfoConstant
|
||||
{
|
||||
public uint[] m_IDArray;
|
||||
public uint m_IndexOffset;
|
||||
|
||||
public LeafInfoConstant(ObjectReader reader)
|
||||
{
|
||||
m_IDArray = reader.ReadUInt32Array();
|
||||
m_IndexOffset = reader.ReadUInt32();
|
||||
}
|
||||
}
|
||||
|
||||
public class MotionNeighborList
|
||||
{
|
||||
public uint[] m_NeighborArray;
|
||||
|
||||
public MotionNeighborList(ObjectReader reader)
|
||||
{
|
||||
m_NeighborArray = reader.ReadUInt32Array();
|
||||
}
|
||||
}
|
||||
|
||||
public class Blend2dDataConstant
|
||||
{
|
||||
public Vector2[] m_ChildPositionArray;
|
||||
public float[] m_ChildMagnitudeArray;
|
||||
public Vector2[] m_ChildPairVectorArray;
|
||||
public float[] m_ChildPairAvgMagInvArray;
|
||||
public MotionNeighborList[] m_ChildNeighborListArray;
|
||||
|
||||
public Blend2dDataConstant(ObjectReader reader)
|
||||
{
|
||||
m_ChildPositionArray = reader.ReadVector2Array();
|
||||
m_ChildMagnitudeArray = reader.ReadSingleArray();
|
||||
m_ChildPairVectorArray = reader.ReadVector2Array();
|
||||
m_ChildPairAvgMagInvArray = reader.ReadSingleArray();
|
||||
|
||||
int numNeighbours = reader.ReadInt32();
|
||||
m_ChildNeighborListArray = new MotionNeighborList[numNeighbours];
|
||||
for (int i = 0; i < numNeighbours; i++)
|
||||
{
|
||||
m_ChildNeighborListArray[i] = new MotionNeighborList(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Blend1dDataConstant // wrong labeled
|
||||
{
|
||||
public float[] m_ChildThresholdArray;
|
||||
|
||||
public Blend1dDataConstant(ObjectReader reader)
|
||||
{
|
||||
m_ChildThresholdArray = reader.ReadSingleArray();
|
||||
}
|
||||
}
|
||||
|
||||
public class BlendDirectDataConstant
|
||||
{
|
||||
public uint[] m_ChildBlendEventIDArray;
|
||||
public bool m_NormalizedBlendValues;
|
||||
|
||||
public BlendDirectDataConstant(ObjectReader reader)
|
||||
{
|
||||
m_ChildBlendEventIDArray = reader.ReadUInt32Array();
|
||||
m_NormalizedBlendValues = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
|
||||
public class BlendTreeNodeConstant
|
||||
{
|
||||
public uint m_BlendType;
|
||||
public uint m_BlendEventID;
|
||||
public uint m_BlendEventYID;
|
||||
public uint[] m_ChildIndices;
|
||||
public float[] m_ChildThresholdArray;
|
||||
public Blend1dDataConstant m_Blend1dData;
|
||||
public Blend2dDataConstant m_Blend2dData;
|
||||
public BlendDirectDataConstant m_BlendDirectData;
|
||||
public uint m_ClipID;
|
||||
public uint m_ClipIndex;
|
||||
public float m_Duration;
|
||||
public float m_CycleOffset;
|
||||
public bool m_Mirror;
|
||||
|
||||
public BlendTreeNodeConstant(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
|
||||
if (version[0] > 4 || (version[0] == 4 && version[1] >= 1)) //4.1 and up
|
||||
{
|
||||
m_BlendType = reader.ReadUInt32();
|
||||
}
|
||||
m_BlendEventID = reader.ReadUInt32();
|
||||
if (version[0] > 4 || (version[0] == 4 && version[1] >= 1)) //4.1 and up
|
||||
{
|
||||
m_BlendEventYID = reader.ReadUInt32();
|
||||
}
|
||||
m_ChildIndices = reader.ReadUInt32Array();
|
||||
if (version[0] < 4 || (version[0] == 4 && version[1] < 1)) //4.1 down
|
||||
{
|
||||
m_ChildThresholdArray = reader.ReadSingleArray();
|
||||
}
|
||||
|
||||
if (version[0] > 4 || (version[0] == 4 && version[1] >= 1)) //4.1 and up
|
||||
{
|
||||
m_Blend1dData = new Blend1dDataConstant(reader);
|
||||
m_Blend2dData = new Blend2dDataConstant(reader);
|
||||
}
|
||||
|
||||
if (version[0] >= 5) //5.0 and up
|
||||
{
|
||||
m_BlendDirectData = new BlendDirectDataConstant(reader);
|
||||
}
|
||||
|
||||
m_ClipID = reader.ReadUInt32();
|
||||
if (version[0] == 4 && version[1] >= 5) //4.5 - 5.0
|
||||
{
|
||||
m_ClipIndex = reader.ReadUInt32();
|
||||
}
|
||||
|
||||
m_Duration = reader.ReadSingle();
|
||||
|
||||
if (version[0] > 4
|
||||
|| (version[0] == 4 && version[1] > 1)
|
||||
|| (version[0] == 4 && version[1] == 1 && version[2] >= 3)) //4.1.3 and up
|
||||
{
|
||||
m_CycleOffset = reader.ReadSingle();
|
||||
m_Mirror = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class BlendTreeConstant
|
||||
{
|
||||
public BlendTreeNodeConstant[] m_NodeArray;
|
||||
public ValueArrayConstant m_BlendEventArrayConstant;
|
||||
|
||||
public BlendTreeConstant(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
|
||||
int numNodes = reader.ReadInt32();
|
||||
m_NodeArray = new BlendTreeNodeConstant[numNodes];
|
||||
for (int i = 0; i < numNodes; i++)
|
||||
{
|
||||
m_NodeArray[i] = new BlendTreeNodeConstant(reader);
|
||||
}
|
||||
|
||||
if (version[0] < 4 || (version[0] == 4 && version[1] < 5)) //4.5 down
|
||||
{
|
||||
m_BlendEventArrayConstant = new ValueArrayConstant(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class StateConstant
|
||||
{
|
||||
public TransitionConstant[] m_TransitionConstantArray;
|
||||
public int[] m_BlendTreeConstantIndexArray;
|
||||
public LeafInfoConstant[] m_LeafInfoArray;
|
||||
public BlendTreeConstant[] m_BlendTreeConstantArray;
|
||||
public uint m_NameID;
|
||||
public uint m_PathID;
|
||||
public uint m_FullPathID;
|
||||
public uint m_TagID;
|
||||
public uint m_SpeedParamID;
|
||||
public uint m_MirrorParamID;
|
||||
public uint m_CycleOffsetParamID;
|
||||
public float m_Speed;
|
||||
public float m_CycleOffset;
|
||||
public bool m_IKOnFeet;
|
||||
public bool m_WriteDefaultValues;
|
||||
public bool m_Loop;
|
||||
public bool m_Mirror;
|
||||
|
||||
public StateConstant(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
|
||||
int numTransistions = reader.ReadInt32();
|
||||
m_TransitionConstantArray = new TransitionConstant[numTransistions];
|
||||
for (int i = 0; i < numTransistions; i++)
|
||||
{
|
||||
m_TransitionConstantArray[i] = new TransitionConstant(reader);
|
||||
}
|
||||
|
||||
m_BlendTreeConstantIndexArray = reader.ReadInt32Array();
|
||||
|
||||
if (version[0] < 5 || (version[0] == 5 && version[1] < 2)) //5.2 down
|
||||
{
|
||||
int numInfos = reader.ReadInt32();
|
||||
m_LeafInfoArray = new LeafInfoConstant[numInfos];
|
||||
for (int i = 0; i < numInfos; i++)
|
||||
{
|
||||
m_LeafInfoArray[i] = new LeafInfoConstant(reader);
|
||||
}
|
||||
}
|
||||
|
||||
int numBlends = reader.ReadInt32();
|
||||
m_BlendTreeConstantArray = new BlendTreeConstant[numBlends];
|
||||
for (int i = 0; i < numBlends; i++)
|
||||
{
|
||||
m_BlendTreeConstantArray[i] = new BlendTreeConstant(reader);
|
||||
}
|
||||
|
||||
m_NameID = reader.ReadUInt32();
|
||||
if (version[0] > 4 || (version[0] == 4 && version[1] >= 3)) //4.3 and up
|
||||
{
|
||||
m_PathID = reader.ReadUInt32();
|
||||
}
|
||||
if (version[0] >= 5) //5.0 and up
|
||||
{
|
||||
m_FullPathID = reader.ReadUInt32();
|
||||
}
|
||||
|
||||
m_TagID = reader.ReadUInt32();
|
||||
if (version[0] > 5 || (version[0] == 5 && version[1] >= 1)) //5.1 and up
|
||||
{
|
||||
m_SpeedParamID = reader.ReadUInt32();
|
||||
m_MirrorParamID = reader.ReadUInt32();
|
||||
m_CycleOffsetParamID = reader.ReadUInt32();
|
||||
}
|
||||
|
||||
if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 2)) //2017.2 and up
|
||||
{
|
||||
var m_TimeParamID = reader.ReadUInt32();
|
||||
}
|
||||
|
||||
m_Speed = reader.ReadSingle();
|
||||
if (version[0] > 4 || (version[0] == 4 && version[1] >= 1)) //4.1 and up
|
||||
{
|
||||
m_CycleOffset = reader.ReadSingle();
|
||||
}
|
||||
m_IKOnFeet = reader.ReadBoolean();
|
||||
if (version[0] >= 5) //5.0 and up
|
||||
{
|
||||
m_WriteDefaultValues = reader.ReadBoolean();
|
||||
}
|
||||
|
||||
m_Loop = reader.ReadBoolean();
|
||||
if (version[0] > 4 || (version[0] == 4 && version[1] >= 1)) //4.1 and up
|
||||
{
|
||||
m_Mirror = reader.ReadBoolean();
|
||||
}
|
||||
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
|
||||
public class SelectorTransitionConstant
|
||||
{
|
||||
public uint m_Destination;
|
||||
public ConditionConstant[] m_ConditionConstantArray;
|
||||
|
||||
public SelectorTransitionConstant(ObjectReader reader)
|
||||
{
|
||||
m_Destination = reader.ReadUInt32();
|
||||
|
||||
int numConditions = reader.ReadInt32();
|
||||
m_ConditionConstantArray = new ConditionConstant[numConditions];
|
||||
for (int i = 0; i < numConditions; i++)
|
||||
{
|
||||
m_ConditionConstantArray[i] = new ConditionConstant(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class SelectorStateConstant
|
||||
{
|
||||
public SelectorTransitionConstant[] m_TransitionConstantArray;
|
||||
public uint m_FullPathID;
|
||||
public bool m_isEntry;
|
||||
|
||||
public SelectorStateConstant(ObjectReader reader)
|
||||
{
|
||||
int numTransitions = reader.ReadInt32();
|
||||
m_TransitionConstantArray = new SelectorTransitionConstant[numTransitions];
|
||||
for (int i = 0; i < numTransitions; i++)
|
||||
{
|
||||
m_TransitionConstantArray[i] = new SelectorTransitionConstant(reader);
|
||||
}
|
||||
|
||||
m_FullPathID = reader.ReadUInt32();
|
||||
m_isEntry = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
|
||||
public class StateMachineConstant
|
||||
{
|
||||
public StateConstant[] m_StateConstantArray;
|
||||
public TransitionConstant[] m_AnyStateTransitionConstantArray;
|
||||
public SelectorStateConstant[] m_SelectorStateConstantArray;
|
||||
public uint m_DefaultState;
|
||||
public uint m_MotionSetCount;
|
||||
|
||||
public StateMachineConstant(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
|
||||
int numStates = reader.ReadInt32();
|
||||
m_StateConstantArray = new StateConstant[numStates];
|
||||
for (int i = 0; i < numStates; i++)
|
||||
{
|
||||
m_StateConstantArray[i] = new StateConstant(reader);
|
||||
}
|
||||
|
||||
int numAnyStates = reader.ReadInt32();
|
||||
m_AnyStateTransitionConstantArray = new TransitionConstant[numAnyStates];
|
||||
for (int i = 0; i < numAnyStates; i++)
|
||||
{
|
||||
m_AnyStateTransitionConstantArray[i] = new TransitionConstant(reader);
|
||||
}
|
||||
|
||||
if (version[0] >= 5) //5.0 and up
|
||||
{
|
||||
int numSelectors = reader.ReadInt32();
|
||||
m_SelectorStateConstantArray = new SelectorStateConstant[numSelectors];
|
||||
for (int i = 0; i < numSelectors; i++)
|
||||
{
|
||||
m_SelectorStateConstantArray[i] = new SelectorStateConstant(reader);
|
||||
}
|
||||
}
|
||||
|
||||
m_DefaultState = reader.ReadUInt32();
|
||||
m_MotionSetCount = reader.ReadUInt32();
|
||||
}
|
||||
}
|
||||
|
||||
public class ValueArray
|
||||
{
|
||||
public bool[] m_BoolValues;
|
||||
public int[] m_IntValues;
|
||||
public float[] m_FloatValues;
|
||||
public Vector4[] m_VectorValues;
|
||||
public Vector3[] m_PositionValues;
|
||||
public Vector4[] m_QuaternionValues;
|
||||
public Vector3[] m_ScaleValues;
|
||||
|
||||
public ValueArray(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
|
||||
if (version[0] < 5 || (version[0] == 5 && version[1] < 5)) //5.5 down
|
||||
{
|
||||
m_BoolValues = reader.ReadBooleanArray();
|
||||
reader.AlignStream();
|
||||
m_IntValues = reader.ReadInt32Array();
|
||||
m_FloatValues = reader.ReadSingleArray();
|
||||
}
|
||||
|
||||
if (version[0] < 4 || (version[0] == 4 && version[1] < 3)) //4.3 down
|
||||
{
|
||||
m_VectorValues = reader.ReadVector4Array();
|
||||
}
|
||||
else
|
||||
{
|
||||
int numPosValues = reader.ReadInt32();
|
||||
m_PositionValues = new Vector3[numPosValues];
|
||||
for (int i = 0; i < numPosValues; i++)
|
||||
{
|
||||
m_PositionValues[i] = version[0] > 5 || (version[0] == 5 && version[1] >= 4) ? reader.ReadVector3() : (Vector3)reader.ReadVector4(); //5.4 and up
|
||||
}
|
||||
|
||||
m_QuaternionValues = reader.ReadVector4Array();
|
||||
|
||||
int numScaleValues = reader.ReadInt32();
|
||||
m_ScaleValues = new Vector3[numScaleValues];
|
||||
for (int i = 0; i < numScaleValues; i++)
|
||||
{
|
||||
m_ScaleValues[i] = version[0] > 5 || (version[0] == 5 && version[1] >= 4) ? reader.ReadVector3() : (Vector3)reader.ReadVector4(); //5.4 and up
|
||||
}
|
||||
|
||||
if (version[0] > 5 || (version[0] == 5 && version[1] >= 5)) //5.5 and up
|
||||
{
|
||||
m_FloatValues = reader.ReadSingleArray();
|
||||
m_IntValues = reader.ReadInt32Array();
|
||||
m_BoolValues = reader.ReadBooleanArray();
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ControllerConstant
|
||||
{
|
||||
public LayerConstant[] m_LayerArray;
|
||||
public StateMachineConstant[] m_StateMachineArray;
|
||||
public ValueArrayConstant m_Values;
|
||||
public ValueArray m_DefaultValues;
|
||||
|
||||
public ControllerConstant(ObjectReader reader)
|
||||
{
|
||||
int numLayers = reader.ReadInt32();
|
||||
m_LayerArray = new LayerConstant[numLayers];
|
||||
for (int i = 0; i < numLayers; i++)
|
||||
{
|
||||
m_LayerArray[i] = new LayerConstant(reader);
|
||||
}
|
||||
|
||||
int numStates = reader.ReadInt32();
|
||||
m_StateMachineArray = new StateMachineConstant[numStates];
|
||||
for (int i = 0; i < numStates; i++)
|
||||
{
|
||||
m_StateMachineArray[i] = new StateMachineConstant(reader);
|
||||
}
|
||||
|
||||
m_Values = new ValueArrayConstant(reader);
|
||||
m_DefaultValues = new ValueArray(reader);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class AnimatorController : RuntimeAnimatorController
|
||||
{
|
||||
public PPtr<AnimationClip>[] m_AnimationClips;
|
||||
|
||||
public AnimatorController(ObjectReader reader) : base(reader)
|
||||
{
|
||||
var m_ControllerSize = reader.ReadUInt32();
|
||||
var m_Controller = new ControllerConstant(reader);
|
||||
|
||||
int tosSize = reader.ReadInt32();
|
||||
var m_TOS = new Dictionary<uint, string>(tosSize);
|
||||
for (int i = 0; i < tosSize; i++)
|
||||
{
|
||||
m_TOS.Add(reader.ReadUInt32(), reader.ReadAlignedString());
|
||||
}
|
||||
|
||||
int numClips = reader.ReadInt32();
|
||||
m_AnimationClips = new PPtr<AnimationClip>[numClips];
|
||||
for (int i = 0; i < numClips; i++)
|
||||
{
|
||||
m_AnimationClips[i] = new PPtr<AnimationClip>(reader);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool IsContainsAnimationClip(AnimationClip clip)
|
||||
{
|
||||
foreach (PPtr<AnimationClip> ptr in m_AnimationClips)
|
||||
{
|
||||
if (ptr.TryGet(out var animationClip) && animationClip.Equals(clip))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
58
AssetStudio/Classes/AnimatorOverrideController.cs
Normal file
58
AssetStudio/Classes/AnimatorOverrideController.cs
Normal file
@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class AnimationClipOverride
|
||||
{
|
||||
public PPtr<AnimationClip> m_OriginalClip;
|
||||
public PPtr<AnimationClip> m_OverrideClip;
|
||||
|
||||
public AnimationClipOverride(ObjectReader reader)
|
||||
{
|
||||
m_OriginalClip = new PPtr<AnimationClip>(reader);
|
||||
m_OverrideClip = new PPtr<AnimationClip>(reader);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class AnimatorOverrideController : RuntimeAnimatorController
|
||||
{
|
||||
public PPtr<RuntimeAnimatorController> m_Controller;
|
||||
public AnimationClipOverride[] m_Clips;
|
||||
|
||||
public AnimatorOverrideController(ObjectReader reader) : base(reader)
|
||||
{
|
||||
m_Controller = new PPtr<RuntimeAnimatorController>(reader);
|
||||
|
||||
int numOverrides = reader.ReadInt32();
|
||||
m_Clips = new AnimationClipOverride[numOverrides];
|
||||
for (int i = 0; i < numOverrides; i++)
|
||||
{
|
||||
m_Clips[i] = new AnimationClipOverride(reader);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool IsContainsAnimationClip(AnimationClip clip)
|
||||
{
|
||||
AnimationClip animationClip;
|
||||
foreach (AnimationClipOverride overClip in m_Clips)
|
||||
{
|
||||
if (overClip.m_OriginalClip.TryGet(out animationClip) && animationClip.Equals(clip))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (overClip.m_OverrideClip.TryGet(out animationClip) && animationClip.Equals(clip))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (m_Controller.TryGet(out var baseController))
|
||||
{
|
||||
return baseController.IsContainsAnimationClip(clip);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
94
AssetStudio/Classes/AssetBundle.cs
Normal file
94
AssetStudio/Classes/AssetBundle.cs
Normal file
@ -0,0 +1,94 @@
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class AssetInfo
|
||||
{
|
||||
public int preloadIndex;
|
||||
public int preloadSize;
|
||||
public PPtr<Object> asset;
|
||||
|
||||
public AssetInfo(ObjectReader reader)
|
||||
{
|
||||
preloadIndex = reader.ReadInt32();
|
||||
preloadSize = reader.ReadInt32();
|
||||
asset = new PPtr<Object>(reader);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class AssetBundle : NamedObject
|
||||
{
|
||||
public static bool Exportable;
|
||||
|
||||
public PPtr<Object>[] PreloadTable;
|
||||
public KeyValuePair<string, AssetInfo>[] Container;
|
||||
public AssetInfo MainAsset;
|
||||
public uint RuntimeComaptability;
|
||||
public string AssetBundleName;
|
||||
public int DependencyCount;
|
||||
public string[] Dependencies;
|
||||
public bool IsStreamedScenessetBundle;
|
||||
public int ExplicitDataLayout;
|
||||
public int PathFlags;
|
||||
public int SceneHashCount;
|
||||
public KeyValuePair<string, string>[] SceneHashes;
|
||||
|
||||
public AssetBundle(ObjectReader reader) : base(reader)
|
||||
{
|
||||
var m_PreloadTableSize = reader.ReadInt32();
|
||||
PreloadTable = new PPtr<Object>[m_PreloadTableSize];
|
||||
for (int i = 0; i < m_PreloadTableSize; i++)
|
||||
{
|
||||
PreloadTable[i] = new PPtr<Object>(reader);
|
||||
}
|
||||
|
||||
var m_ContainerSize = reader.ReadInt32();
|
||||
Container = new KeyValuePair<string, AssetInfo>[m_ContainerSize];
|
||||
for (int i = 0; i < m_ContainerSize; i++)
|
||||
{
|
||||
Container[i] = new KeyValuePair<string, AssetInfo>(reader.ReadAlignedString(), new AssetInfo(reader));
|
||||
}
|
||||
|
||||
if (reader.Game.Name == "GI" || reader.Game.Name == "GI_CB1" || reader.Game.Name == "GI_CB2" || reader.Game.Name == "GI_CB3")
|
||||
{
|
||||
MainAsset = new AssetInfo(reader);
|
||||
RuntimeComaptability = reader.ReadUInt32();
|
||||
}
|
||||
|
||||
AssetBundleName = reader.ReadAlignedString();
|
||||
DependencyCount = reader.ReadInt32();
|
||||
Dependencies = new string[DependencyCount];
|
||||
for (int k = 0; k < DependencyCount; k++)
|
||||
{
|
||||
Dependencies[k] = reader.ReadAlignedString();
|
||||
}
|
||||
if (reader.Game.Name == "GI_CB1" || reader.Game.Name == "GI_CB2")
|
||||
{
|
||||
IsStreamedScenessetBundle = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
PathFlags = reader.ReadInt32();
|
||||
}
|
||||
else if (reader.Game.Name == "GI_CB3")
|
||||
{
|
||||
IsStreamedScenessetBundle = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
ExplicitDataLayout = reader.ReadInt32();
|
||||
PathFlags = reader.ReadInt32();
|
||||
}
|
||||
else if (reader.Game.Name == "GI")
|
||||
{
|
||||
IsStreamedScenessetBundle = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
ExplicitDataLayout = reader.ReadInt32();
|
||||
PathFlags = reader.ReadInt32();
|
||||
SceneHashCount = reader.ReadInt32();
|
||||
SceneHashes = new KeyValuePair<string, string>[SceneHashCount];
|
||||
for (int l = 0; l < SceneHashCount; l++)
|
||||
{
|
||||
SceneHashes[l] = new KeyValuePair<string, string>(reader.ReadAlignedString(), reader.ReadAlignedString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
142
AssetStudio/Classes/AudioClip.cs
Normal file
142
AssetStudio/Classes/AudioClip.cs
Normal file
@ -0,0 +1,142 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public sealed class AudioClip : NamedObject
|
||||
{
|
||||
public int m_Format;
|
||||
public FMODSoundType m_Type;
|
||||
public bool m_3D;
|
||||
public bool m_UseHardware;
|
||||
|
||||
//version 5
|
||||
public int m_LoadType;
|
||||
public int m_Channels;
|
||||
public int m_Frequency;
|
||||
public int m_BitsPerSample;
|
||||
public float m_Length;
|
||||
public bool m_IsTrackerFormat;
|
||||
public int m_SubsoundIndex;
|
||||
public bool m_PreloadAudioData;
|
||||
public bool m_LoadInBackground;
|
||||
public bool m_Legacy3D;
|
||||
public AudioCompressionFormat m_CompressionFormat;
|
||||
|
||||
public string m_Source;
|
||||
public long m_Offset; //ulong
|
||||
public long m_Size; //ulong
|
||||
public ResourceReader m_AudioData;
|
||||
|
||||
public AudioClip(ObjectReader reader) : base(reader)
|
||||
{
|
||||
if (version[0] < 5)
|
||||
{
|
||||
m_Format = reader.ReadInt32();
|
||||
m_Type = (FMODSoundType)reader.ReadInt32();
|
||||
m_3D = reader.ReadBoolean();
|
||||
m_UseHardware = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
|
||||
if (version[0] >= 4 || (version[0] == 3 && version[1] >= 2)) //3.2.0 to 5
|
||||
{
|
||||
int m_Stream = reader.ReadInt32();
|
||||
m_Size = reader.ReadInt32();
|
||||
var tsize = m_Size % 4 != 0 ? m_Size + 4 - m_Size % 4 : m_Size;
|
||||
if (reader.byteSize + reader.byteStart - reader.Position != tsize)
|
||||
{
|
||||
m_Offset = reader.ReadUInt32();
|
||||
m_Source = assetsFile.fullName + ".resS";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Size = reader.ReadInt32();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_LoadType = reader.ReadInt32();
|
||||
m_Channels = reader.ReadInt32();
|
||||
m_Frequency = reader.ReadInt32();
|
||||
m_BitsPerSample = reader.ReadInt32();
|
||||
m_Length = reader.ReadSingle();
|
||||
m_IsTrackerFormat = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
m_SubsoundIndex = reader.ReadInt32();
|
||||
m_PreloadAudioData = reader.ReadBoolean();
|
||||
m_LoadInBackground = reader.ReadBoolean();
|
||||
m_Legacy3D = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
|
||||
//StreamedResource m_Resource
|
||||
m_Source = reader.ReadAlignedString();
|
||||
m_Offset = reader.ReadInt64();
|
||||
m_Size = reader.ReadInt64();
|
||||
m_CompressionFormat = (AudioCompressionFormat)reader.ReadInt32();
|
||||
}
|
||||
|
||||
ResourceReader resourceReader;
|
||||
if (!string.IsNullOrEmpty(m_Source))
|
||||
{
|
||||
resourceReader = new ResourceReader(m_Source, assetsFile, m_Offset, m_Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
resourceReader = new ResourceReader(reader, reader.BaseStream.Position, m_Size);
|
||||
}
|
||||
m_AudioData = resourceReader;
|
||||
}
|
||||
}
|
||||
|
||||
public enum FMODSoundType
|
||||
{
|
||||
UNKNOWN = 0,
|
||||
ACC = 1,
|
||||
AIFF = 2,
|
||||
ASF = 3,
|
||||
AT3 = 4,
|
||||
CDDA = 5,
|
||||
DLS = 6,
|
||||
FLAC = 7,
|
||||
FSB = 8,
|
||||
GCADPCM = 9,
|
||||
IT = 10,
|
||||
MIDI = 11,
|
||||
MOD = 12,
|
||||
MPEG = 13,
|
||||
OGGVORBIS = 14,
|
||||
PLAYLIST = 15,
|
||||
RAW = 16,
|
||||
S3M = 17,
|
||||
SF2 = 18,
|
||||
USER = 19,
|
||||
WAV = 20,
|
||||
XM = 21,
|
||||
XMA = 22,
|
||||
VAG = 23,
|
||||
AUDIOQUEUE = 24,
|
||||
XWMA = 25,
|
||||
BCWAV = 26,
|
||||
AT9 = 27,
|
||||
VORBIS = 28,
|
||||
MEDIA_FOUNDATION = 29
|
||||
}
|
||||
|
||||
public enum AudioCompressionFormat
|
||||
{
|
||||
PCM = 0,
|
||||
Vorbis = 1,
|
||||
ADPCM = 2,
|
||||
MP3 = 3,
|
||||
PSMVAG = 4,
|
||||
HEVAG = 5,
|
||||
XMA = 6,
|
||||
AAC = 7,
|
||||
GCADPCM = 8,
|
||||
ATRAC9 = 9
|
||||
}
|
||||
}
|
313
AssetStudio/Classes/Avatar.cs
Normal file
313
AssetStudio/Classes/Avatar.cs
Normal file
@ -0,0 +1,313 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class Node
|
||||
{
|
||||
public int m_ParentId;
|
||||
public int m_AxesId;
|
||||
|
||||
public Node(ObjectReader reader)
|
||||
{
|
||||
m_ParentId = reader.ReadInt32();
|
||||
m_AxesId = reader.ReadInt32();
|
||||
}
|
||||
}
|
||||
|
||||
public class Limit
|
||||
{
|
||||
public object m_Min;
|
||||
public object m_Max;
|
||||
|
||||
public Limit(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
if (version[0] > 5 || (version[0] == 5 && version[1] >= 4))//5.4 and up
|
||||
{
|
||||
m_Min = reader.ReadVector3();
|
||||
m_Max = reader.ReadVector3();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Min = reader.ReadVector4();
|
||||
m_Max = reader.ReadVector4();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Axes
|
||||
{
|
||||
public Vector4 m_PreQ;
|
||||
public Vector4 m_PostQ;
|
||||
public object m_Sgn;
|
||||
public Limit m_Limit;
|
||||
public float m_Length;
|
||||
public uint m_Type;
|
||||
|
||||
public Axes(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
m_PreQ = reader.ReadVector4();
|
||||
m_PostQ = reader.ReadVector4();
|
||||
if (version[0] > 5 || (version[0] == 5 && version[1] >= 4)) //5.4 and up
|
||||
{
|
||||
m_Sgn = reader.ReadVector3();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Sgn = reader.ReadVector4();
|
||||
}
|
||||
m_Limit = new Limit(reader);
|
||||
m_Length = reader.ReadSingle();
|
||||
m_Type = reader.ReadUInt32();
|
||||
}
|
||||
}
|
||||
|
||||
public class Skeleton
|
||||
{
|
||||
public Node[] m_Node;
|
||||
public uint[] m_ID;
|
||||
public Axes[] m_AxesArray;
|
||||
|
||||
|
||||
public Skeleton(ObjectReader reader)
|
||||
{
|
||||
int numNodes = reader.ReadInt32();
|
||||
m_Node = new Node[numNodes];
|
||||
for (int i = 0; i < numNodes; i++)
|
||||
{
|
||||
m_Node[i] = new Node(reader);
|
||||
}
|
||||
|
||||
m_ID = reader.ReadUInt32Array();
|
||||
|
||||
int numAxes = reader.ReadInt32();
|
||||
m_AxesArray = new Axes[numAxes];
|
||||
for (int i = 0; i < numAxes; i++)
|
||||
{
|
||||
m_AxesArray[i] = new Axes(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class SkeletonPose
|
||||
{
|
||||
public xform[] m_X;
|
||||
|
||||
public SkeletonPose(ObjectReader reader)
|
||||
{
|
||||
int numXforms = reader.ReadInt32();
|
||||
m_X = new xform[numXforms];
|
||||
for (int i = 0; i < numXforms; i++)
|
||||
{
|
||||
m_X[i] = new xform(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Hand
|
||||
{
|
||||
public int[] m_HandBoneIndex;
|
||||
|
||||
public Hand(ObjectReader reader)
|
||||
{
|
||||
m_HandBoneIndex = reader.ReadInt32Array();
|
||||
}
|
||||
}
|
||||
|
||||
public class Handle
|
||||
{
|
||||
public xform m_X;
|
||||
public uint m_ParentHumanIndex;
|
||||
public uint m_ID;
|
||||
|
||||
public Handle(ObjectReader reader)
|
||||
{
|
||||
m_X = new xform(reader);
|
||||
m_ParentHumanIndex = reader.ReadUInt32();
|
||||
m_ID = reader.ReadUInt32();
|
||||
}
|
||||
}
|
||||
|
||||
public class Collider
|
||||
{
|
||||
public xform m_X;
|
||||
public uint m_Type;
|
||||
public uint m_XMotionType;
|
||||
public uint m_YMotionType;
|
||||
public uint m_ZMotionType;
|
||||
public float m_MinLimitX;
|
||||
public float m_MaxLimitX;
|
||||
public float m_MaxLimitY;
|
||||
public float m_MaxLimitZ;
|
||||
|
||||
public Collider(ObjectReader reader)
|
||||
{
|
||||
m_X = new xform(reader);
|
||||
m_Type = reader.ReadUInt32();
|
||||
m_XMotionType = reader.ReadUInt32();
|
||||
m_YMotionType = reader.ReadUInt32();
|
||||
m_ZMotionType = reader.ReadUInt32();
|
||||
m_MinLimitX = reader.ReadSingle();
|
||||
m_MaxLimitX = reader.ReadSingle();
|
||||
m_MaxLimitY = reader.ReadSingle();
|
||||
m_MaxLimitZ = reader.ReadSingle();
|
||||
}
|
||||
}
|
||||
|
||||
public class Human
|
||||
{
|
||||
public xform m_RootX;
|
||||
public Skeleton m_Skeleton;
|
||||
public SkeletonPose m_SkeletonPose;
|
||||
public Hand m_LeftHand;
|
||||
public Hand m_RightHand;
|
||||
public Handle[] m_Handles;
|
||||
public Collider[] m_ColliderArray;
|
||||
public int[] m_HumanBoneIndex;
|
||||
public float[] m_HumanBoneMass;
|
||||
public int[] m_ColliderIndex;
|
||||
public float m_Scale;
|
||||
public float m_ArmTwist;
|
||||
public float m_ForeArmTwist;
|
||||
public float m_UpperLegTwist;
|
||||
public float m_LegTwist;
|
||||
public float m_ArmStretch;
|
||||
public float m_LegStretch;
|
||||
public float m_FeetSpacing;
|
||||
public bool m_HasLeftHand;
|
||||
public bool m_HasRightHand;
|
||||
public bool m_HasTDoF;
|
||||
|
||||
public Human(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
m_RootX = new xform(reader);
|
||||
m_Skeleton = new Skeleton(reader);
|
||||
m_SkeletonPose = new SkeletonPose(reader);
|
||||
m_LeftHand = new Hand(reader);
|
||||
m_RightHand = new Hand(reader);
|
||||
|
||||
if (version[0] < 2018 || (version[0] == 2018 && version[1] < 2)) //2018.2 down
|
||||
{
|
||||
int numHandles = reader.ReadInt32();
|
||||
m_Handles = new Handle[numHandles];
|
||||
for (int i = 0; i < numHandles; i++)
|
||||
{
|
||||
m_Handles[i] = new Handle(reader);
|
||||
}
|
||||
|
||||
int numColliders = reader.ReadInt32();
|
||||
m_ColliderArray = new Collider[numColliders];
|
||||
for (int i = 0; i < numColliders; i++)
|
||||
{
|
||||
m_ColliderArray[i] = new Collider(reader);
|
||||
}
|
||||
}
|
||||
|
||||
m_HumanBoneIndex = reader.ReadInt32Array();
|
||||
|
||||
m_HumanBoneMass = reader.ReadSingleArray();
|
||||
|
||||
if (version[0] < 2018 || (version[0] == 2018 && version[1] < 2)) //2018.2 down
|
||||
{
|
||||
m_ColliderIndex = reader.ReadInt32Array();
|
||||
}
|
||||
|
||||
m_Scale = reader.ReadSingle();
|
||||
m_ArmTwist = reader.ReadSingle();
|
||||
m_ForeArmTwist = reader.ReadSingle();
|
||||
m_UpperLegTwist = reader.ReadSingle();
|
||||
m_LegTwist = reader.ReadSingle();
|
||||
m_ArmStretch = reader.ReadSingle();
|
||||
m_LegStretch = reader.ReadSingle();
|
||||
m_FeetSpacing = reader.ReadSingle();
|
||||
m_HasLeftHand = reader.ReadBoolean();
|
||||
m_HasRightHand = reader.ReadBoolean();
|
||||
if (version[0] > 5 || (version[0] == 5 && version[1] >= 2)) //5.2 and up
|
||||
{
|
||||
m_HasTDoF = reader.ReadBoolean();
|
||||
}
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
|
||||
public class AvatarConstant
|
||||
{
|
||||
public Skeleton m_AvatarSkeleton;
|
||||
public SkeletonPose m_AvatarSkeletonPose;
|
||||
public SkeletonPose m_DefaultPose;
|
||||
public uint[] m_SkeletonNameIDArray;
|
||||
public Human m_Human;
|
||||
public int[] m_HumanSkeletonIndexArray;
|
||||
public int[] m_HumanSkeletonReverseIndexArray;
|
||||
public int m_RootMotionBoneIndex;
|
||||
public xform m_RootMotionBoneX;
|
||||
public Skeleton m_RootMotionSkeleton;
|
||||
public SkeletonPose m_RootMotionSkeletonPose;
|
||||
public int[] m_RootMotionSkeletonIndexArray;
|
||||
|
||||
public AvatarConstant(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
m_AvatarSkeleton = new Skeleton(reader);
|
||||
m_AvatarSkeletonPose = new SkeletonPose(reader);
|
||||
|
||||
if (version[0] > 4 || (version[0] == 4 && version[1] >= 3)) //4.3 and up
|
||||
{
|
||||
m_DefaultPose = new SkeletonPose(reader);
|
||||
|
||||
m_SkeletonNameIDArray = reader.ReadUInt32Array();
|
||||
}
|
||||
|
||||
m_Human = new Human(reader);
|
||||
|
||||
m_HumanSkeletonIndexArray = reader.ReadInt32Array();
|
||||
|
||||
if (version[0] > 4 || (version[0] == 4 && version[1] >= 3)) //4.3 and up
|
||||
{
|
||||
m_HumanSkeletonReverseIndexArray = reader.ReadInt32Array();
|
||||
}
|
||||
|
||||
m_RootMotionBoneIndex = reader.ReadInt32();
|
||||
m_RootMotionBoneX = new xform(reader);
|
||||
|
||||
if (version[0] > 4 || (version[0] == 4 && version[1] >= 3)) //4.3 and up
|
||||
{
|
||||
m_RootMotionSkeleton = new Skeleton(reader);
|
||||
m_RootMotionSkeletonPose = new SkeletonPose(reader);
|
||||
|
||||
m_RootMotionSkeletonIndexArray = reader.ReadInt32Array();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class Avatar : NamedObject
|
||||
{
|
||||
public uint m_AvatarSize;
|
||||
public AvatarConstant m_Avatar;
|
||||
public Dictionary<uint, string> m_TOS;
|
||||
|
||||
public Avatar(ObjectReader reader) : base(reader)
|
||||
{
|
||||
m_AvatarSize = reader.ReadUInt32();
|
||||
m_Avatar = new AvatarConstant(reader);
|
||||
|
||||
int numTOS = reader.ReadInt32();
|
||||
m_TOS = new Dictionary<uint, string>(numTOS);
|
||||
for (int i = 0; i < numTOS; i++)
|
||||
{
|
||||
m_TOS.Add(reader.ReadUInt32(), reader.ReadAlignedString());
|
||||
}
|
||||
|
||||
//HumanDescription m_HumanDescription 2019 and up
|
||||
}
|
||||
|
||||
public string FindBonePath(uint hash)
|
||||
{
|
||||
m_TOS.TryGetValue(hash, out string path);
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
18
AssetStudio/Classes/Behaviour.cs
Normal file
18
AssetStudio/Classes/Behaviour.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public abstract class Behaviour : Component
|
||||
{
|
||||
public byte m_Enabled;
|
||||
|
||||
protected Behaviour(ObjectReader reader) : base(reader)
|
||||
{
|
||||
m_Enabled = reader.ReadByte();
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
}
|
24
AssetStudio/Classes/BuildSettings.cs
Normal file
24
AssetStudio/Classes/BuildSettings.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public sealed class BuildSettings : Object
|
||||
{
|
||||
public string m_Version;
|
||||
|
||||
public BuildSettings(ObjectReader reader) : base(reader)
|
||||
{
|
||||
var levels = reader.ReadStringArray();
|
||||
|
||||
var hasRenderTexture = reader.ReadBoolean();
|
||||
var hasPROVersion = reader.ReadBoolean();
|
||||
var hasPublishingRights = reader.ReadBoolean();
|
||||
var hasShadows = reader.ReadBoolean();
|
||||
|
||||
m_Version = reader.ReadAlignedString();
|
||||
}
|
||||
}
|
||||
}
|
17
AssetStudio/Classes/Component.cs
Normal file
17
AssetStudio/Classes/Component.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public abstract class Component : EditorExtension
|
||||
{
|
||||
public PPtr<GameObject> m_GameObject;
|
||||
|
||||
protected Component(ObjectReader reader) : base(reader)
|
||||
{
|
||||
m_GameObject = new PPtr<GameObject>(reader);
|
||||
}
|
||||
}
|
||||
}
|
19
AssetStudio/Classes/EditorExtension.cs
Normal file
19
AssetStudio/Classes/EditorExtension.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public abstract class EditorExtension : Object
|
||||
{
|
||||
protected EditorExtension(ObjectReader reader) : base(reader)
|
||||
{
|
||||
if (platform == BuildTarget.NoTarget)
|
||||
{
|
||||
var m_PrefabParentObject = new PPtr<EditorExtension>(reader);
|
||||
var m_PrefabInternal = new PPtr<Object>(reader); //PPtr<Prefab>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
121
AssetStudio/Classes/Font.cs
Normal file
121
AssetStudio/Classes/Font.cs
Normal file
@ -0,0 +1,121 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public sealed class Font : NamedObject
|
||||
{
|
||||
public byte[] m_FontData;
|
||||
|
||||
public Font(ObjectReader reader) : base(reader)
|
||||
{
|
||||
if ((version[0] == 5 && version[1] >= 5) || version[0] > 5)//5.5 and up
|
||||
{
|
||||
var m_LineSpacing = reader.ReadSingle();
|
||||
var m_DefaultMaterial = new PPtr<Material>(reader);
|
||||
var m_FontSize = reader.ReadSingle();
|
||||
var m_Texture = new PPtr<Texture>(reader);
|
||||
int m_AsciiStartOffset = reader.ReadInt32();
|
||||
var m_Tracking = reader.ReadSingle();
|
||||
var m_CharacterSpacing = reader.ReadInt32();
|
||||
var m_CharacterPadding = reader.ReadInt32();
|
||||
var m_ConvertCase = reader.ReadInt32();
|
||||
int m_CharacterRects_size = reader.ReadInt32();
|
||||
for (int i = 0; i < m_CharacterRects_size; i++)
|
||||
{
|
||||
reader.Position += 44;//CharacterInfo data 41
|
||||
}
|
||||
int m_KerningValues_size = reader.ReadInt32();
|
||||
for (int i = 0; i < m_KerningValues_size; i++)
|
||||
{
|
||||
reader.Position += 8;
|
||||
}
|
||||
var m_PixelScale = reader.ReadSingle();
|
||||
int m_FontData_size = reader.ReadInt32();
|
||||
if (m_FontData_size > 0)
|
||||
{
|
||||
m_FontData = reader.ReadBytes(m_FontData_size);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int m_AsciiStartOffset = reader.ReadInt32();
|
||||
|
||||
if (version[0] <= 3)
|
||||
{
|
||||
int m_FontCountX = reader.ReadInt32();
|
||||
int m_FontCountY = reader.ReadInt32();
|
||||
}
|
||||
|
||||
float m_Kerning = reader.ReadSingle();
|
||||
float m_LineSpacing = reader.ReadSingle();
|
||||
|
||||
if (version[0] <= 3)
|
||||
{
|
||||
int m_PerCharacterKerning_size = reader.ReadInt32();
|
||||
for (int i = 0; i < m_PerCharacterKerning_size; i++)
|
||||
{
|
||||
int first = reader.ReadInt32();
|
||||
float second = reader.ReadSingle();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int m_CharacterSpacing = reader.ReadInt32();
|
||||
int m_CharacterPadding = reader.ReadInt32();
|
||||
}
|
||||
|
||||
int m_ConvertCase = reader.ReadInt32();
|
||||
var m_DefaultMaterial = new PPtr<Material>(reader);
|
||||
|
||||
int m_CharacterRects_size = reader.ReadInt32();
|
||||
for (int i = 0; i < m_CharacterRects_size; i++)
|
||||
{
|
||||
int index = reader.ReadInt32();
|
||||
//Rectf uv
|
||||
float uvx = reader.ReadSingle();
|
||||
float uvy = reader.ReadSingle();
|
||||
float uvwidth = reader.ReadSingle();
|
||||
float uvheight = reader.ReadSingle();
|
||||
//Rectf vert
|
||||
float vertx = reader.ReadSingle();
|
||||
float verty = reader.ReadSingle();
|
||||
float vertwidth = reader.ReadSingle();
|
||||
float vertheight = reader.ReadSingle();
|
||||
float width = reader.ReadSingle();
|
||||
|
||||
if (version[0] >= 4)
|
||||
{
|
||||
var flipped = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
|
||||
var m_Texture = new PPtr<Texture>(reader);
|
||||
|
||||
int m_KerningValues_size = reader.ReadInt32();
|
||||
for (int i = 0; i < m_KerningValues_size; i++)
|
||||
{
|
||||
int pairfirst = reader.ReadInt16();
|
||||
int pairsecond = reader.ReadInt16();
|
||||
float second = reader.ReadSingle();
|
||||
}
|
||||
|
||||
if (version[0] <= 3)
|
||||
{
|
||||
var m_GridFont = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
}
|
||||
else { float m_PixelScale = reader.ReadSingle(); }
|
||||
|
||||
int m_FontData_size = reader.ReadInt32();
|
||||
if (m_FontData_size > 0)
|
||||
{
|
||||
m_FontData = reader.ReadBytes(m_FontData_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
101
AssetStudio/Classes/GameObject.cs
Normal file
101
AssetStudio/Classes/GameObject.cs
Normal file
@ -0,0 +1,101 @@
|
||||
using SevenZip;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public sealed class GameObject : EditorExtension
|
||||
{
|
||||
public PPtr<Component>[] m_Components;
|
||||
public string m_Name;
|
||||
public uint m_Tag;
|
||||
public bool m_IsActive;
|
||||
|
||||
public Transform m_Transform;
|
||||
public MeshRenderer m_MeshRenderer;
|
||||
public MeshFilter m_MeshFilter;
|
||||
public SkinnedMeshRenderer m_SkinnedMeshRenderer;
|
||||
public Animator m_Animator;
|
||||
public Animation m_Animation;
|
||||
|
||||
public GameObject(ObjectReader reader) : base(reader)
|
||||
{
|
||||
int m_Component_size = reader.ReadInt32();
|
||||
m_Components = new PPtr<Component>[m_Component_size];
|
||||
for (int i = 0; i < m_Component_size; i++)
|
||||
{
|
||||
if ((version[0] == 5 && version[1] < 5) || version[0] < 5) //5.5 down
|
||||
{
|
||||
int first = reader.ReadInt32();
|
||||
}
|
||||
m_Components[i] = new PPtr<Component>(reader);
|
||||
}
|
||||
|
||||
var m_Layer = reader.ReadInt32();
|
||||
m_Name = reader.ReadAlignedString();
|
||||
m_Tag = reader.ReadUInt16();
|
||||
m_IsActive = reader.ReadBoolean();
|
||||
}
|
||||
public Transform GetTransform()
|
||||
{
|
||||
foreach (PPtr<Component> ptr in FetchComponents())
|
||||
{
|
||||
if (!ptr.TryGet(out var comp))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (comp.type == ClassIDType.Transform)
|
||||
{
|
||||
return comp as Transform;
|
||||
}
|
||||
}
|
||||
throw new Exception("Can't find transform component");
|
||||
}
|
||||
|
||||
private List<PPtr<Component>> FetchComponents()
|
||||
{
|
||||
return m_Components.ToList();
|
||||
}
|
||||
|
||||
public T FindComponent<T>()
|
||||
where T : Component
|
||||
{
|
||||
foreach (PPtr<Component> ptr in FetchComponents())
|
||||
{
|
||||
// component could has not impelemented asset type
|
||||
if (ptr.TryGet(out var comp) && comp is T t)
|
||||
{
|
||||
return t;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Dictionary<uint, string> BuildTOS()
|
||||
{
|
||||
Dictionary<uint, string> tos = new Dictionary<uint, string>() { { 0, string.Empty } };
|
||||
BuildTOS(this, string.Empty, tos);
|
||||
return tos;
|
||||
}
|
||||
private void BuildTOS(GameObject parent, string parentPath, Dictionary<uint, string> tos)
|
||||
{
|
||||
Transform transform = parent.GetTransform();
|
||||
foreach (PPtr<Transform> childPtr in transform.m_Children)
|
||||
{
|
||||
if (childPtr.TryGet(out var childTransform))
|
||||
{
|
||||
if (childTransform.m_GameObject.TryGet(out var child))
|
||||
{
|
||||
string path = parentPath != string.Empty ? parentPath + '/' + child.m_Name : child.m_Name;
|
||||
var pathHash = CRC.CalculateDigestUTF8(path);
|
||||
tos[pathHash] = path;
|
||||
BuildTOS(child, path, tos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
43
AssetStudio/Classes/IndexObject.cs
Normal file
43
AssetStudio/Classes/IndexObject.cs
Normal file
@ -0,0 +1,43 @@
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class Index
|
||||
{
|
||||
public PPtr<Object> Object;
|
||||
public ulong Size;
|
||||
|
||||
public Index(ObjectReader reader)
|
||||
{
|
||||
|
||||
Object = new PPtr<Object>(reader);
|
||||
Size = reader.ReadUInt64();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class IndexObject : NamedObject
|
||||
{
|
||||
public static bool Exportable;
|
||||
|
||||
public int Count;
|
||||
public Dictionary<string, Index> AssetMap;
|
||||
public Dictionary<long, string> Names = new Dictionary<long, string>();
|
||||
|
||||
public IndexObject(ObjectReader reader) : base(reader)
|
||||
{
|
||||
Count = reader.ReadInt32();
|
||||
AssetMap = new Dictionary<string, Index>(Count);
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
var key = reader.ReadAlignedString();
|
||||
var value = new Index(reader);
|
||||
|
||||
AssetMap.Add(key, value);
|
||||
|
||||
if (value.Object.m_FileID == 0)
|
||||
Names.Add(value.Object.m_PathID, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
167
AssetStudio/Classes/Material.cs
Normal file
167
AssetStudio/Classes/Material.cs
Normal file
@ -0,0 +1,167 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using SevenZip;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class UnityTexEnv
|
||||
{
|
||||
public PPtr<Texture> m_Texture;
|
||||
public Vector2 m_Scale;
|
||||
public Vector2 m_Offset;
|
||||
|
||||
public UnityTexEnv(ObjectReader reader)
|
||||
{
|
||||
m_Texture = new PPtr<Texture>(reader);
|
||||
m_Scale = reader.ReadVector2();
|
||||
m_Offset = reader.ReadVector2();
|
||||
}
|
||||
}
|
||||
|
||||
public class UnityPropertySheet
|
||||
{
|
||||
private const string HDRPostfixName = "_HDR";
|
||||
private const string STPostfixName = "_ST";
|
||||
private const string TexelSizePostfixName = "_TexelSize";
|
||||
|
||||
public Dictionary<string, UnityTexEnv> m_TexEnvs;
|
||||
public Dictionary<string, int> m_Ints;
|
||||
public Dictionary<string, float> m_Floats;
|
||||
public Dictionary<string, Color> m_Colors;
|
||||
|
||||
public UnityPropertySheet(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
|
||||
int m_TexEnvsSize = reader.ReadInt32();
|
||||
m_TexEnvs = new Dictionary<string, UnityTexEnv>(m_TexEnvsSize);
|
||||
for (int i = 0; i < m_TexEnvsSize; i++)
|
||||
{
|
||||
m_TexEnvs.Add(reader.ReadAlignedString(), new UnityTexEnv(reader));
|
||||
}
|
||||
|
||||
if (version[0] >= 2021) //2021.1 and up
|
||||
{
|
||||
int m_IntsSize = reader.ReadInt32();
|
||||
m_Ints = new Dictionary<string, int>(m_IntsSize);
|
||||
for (int i = 0; i < m_IntsSize; i++)
|
||||
{
|
||||
m_Ints.Add(reader.ReadAlignedString(), reader.ReadInt32());
|
||||
}
|
||||
}
|
||||
|
||||
int m_FloatsSize = reader.ReadInt32();
|
||||
m_Floats = new Dictionary<string, float>(m_FloatsSize);
|
||||
for (int i = 0; i < m_FloatsSize; i++)
|
||||
{
|
||||
m_Floats.Add(reader.ReadAlignedString(), reader.ReadSingle());
|
||||
}
|
||||
|
||||
int m_ColorsSize = reader.ReadInt32();
|
||||
m_Colors = new Dictionary<string, Color>(m_ColorsSize);
|
||||
for (int i = 0; i < m_ColorsSize; i++)
|
||||
{
|
||||
m_Colors.Add(reader.ReadAlignedString(), reader.ReadColor4());
|
||||
}
|
||||
}
|
||||
|
||||
public string FindPropertyNameByCRC28(uint crc)
|
||||
{
|
||||
foreach (var property in m_TexEnvs.Keys)
|
||||
{
|
||||
string hdrName = property + HDRPostfixName;
|
||||
if (CRC.Verify28DigestUTF8(hdrName, crc))
|
||||
{
|
||||
return hdrName;
|
||||
}
|
||||
string stName = property + STPostfixName;
|
||||
if (CRC.Verify28DigestUTF8(stName, crc))
|
||||
{
|
||||
return stName;
|
||||
}
|
||||
string texelName = property + TexelSizePostfixName;
|
||||
if (CRC.Verify28DigestUTF8(texelName, crc))
|
||||
{
|
||||
return texelName;
|
||||
}
|
||||
}
|
||||
foreach (var property in m_Floats.Keys)
|
||||
{
|
||||
if (CRC.Verify28DigestUTF8(property, crc))
|
||||
{
|
||||
return property;
|
||||
}
|
||||
}
|
||||
foreach (var property in m_Colors.Keys)
|
||||
{
|
||||
if (CRC.Verify28DigestUTF8(property, crc))
|
||||
{
|
||||
return property;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class Material : NamedObject
|
||||
{
|
||||
public PPtr<Shader> m_Shader;
|
||||
public UnityPropertySheet m_SavedProperties;
|
||||
public Dictionary<string, string> m_StringTagMap;
|
||||
|
||||
public Material(ObjectReader reader) : base(reader)
|
||||
{
|
||||
m_Shader = new PPtr<Shader>(reader);
|
||||
|
||||
if (version[0] == 4 && version[1] >= 1) //4.x
|
||||
{
|
||||
var m_ShaderKeywords = reader.ReadStringArray();
|
||||
}
|
||||
|
||||
if (version[0] >= 5) //5.0 and up
|
||||
{
|
||||
var m_ShaderKeywords = reader.ReadAlignedString();
|
||||
var m_LightmapFlags = reader.ReadUInt32();
|
||||
}
|
||||
|
||||
if (version[0] > 5 || (version[0] == 5 && version[1] >= 6)) //5.6 and up
|
||||
{
|
||||
var m_EnableInstancingVariants = reader.ReadBoolean();
|
||||
var m_DoubleSidedGI = reader.ReadBoolean(); //2017 and up
|
||||
reader.AlignStream();
|
||||
}
|
||||
|
||||
if (version[0] > 4 || (version[0] == 4 && version[1] >= 3)) //4.3 and up
|
||||
{
|
||||
var m_CustomRenderQueue = reader.ReadInt32();
|
||||
}
|
||||
|
||||
if (version[0] > 5 || (version[0] == 5 && version[1] >= 1)) //5.1 and up
|
||||
{
|
||||
var stringTagMapSize = reader.ReadInt32();
|
||||
m_StringTagMap = new Dictionary<string, string>(stringTagMapSize);
|
||||
for (int i = 0; i < stringTagMapSize; i++)
|
||||
{
|
||||
var first = reader.ReadAlignedString();
|
||||
var second = reader.ReadAlignedString();
|
||||
m_StringTagMap.Add(first, second);
|
||||
}
|
||||
}
|
||||
|
||||
if (version[0] > 5 || (version[0] == 5 && version[1] >= 6)) //5.6 and up
|
||||
{
|
||||
var disabledShaderPasses = reader.ReadStringArray();
|
||||
}
|
||||
|
||||
m_SavedProperties = new UnityPropertySheet(reader);
|
||||
|
||||
//vector m_BuildTextureStacks 2020 and up
|
||||
}
|
||||
|
||||
public string FindPropertyNameByCRC28(uint crc)
|
||||
{
|
||||
return m_SavedProperties.FindPropertyNameByCRC28(crc);
|
||||
}
|
||||
}
|
||||
}
|
1462
AssetStudio/Classes/Mesh.cs
Normal file
1462
AssetStudio/Classes/Mesh.cs
Normal file
File diff suppressed because it is too large
Load Diff
17
AssetStudio/Classes/MeshFilter.cs
Normal file
17
AssetStudio/Classes/MeshFilter.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public sealed class MeshFilter : Component
|
||||
{
|
||||
public PPtr<Mesh> m_Mesh;
|
||||
|
||||
public MeshFilter(ObjectReader reader) : base(reader)
|
||||
{
|
||||
m_Mesh = new PPtr<Mesh>(reader);
|
||||
}
|
||||
}
|
||||
}
|
15
AssetStudio/Classes/MeshRenderer.cs
Normal file
15
AssetStudio/Classes/MeshRenderer.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public sealed class MeshRenderer : Renderer
|
||||
{
|
||||
public MeshRenderer(ObjectReader reader) : base(reader)
|
||||
{
|
||||
var m_AdditionalVertexStreams = new PPtr<Mesh>(reader);
|
||||
}
|
||||
}
|
||||
}
|
93
AssetStudio/Classes/MiHoYoBinData.cs
Normal file
93
AssetStudio/Classes/MiHoYoBinData.cs
Normal file
@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public enum MiHoYoBinDataType
|
||||
{
|
||||
None,
|
||||
Bytes,
|
||||
JSON
|
||||
}
|
||||
public sealed class MiHoYoBinData : Object
|
||||
{
|
||||
public static bool doXOR;
|
||||
public static byte Key;
|
||||
public byte[] RawData;
|
||||
|
||||
public byte[] Data
|
||||
{
|
||||
get
|
||||
{
|
||||
if (doXOR)
|
||||
{
|
||||
byte[] bytes = new byte[RawData.Length];
|
||||
for (int i = 0; i < RawData.Length; i++)
|
||||
{
|
||||
bytes[i] = (byte)(RawData[i] ^ Key);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
else return RawData;
|
||||
}
|
||||
}
|
||||
|
||||
public string Str
|
||||
{
|
||||
get
|
||||
{
|
||||
var str = Encoding.UTF8.GetString(Data);
|
||||
switch (Type)
|
||||
{
|
||||
case MiHoYoBinDataType.JSON:
|
||||
return JToken.Parse(str).ToString(Formatting.Indented);
|
||||
case MiHoYoBinDataType.Bytes:
|
||||
return Regex.Replace(str, @"[^\u0020-\u007E]", string.Empty);
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public MiHoYoBinDataType Type
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
var str = Encoding.UTF8.GetString(Data);
|
||||
var asToken = JToken.Parse(str);
|
||||
if (asToken.Type == JTokenType.Object || asToken.Type == JTokenType.Array)
|
||||
return MiHoYoBinDataType.JSON;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return MiHoYoBinDataType.Bytes;
|
||||
}
|
||||
return MiHoYoBinDataType.None;
|
||||
}
|
||||
}
|
||||
|
||||
public MiHoYoBinData(ObjectReader reader) : base(reader)
|
||||
{
|
||||
var length = reader.ReadInt32();
|
||||
RawData = reader.ReadBytes(length);
|
||||
}
|
||||
|
||||
public new dynamic Dump()
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case MiHoYoBinDataType.JSON:
|
||||
return Str;
|
||||
case MiHoYoBinDataType.Bytes:
|
||||
return Data;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
19
AssetStudio/Classes/MonoBehaviour.cs
Normal file
19
AssetStudio/Classes/MonoBehaviour.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public sealed class MonoBehaviour : Behaviour
|
||||
{
|
||||
public PPtr<MonoScript> m_Script;
|
||||
public string m_Name;
|
||||
|
||||
public MonoBehaviour(ObjectReader reader) : base(reader)
|
||||
{
|
||||
m_Script = new PPtr<MonoScript>(reader);
|
||||
m_Name = reader.ReadAlignedString();
|
||||
}
|
||||
}
|
||||
}
|
44
AssetStudio/Classes/MonoScript.cs
Normal file
44
AssetStudio/Classes/MonoScript.cs
Normal file
@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public sealed class MonoScript : NamedObject
|
||||
{
|
||||
public string m_ClassName;
|
||||
public string m_Namespace;
|
||||
public string m_AssemblyName;
|
||||
|
||||
public MonoScript(ObjectReader reader) : base(reader)
|
||||
{
|
||||
if (version[0] > 3 || (version[0] == 3 && version[1] >= 4)) //3.4 and up
|
||||
{
|
||||
var m_ExecutionOrder = reader.ReadInt32();
|
||||
}
|
||||
if (version[0] < 5) //5.0 down
|
||||
{
|
||||
var m_PropertiesHash = reader.ReadUInt32();
|
||||
}
|
||||
else
|
||||
{
|
||||
var m_PropertiesHash = reader.ReadBytes(16);
|
||||
}
|
||||
if (version[0] < 3) //3.0 down
|
||||
{
|
||||
var m_PathName = reader.ReadAlignedString();
|
||||
}
|
||||
m_ClassName = reader.ReadAlignedString();
|
||||
if (version[0] >= 3) //3.0 and up
|
||||
{
|
||||
m_Namespace = reader.ReadAlignedString();
|
||||
}
|
||||
m_AssemblyName = reader.ReadAlignedString();
|
||||
if (version[0] < 2018 || (version[0] == 2018 && version[1] < 2)) //2018.2 down
|
||||
{
|
||||
var m_IsEditorScript = reader.ReadBoolean();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
21
AssetStudio/Classes/MovieTexture.cs
Normal file
21
AssetStudio/Classes/MovieTexture.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public sealed class MovieTexture : Texture
|
||||
{
|
||||
public byte[] m_MovieData;
|
||||
public PPtr<AudioClip> m_AudioClip;
|
||||
|
||||
public MovieTexture(ObjectReader reader) : base(reader)
|
||||
{
|
||||
var m_Loop = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
m_AudioClip = new PPtr<AudioClip>(reader);
|
||||
m_MovieData = reader.ReadUInt8Array();
|
||||
}
|
||||
}
|
||||
}
|
17
AssetStudio/Classes/NamedObject.cs
Normal file
17
AssetStudio/Classes/NamedObject.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class NamedObject : EditorExtension
|
||||
{
|
||||
public string m_Name;
|
||||
|
||||
protected NamedObject(ObjectReader reader) : base(reader)
|
||||
{
|
||||
m_Name = reader.ReadAlignedString();
|
||||
}
|
||||
}
|
||||
}
|
88
AssetStudio/Classes/Object.cs
Normal file
88
AssetStudio/Classes/Object.cs
Normal file
@ -0,0 +1,88 @@
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Specialized;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class Object
|
||||
{
|
||||
[JsonIgnore]
|
||||
public SerializedFile assetsFile;
|
||||
[JsonIgnore]
|
||||
public ObjectReader reader;
|
||||
[JsonIgnore]
|
||||
public long m_PathID;
|
||||
[JsonIgnore]
|
||||
public int[] version;
|
||||
[JsonIgnore]
|
||||
protected BuildType buildType;
|
||||
[JsonIgnore]
|
||||
public BuildTarget platform;
|
||||
[JsonIgnore]
|
||||
public ClassIDType type;
|
||||
[JsonIgnore]
|
||||
public SerializedType serializedType;
|
||||
[JsonIgnore]
|
||||
public uint byteSize;
|
||||
|
||||
public Object(ObjectReader reader)
|
||||
{
|
||||
this.reader = reader;
|
||||
reader.Reset();
|
||||
assetsFile = reader.assetsFile;
|
||||
type = reader.type;
|
||||
m_PathID = reader.m_PathID;
|
||||
version = reader.version;
|
||||
buildType = reader.buildType;
|
||||
platform = reader.platform;
|
||||
serializedType = reader.serializedType;
|
||||
byteSize = reader.byteSize;
|
||||
|
||||
if (platform == BuildTarget.NoTarget)
|
||||
{
|
||||
var m_ObjectHideFlags = reader.ReadUInt32();
|
||||
}
|
||||
}
|
||||
|
||||
public string Dump()
|
||||
{
|
||||
if (serializedType?.m_Type != null)
|
||||
{
|
||||
return TypeTreeHelper.ReadTypeString(serializedType.m_Type, reader);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public string Dump(TypeTree m_Type)
|
||||
{
|
||||
if (m_Type != null)
|
||||
{
|
||||
return TypeTreeHelper.ReadTypeString(m_Type, reader);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public OrderedDictionary ToType()
|
||||
{
|
||||
if (serializedType?.m_Type != null)
|
||||
{
|
||||
return TypeTreeHelper.ReadType(serializedType.m_Type, reader);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public OrderedDictionary ToType(TypeTree m_Type)
|
||||
{
|
||||
if (m_Type != null)
|
||||
{
|
||||
return TypeTreeHelper.ReadType(m_Type, reader);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte[] GetRawData()
|
||||
{
|
||||
reader.Reset();
|
||||
return reader.ReadBytes((int)byteSize);
|
||||
}
|
||||
}
|
||||
}
|
152
AssetStudio/Classes/PPtr.cs
Normal file
152
AssetStudio/Classes/PPtr.cs
Normal file
@ -0,0 +1,152 @@
|
||||
using System;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public sealed class PPtr<T> : IYAMLExportable
|
||||
where T : Object
|
||||
{
|
||||
public int m_FileID;
|
||||
public long m_PathID;
|
||||
|
||||
private SerializedFile assetsFile;
|
||||
private int index = -2; //-2 - Prepare, -1 - Missing
|
||||
|
||||
public PPtr(ObjectReader reader)
|
||||
{
|
||||
m_FileID = reader.ReadInt32();
|
||||
m_PathID = reader.m_Version < SerializedFileFormatVersion.Unknown_14 ? reader.ReadInt32() : reader.ReadInt64();
|
||||
assetsFile = reader.assetsFile;
|
||||
}
|
||||
|
||||
public PPtr(int fileID, long pathID, SerializedFile assetsFile)
|
||||
{
|
||||
m_FileID = fileID;
|
||||
m_PathID = pathID;
|
||||
this.assetsFile = assetsFile;
|
||||
}
|
||||
|
||||
public YAMLNode ExportYAML()
|
||||
{
|
||||
var node = new YAMLMappingNode();
|
||||
node.Style = MappingStyle.Flow;
|
||||
node.Add("fileID", m_FileID);
|
||||
return node;
|
||||
}
|
||||
|
||||
private bool TryGetAssetsFile(out SerializedFile result)
|
||||
{
|
||||
result = null;
|
||||
if (m_FileID == 0)
|
||||
{
|
||||
result = assetsFile;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_FileID > 0 && m_FileID - 1 < assetsFile.m_Externals.Count)
|
||||
{
|
||||
var assetsManager = assetsFile.assetsManager;
|
||||
var assetsFileList = assetsManager.assetsFileList;
|
||||
var assetsFileIndexCache = assetsManager.assetsFileIndexCache;
|
||||
|
||||
if (index == -2)
|
||||
{
|
||||
var m_External = assetsFile.m_Externals[m_FileID - 1];
|
||||
var name = m_External.fileName;
|
||||
if (!assetsFileIndexCache.TryGetValue(name, out index))
|
||||
{
|
||||
index = assetsFileList.FindIndex(x => x.fileName.Equals(name, StringComparison.OrdinalIgnoreCase));
|
||||
assetsFileIndexCache.Add(name, index);
|
||||
}
|
||||
}
|
||||
|
||||
if (index >= 0)
|
||||
{
|
||||
result = assetsFileList[index];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryGet(out T result)
|
||||
{
|
||||
if (TryGetAssetsFile(out var sourceFile))
|
||||
{
|
||||
if (sourceFile.ObjectsDic.TryGetValue(m_PathID, out var obj))
|
||||
{
|
||||
if (obj is T variable)
|
||||
{
|
||||
result = variable;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryGet<T2>(out T2 result) where T2 : Object
|
||||
{
|
||||
if (TryGetAssetsFile(out var sourceFile))
|
||||
{
|
||||
if (sourceFile.ObjectsDic.TryGetValue(m_PathID, out var obj))
|
||||
{
|
||||
if (obj is T2 variable)
|
||||
{
|
||||
result = variable;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Set(T m_Object)
|
||||
{
|
||||
var name = m_Object.assetsFile.fileName;
|
||||
if (string.Equals(assetsFile.fileName, name, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
m_FileID = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_FileID = assetsFile.m_Externals.FindIndex(x => string.Equals(x.fileName, name, StringComparison.OrdinalIgnoreCase));
|
||||
if (m_FileID == -1)
|
||||
{
|
||||
assetsFile.m_Externals.Add(new FileIdentifier
|
||||
{
|
||||
fileName = m_Object.assetsFile.fileName
|
||||
});
|
||||
m_FileID = assetsFile.m_Externals.Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_FileID += 1;
|
||||
}
|
||||
}
|
||||
|
||||
var assetsManager = assetsFile.assetsManager;
|
||||
var assetsFileList = assetsManager.assetsFileList;
|
||||
var assetsFileIndexCache = assetsManager.assetsFileIndexCache;
|
||||
|
||||
if (!assetsFileIndexCache.TryGetValue(name, out index))
|
||||
{
|
||||
index = assetsFileList.FindIndex(x => x.fileName.Equals(name, StringComparison.OrdinalIgnoreCase));
|
||||
assetsFileIndexCache.Add(name, index);
|
||||
}
|
||||
|
||||
m_PathID = m_Object.m_PathID;
|
||||
}
|
||||
|
||||
public PPtr<T2> CastTo<T2>() where T2 : Object
|
||||
{
|
||||
return new PPtr<T2>(m_FileID, m_PathID, assetsFile);
|
||||
}
|
||||
|
||||
public bool IsNull => m_PathID == 0 || m_FileID < 0;
|
||||
}
|
||||
}
|
51
AssetStudio/Classes/PlayerSettings.cs
Normal file
51
AssetStudio/Classes/PlayerSettings.cs
Normal file
@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public sealed class PlayerSettings : Object
|
||||
{
|
||||
public string companyName;
|
||||
public string productName;
|
||||
|
||||
public PlayerSettings(ObjectReader reader) : base(reader)
|
||||
{
|
||||
if (version[0] > 5 || (version[0] == 5 && version[1] >= 4)) //5.4.0 nad up
|
||||
{
|
||||
var productGUID = reader.ReadBytes(16);
|
||||
}
|
||||
|
||||
var AndroidProfiler = reader.ReadBoolean();
|
||||
//bool AndroidFilterTouchesWhenObscured 2017.2 and up
|
||||
//bool AndroidEnableSustainedPerformanceMode 2018 and up
|
||||
reader.AlignStream();
|
||||
int defaultScreenOrientation = reader.ReadInt32();
|
||||
int targetDevice = reader.ReadInt32();
|
||||
if (version[0] < 5 || (version[0] == 5 && version[1] < 3)) //5.3 down
|
||||
{
|
||||
if (version[0] < 5) //5.0 down
|
||||
{
|
||||
int targetPlatform = reader.ReadInt32(); //4.0 and up targetGlesGraphics
|
||||
if (version[0] > 4 || (version[0] == 4 && version[1] >= 6)) //4.6 and up
|
||||
{
|
||||
var targetIOSGraphics = reader.ReadInt32();
|
||||
}
|
||||
}
|
||||
int targetResolution = reader.ReadInt32();
|
||||
}
|
||||
else
|
||||
{
|
||||
var useOnDemandResources = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
}
|
||||
if (version[0] > 3 || (version[0] == 3 && version[1] >= 5)) //3.5 and up
|
||||
{
|
||||
var accelerometerFrequency = reader.ReadInt32();
|
||||
}
|
||||
companyName = reader.ReadAlignedString();
|
||||
productName = reader.ReadAlignedString();
|
||||
}
|
||||
}
|
||||
}
|
14
AssetStudio/Classes/RectTransform.cs
Normal file
14
AssetStudio/Classes/RectTransform.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public sealed class RectTransform : Transform
|
||||
{
|
||||
public RectTransform(ObjectReader reader) : base(reader)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
271
AssetStudio/Classes/Renderer.cs
Normal file
271
AssetStudio/Classes/Renderer.cs
Normal file
@ -0,0 +1,271 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class StaticBatchInfo
|
||||
{
|
||||
public ushort firstSubMesh;
|
||||
public ushort subMeshCount;
|
||||
|
||||
public StaticBatchInfo(ObjectReader reader)
|
||||
{
|
||||
firstSubMesh = reader.ReadUInt16();
|
||||
subMeshCount = reader.ReadUInt16();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class Renderer : Component
|
||||
{
|
||||
public static bool Parsable;
|
||||
public PPtr<Material>[] m_Materials;
|
||||
public StaticBatchInfo m_StaticBatchInfo;
|
||||
public uint[] m_SubsetIndices;
|
||||
private bool isNewHeader = false;
|
||||
protected Renderer(ObjectReader reader) : base(reader)
|
||||
{
|
||||
if (version[0] < 5) //5.0 down
|
||||
{
|
||||
var m_Enabled = reader.ReadBoolean();
|
||||
var m_CastShadows = reader.ReadBoolean();
|
||||
var m_ReceiveShadows = reader.ReadBoolean();
|
||||
var m_LightmapIndex = reader.ReadByte();
|
||||
}
|
||||
else //5.0 and up
|
||||
{
|
||||
if (version[0] > 5 || (version[0] == 5 && version[1] >= 4)) //5.4 and up
|
||||
{
|
||||
if (reader.Game.Name == "GI")
|
||||
{
|
||||
CheckHeader(reader);
|
||||
}
|
||||
var m_Enabled = reader.ReadBoolean();
|
||||
var m_CastShadows = reader.ReadByte();
|
||||
var m_ReceiveShadows = reader.ReadByte();
|
||||
if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 2)) //2017.2 and up
|
||||
{
|
||||
var m_DynamicOccludee = reader.ReadByte();
|
||||
if (reader.Game.Name == "BH3")
|
||||
{
|
||||
var m_AllowHalfResolution = reader.ReadByte();
|
||||
}
|
||||
else if (reader.Game.Name == "GI_CB3")
|
||||
{
|
||||
var m_ReceiveDecals = reader.ReadByte();
|
||||
var m_EnableShadowCulling = reader.ReadByte();
|
||||
var m_EnableGpuQuery = reader.ReadByte();
|
||||
var m_AllowHalfResolution = reader.ReadByte();
|
||||
var m_IsRainOccluder = reader.ReadByte();
|
||||
var m_IsDynamicAOOccluder = reader.ReadByte();
|
||||
var m_IsDynamic = reader.ReadByte();
|
||||
}
|
||||
else if (reader.Game.Name == "GI")
|
||||
{
|
||||
var m_ReceiveDecals = reader.ReadByte();
|
||||
var m_EnableShadowCulling = reader.ReadByte();
|
||||
var m_EnableGpuQuery = reader.ReadByte();
|
||||
var m_AllowHalfResolution = reader.ReadByte();
|
||||
var m_IsRainOccluder = reader.ReadByte();
|
||||
var m_IsDynamicAOOccluder = reader.ReadByte();
|
||||
var m_IsCloudObject = reader.ReadByte();
|
||||
var m_IsInteriorVolume = reader.ReadByte();
|
||||
var m_IsDynamic = reader.ReadByte();
|
||||
var m_UseTessellation = reader.ReadByte();
|
||||
var m_IsTerrainTessInfo = reader.ReadByte();
|
||||
if (isNewHeader)
|
||||
{
|
||||
var m_UseVertexLightInForward = reader.ReadByte();
|
||||
var m_CombineSubMeshInGeoPass = reader.ReadByte();
|
||||
var m_AllowPerMaterialProp = reader.ReadByte();
|
||||
var m_IsHQDynamicAOOccluder = reader.ReadByte();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (version[0] >= 2021) //2021.1 and up
|
||||
{
|
||||
var m_StaticShadowCaster = reader.ReadByte();
|
||||
}
|
||||
if (reader.Game.Name == "GI_CB2")
|
||||
{
|
||||
var m_ReceiveDecals = reader.ReadByte();
|
||||
var m_EnableShadowCulling = reader.ReadByte();
|
||||
var m_EnableGpuQuery = reader.ReadByte();
|
||||
var m_AllowHalfResolution = reader.ReadByte();
|
||||
var m_IsRainOccluder = reader.ReadByte();
|
||||
var m_IsDynamic = reader.ReadByte();
|
||||
}
|
||||
if (reader.Game.Name == "GI_CB1")
|
||||
{
|
||||
var m_ReceiveDecals = reader.ReadByte();
|
||||
var m_EnableShadowCulling = reader.ReadByte();
|
||||
var m_EnableGpuQuery = reader.ReadByte();
|
||||
var m_AllowHalfResolution = reader.ReadByte();
|
||||
}
|
||||
var m_MotionVectors = reader.ReadByte();
|
||||
var m_LightProbeUsage = reader.ReadByte();
|
||||
var m_ReflectionProbeUsage = reader.ReadByte();
|
||||
if (version[0] > 2019 || (version[0] == 2019 && version[1] >= 3)) //2019.3 and up
|
||||
{
|
||||
var m_RayTracingMode = reader.ReadByte();
|
||||
}
|
||||
if (version[0] >= 2020) //2020.1 and up
|
||||
{
|
||||
var m_RayTraceProcedural = reader.ReadByte();
|
||||
}
|
||||
if (reader.Game.Name == "GI" || reader.Game.Name == "GI_CB3")
|
||||
{
|
||||
var m_MeshShowQuality = reader.ReadByte();
|
||||
}
|
||||
reader.AlignStream();
|
||||
}
|
||||
else
|
||||
{
|
||||
var m_Enabled = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
var m_CastShadows = reader.ReadByte();
|
||||
var m_ReceiveShadows = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
}
|
||||
|
||||
if (version[0] >= 2018) //2018 and up
|
||||
{
|
||||
var m_RenderingLayerMask = reader.ReadUInt32();
|
||||
}
|
||||
|
||||
if (version[0] > 2018 || (version[0] == 2018 && version[1] >= 3)) //2018.3 and up
|
||||
{
|
||||
var m_RendererPriority = reader.ReadInt32();
|
||||
}
|
||||
|
||||
var m_LightmapIndex = reader.ReadInt16();
|
||||
var m_LightmapIndexDynamic = reader.ReadInt16();
|
||||
if (reader.Game.Name == "GI" || reader.Game.Name == "GI_CB1" || reader.Game.Name == "GI_CB2" || reader.Game.Name == "GI_CB3")
|
||||
{
|
||||
if (m_LightmapIndex != -1 || m_LightmapIndexDynamic != -1)
|
||||
throw new Exception("Not Supported !! skipping....");
|
||||
}
|
||||
}
|
||||
|
||||
if (version[0] >= 3) //3.0 and up
|
||||
{
|
||||
var m_LightmapTilingOffset = reader.ReadVector4();
|
||||
}
|
||||
|
||||
if (version[0] >= 5) //5.0 and up
|
||||
{
|
||||
var m_LightmapTilingOffsetDynamic = reader.ReadVector4();
|
||||
}
|
||||
|
||||
if (reader.Game.Name == "GI" || reader.Game.Name == "GI_CB1" || reader.Game.Name == "GI_CB2" || reader.Game.Name == "GI_CB3")
|
||||
{
|
||||
var m_ViewDistanceRatio = reader.ReadSingle();
|
||||
var m_ShaderLODDistanceRatio = reader.ReadSingle();
|
||||
}
|
||||
var m_MaterialsSize = reader.ReadInt32();
|
||||
m_Materials = new PPtr<Material>[m_MaterialsSize];
|
||||
for (int i = 0; i < m_MaterialsSize; i++)
|
||||
{
|
||||
m_Materials[i] = new PPtr<Material>(reader);
|
||||
}
|
||||
|
||||
if (version[0] < 3) //3.0 down
|
||||
{
|
||||
var m_LightmapTilingOffset = reader.ReadVector4();
|
||||
}
|
||||
else //3.0 and up
|
||||
{
|
||||
if (version[0] > 5 || (version[0] == 5 && version[1] >= 5)) //5.5 and up
|
||||
{
|
||||
m_StaticBatchInfo = new StaticBatchInfo(reader);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_SubsetIndices = reader.ReadUInt32Array();
|
||||
}
|
||||
|
||||
var m_StaticBatchRoot = new PPtr<Transform>(reader);
|
||||
}
|
||||
if (reader.Game.Name == "GI" || reader.Game.Name == "GI_CB1" || reader.Game.Name == "GI_CB2" || reader.Game.Name == "GI_CB3")
|
||||
{
|
||||
var m_MatLayers = reader.ReadInt32();
|
||||
}
|
||||
|
||||
if (version[0] > 5 || (version[0] == 5 && version[1] >= 4)) //5.4 and up
|
||||
{
|
||||
var m_ProbeAnchor = new PPtr<Transform>(reader);
|
||||
var m_LightProbeVolumeOverride = new PPtr<GameObject>(reader);
|
||||
}
|
||||
else if (version[0] > 3 || (version[0] == 3 && version[1] >= 5)) //3.5 - 5.3
|
||||
{
|
||||
var m_UseLightProbes = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
|
||||
if (version[0] >= 5)//5.0 and up
|
||||
{
|
||||
var m_ReflectionProbeUsage = reader.ReadInt32();
|
||||
}
|
||||
|
||||
var m_LightProbeAnchor = new PPtr<Transform>(reader); //5.0 and up m_ProbeAnchor
|
||||
}
|
||||
|
||||
if (version[0] > 4 || (version[0] == 4 && version[1] >= 3)) //4.3 and up
|
||||
{
|
||||
if (version[0] == 4 && version[1] == 3) //4.3
|
||||
{
|
||||
var m_SortingLayer = reader.ReadInt16();
|
||||
}
|
||||
else
|
||||
{
|
||||
var m_SortingLayerID = reader.ReadInt32();
|
||||
var m_SortingLayer = reader.ReadInt16();
|
||||
}
|
||||
|
||||
//SInt16 m_SortingLayer 5.6 and up
|
||||
var m_SortingOrder = reader.ReadInt16();
|
||||
reader.AlignStream();
|
||||
if (reader.Game.Name == "GI" || reader.Game.Name == "GI_CB1" || reader.Game.Name == "GI_CB2" || reader.Game.Name == "GI_CB3" || reader.Game.Name == "BH3")
|
||||
{
|
||||
var m_UseHighestMip = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
}
|
||||
if (reader.Game.Name == "SR_CB3")
|
||||
{
|
||||
var _RenderFlag = reader.ReadUInt32();
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckHeader(ObjectReader reader)
|
||||
{
|
||||
short index = 0;
|
||||
var pos = reader.Position;
|
||||
while (index != -1 && reader.Position <= pos + 0x1A)
|
||||
index = reader.ReadInt16();
|
||||
isNewHeader = (reader.Position - pos) == 0x1A;
|
||||
reader.Position = pos;
|
||||
}
|
||||
|
||||
public string FindMaterialPropertyNameByCRC28(uint crc)
|
||||
{
|
||||
foreach (PPtr<Material> materialPtr in m_Materials)
|
||||
{
|
||||
if (!materialPtr.TryGet(out var material))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
string property = material.FindPropertyNameByCRC28(crc);
|
||||
if (property == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
return property;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
19
AssetStudio/Classes/ResourceManager.cs
Normal file
19
AssetStudio/Classes/ResourceManager.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class ResourceManager : Object
|
||||
{
|
||||
public KeyValuePair<string, PPtr<Object>>[] m_Container;
|
||||
|
||||
public ResourceManager(ObjectReader reader) : base(reader)
|
||||
{
|
||||
var m_ContainerSize = reader.ReadInt32();
|
||||
m_Container = new KeyValuePair<string, PPtr<Object>>[m_ContainerSize];
|
||||
for (int i = 0; i < m_ContainerSize; i++)
|
||||
{
|
||||
m_Container[i] = new KeyValuePair<string, PPtr<Object>>(reader.ReadAlignedString(), new PPtr<Object>(reader));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
17
AssetStudio/Classes/RuntimeAnimatorController.cs
Normal file
17
AssetStudio/Classes/RuntimeAnimatorController.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public abstract class RuntimeAnimatorController : NamedObject
|
||||
{
|
||||
protected RuntimeAnimatorController(ObjectReader reader) : base(reader)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public abstract bool IsContainsAnimationClip(AnimationClip clip);
|
||||
}
|
||||
}
|
1041
AssetStudio/Classes/Shader.cs
Normal file
1041
AssetStudio/Classes/Shader.cs
Normal file
File diff suppressed because it is too large
Load Diff
48
AssetStudio/Classes/SkinnedMeshRenderer.cs
Normal file
48
AssetStudio/Classes/SkinnedMeshRenderer.cs
Normal file
@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public sealed class SkinnedMeshRenderer : Renderer
|
||||
{
|
||||
public PPtr<Mesh> m_Mesh;
|
||||
public PPtr<Transform>[] m_Bones;
|
||||
public PPtr<Transform> m_RootBone;
|
||||
public float[] m_BlendShapeWeights;
|
||||
public AABB m_AABB;
|
||||
public bool m_DirtyAABB;
|
||||
|
||||
public SkinnedMeshRenderer(ObjectReader reader) : base(reader)
|
||||
{
|
||||
int m_Quality = reader.ReadInt32();
|
||||
var m_UpdateWhenOffscreen = reader.ReadBoolean();
|
||||
var m_SkinNormals = reader.ReadBoolean(); //3.1.0 and below
|
||||
reader.AlignStream();
|
||||
|
||||
if (version[0] == 2 && version[1] < 6) //2.6 down
|
||||
{
|
||||
var m_DisableAnimationWhenOffscreen = new PPtr<Animation>(reader);
|
||||
}
|
||||
|
||||
m_Mesh = new PPtr<Mesh>(reader);
|
||||
|
||||
m_Bones = new PPtr<Transform>[reader.ReadInt32()];
|
||||
for (int b = 0; b < m_Bones.Length; b++)
|
||||
{
|
||||
m_Bones[b] = new PPtr<Transform>(reader);
|
||||
}
|
||||
reader.AlignStream();
|
||||
if (version[0] > 4 || (version[0] == 4 && version[1] >= 3)) //4.3 and up
|
||||
{
|
||||
m_BlendShapeWeights = reader.ReadSingleArray();
|
||||
}
|
||||
reader.AlignStream();
|
||||
m_RootBone = new PPtr<Transform>(reader);
|
||||
m_AABB = new AABB(reader);
|
||||
m_DirtyAABB = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
}
|
260
AssetStudio/Classes/Sprite.cs
Normal file
260
AssetStudio/Classes/Sprite.cs
Normal file
@ -0,0 +1,260 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class SecondarySpriteTexture
|
||||
{
|
||||
public PPtr<Texture2D> texture;
|
||||
public string name;
|
||||
|
||||
public SecondarySpriteTexture(ObjectReader reader)
|
||||
{
|
||||
texture = new PPtr<Texture2D>(reader);
|
||||
name = reader.ReadStringToNull();
|
||||
}
|
||||
}
|
||||
|
||||
public enum SpritePackingRotation
|
||||
{
|
||||
None = 0,
|
||||
FlipHorizontal = 1,
|
||||
FlipVertical = 2,
|
||||
Rotate180 = 3,
|
||||
Rotate90 = 4
|
||||
};
|
||||
|
||||
public enum SpritePackingMode
|
||||
{
|
||||
Tight = 0,
|
||||
Rectangle
|
||||
};
|
||||
|
||||
public enum SpriteMeshType
|
||||
{
|
||||
FullRect,
|
||||
Tight
|
||||
};
|
||||
|
||||
public class SpriteSettings
|
||||
{
|
||||
public uint settingsRaw;
|
||||
|
||||
public uint packed;
|
||||
public SpritePackingMode packingMode;
|
||||
public SpritePackingRotation packingRotation;
|
||||
public SpriteMeshType meshType;
|
||||
|
||||
public SpriteSettings(BinaryReader reader)
|
||||
{
|
||||
settingsRaw = reader.ReadUInt32();
|
||||
|
||||
packed = settingsRaw & 1; //1
|
||||
packingMode = (SpritePackingMode)((settingsRaw >> 1) & 1); //1
|
||||
packingRotation = (SpritePackingRotation)((settingsRaw >> 2) & 0xf); //4
|
||||
meshType = (SpriteMeshType)((settingsRaw >> 6) & 1); //1
|
||||
//reserved
|
||||
}
|
||||
}
|
||||
|
||||
public class SpriteVertex
|
||||
{
|
||||
public Vector3 pos;
|
||||
public Vector2 uv;
|
||||
|
||||
public SpriteVertex(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
|
||||
pos = reader.ReadVector3();
|
||||
if (version[0] < 4 || (version[0] == 4 && version[1] <= 3)) //4.3 and down
|
||||
{
|
||||
uv = reader.ReadVector2();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class SpriteRenderData
|
||||
{
|
||||
public PPtr<Texture2D> texture;
|
||||
public PPtr<Texture2D> alphaTexture;
|
||||
public SecondarySpriteTexture[] secondaryTextures;
|
||||
public SubMesh[] m_SubMeshes;
|
||||
public byte[] m_IndexBuffer;
|
||||
public VertexData m_VertexData;
|
||||
public SpriteVertex[] vertices;
|
||||
public ushort[] indices;
|
||||
public Matrix4x4[] m_Bindpose;
|
||||
public BoneWeights4[] m_SourceSkin;
|
||||
public Rectf textureRect;
|
||||
public Vector2 textureRectOffset;
|
||||
public Vector2 atlasRectOffset;
|
||||
public SpriteSettings settingsRaw;
|
||||
public Vector4 uvTransform;
|
||||
public float downscaleMultiplier;
|
||||
|
||||
public SpriteRenderData(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
|
||||
texture = new PPtr<Texture2D>(reader);
|
||||
if (version[0] > 5 || (version[0] == 5 && version[1] >= 2)) //5.2 and up
|
||||
{
|
||||
alphaTexture = new PPtr<Texture2D>(reader);
|
||||
}
|
||||
|
||||
if (version[0] >= 2019) //2019 and up
|
||||
{
|
||||
var secondaryTexturesSize = reader.ReadInt32();
|
||||
secondaryTextures = new SecondarySpriteTexture[secondaryTexturesSize];
|
||||
for (int i = 0; i < secondaryTexturesSize; i++)
|
||||
{
|
||||
secondaryTextures[i] = new SecondarySpriteTexture(reader);
|
||||
}
|
||||
}
|
||||
|
||||
if (version[0] > 5 || (version[0] == 5 && version[1] >= 6)) //5.6 and up
|
||||
{
|
||||
var m_SubMeshesSize = reader.ReadInt32();
|
||||
m_SubMeshes = new SubMesh[m_SubMeshesSize];
|
||||
for (int i = 0; i < m_SubMeshesSize; i++)
|
||||
{
|
||||
m_SubMeshes[i] = new SubMesh(reader);
|
||||
}
|
||||
|
||||
m_IndexBuffer = reader.ReadUInt8Array();
|
||||
reader.AlignStream();
|
||||
|
||||
m_VertexData = new VertexData(reader);
|
||||
}
|
||||
else
|
||||
{
|
||||
var verticesSize = reader.ReadInt32();
|
||||
vertices = new SpriteVertex[verticesSize];
|
||||
for (int i = 0; i < verticesSize; i++)
|
||||
{
|
||||
vertices[i] = new SpriteVertex(reader);
|
||||
}
|
||||
|
||||
indices = reader.ReadUInt16Array();
|
||||
reader.AlignStream();
|
||||
}
|
||||
|
||||
if (version[0] >= 2018) //2018 and up
|
||||
{
|
||||
m_Bindpose = reader.ReadMatrixArray();
|
||||
|
||||
if (version[0] == 2018 && version[1] < 2) //2018.2 down
|
||||
{
|
||||
var m_SourceSkinSize = reader.ReadInt32();
|
||||
for (int i = 0; i < m_SourceSkinSize; i++)
|
||||
{
|
||||
m_SourceSkin[i] = new BoneWeights4(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
textureRect = new Rectf(reader);
|
||||
textureRectOffset = reader.ReadVector2();
|
||||
if (version[0] > 5 || (version[0] == 5 && version[1] >= 6)) //5.6 and up
|
||||
{
|
||||
atlasRectOffset = reader.ReadVector2();
|
||||
}
|
||||
|
||||
settingsRaw = new SpriteSettings(reader);
|
||||
if (version[0] > 4 || (version[0] == 4 && version[1] >= 5)) //4.5 and up
|
||||
{
|
||||
uvTransform = reader.ReadVector4();
|
||||
}
|
||||
|
||||
if (version[0] >= 2017) //2017 and up
|
||||
{
|
||||
downscaleMultiplier = reader.ReadSingle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Rectf
|
||||
{
|
||||
public float x;
|
||||
public float y;
|
||||
public float width;
|
||||
public float height;
|
||||
|
||||
public Rectf(BinaryReader reader)
|
||||
{
|
||||
x = reader.ReadSingle();
|
||||
y = reader.ReadSingle();
|
||||
width = reader.ReadSingle();
|
||||
height = reader.ReadSingle();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class Sprite : NamedObject
|
||||
{
|
||||
public Rectf m_Rect;
|
||||
public Vector2 m_Offset;
|
||||
public Vector4 m_Border;
|
||||
public float m_PixelsToUnits;
|
||||
public Vector2 m_Pivot = new Vector2(0.5f, 0.5f);
|
||||
public uint m_Extrude;
|
||||
public bool m_IsPolygon;
|
||||
public KeyValuePair<Guid, long> m_RenderDataKey;
|
||||
public string[] m_AtlasTags;
|
||||
public PPtr<SpriteAtlas> m_SpriteAtlas;
|
||||
public SpriteRenderData m_RD;
|
||||
public Vector2[][] m_PhysicsShape;
|
||||
|
||||
public Sprite(ObjectReader reader) : base(reader)
|
||||
{
|
||||
m_Rect = new Rectf(reader);
|
||||
m_Offset = reader.ReadVector2();
|
||||
if (version[0] > 4 || (version[0] == 4 && version[1] >= 5)) //4.5 and up
|
||||
{
|
||||
m_Border = reader.ReadVector4();
|
||||
}
|
||||
|
||||
m_PixelsToUnits = reader.ReadSingle();
|
||||
if (version[0] > 5
|
||||
|| (version[0] == 5 && version[1] > 4)
|
||||
|| (version[0] == 5 && version[1] == 4 && version[2] >= 2)
|
||||
|| (version[0] == 5 && version[1] == 4 && version[2] == 1 && buildType.IsPatch && version[3] >= 3)) //5.4.1p3 and up
|
||||
{
|
||||
m_Pivot = reader.ReadVector2();
|
||||
}
|
||||
|
||||
m_Extrude = reader.ReadUInt32();
|
||||
if (version[0] > 5 || (version[0] == 5 && version[1] >= 3)) //5.3 and up
|
||||
{
|
||||
m_IsPolygon = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
}
|
||||
|
||||
if (version[0] >= 2017) //2017 and up
|
||||
{
|
||||
var first = new Guid(reader.ReadBytes(16));
|
||||
var second = reader.ReadInt64();
|
||||
m_RenderDataKey = new KeyValuePair<Guid, long>(first, second);
|
||||
|
||||
m_AtlasTags = reader.ReadStringArray();
|
||||
|
||||
m_SpriteAtlas = new PPtr<SpriteAtlas>(reader);
|
||||
}
|
||||
|
||||
m_RD = new SpriteRenderData(reader);
|
||||
|
||||
if (version[0] >= 2017) //2017 and up
|
||||
{
|
||||
var m_PhysicsShapeSize = reader.ReadInt32();
|
||||
m_PhysicsShape = new Vector2[m_PhysicsShapeSize][];
|
||||
for (int i = 0; i < m_PhysicsShapeSize; i++)
|
||||
{
|
||||
m_PhysicsShape[i] = reader.ReadVector2Array();
|
||||
}
|
||||
}
|
||||
|
||||
//vector m_Bones 2018 and up
|
||||
}
|
||||
}
|
||||
}
|
76
AssetStudio/Classes/SpriteAtlas.cs
Normal file
76
AssetStudio/Classes/SpriteAtlas.cs
Normal file
@ -0,0 +1,76 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class SpriteAtlasData
|
||||
{
|
||||
public PPtr<Texture2D> texture;
|
||||
public PPtr<Texture2D> alphaTexture;
|
||||
public Rectf textureRect;
|
||||
public Vector2 textureRectOffset;
|
||||
public Vector2 atlasRectOffset;
|
||||
public Vector4 uvTransform;
|
||||
public float downscaleMultiplier;
|
||||
public SpriteSettings settingsRaw;
|
||||
public SecondarySpriteTexture[] secondaryTextures;
|
||||
|
||||
public SpriteAtlasData(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
texture = new PPtr<Texture2D>(reader);
|
||||
alphaTexture = new PPtr<Texture2D>(reader);
|
||||
textureRect = new Rectf(reader);
|
||||
textureRectOffset = reader.ReadVector2();
|
||||
if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 2)) //2017.2 and up
|
||||
{
|
||||
atlasRectOffset = reader.ReadVector2();
|
||||
}
|
||||
uvTransform = reader.ReadVector4();
|
||||
downscaleMultiplier = reader.ReadSingle();
|
||||
settingsRaw = new SpriteSettings(reader);
|
||||
if (version[0] > 2020 || (version[0] == 2020 && version[1] >= 2)) //2020.2 and up
|
||||
{
|
||||
var secondaryTexturesSize = reader.ReadInt32();
|
||||
secondaryTextures = new SecondarySpriteTexture[secondaryTexturesSize];
|
||||
for (int i = 0; i < secondaryTexturesSize; i++)
|
||||
{
|
||||
secondaryTextures[i] = new SecondarySpriteTexture(reader);
|
||||
}
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class SpriteAtlas : NamedObject
|
||||
{
|
||||
public PPtr<Sprite>[] m_PackedSprites;
|
||||
public Dictionary<KeyValuePair<Guid, long>, SpriteAtlasData> m_RenderDataMap;
|
||||
public bool m_IsVariant;
|
||||
|
||||
public SpriteAtlas(ObjectReader reader) : base(reader)
|
||||
{
|
||||
var m_PackedSpritesSize = reader.ReadInt32();
|
||||
m_PackedSprites = new PPtr<Sprite>[m_PackedSpritesSize];
|
||||
for (int i = 0; i < m_PackedSpritesSize; i++)
|
||||
{
|
||||
m_PackedSprites[i] = new PPtr<Sprite>(reader);
|
||||
}
|
||||
|
||||
var m_PackedSpriteNamesToIndex = reader.ReadStringArray();
|
||||
|
||||
var m_RenderDataMapSize = reader.ReadInt32();
|
||||
m_RenderDataMap = new Dictionary<KeyValuePair<Guid, long>, SpriteAtlasData>(m_RenderDataMapSize);
|
||||
for (int i = 0; i < m_RenderDataMapSize; i++)
|
||||
{
|
||||
var first = new Guid(reader.ReadBytes(16));
|
||||
var second = reader.ReadInt64();
|
||||
var value = new SpriteAtlasData(reader);
|
||||
m_RenderDataMap.Add(new KeyValuePair<Guid, long>(first, second), value);
|
||||
}
|
||||
var m_Tag = reader.ReadAlignedString();
|
||||
m_IsVariant = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
}
|
18
AssetStudio/Classes/TextAsset.cs
Normal file
18
AssetStudio/Classes/TextAsset.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public sealed class TextAsset : NamedObject
|
||||
{
|
||||
public byte[] m_Script;
|
||||
|
||||
public TextAsset(ObjectReader reader) : base(reader)
|
||||
{
|
||||
m_Script = reader.ReadUInt8Array();
|
||||
}
|
||||
}
|
||||
}
|
24
AssetStudio/Classes/Texture.cs
Normal file
24
AssetStudio/Classes/Texture.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public abstract class Texture : NamedObject
|
||||
{
|
||||
protected Texture(ObjectReader reader) : base(reader)
|
||||
{
|
||||
if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 3)) //2017.3 and up
|
||||
{
|
||||
var m_ForcedFallbackFormat = reader.ReadInt32();
|
||||
var m_DownscaleFallback = reader.ReadBoolean();
|
||||
if (version[0] > 2020 || (version[0] == 2020 && version[1] >= 2)) //2020.2 and up
|
||||
{
|
||||
var m_IsAlphaChannelOptional = reader.ReadBoolean();
|
||||
}
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
218
AssetStudio/Classes/Texture2D.cs
Normal file
218
AssetStudio/Classes/Texture2D.cs
Normal file
@ -0,0 +1,218 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class StreamingInfo
|
||||
{
|
||||
public long offset; //ulong
|
||||
public uint size;
|
||||
public string path;
|
||||
|
||||
public StreamingInfo(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
|
||||
if (version[0] >= 2020) //2020.1 and up
|
||||
{
|
||||
offset = reader.ReadInt64();
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = reader.ReadUInt32();
|
||||
}
|
||||
size = reader.ReadUInt32();
|
||||
path = reader.ReadAlignedString();
|
||||
}
|
||||
}
|
||||
|
||||
public class GLTextureSettings
|
||||
{
|
||||
public int m_FilterMode;
|
||||
public int m_Aniso;
|
||||
public float m_MipBias;
|
||||
public int m_WrapMode;
|
||||
|
||||
public GLTextureSettings(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
|
||||
m_FilterMode = reader.ReadInt32();
|
||||
m_Aniso = reader.ReadInt32();
|
||||
m_MipBias = reader.ReadSingle();
|
||||
if (version[0] >= 2017)//2017.x and up
|
||||
{
|
||||
m_WrapMode = reader.ReadInt32(); //m_WrapU
|
||||
int m_WrapV = reader.ReadInt32();
|
||||
int m_WrapW = reader.ReadInt32();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_WrapMode = reader.ReadInt32();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class Texture2D : Texture
|
||||
{
|
||||
public int m_Width;
|
||||
public int m_Height;
|
||||
public TextureFormat m_TextureFormat;
|
||||
public bool m_MipMap;
|
||||
public int m_MipCount;
|
||||
public GLTextureSettings m_TextureSettings;
|
||||
public ResourceReader image_data;
|
||||
public StreamingInfo m_StreamData;
|
||||
|
||||
public Texture2D(ObjectReader reader) : base(reader)
|
||||
{
|
||||
m_Width = reader.ReadInt32();
|
||||
m_Height = reader.ReadInt32();
|
||||
var m_CompleteImageSize = reader.ReadInt32();
|
||||
if (version[0] >= 2020) //2020.1 and up
|
||||
{
|
||||
var m_MipsStripped = reader.ReadInt32();
|
||||
}
|
||||
m_TextureFormat = (TextureFormat)reader.ReadInt32();
|
||||
if (version[0] < 5 || (version[0] == 5 && version[1] < 2)) //5.2 down
|
||||
{
|
||||
m_MipMap = reader.ReadBoolean();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_MipCount = reader.ReadInt32();
|
||||
}
|
||||
if (version[0] > 2 || (version[0] == 2 && version[1] >= 6)) //2.6.0 and up
|
||||
{
|
||||
var m_IsReadable = reader.ReadBoolean();
|
||||
}
|
||||
if (version[0] >= 2020) //2020.1 and up
|
||||
{
|
||||
var m_IsPreProcessed = reader.ReadBoolean();
|
||||
}
|
||||
if (version[0] > 2019 || (version[0] == 2019 && version[1] >= 3)) //2019.3 and up
|
||||
{
|
||||
var m_IgnoreMasterTextureLimit = reader.ReadBoolean();
|
||||
}
|
||||
if (version[0] >= 3) //3.0.0 - 5.4
|
||||
{
|
||||
if (version[0] < 5 || (version[0] == 5 && version[1] <= 4))
|
||||
{
|
||||
var m_ReadAllowed = reader.ReadBoolean();
|
||||
}
|
||||
}
|
||||
if (version[0] > 2018 || (version[0] == 2018 && version[1] >= 2)) //2018.2 and up
|
||||
{
|
||||
var m_StreamingMipmaps = reader.ReadBoolean();
|
||||
}
|
||||
reader.AlignStream();
|
||||
if (version[0] > 2018 || (version[0] == 2018 && version[1] >= 2)) //2018.2 and up
|
||||
{
|
||||
var m_StreamingMipmapsPriority = reader.ReadInt32();
|
||||
}
|
||||
var m_ImageCount = reader.ReadInt32();
|
||||
var m_TextureDimension = reader.ReadInt32();
|
||||
m_TextureSettings = new GLTextureSettings(reader);
|
||||
if (version[0] >= 3) //3.0 and up
|
||||
{
|
||||
var m_LightmapFormat = reader.ReadInt32();
|
||||
}
|
||||
if (version[0] > 3 || (version[0] == 3 && version[1] >= 5)) //3.5.0 and up
|
||||
{
|
||||
var m_ColorSpace = reader.ReadInt32();
|
||||
}
|
||||
if (version[0] > 2020 || (version[0] == 2020 && version[1] >= 2)) //2020.2 and up
|
||||
{
|
||||
var m_PlatformBlob = reader.ReadUInt8Array();
|
||||
reader.AlignStream();
|
||||
}
|
||||
var image_data_size = reader.ReadInt32();
|
||||
if (image_data_size == 0 && ((version[0] == 5 && version[1] >= 3) || version[0] > 5))//5.3.0 and up
|
||||
{
|
||||
m_StreamData = new StreamingInfo(reader);
|
||||
}
|
||||
|
||||
ResourceReader resourceReader;
|
||||
if (!string.IsNullOrEmpty(m_StreamData?.path))
|
||||
resourceReader = new ResourceReader(m_StreamData.path, assetsFile, m_StreamData.offset, m_StreamData.size);
|
||||
else
|
||||
resourceReader = new ResourceReader(reader, reader.BaseStream.Position, image_data_size);
|
||||
image_data = resourceReader;
|
||||
}
|
||||
}
|
||||
|
||||
public enum TextureFormat
|
||||
{
|
||||
Alpha8 = 1,
|
||||
ARGB4444,
|
||||
RGB24,
|
||||
RGBA32,
|
||||
ARGB32,
|
||||
ARGBFloat,
|
||||
RGB565,
|
||||
BGR24,
|
||||
R16,
|
||||
DXT1,
|
||||
DXT3,
|
||||
DXT5,
|
||||
RGBA4444,
|
||||
BGRA32,
|
||||
RHalf,
|
||||
RGHalf,
|
||||
RGBAHalf,
|
||||
RFloat,
|
||||
RGFloat,
|
||||
RGBAFloat,
|
||||
YUY2,
|
||||
RGB9e5Float,
|
||||
RGBFloat,
|
||||
BC6H,
|
||||
BC7,
|
||||
BC4,
|
||||
BC5,
|
||||
DXT1Crunched,
|
||||
DXT5Crunched,
|
||||
PVRTC_RGB2,
|
||||
PVRTC_RGBA2,
|
||||
PVRTC_RGB4,
|
||||
PVRTC_RGBA4,
|
||||
ETC_RGB4,
|
||||
ATC_RGB4,
|
||||
ATC_RGBA8,
|
||||
EAC_R = 41,
|
||||
EAC_R_SIGNED,
|
||||
EAC_RG,
|
||||
EAC_RG_SIGNED,
|
||||
ETC2_RGB,
|
||||
ETC2_RGBA1,
|
||||
ETC2_RGBA8,
|
||||
ASTC_RGB_4x4,
|
||||
ASTC_RGB_5x5,
|
||||
ASTC_RGB_6x6,
|
||||
ASTC_RGB_8x8,
|
||||
ASTC_RGB_10x10,
|
||||
ASTC_RGB_12x12,
|
||||
ASTC_RGBA_4x4,
|
||||
ASTC_RGBA_5x5,
|
||||
ASTC_RGBA_6x6,
|
||||
ASTC_RGBA_8x8,
|
||||
ASTC_RGBA_10x10,
|
||||
ASTC_RGBA_12x12,
|
||||
ETC_RGB4_3DS,
|
||||
ETC_RGBA8_3DS,
|
||||
RG16,
|
||||
R8,
|
||||
ETC_RGB4Crunched,
|
||||
ETC2_RGBA8Crunched,
|
||||
R16_2,
|
||||
ASTC_HDR_4x4,
|
||||
ASTC_HDR_5x5,
|
||||
ASTC_HDR_6x6,
|
||||
ASTC_HDR_8x8,
|
||||
ASTC_HDR_10x10,
|
||||
ASTC_HDR_12x12,
|
||||
RG32,
|
||||
RGB48,
|
||||
RGBA64
|
||||
}
|
||||
}
|
58
AssetStudio/Classes/Transform.cs
Normal file
58
AssetStudio/Classes/Transform.cs
Normal file
@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class Transform : Component
|
||||
{
|
||||
public Quaternion m_LocalRotation;
|
||||
public Vector3 m_LocalPosition;
|
||||
public Vector3 m_LocalScale;
|
||||
public PPtr<Transform>[] m_Children;
|
||||
public PPtr<Transform> m_Father;
|
||||
|
||||
public Transform(ObjectReader reader) : base(reader)
|
||||
{
|
||||
m_LocalRotation = reader.ReadQuaternion();
|
||||
m_LocalPosition = reader.ReadVector3();
|
||||
m_LocalScale = reader.ReadVector3();
|
||||
|
||||
int m_ChildrenCount = reader.ReadInt32();
|
||||
m_Children = new PPtr<Transform>[m_ChildrenCount];
|
||||
for (int i = 0; i < m_ChildrenCount; i++)
|
||||
{
|
||||
m_Children[i] = new PPtr<Transform>(reader);
|
||||
}
|
||||
m_Father = new PPtr<Transform>(reader);
|
||||
}
|
||||
|
||||
public Transform FindChild(string path)
|
||||
{
|
||||
if (path.Length == 0)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
return FindChild(path, 0);
|
||||
}
|
||||
private Transform FindChild(string path, int startIndex)
|
||||
{
|
||||
int separatorIndex = path.IndexOf('/', startIndex);
|
||||
string childName = separatorIndex == -1 ?
|
||||
path.Substring(startIndex, path.Length - startIndex) :
|
||||
path.Substring(startIndex, separatorIndex - startIndex);
|
||||
foreach (PPtr<Transform> childPtr in m_Children)
|
||||
{
|
||||
if(childPtr.TryGet(out var child))
|
||||
{
|
||||
if (child.m_GameObject.TryGet(out var childGO) && childGO.m_Name == childName)
|
||||
{
|
||||
return separatorIndex == -1 ? child : child.FindChild(path, separatorIndex + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
72
AssetStudio/Classes/VideoClip.cs
Normal file
72
AssetStudio/Classes/VideoClip.cs
Normal file
@ -0,0 +1,72 @@
|
||||
using System.IO;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class StreamedResource
|
||||
{
|
||||
public string m_Source;
|
||||
public long m_Offset; //ulong
|
||||
public long m_Size; //ulong
|
||||
|
||||
public StreamedResource(BinaryReader reader)
|
||||
{
|
||||
m_Source = reader.ReadAlignedString();
|
||||
m_Offset = reader.ReadInt64();
|
||||
m_Size = reader.ReadInt64();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class VideoClip : NamedObject
|
||||
{
|
||||
public ResourceReader m_VideoData;
|
||||
public string m_OriginalPath;
|
||||
public StreamedResource m_ExternalResources;
|
||||
|
||||
public VideoClip(ObjectReader reader) : base(reader)
|
||||
{
|
||||
m_OriginalPath = reader.ReadAlignedString();
|
||||
var m_ProxyWidth = reader.ReadUInt32();
|
||||
var m_ProxyHeight = reader.ReadUInt32();
|
||||
var Width = reader.ReadUInt32();
|
||||
var Height = reader.ReadUInt32();
|
||||
if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 2)) //2017.2 and up
|
||||
{
|
||||
var m_PixelAspecRatioNum = reader.ReadUInt32();
|
||||
var m_PixelAspecRatioDen = reader.ReadUInt32();
|
||||
}
|
||||
var m_FrameRate = reader.ReadDouble();
|
||||
var m_FrameCount = reader.ReadUInt64();
|
||||
var m_Format = reader.ReadInt32();
|
||||
var m_AudioChannelCount = reader.ReadUInt16Array();
|
||||
reader.AlignStream();
|
||||
var m_AudioSampleRate = reader.ReadUInt32Array();
|
||||
var m_AudioLanguage = reader.ReadStringArray();
|
||||
if (version[0] >= 2020) //2020.1 and up
|
||||
{
|
||||
var m_VideoShadersSize = reader.ReadInt32();
|
||||
var m_VideoShaders = new PPtr<Shader>[m_VideoShadersSize];
|
||||
for (int i = 0; i < m_VideoShadersSize; i++)
|
||||
{
|
||||
m_VideoShaders[i] = new PPtr<Shader>(reader);
|
||||
}
|
||||
}
|
||||
m_ExternalResources = new StreamedResource(reader);
|
||||
var m_HasSplitAlpha = reader.ReadBoolean();
|
||||
if (version[0] >= 2020) //2020.1 and up
|
||||
{
|
||||
var m_sRGB = reader.ReadBoolean();
|
||||
}
|
||||
|
||||
ResourceReader resourceReader;
|
||||
if (!string.IsNullOrEmpty(m_ExternalResources.m_Source))
|
||||
{
|
||||
resourceReader = new ResourceReader(m_ExternalResources.m_Source, assetsFile, m_ExternalResources.m_Offset, m_ExternalResources.m_Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
resourceReader = new ResourceReader(reader, reader.BaseStream.Position, m_ExternalResources.m_Size);
|
||||
}
|
||||
m_VideoData = resourceReader;
|
||||
}
|
||||
}
|
||||
}
|
120
AssetStudio/CommonString.cs
Normal file
120
AssetStudio/CommonString.cs
Normal file
@ -0,0 +1,120 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public static class CommonString
|
||||
{
|
||||
public static readonly Dictionary<uint, string> StringBuffer = new Dictionary<uint, string>
|
||||
{
|
||||
{0, "AABB"},
|
||||
{5, "AnimationClip"},
|
||||
{19, "AnimationCurve"},
|
||||
{34, "AnimationState"},
|
||||
{49, "Array"},
|
||||
{55, "Base"},
|
||||
{60, "BitField"},
|
||||
{69, "bitset"},
|
||||
{76, "bool"},
|
||||
{81, "char"},
|
||||
{86, "ColorRGBA"},
|
||||
{96, "Component"},
|
||||
{106, "data"},
|
||||
{111, "deque"},
|
||||
{117, "double"},
|
||||
{124, "dynamic_array"},
|
||||
{138, "FastPropertyName"},
|
||||
{155, "first"},
|
||||
{161, "float"},
|
||||
{167, "Font"},
|
||||
{172, "GameObject"},
|
||||
{183, "Generic Mono"},
|
||||
{196, "GradientNEW"},
|
||||
{208, "GUID"},
|
||||
{213, "GUIStyle"},
|
||||
{222, "int"},
|
||||
{226, "list"},
|
||||
{231, "long long"},
|
||||
{241, "map"},
|
||||
{245, "Matrix4x4f"},
|
||||
{256, "MdFour"},
|
||||
{263, "MonoBehaviour"},
|
||||
{277, "MonoScript"},
|
||||
{288, "m_ByteSize"},
|
||||
{299, "m_Curve"},
|
||||
{307, "m_EditorClassIdentifier"},
|
||||
{331, "m_EditorHideFlags"},
|
||||
{349, "m_Enabled"},
|
||||
{359, "m_ExtensionPtr"},
|
||||
{374, "m_GameObject"},
|
||||
{387, "m_Index"},
|
||||
{395, "m_IsArray"},
|
||||
{405, "m_IsStatic"},
|
||||
{416, "m_MetaFlag"},
|
||||
{427, "m_Name"},
|
||||
{434, "m_ObjectHideFlags"},
|
||||
{452, "m_PrefabInternal"},
|
||||
{469, "m_PrefabParentObject"},
|
||||
{490, "m_Script"},
|
||||
{499, "m_StaticEditorFlags"},
|
||||
{519, "m_Type"},
|
||||
{526, "m_Version"},
|
||||
{536, "Object"},
|
||||
{543, "pair"},
|
||||
{548, "PPtr<Component>"},
|
||||
{564, "PPtr<GameObject>"},
|
||||
{581, "PPtr<Material>"},
|
||||
{596, "PPtr<MonoBehaviour>"},
|
||||
{616, "PPtr<MonoScript>"},
|
||||
{633, "PPtr<Object>"},
|
||||
{646, "PPtr<Prefab>"},
|
||||
{659, "PPtr<Sprite>"},
|
||||
{672, "PPtr<TextAsset>"},
|
||||
{688, "PPtr<Texture>"},
|
||||
{702, "PPtr<Texture2D>"},
|
||||
{718, "PPtr<Transform>"},
|
||||
{734, "Prefab"},
|
||||
{741, "Quaternionf"},
|
||||
{753, "Rectf"},
|
||||
{759, "RectInt"},
|
||||
{767, "RectOffset"},
|
||||
{778, "second"},
|
||||
{785, "set"},
|
||||
{789, "short"},
|
||||
{795, "size"},
|
||||
{800, "SInt16"},
|
||||
{807, "SInt32"},
|
||||
{814, "SInt64"},
|
||||
{821, "SInt8"},
|
||||
{827, "staticvector"},
|
||||
{840, "string"},
|
||||
{847, "TextAsset"},
|
||||
{857, "TextMesh"},
|
||||
{866, "Texture"},
|
||||
{874, "Texture2D"},
|
||||
{884, "Transform"},
|
||||
{894, "TypelessData"},
|
||||
{907, "UInt16"},
|
||||
{914, "UInt32"},
|
||||
{921, "UInt64"},
|
||||
{928, "UInt8"},
|
||||
{934, "unsigned int"},
|
||||
{947, "unsigned long long"},
|
||||
{966, "unsigned short"},
|
||||
{981, "vector"},
|
||||
{988, "Vector2f"},
|
||||
{997, "Vector3f"},
|
||||
{1006, "Vector4f"},
|
||||
{1015, "m_ScriptingClassIdentifier"},
|
||||
{1042, "Gradient"},
|
||||
{1051, "Type*"},
|
||||
{1057, "int2_storage"},
|
||||
{1070, "int3_storage"},
|
||||
{1083, "BoundsInt"},
|
||||
{1093, "m_CorrespondingSourceObject"},
|
||||
{1121, "m_PrefabInstance"},
|
||||
{1138, "m_PrefabAsset"},
|
||||
{1152, "FileSize"},
|
||||
{1161, "Hash128"}
|
||||
};
|
||||
}
|
||||
}
|
116
AssetStudio/EndianBinaryReader.cs
Normal file
116
AssetStudio/EndianBinaryReader.cs
Normal file
@ -0,0 +1,116 @@
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.IO;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class EndianBinaryReader : BinaryReader
|
||||
{
|
||||
private readonly byte[] buffer;
|
||||
|
||||
public EndianType Endian;
|
||||
|
||||
public EndianBinaryReader(Stream stream, EndianType endian = EndianType.BigEndian, Game game = null) : base(stream)
|
||||
{
|
||||
Endian = endian;
|
||||
buffer = new byte[8];
|
||||
Game = game;
|
||||
}
|
||||
|
||||
public long Position
|
||||
{
|
||||
get => BaseStream.Position;
|
||||
set => BaseStream.Position = value;
|
||||
}
|
||||
|
||||
public long[] BundlePos = Array.Empty<long>();
|
||||
public Game Game;
|
||||
|
||||
public override short ReadInt16()
|
||||
{
|
||||
if (Endian == EndianType.BigEndian)
|
||||
{
|
||||
Read(buffer, 0, 2);
|
||||
return BinaryPrimitives.ReadInt16BigEndian(buffer);
|
||||
}
|
||||
return base.ReadInt16();
|
||||
}
|
||||
|
||||
public override int ReadInt32()
|
||||
{
|
||||
if (Endian == EndianType.BigEndian)
|
||||
{
|
||||
Read(buffer, 0, 4);
|
||||
return BinaryPrimitives.ReadInt32BigEndian(buffer);
|
||||
}
|
||||
return base.ReadInt32();
|
||||
}
|
||||
|
||||
public override long ReadInt64()
|
||||
{
|
||||
if (Endian == EndianType.BigEndian)
|
||||
{
|
||||
Read(buffer, 0, 8);
|
||||
return BinaryPrimitives.ReadInt64BigEndian(buffer);
|
||||
}
|
||||
return base.ReadInt64();
|
||||
}
|
||||
|
||||
public override ushort ReadUInt16()
|
||||
{
|
||||
if (Endian == EndianType.BigEndian)
|
||||
{
|
||||
Read(buffer, 0, 2);
|
||||
return BinaryPrimitives.ReadUInt16BigEndian(buffer);
|
||||
}
|
||||
return base.ReadUInt16();
|
||||
}
|
||||
|
||||
public override uint ReadUInt32()
|
||||
{
|
||||
if (Endian == EndianType.BigEndian)
|
||||
{
|
||||
Read(buffer, 0, 4);
|
||||
return BinaryPrimitives.ReadUInt32BigEndian(buffer);
|
||||
}
|
||||
return base.ReadUInt32();
|
||||
}
|
||||
|
||||
public override ulong ReadUInt64()
|
||||
{
|
||||
if (Endian == EndianType.BigEndian)
|
||||
{
|
||||
Read(buffer, 0, 8);
|
||||
return BinaryPrimitives.ReadUInt64BigEndian(buffer);
|
||||
}
|
||||
return base.ReadUInt64();
|
||||
}
|
||||
|
||||
public override float ReadSingle()
|
||||
{
|
||||
if (Endian == EndianType.BigEndian)
|
||||
{
|
||||
Read(buffer, 0, 4);
|
||||
Array.Reverse(buffer, 0, 4);
|
||||
return BitConverter.ToSingle(buffer, 0);
|
||||
}
|
||||
return base.ReadSingle();
|
||||
}
|
||||
|
||||
public override double ReadDouble()
|
||||
{
|
||||
if (Endian == EndianType.BigEndian)
|
||||
{
|
||||
Read(buffer, 0, 8);
|
||||
Array.Reverse(buffer);
|
||||
return BitConverter.ToDouble(buffer, 0);
|
||||
}
|
||||
return base.ReadDouble();
|
||||
}
|
||||
|
||||
public Float ReadFloat()
|
||||
{
|
||||
return new Float(ReadSingle());
|
||||
}
|
||||
}
|
||||
}
|
14
AssetStudio/EndianType.cs
Normal file
14
AssetStudio/EndianType.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public enum EndianType
|
||||
{
|
||||
LittleEndian,
|
||||
BigEndian
|
||||
}
|
||||
}
|
192
AssetStudio/Extensions/BinaryReaderExtensions.cs
Normal file
192
AssetStudio/Extensions/BinaryReaderExtensions.cs
Normal file
@ -0,0 +1,192 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public static class BinaryReaderExtensions
|
||||
{
|
||||
public static void AlignStream(this BinaryReader reader)
|
||||
{
|
||||
reader.AlignStream(4);
|
||||
}
|
||||
|
||||
public static void AlignStream(this BinaryReader reader, int alignment)
|
||||
{
|
||||
var pos = reader.BaseStream.Position;
|
||||
var mod = pos % alignment;
|
||||
if (mod != 0)
|
||||
{
|
||||
reader.BaseStream.Position += alignment - mod;
|
||||
}
|
||||
}
|
||||
|
||||
public static string ReadAlignedString(this BinaryReader reader)
|
||||
{
|
||||
var length = reader.ReadInt32();
|
||||
if (length > 0 && length <= reader.BaseStream.Length - reader.BaseStream.Position)
|
||||
{
|
||||
var stringData = reader.ReadBytes(length);
|
||||
var result = Encoding.UTF8.GetString(stringData);
|
||||
reader.AlignStream(4);
|
||||
return result;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public static string ReadStringToNull(this BinaryReader reader, int maxLength = 32767)
|
||||
{
|
||||
var bytes = new List<byte>();
|
||||
int count = 0;
|
||||
while (reader.BaseStream.Position != reader.BaseStream.Length && count < maxLength)
|
||||
{
|
||||
var b = reader.ReadByte();
|
||||
if (b == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
bytes.Add(b);
|
||||
count++;
|
||||
}
|
||||
return Encoding.UTF8.GetString(bytes.ToArray());
|
||||
}
|
||||
|
||||
public static Quaternion ReadQuaternion(this BinaryReader reader)
|
||||
{
|
||||
return new Quaternion(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
|
||||
}
|
||||
|
||||
public static Vector2 ReadVector2(this BinaryReader reader)
|
||||
{
|
||||
return new Vector2(reader.ReadSingle(), reader.ReadSingle());
|
||||
}
|
||||
|
||||
public static Vector3 ReadVector3(this BinaryReader reader)
|
||||
{
|
||||
return new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
|
||||
}
|
||||
|
||||
public static Vector4 ReadVector4(this BinaryReader reader)
|
||||
{
|
||||
return new Vector4(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
|
||||
}
|
||||
|
||||
public static Color ReadColor4(this BinaryReader reader)
|
||||
{
|
||||
return new Color(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
|
||||
}
|
||||
|
||||
public static Matrix4x4 ReadMatrix(this BinaryReader reader)
|
||||
{
|
||||
return new Matrix4x4(reader.ReadSingleArray(16));
|
||||
}
|
||||
|
||||
public static int ReadMhy0Int1(this BinaryReader reader)
|
||||
{
|
||||
var buffer = reader.ReadBytes(7);
|
||||
return buffer[1] | (buffer[6] << 8) | (buffer[3] << 0x10) | (buffer[2] << 0x18);
|
||||
}
|
||||
|
||||
public static int ReadMhy0Int2(this BinaryReader reader)
|
||||
{
|
||||
var buffer = reader.ReadBytes(6);
|
||||
return buffer[2] | (buffer[4] << 8) | (buffer[0] << 0x10) | (buffer[5] << 0x18);
|
||||
}
|
||||
|
||||
public static string ReadMhy0String(this BinaryReader reader)
|
||||
{
|
||||
var bytes = reader.ReadBytes(0x100);
|
||||
return Encoding.UTF8.GetString(bytes.TakeWhile(b => !b.Equals(0)).ToArray());
|
||||
}
|
||||
|
||||
public static bool ReadMhy0Bool(this BinaryReader reader)
|
||||
{
|
||||
var value = reader.ReadMhy0Int2();
|
||||
var bytes = BitConverter.GetBytes(value);
|
||||
Array.Reverse(bytes);
|
||||
return BitConverter.ToBoolean(bytes, 0);
|
||||
}
|
||||
|
||||
private static T[] ReadArray<T>(Func<T> del, int length)
|
||||
{
|
||||
var array = new T[length];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
array[i] = del();
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
public static bool[] ReadBooleanArray(this BinaryReader reader)
|
||||
{
|
||||
return ReadArray(reader.ReadBoolean, reader.ReadInt32());
|
||||
}
|
||||
|
||||
public static byte[] ReadUInt8Array(this BinaryReader reader)
|
||||
{
|
||||
return reader.ReadBytes(reader.ReadInt32());
|
||||
}
|
||||
|
||||
public static ushort[] ReadUInt16Array(this BinaryReader reader)
|
||||
{
|
||||
return ReadArray(reader.ReadUInt16, reader.ReadInt32());
|
||||
}
|
||||
|
||||
public static int[] ReadInt32Array(this BinaryReader reader)
|
||||
{
|
||||
return ReadArray(reader.ReadInt32, reader.ReadInt32());
|
||||
}
|
||||
|
||||
public static int[] ReadInt32Array(this BinaryReader reader, int length)
|
||||
{
|
||||
return ReadArray(reader.ReadInt32, length);
|
||||
}
|
||||
|
||||
public static uint[] ReadUInt32Array(this BinaryReader reader)
|
||||
{
|
||||
return ReadArray(reader.ReadUInt32, reader.ReadInt32());
|
||||
}
|
||||
|
||||
public static uint[][] ReadUInt32ArrayArray(this BinaryReader reader)
|
||||
{
|
||||
return ReadArray(reader.ReadUInt32Array, reader.ReadInt32());
|
||||
}
|
||||
|
||||
public static uint[] ReadUInt32Array(this BinaryReader reader, int length)
|
||||
{
|
||||
return ReadArray(reader.ReadUInt32, length);
|
||||
}
|
||||
|
||||
public static float[] ReadSingleArray(this BinaryReader reader)
|
||||
{
|
||||
return ReadArray(reader.ReadSingle, reader.ReadInt32());
|
||||
}
|
||||
|
||||
public static float[] ReadSingleArray(this BinaryReader reader, int length)
|
||||
{
|
||||
return ReadArray(reader.ReadSingle, length);
|
||||
}
|
||||
|
||||
public static string[] ReadStringArray(this BinaryReader reader)
|
||||
{
|
||||
return ReadArray(reader.ReadAlignedString, reader.ReadInt32());
|
||||
}
|
||||
|
||||
public static Vector2[] ReadVector2Array(this BinaryReader reader)
|
||||
{
|
||||
return ReadArray(reader.ReadVector2, reader.ReadInt32());
|
||||
}
|
||||
|
||||
public static Vector4[] ReadVector4Array(this BinaryReader reader)
|
||||
{
|
||||
return ReadArray(reader.ReadVector4, reader.ReadInt32());
|
||||
}
|
||||
|
||||
public static Matrix4x4[] ReadMatrixArray(this BinaryReader reader)
|
||||
{
|
||||
return ReadArray(reader.ReadMatrix, reader.ReadInt32());
|
||||
}
|
||||
}
|
||||
}
|
27
AssetStudio/Extensions/BinaryWriterExtensions.cs
Normal file
27
AssetStudio/Extensions/BinaryWriterExtensions.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public static class BinaryWriterExtensions
|
||||
{
|
||||
public static void AlignStream(this BinaryWriter writer, int alignment)
|
||||
{
|
||||
var pos = writer.BaseStream.Position;
|
||||
var mod = pos % alignment;
|
||||
if (mod != 0)
|
||||
{
|
||||
writer.Write(new byte[alignment - mod]);
|
||||
}
|
||||
}
|
||||
|
||||
public static void WriteAlignedString(this BinaryWriter writer, string str)
|
||||
{
|
||||
var bytes = Encoding.UTF8.GetBytes(str);
|
||||
writer.Write(bytes.Length);
|
||||
writer.Write(bytes);
|
||||
writer.AlignStream(4);
|
||||
}
|
||||
}
|
||||
}
|
107
AssetStudio/Extensions/BitConverterExtensions.cs
Normal file
107
AssetStudio/Extensions/BitConverterExtensions.cs
Normal file
@ -0,0 +1,107 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public static class BitConverterExtensions
|
||||
{
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
private struct FloatUIntUnion
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public uint Int;
|
||||
[FieldOffset(0)]
|
||||
public float Float;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint ToUInt32(float value)
|
||||
{
|
||||
return new FloatUIntUnion { Float = value }.Int;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ulong ToUInt64(double value)
|
||||
{
|
||||
return unchecked((ulong)BitConverter.DoubleToInt64Bits(value));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float ToSingle(uint value)
|
||||
{
|
||||
return new FloatUIntUnion { Int = value }.Float;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static double ToDouble(ulong value)
|
||||
{
|
||||
return BitConverter.Int64BitsToDouble(unchecked((long)value));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void GetBytes(ushort value, byte[] buffer, int offset)
|
||||
{
|
||||
buffer[offset + 0] = unchecked((byte)(value >> 0));
|
||||
buffer[offset + 1] = unchecked((byte)(value >> 8));
|
||||
}
|
||||
|
||||
public static void GetBytes(uint value, byte[] buffer, int offset)
|
||||
{
|
||||
buffer[offset + 0] = unchecked((byte)(value >> 0));
|
||||
buffer[offset + 1] = unchecked((byte)(value >> 8));
|
||||
buffer[offset + 2] = unchecked((byte)(value >> 16));
|
||||
buffer[offset + 3] = unchecked((byte)(value >> 24));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static short Swap(short value)
|
||||
{
|
||||
return unchecked((short)(Swap(unchecked((ushort)value))));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ushort Swap(ushort value)
|
||||
{
|
||||
return unchecked((ushort)(value >> 8 | value << 8));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int Swap(int value)
|
||||
{
|
||||
return unchecked((int)(Swap(unchecked((uint)value))));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint Swap(uint value)
|
||||
{
|
||||
value = value >> 16 | value << 16;
|
||||
return ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static long Swap(long value)
|
||||
{
|
||||
return unchecked((long)(Swap(unchecked((ulong)value))));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ulong Swap(ulong value)
|
||||
{
|
||||
value = value >> 32 | value << 32;
|
||||
value = ((value & 0xFFFF0000FFFF0000) >> 16) | ((value & 0x0000FFFF0000FFFF) << 16);
|
||||
return ((value & 0xFF00FF00FF00FF00) >> 8) | ((value & 0x00FF00FF00FF00FF) << 8);
|
||||
}
|
||||
|
||||
public static int GetDigitsCount(uint value)
|
||||
{
|
||||
int count = 0;
|
||||
while (value != 0)
|
||||
{
|
||||
value /= 10;
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
79
AssetStudio/Extensions/PrimitiveExtensions.cs
Normal file
79
AssetStudio/Extensions/PrimitiveExtensions.cs
Normal file
@ -0,0 +1,79 @@
|
||||
namespace AssetStudio
|
||||
{
|
||||
public static class PrimitiveExtensions
|
||||
{
|
||||
public static int ParseDigit(this char _this)
|
||||
{
|
||||
return _this - '0';
|
||||
}
|
||||
|
||||
public static string ToHexString(this byte _this)
|
||||
{
|
||||
return _this.ToString("x2");
|
||||
}
|
||||
|
||||
public static string ToHexString(this short _this)
|
||||
{
|
||||
ushort value = unchecked((ushort)_this);
|
||||
return ToHexString(value);
|
||||
}
|
||||
|
||||
public static string ToHexString(this ushort _this)
|
||||
{
|
||||
ushort reverse = unchecked((ushort)(((0xFF00 & _this) >> 8) | ((0x00FF & _this) << 8)));
|
||||
return reverse.ToString("x4");
|
||||
}
|
||||
|
||||
public static string ToHexString(this int _this)
|
||||
{
|
||||
uint value = unchecked((uint)_this);
|
||||
return ToHexString(value);
|
||||
}
|
||||
|
||||
public static string ToHexString(this uint _this)
|
||||
{
|
||||
uint reverse = ((0xFF000000 & _this) >> 24) | ((0x00FF0000 & _this) >> 8) | ((0x0000FF00 & _this) << 8) | ((0x000000FF & _this) << 24);
|
||||
return reverse.ToString("x8");
|
||||
}
|
||||
|
||||
public static string ToHexString(this long _this)
|
||||
{
|
||||
ulong value = unchecked((ulong)_this);
|
||||
return ToHexString(value);
|
||||
}
|
||||
|
||||
public static string ToHexString(this ulong _this)
|
||||
{
|
||||
ulong reverse = (_this & 0x00000000000000FFUL) << 56 | (_this & 0x000000000000FF00UL) << 40 |
|
||||
(_this & 0x0000000000FF0000UL) << 24 | (_this & 0x00000000FF000000UL) << 8 |
|
||||
(_this & 0x000000FF00000000UL) >> 8 | (_this & 0x0000FF0000000000UL) >> 24 |
|
||||
(_this & 0x00FF000000000000UL) >> 40 | (_this & 0xFF00000000000000UL) >> 56;
|
||||
return reverse.ToString("x16");
|
||||
}
|
||||
|
||||
public static string ToHexString(this float _this)
|
||||
{
|
||||
uint value = BitConverterExtensions.ToUInt32(_this);
|
||||
return ToHexString(value);
|
||||
}
|
||||
|
||||
public static string ToHexString(this double _this)
|
||||
{
|
||||
ulong value = BitConverterExtensions.ToUInt64(_this);
|
||||
return ToHexString(value);
|
||||
}
|
||||
|
||||
public static int ToClosestInt(this long _this)
|
||||
{
|
||||
if (_this > int.MaxValue)
|
||||
{
|
||||
return int.MaxValue;
|
||||
}
|
||||
if (_this < int.MinValue)
|
||||
{
|
||||
return int.MinValue;
|
||||
}
|
||||
return unchecked((int)_this);
|
||||
}
|
||||
}
|
||||
}
|
24
AssetStudio/Extensions/StreamExtensions.cs
Normal file
24
AssetStudio/Extensions/StreamExtensions.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using System.IO;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public static class StreamExtensions
|
||||
{
|
||||
private const int BufferSize = 81920;
|
||||
|
||||
public static void CopyTo(this Stream source, Stream destination, long size)
|
||||
{
|
||||
var buffer = new byte[BufferSize];
|
||||
for (var left = size; left > 0; left -= BufferSize)
|
||||
{
|
||||
int toRead = BufferSize < left ? BufferSize : (int)left;
|
||||
int read = source.Read(buffer, 0, toRead);
|
||||
destination.Write(buffer, 0, read);
|
||||
if (read != toRead)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
87
AssetStudio/Extensions/StringBuilderExtensions.cs
Normal file
87
AssetStudio/Extensions/StringBuilderExtensions.cs
Normal file
@ -0,0 +1,87 @@
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public static class StringBuilderExtensions
|
||||
{
|
||||
static StringBuilderExtensions()
|
||||
{
|
||||
for (int i = 0; i <= byte.MaxValue; i++)
|
||||
{
|
||||
ByteHexRepresentations[i] = i.ToString("x2");
|
||||
}
|
||||
}
|
||||
|
||||
public static StringBuilder AppendHex(this StringBuilder _this, byte value)
|
||||
{
|
||||
_this.Append(ByteHexRepresentations[value]);
|
||||
return _this;
|
||||
}
|
||||
|
||||
public static StringBuilder AppendHex(this StringBuilder _this, ushort value)
|
||||
{
|
||||
_this.Append(ByteHexRepresentations[(value >> 0) & 0xFF]);
|
||||
_this.Append(ByteHexRepresentations[(value >> 8) & 0xFF]);
|
||||
return _this;
|
||||
}
|
||||
|
||||
public static StringBuilder AppendHex(this StringBuilder _this, short value)
|
||||
{
|
||||
return AppendHex(_this, unchecked((ushort)value));
|
||||
}
|
||||
|
||||
public static StringBuilder AppendHex(this StringBuilder _this, uint value)
|
||||
{
|
||||
_this.Append(ByteHexRepresentations[unchecked((int)(value >> 0) & 0xFF)]);
|
||||
_this.Append(ByteHexRepresentations[unchecked((int)(value >> 8) & 0xFF)]);
|
||||
_this.Append(ByteHexRepresentations[unchecked((int)(value >> 16) & 0xFF)]);
|
||||
_this.Append(ByteHexRepresentations[unchecked((int)(value >> 24) & 0xFF)]);
|
||||
return _this;
|
||||
}
|
||||
|
||||
public static StringBuilder AppendHex(this StringBuilder _this, int value)
|
||||
{
|
||||
return AppendHex(_this, unchecked((uint)value));
|
||||
}
|
||||
|
||||
public static StringBuilder AppendHex(this StringBuilder _this, ulong value)
|
||||
{
|
||||
_this.Append(ByteHexRepresentations[unchecked((int)(value >> 0) & 0xFF)]);
|
||||
_this.Append(ByteHexRepresentations[unchecked((int)(value >> 8) & 0xFF)]);
|
||||
_this.Append(ByteHexRepresentations[unchecked((int)(value >> 16) & 0xFF)]);
|
||||
_this.Append(ByteHexRepresentations[unchecked((int)(value >> 24) & 0xFF)]);
|
||||
_this.Append(ByteHexRepresentations[unchecked((int)(value >> 32) & 0xFF)]);
|
||||
_this.Append(ByteHexRepresentations[unchecked((int)(value >> 40) & 0xFF)]);
|
||||
_this.Append(ByteHexRepresentations[unchecked((int)(value >> 48) & 0xFF)]);
|
||||
_this.Append(ByteHexRepresentations[unchecked((int)(value >> 56) & 0xFF)]);
|
||||
return _this;
|
||||
}
|
||||
|
||||
public static StringBuilder AppendHex(this StringBuilder _this, long value)
|
||||
{
|
||||
return AppendHex(_this, unchecked((ulong)value));
|
||||
}
|
||||
|
||||
public static StringBuilder AppendHex(this StringBuilder _this, float value)
|
||||
{
|
||||
return AppendHex(_this, BitConverterExtensions.ToUInt32(value));
|
||||
}
|
||||
|
||||
public static StringBuilder AppendHex(this StringBuilder _this, double value)
|
||||
{
|
||||
return AppendHex(_this, BitConverterExtensions.ToUInt64(value));
|
||||
}
|
||||
|
||||
public static StringBuilder AppendIndent(this StringBuilder _this, int count)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
_this.Append('\t');
|
||||
}
|
||||
return _this;
|
||||
}
|
||||
|
||||
public static readonly string HexAlphabet = "0123456789abcdef";
|
||||
public static readonly string[] ByteHexRepresentations = new string[256];
|
||||
}
|
||||
}
|
17
AssetStudio/FileIdentifier.cs
Normal file
17
AssetStudio/FileIdentifier.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class FileIdentifier
|
||||
{
|
||||
public Guid guid;
|
||||
public int type; //enum { kNonAssetType = 0, kDeprecatedCachedAssetType = 1, kSerializedAssetType = 2, kMetaAssetType = 3 };
|
||||
public string pathName;
|
||||
|
||||
//custom
|
||||
public string fileName;
|
||||
}
|
||||
}
|
116
AssetStudio/FileReader.cs
Normal file
116
AssetStudio/FileReader.cs
Normal file
@ -0,0 +1,116 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class FileReader : EndianBinaryReader
|
||||
{
|
||||
public string FullPath;
|
||||
public string FileName;
|
||||
public FileType FileType;
|
||||
public long Length;
|
||||
|
||||
private static readonly byte[] gzipMagic = { 0x1f, 0x8b };
|
||||
private static readonly byte[] brotliMagic = { 0x62, 0x72, 0x6F, 0x74, 0x6C, 0x69 };
|
||||
private static readonly byte[] zipMagic = { 0x50, 0x4B, 0x03, 0x04 };
|
||||
private static readonly byte[] zipSpannedMagic = { 0x50, 0x4B, 0x07, 0x08 };
|
||||
|
||||
public FileReader(string path, Game game = null) : this(path, File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite), game) { }
|
||||
|
||||
public FileReader(string path, Stream stream, Game game = null) : base(stream, EndianType.BigEndian, game)
|
||||
{
|
||||
Game = game;
|
||||
FullPath = Path.GetFullPath(path);
|
||||
FileName = Path.GetFileName(path);
|
||||
FileType = CheckFileType();
|
||||
Length = stream.Length;
|
||||
|
||||
}
|
||||
|
||||
private FileType CheckFileType()
|
||||
{
|
||||
if (IsSerializedFile())
|
||||
{
|
||||
return FileType.AssetsFile;
|
||||
}
|
||||
else if (Game != null)
|
||||
{
|
||||
return FileType.GameFile;
|
||||
}
|
||||
|
||||
var signature = this.ReadStringToNull(20);
|
||||
Position = 0;
|
||||
switch (signature)
|
||||
{
|
||||
case "UnityWeb":
|
||||
case "UnityRaw":
|
||||
case "UnityArchive":
|
||||
case "UnityFS":
|
||||
return FileType.BundleFile;
|
||||
case "UnityWebData1.0":
|
||||
return FileType.WebFile;
|
||||
default:
|
||||
{
|
||||
byte[] magic = ReadBytes(2);
|
||||
Position = 0;
|
||||
if (gzipMagic.SequenceEqual(magic))
|
||||
{
|
||||
return FileType.GZipFile;
|
||||
}
|
||||
Position = 0x20;
|
||||
magic = ReadBytes(6);
|
||||
Position = 0;
|
||||
if (brotliMagic.SequenceEqual(magic))
|
||||
{
|
||||
return FileType.BrotliFile;
|
||||
}
|
||||
if (IsSerializedFile())
|
||||
{
|
||||
return FileType.AssetsFile;
|
||||
}
|
||||
magic = ReadBytes(4);
|
||||
Position = 0;
|
||||
if (zipMagic.SequenceEqual(magic) || zipSpannedMagic.SequenceEqual(magic))
|
||||
return FileType.ZipFile;
|
||||
return FileType.ResourceFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsSerializedFile()
|
||||
{
|
||||
var fileSize = BaseStream.Length;
|
||||
if (fileSize < 20)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var m_MetadataSize = ReadUInt32();
|
||||
long m_FileSize = ReadUInt32();
|
||||
var m_Version = ReadUInt32();
|
||||
long m_DataOffset = ReadUInt32();
|
||||
var m_Endianess = ReadByte();
|
||||
var m_Reserved = ReadBytes(3);
|
||||
if (m_Version >= 22)
|
||||
{
|
||||
if (fileSize < 48)
|
||||
{
|
||||
Position = 0;
|
||||
return false;
|
||||
}
|
||||
m_MetadataSize = ReadUInt32();
|
||||
m_FileSize = ReadInt64();
|
||||
m_DataOffset = ReadInt64();
|
||||
}
|
||||
Position = 0;
|
||||
if (m_FileSize != fileSize)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (m_DataOffset > fileSize)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
20
AssetStudio/FileType.cs
Normal file
20
AssetStudio/FileType.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public enum FileType
|
||||
{
|
||||
AssetsFile,
|
||||
BundleFile,
|
||||
GameFile,
|
||||
WebFile,
|
||||
ResourceFile,
|
||||
GZipFile,
|
||||
BrotliFile,
|
||||
ZipFile
|
||||
}
|
||||
}
|
30
AssetStudio/Game/BH3/WMVFile.cs
Normal file
30
AssetStudio/Game/BH3/WMVFile.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class WMVFile
|
||||
{
|
||||
public Dictionary<long, StreamFile[]> Bundles = new Dictionary<long, StreamFile[]>();
|
||||
public WMVFile(FileReader reader)
|
||||
{
|
||||
if (reader.BundlePos.Length != 0)
|
||||
{
|
||||
foreach (var pos in reader.BundlePos)
|
||||
{
|
||||
reader.Position = pos;
|
||||
var bundle = new BundleFile(reader);
|
||||
Bundles.Add(pos, bundle.FileList);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (reader.Position != reader.Length)
|
||||
{
|
||||
var pos = reader.Position;
|
||||
var bundle = new BundleFile(reader);
|
||||
Bundles.Add(pos, bundle.FileList);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
21
AssetStudio/Game/CB1/CB1File.cs
Normal file
21
AssetStudio/Game/CB1/CB1File.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class CB1File
|
||||
{
|
||||
public Dictionary<long, StreamFile[]> Bundles = new Dictionary<long, StreamFile[]>();
|
||||
public CB1File(FileReader reader)
|
||||
{
|
||||
var data = Mark.Decrypt(reader);
|
||||
|
||||
using (var ms = new MemoryStream(data))
|
||||
using (var subReader = new FileReader(reader.FullPath, ms, reader.Game))
|
||||
{
|
||||
var bundle = new BundleFile(subReader);
|
||||
Bundles.Add(0, bundle.FileList);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user