Chinese Translated

This commit is contained in:
15459 2023-10-29 00:46:17 +08:00
commit 242a387a79
309 changed files with 71589 additions and 0 deletions

63
.gitattributes vendored Normal file
View 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
View 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

View 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>

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

View 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
View 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

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

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

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

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

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

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

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

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

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

View 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) {}
*/
}
}

File diff suppressed because it is too large Load Diff

View 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(); }
}
}

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

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

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

View 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>

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

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

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

View 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() {}
}
}

View 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)
{
}
}
}

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

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

File diff suppressed because one or more lines are too long

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

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

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

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

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

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

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

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

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

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

File diff suppressed because it is too large Load Diff

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

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

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

View 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());
}
}
}
}
}

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

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

View 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();
}
}
}

View 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();
}
}
}

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

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

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

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

View 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

File diff suppressed because it is too large Load Diff

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

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

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

View 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();
}
}
}

View 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();
}
}
}
}

View 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();
}
}
}

View 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();
}
}
}

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

View 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();
}
}
}

View 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)
{
}
}
}

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

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

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

File diff suppressed because it is too large Load Diff

View 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();
}
}
}

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

View 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();
}
}
}

View 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();
}
}
}

View 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();
}
}
}
}

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

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

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

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

View 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());
}
}
}

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

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

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

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

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

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

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

View 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