Compare commits
523 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
571ea2da4a | ||
|
|
9cbe91decb | ||
|
|
19c6c5fe73 | ||
|
|
792850dbb2 | ||
|
|
2ce9cae957 | ||
|
|
af5e50cfa9 | ||
|
|
ce1172ca9a | ||
|
|
a7e6d91f5b | ||
|
|
34a0af683a | ||
|
|
91410a33b1 | ||
|
|
d08b78c2cf | ||
|
|
2ef52afe1e | ||
|
|
05a41d2f1e | ||
|
|
34c38e1415 | ||
|
|
c85873b729 | ||
|
|
b146d251a7 | ||
|
|
3129d67fc1 | ||
|
|
850ba63a10 | ||
|
|
17b91984d6 | ||
|
|
7ab2cda120 | ||
|
|
4345885cc9 | ||
|
|
53720e37ab | ||
|
|
7c3cb36630 | ||
|
|
c1cddce031 | ||
|
|
973a1076e4 | ||
|
|
089e164756 | ||
|
|
c2b6691fd9 | ||
|
|
8dec094304 | ||
|
|
bedee240be | ||
|
|
d963d71b12 | ||
|
|
77a0c9c40a | ||
|
|
f3e406983b | ||
|
|
08b7bfcf9a | ||
|
|
57e4f7cefd | ||
|
|
c9cf2d188e | ||
|
|
ab98585b6a | ||
|
|
075d53a455 | ||
|
|
432116d834 | ||
|
|
caa45216ef | ||
|
|
c9394cd957 | ||
|
|
46c0e8ffe1 | ||
|
|
d14c232015 | ||
|
|
4002bdecb8 | ||
|
|
17259e00c7 | ||
|
|
44b02b92d8 | ||
|
|
251854cc41 | ||
|
|
6f7b77245d | ||
|
|
6d99f5ebf6 | ||
|
|
f1f2430f97 | ||
|
|
b52696c965 | ||
|
|
5fba52dc83 | ||
|
|
dfb74baf79 | ||
|
|
978e90a403 | ||
|
|
c17d7d6331 | ||
|
|
9fef18d6ea | ||
|
|
ee0cd4ab52 | ||
|
|
f904bc138b | ||
|
|
7ed5345b1b | ||
|
|
d7f652d572 | ||
|
|
32ce032655 | ||
|
|
e1cf36aa3c | ||
|
|
f644396a15 | ||
|
|
3e77c34bd5 | ||
|
|
052c60f629 | ||
|
|
a1f2e3e7fe | ||
|
|
32ee8b326f | ||
|
|
06ce479eb6 | ||
|
|
03f74bac64 | ||
|
|
344b675745 | ||
|
|
86590d95a5 | ||
|
|
bbea1341b2 | ||
|
|
ca60dd9834 | ||
|
|
7aa35b5b8c | ||
|
|
bd2decdb8f | ||
|
|
9b2c85bcae | ||
|
|
efbab7c43a | ||
|
|
729a8a8263 | ||
|
|
0ec29f62ca | ||
|
|
796317f9d9 | ||
|
|
7596dcc7cd | ||
|
|
422851cdab | ||
|
|
ec0a2a47f1 | ||
|
|
8ce5b947f6 | ||
|
|
419ca63f9d | ||
|
|
6fdb0c7b0e | ||
|
|
4e97b4b898 | ||
|
|
1766dcbdeb | ||
|
|
ef38471ff1 | ||
|
|
217a7993e9 | ||
|
|
0a41615763 | ||
|
|
9d34f668d5 | ||
|
|
9269a36725 | ||
|
|
813e8b10a6 | ||
|
|
84c75fadf5 | ||
|
|
c76e41b1ab | ||
|
|
fefeea5f35 | ||
|
|
4a81c461e8 | ||
|
|
b10d03d50d | ||
|
|
da98a0c5b8 | ||
|
|
76d17bacf5 | ||
|
|
6678ce082b | ||
|
|
07074b3deb | ||
|
|
df5d9f90d4 | ||
|
|
4f2d30552a | ||
|
|
d259c7a5cd | ||
|
|
c71ceb7ea6 | ||
|
|
85cf134a49 | ||
|
|
687b1d3a0d | ||
|
|
a30a0d0bc5 | ||
|
|
e1dc54d6d7 | ||
|
|
c4270e186d | ||
|
|
182a42ace2 | ||
|
|
06fbe69a97 | ||
|
|
a0bf4f9acd | ||
|
|
12568ba044 | ||
|
|
de95b02285 | ||
|
|
286edfe72c | ||
|
|
d717b223b7 | ||
|
|
9e195832ef | ||
|
|
c8d08b2793 | ||
|
|
2bcd9662be | ||
|
|
ea461ee3d2 | ||
|
|
fda821b441 | ||
|
|
5c193c761a | ||
|
|
14f47c6d30 | ||
|
|
e53eacef78 | ||
|
|
ada26db659 | ||
|
|
48ca96807f | ||
|
|
2018028853 | ||
|
|
6f138dcc05 | ||
|
|
69bcd2be67 | ||
|
|
45ad53b19a | ||
|
|
6230240ee3 | ||
|
|
73ec9f4bee | ||
|
|
f3a0bf505e | ||
|
|
290708876d | ||
|
|
5b96a29cca | ||
|
|
948e2c4d92 | ||
|
|
76da1c33ae | ||
|
|
72b84ee24d | ||
|
|
7b33d41172 | ||
|
|
c7043c1a83 | ||
|
|
d0baf26c61 | ||
|
|
60ac10b043 | ||
|
|
80dc24b487 | ||
|
|
9d32a9dd6a | ||
|
|
d96cc3c762 | ||
|
|
509df42730 | ||
|
|
4efa5b0507 | ||
|
|
cffe96b409 | ||
|
|
16dddc01e3 | ||
|
|
b5d2c2cadb | ||
|
|
1d2c0ab6cb | ||
|
|
c6b7e04c47 | ||
|
|
5704813b28 | ||
|
|
465c989e75 | ||
|
|
d335aaef9e | ||
|
|
495b48c783 | ||
|
|
05b55722fb | ||
|
|
de54257eef | ||
|
|
e62b6c3d77 | ||
|
|
dc05e5b5eb | ||
|
|
f377381e26 | ||
|
|
20f9fe493f | ||
|
|
0b462754a5 | ||
|
|
b1ea8dd346 | ||
|
|
4a46f897bd | ||
|
|
6a5ec80de7 | ||
|
|
4f2046d412 | ||
|
|
1cf59e8d67 | ||
|
|
e9e8390bbc | ||
|
|
738b084440 | ||
|
|
32cce894ac | ||
|
|
a6264b39d1 | ||
|
|
eb4981808b | ||
|
|
50c17c2ec4 | ||
|
|
e001dff3de | ||
|
|
3a0100ed37 | ||
|
|
58ab3116db | ||
|
|
6b93df41f2 | ||
|
|
b9cf7d5874 | ||
|
|
da4eb15d6b | ||
|
|
378840bc1b | ||
|
|
3441135b2f | ||
|
|
afcbba8182 | ||
|
|
cefdf08873 | ||
|
|
59be547a82 | ||
|
|
a2be5ebdac | ||
|
|
f76d3d8fcd | ||
|
|
edb6256fc9 | ||
|
|
8946a4fba5 | ||
|
|
87e1739208 | ||
|
|
10f4aaa39f | ||
|
|
957073b041 | ||
|
|
e1bb9a6cf0 | ||
|
|
558adb0b66 | ||
|
|
6a4979f999 | ||
|
|
9e76d94eea | ||
|
|
fa91820016 | ||
|
|
be091ecebb | ||
|
|
903be743ac | ||
|
|
c3c4697562 | ||
|
|
e6ed312de2 | ||
|
|
33461e068f | ||
|
|
7f13c90189 | ||
|
|
54ed3971a2 | ||
|
|
e602a5cf3b | ||
|
|
dec0a22ffe | ||
|
|
911272167a | ||
|
|
54d78d55a0 | ||
|
|
ff550b457f | ||
|
|
f449d7a8ab | ||
|
|
761579ab1a | ||
|
|
5cd4cf67cf | ||
|
|
fabfc77a52 | ||
|
|
f8ffaa0400 | ||
|
|
d156b5d947 | ||
|
|
d7551bdeb2 | ||
|
|
7d5e06bce4 | ||
|
|
0bc17f0ff5 | ||
|
|
9edc268cd4 | ||
|
|
356d5fa8a4 | ||
|
|
eb170d4f34 | ||
|
|
324c5ec7a2 | ||
|
|
ae155ca603 | ||
|
|
eb13585174 | ||
|
|
98c9eea58a | ||
|
|
067517740f | ||
|
|
3addb0e894 | ||
|
|
7452d4275e | ||
|
|
96ea522e83 | ||
|
|
ab24f049cf | ||
|
|
ec9184ba93 | ||
|
|
0a5b866a03 | ||
|
|
58d5a3fc37 | ||
|
|
19534ebb4d | ||
|
|
0a764c74d6 | ||
|
|
ab5f5fbd9d | ||
|
|
7dbc2ff95d | ||
|
|
bfaa207853 | ||
|
|
8c749e21e1 | ||
|
|
8ea998b81f | ||
|
|
b93866d196 | ||
|
|
c0a5a7a5dd | ||
|
|
6d68f2bde5 | ||
|
|
a89fd049f1 | ||
|
|
e7c5976f7c | ||
|
|
798a63e33c | ||
|
|
e13b4489c3 | ||
|
|
c6484ba77e | ||
|
|
a98fd52831 | ||
|
|
9d3cae8b28 | ||
|
|
f5aef9486f | ||
|
|
c2ae9e63e0 | ||
|
|
b04cdbf12b | ||
|
|
1f897cf431 | ||
|
|
d380c38710 | ||
|
|
3cd6126ed9 | ||
|
|
22b2d472bc | ||
|
|
2c58fae804 | ||
|
|
1e9b8037ab | ||
|
|
0dbd5b52f0 | ||
|
|
21a8d7ef49 | ||
|
|
17bd7a210a | ||
|
|
40b191f039 | ||
|
|
3442b39784 | ||
|
|
f15ee038b4 | ||
|
|
ec8b41155a | ||
|
|
d54bfbdfe7 | ||
|
|
a1f491af25 | ||
|
|
f2b041741b | ||
|
|
97169ff6dd | ||
|
|
11019a8473 | ||
|
|
767e4d0bf6 | ||
|
|
250856598b | ||
|
|
61751eeb1b | ||
|
|
99651a5d77 | ||
|
|
b31614641d | ||
|
|
310c165824 | ||
|
|
a233af5b8f | ||
|
|
2d0278db87 | ||
|
|
18af0a8856 | ||
|
|
d7d56b4ad8 | ||
|
|
3034dbc392 | ||
|
|
0b508509af | ||
|
|
14ad9431b9 | ||
|
|
c9a98d7163 | ||
|
|
afae830ece | ||
|
|
ec8c3e71d6 | ||
|
|
a7c5330042 | ||
|
|
10f02af70b | ||
|
|
2fd2b71148 | ||
|
|
d1bec6a672 | ||
|
|
9336613755 | ||
|
|
9f482b7cf9 | ||
|
|
0c8fcb07b1 | ||
|
|
eb302be569 | ||
|
|
cb3cf2a5ea | ||
|
|
9e5a06c107 | ||
|
|
b49d5bdeb4 | ||
|
|
0c23548817 | ||
|
|
cdaeb36e06 | ||
|
|
114073f359 | ||
|
|
959a1a65b9 | ||
|
|
3e59a78376 | ||
|
|
2bd4729fe7 | ||
|
|
84054428a8 | ||
|
|
9ad063bd0a | ||
|
|
9d1fd2f945 | ||
|
|
35edb9d391 | ||
|
|
d523862fac | ||
|
|
21ff88c890 | ||
|
|
e034ac5c1e | ||
|
|
adf39dde27 | ||
|
|
9b1e3435d6 | ||
|
|
66a2dbe730 | ||
|
|
28a3b6cb23 | ||
|
|
2adda81b28 | ||
|
|
380afbf295 | ||
|
|
d39e24246e | ||
|
|
a3e430d98d | ||
|
|
e0dcd6ac10 | ||
|
|
02f8d46620 | ||
|
|
dc6b9748a3 | ||
|
|
54c2bdc728 | ||
|
|
18275557df | ||
|
|
453f6b6e36 | ||
|
|
7236136cf1 | ||
|
|
ac6bd5236e | ||
|
|
b2acf9a2a7 | ||
|
|
7a8ac79ec4 | ||
|
|
70c9d0edb3 | ||
|
|
18e934dd7e | ||
|
|
3457d4d22c | ||
|
|
f65514b320 | ||
|
|
0a0b172a09 | ||
|
|
3e2d0935b8 | ||
|
|
71c633b506 | ||
|
|
79af119cf4 | ||
|
|
9385b4da76 | ||
|
|
75985c8bf0 | ||
|
|
9c8601a665 | ||
|
|
8218662548 | ||
|
|
52ba354dc5 | ||
|
|
87d6a26232 | ||
|
|
546fe52ff0 | ||
|
|
674c634c2c | ||
|
|
a3c92ddb8f | ||
|
|
4bcc16245c | ||
|
|
bd5eb3be5d | ||
|
|
ffda15a1a5 | ||
|
|
5354506315 | ||
|
|
ed569bfaf8 | ||
|
|
592bfb64e7 | ||
|
|
17b986f5df | ||
|
|
de464dfe10 | ||
|
|
906149a58a | ||
|
|
e3a0ab4e4a | ||
|
|
500f7788d4 | ||
|
|
af80b270cf | ||
|
|
8031d1a03f | ||
|
|
bc2469e11a | ||
|
|
9e4be3e082 | ||
|
|
7410511c40 | ||
|
|
8906c856e8 | ||
|
|
dec672f9e2 | ||
|
|
0b111d5f79 | ||
|
|
4bcbdbc57d | ||
|
|
d5d937247e | ||
|
|
4ab513002f | ||
|
|
140a732046 | ||
|
|
e5104d5cc7 | ||
|
|
f87390cc2b | ||
|
|
a062905734 | ||
|
|
62206f8977 | ||
|
|
8891414f60 | ||
|
|
90dce1c17d | ||
|
|
a9f1bd320e | ||
|
|
c8393e165f | ||
|
|
9d7c3b9f64 | ||
|
|
aa653cd508 | ||
|
|
3d60c5a7f6 | ||
|
|
4ef160de34 | ||
|
|
8f7def379d | ||
|
|
351228e45c | ||
|
|
ee6c050330 | ||
|
|
b4ce12a9e8 | ||
|
|
8664531c47 | ||
|
|
40f6dbcc06 | ||
|
|
1f21a67610 | ||
|
|
929781a380 | ||
|
|
4d85c7f665 | ||
|
|
7e67f354e4 | ||
|
|
0cd8d51526 | ||
|
|
6f2c4521b2 | ||
|
|
738e7d3785 | ||
|
|
fc44ba373b | ||
|
|
468976db58 | ||
|
|
647ce56f81 | ||
|
|
db92daedf0 | ||
|
|
6969412385 | ||
|
|
8da4c4623f | ||
|
|
50265c1d57 | ||
|
|
c00da37267 | ||
|
|
17d2140909 | ||
|
|
40153f6f19 | ||
|
|
e75b9858da | ||
|
|
1f69f476f9 | ||
|
|
b2ecc65885 | ||
|
|
682ef4552e | ||
|
|
96c7aaabb0 | ||
|
|
38f1f068d2 | ||
|
|
0359169802 | ||
|
|
a49d409619 | ||
|
|
7e6ef31875 | ||
|
|
5dd9f31398 | ||
|
|
120c3e235d | ||
|
|
3a6ebf7ce6 | ||
|
|
9d505c8900 | ||
|
|
d0486d855a | ||
|
|
7ddbf3ce3e | ||
|
|
4666b378b3 | ||
|
|
2a7d40616d | ||
|
|
96b8732d91 | ||
|
|
e19ecf4770 | ||
|
|
df45fa9b8e | ||
|
|
bd7a43f0dc | ||
|
|
01f1d7c14e | ||
|
|
cc74130ad4 | ||
|
|
dc8990115a | ||
|
|
1c777aa1a8 | ||
|
|
6d019e6e8a | ||
|
|
2d7fd68ff5 | ||
|
|
cdfc9cf2e6 | ||
|
|
6e3c808799 | ||
|
|
1ecf4c8c27 | ||
|
|
3dea2936d7 | ||
|
|
e4533b4ec3 | ||
|
|
9d87fead21 | ||
|
|
14bd7f9789 | ||
|
|
d02a4ea02e | ||
|
|
14829c5e1b | ||
|
|
ef29d220e0 | ||
|
|
14ec7c8259 | ||
|
|
9687f823fb | ||
|
|
bb36839774 | ||
|
|
b0114520a8 | ||
|
|
8a3af0bfba | ||
|
|
65a13e97c4 | ||
|
|
fe6b7760b0 | ||
|
|
b319e92b3e | ||
|
|
06b8fcea64 | ||
|
|
100238d232 | ||
|
|
df3e5b31cd | ||
|
|
a04c0d0223 | ||
|
|
d1ec1c29a4 | ||
|
|
a928660dd3 | ||
|
|
e37a04e05b | ||
|
|
2c721272dd | ||
|
|
6f3b438d92 | ||
|
|
f8e7303169 | ||
|
|
bd18bfb8ea | ||
|
|
86843f81da | ||
|
|
60cc81b2dd | ||
|
|
cfbcdecfe6 | ||
|
|
45b9b781b1 | ||
|
|
29068481f5 | ||
|
|
384dd2e4e3 | ||
|
|
b4bce77381 | ||
|
|
631f2e7027 | ||
|
|
2585be69f9 | ||
|
|
332e4cc6e2 | ||
|
|
16ed347a30 | ||
|
|
b580b293f3 | ||
|
|
66b9b46523 | ||
|
|
2357e55337 | ||
|
|
256eeb8f7c | ||
|
|
5688f03869 | ||
|
|
c2f7f0a92d | ||
|
|
0ad6e6a456 | ||
|
|
fff759fe72 | ||
|
|
7e7397ab7e | ||
|
|
86e30c5dc0 | ||
|
|
2e8ef2a403 | ||
|
|
7456f9b106 | ||
|
|
3b7b88be57 | ||
|
|
05fd0588e8 | ||
|
|
f60f7ac413 | ||
|
|
344f69fddc | ||
|
|
dc5691aefc | ||
|
|
797216fed4 | ||
|
|
4899d6d7d0 | ||
|
|
8637c31311 | ||
|
|
ac33fd5ab8 | ||
|
|
8ccfbcf66a | ||
|
|
2e84b08494 | ||
|
|
08bf84146b | ||
|
|
fbfdb789f5 | ||
|
|
dcde8902f1 | ||
|
|
d079368acf | ||
|
|
92426fa585 | ||
|
|
248063276d | ||
|
|
d61f1ac676 | ||
|
|
1f1a8c5956 | ||
|
|
4b8b8fb8ea | ||
|
|
0df3b54499 | ||
|
|
cc3b08fea5 | ||
|
|
4eebbaa5ef | ||
|
|
a831456242 | ||
|
|
88d78e5166 | ||
|
|
f7948e58b4 | ||
|
|
aeccee3fbc | ||
|
|
f8476e4f4e | ||
|
|
ff23e633ee | ||
|
|
0e726919cc | ||
|
|
6f5bf443ae | ||
|
|
4a364c4ffc | ||
|
|
56825b5e48 | ||
|
|
ff144b41eb | ||
|
|
03b2ab97d6 | ||
|
|
63bc2ca970 | ||
|
|
3f54abaa45 | ||
|
|
d7a5a44d41 |
170
.gitignore
vendored
170
.gitignore
vendored
@@ -1,7 +1,10 @@
|
||||
## 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
|
||||
@@ -17,13 +20,20 @@
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
build/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
|
||||
# Visual Studio 2015 cache/options directory
|
||||
# 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*/
|
||||
@@ -38,18 +48,28 @@ TestResult.xml
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# DNX
|
||||
# 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
|
||||
*_i.h
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
@@ -59,6 +79,7 @@ artifacts/
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
@@ -74,14 +95,21 @@ _Chutzpah*
|
||||
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/
|
||||
@@ -103,9 +131,18 @@ _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.*
|
||||
@@ -133,47 +170,68 @@ publish/
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
## TODO: Comment the next line if you want to checkin your
|
||||
## web deploy settings but do note that will include unencrypted
|
||||
## passwords
|
||||
#*.pubxml
|
||||
|
||||
# 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
|
||||
**/packages/*
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/packages/build/
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/packages/repositories.config
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Windows Azure Build Output
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Windows Store app package directory
|
||||
# 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/
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
[Ss]tyle[Cc]op.*
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
node_modules/
|
||||
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/
|
||||
|
||||
@@ -184,21 +242,30 @@ _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
|
||||
@@ -206,7 +273,68 @@ FakesAssemblies/
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# LightSwitch generated files
|
||||
GeneratedArtifacts/
|
||||
_Pvt_Extensions/
|
||||
ModelManifest.xml
|
||||
# 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
|
||||
17
AssetStudio.PInvoke/AssetStudio.PInvoke.csproj
Normal file
17
AssetStudio.PInvoke/AssetStudio.PInvoke.csproj
Normal file
@@ -0,0 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472;netstandard2.0</TargetFrameworks>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Version>0.16.8.1</Version>
|
||||
<AssemblyVersion>0.16.8.1</AssemblyVersion>
|
||||
<FileVersion>0.16.8.1</FileVersion>
|
||||
<Copyright>Copyright © Perfare 2020-2021; Copyright © hozuki 2020</Copyright>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net472|AnyCPU'">
|
||||
<DebugType>none</DebugType>
|
||||
<DebugSymbols>false</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
124
AssetStudio.PInvoke/DllLoader.cs
Normal file
124
AssetStudio.PInvoke/DllLoader.cs
Normal file
@@ -0,0 +1,124 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace AssetStudio.PInvoke
|
||||
{
|
||||
public static class DllLoader
|
||||
{
|
||||
|
||||
public static void PreloadDll(string dllName)
|
||||
{
|
||||
var dllDir = GetDirectedDllDirectory();
|
||||
|
||||
// Not using OperatingSystem.Platform.
|
||||
// See: https://www.mono-project.com/docs/faq/technical/#how-to-detect-the-execution-platform
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
Win32.LoadDll(dllDir, dllName);
|
||||
}
|
||||
else
|
||||
{
|
||||
Posix.LoadDll(dllDir, dllName);
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetDirectedDllDirectory()
|
||||
{
|
||||
var localPath = Process.GetCurrentProcess().MainModule.FileName;
|
||||
var localDir = Path.GetDirectoryName(localPath);
|
||||
|
||||
var subDir = Environment.Is64BitProcess ? "x64" : "x86";
|
||||
|
||||
var directedDllDir = Path.Combine(localDir, subDir);
|
||||
|
||||
return directedDllDir;
|
||||
}
|
||||
|
||||
private static class Win32
|
||||
{
|
||||
|
||||
internal static void LoadDll(string dllDir, string dllName)
|
||||
{
|
||||
var dllFileName = $"{dllName}.dll";
|
||||
var directedDllPath = Path.Combine(dllDir, dllFileName);
|
||||
|
||||
// Specify SEARCH_DLL_LOAD_DIR to load dependent libraries located in the same platform-specific directory.
|
||||
var hLibrary = LoadLibraryEx(directedDllPath, IntPtr.Zero, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR);
|
||||
|
||||
if (hLibrary == IntPtr.Zero)
|
||||
{
|
||||
var errorCode = Marshal.GetLastWin32Error();
|
||||
var exception = new Win32Exception(errorCode);
|
||||
|
||||
throw new DllNotFoundException(exception.Message, exception);
|
||||
}
|
||||
}
|
||||
|
||||
// HMODULE LoadLibraryExA(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags);
|
||||
// HMODULE LoadLibraryExW(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags);
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
private static extern IntPtr LoadLibraryEx(string lpLibFileName, IntPtr hFile, uint dwFlags);
|
||||
|
||||
private const uint LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x1000;
|
||||
private const uint LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR = 0x100;
|
||||
|
||||
}
|
||||
|
||||
private static class Posix
|
||||
{
|
||||
|
||||
internal static void LoadDll(string dllDir, string dllName)
|
||||
{
|
||||
string dllExtension;
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
dllExtension = ".so";
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
dllExtension = ".dylib";
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
var dllFileName = $"lib{dllName}{dllExtension}";
|
||||
var directedDllPath = Path.Combine(dllDir, dllFileName);
|
||||
|
||||
const int ldFlags = RTLD_NOW | RTLD_GLOBAL;
|
||||
var hLibrary = DlOpen(directedDllPath, ldFlags);
|
||||
|
||||
if (hLibrary == IntPtr.Zero)
|
||||
{
|
||||
var pErrStr = DlError();
|
||||
// `PtrToStringAnsi` always uses the specific constructor of `String` (see dotnet/core#2325),
|
||||
// which in turn interprets the byte sequence with system default codepage. On OSX and Linux
|
||||
// the codepage is UTF-8 so the error message should be handled correctly.
|
||||
var errorMessage = Marshal.PtrToStringAnsi(pErrStr);
|
||||
|
||||
throw new DllNotFoundException(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
// OSX and most Linux OS use LP64 so `int` is still 32-bit even on 64-bit platforms.
|
||||
// void *dlopen(const char *filename, int flag);
|
||||
[DllImport("libdl", EntryPoint = "dlopen")]
|
||||
private static extern IntPtr DlOpen([MarshalAs(UnmanagedType.LPStr)] string fileName, int flags);
|
||||
|
||||
// char *dlerror(void);
|
||||
[DllImport("libdl", EntryPoint = "dlerror")]
|
||||
private static extern IntPtr DlError();
|
||||
|
||||
private const int RTLD_LAZY = 0x1;
|
||||
private const int RTLD_NOW = 0x2;
|
||||
private const int RTLD_GLOBAL = 0x100;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
100
AssetStudio.PInvoke/Utf8StringHandle.cs
Normal file
100
AssetStudio.PInvoke/Utf8StringHandle.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace AssetStudio.PInvoke
|
||||
{
|
||||
// Generally the technique from Steamworks.NET
|
||||
public class Utf8StringHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
{
|
||||
|
||||
static Utf8StringHandle()
|
||||
{
|
||||
Utf8 = new UTF8Encoding(false);
|
||||
}
|
||||
|
||||
public Utf8StringHandle(string str)
|
||||
: base(true)
|
||||
{
|
||||
IntPtr buffer;
|
||||
|
||||
if (str == null)
|
||||
{
|
||||
buffer = IntPtr.Zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (str.Length == 0)
|
||||
{
|
||||
buffer = Marshal.AllocHGlobal(1);
|
||||
|
||||
unsafe
|
||||
{
|
||||
*(byte*)buffer = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var strlen = Utf8.GetByteCount(str);
|
||||
var strBuffer = new byte[strlen + 1];
|
||||
|
||||
Utf8.GetBytes(str, 0, str.Length, strBuffer, 0);
|
||||
|
||||
buffer = Marshal.AllocHGlobal(strBuffer.Length);
|
||||
|
||||
Marshal.Copy(strBuffer, 0, buffer, strBuffer.Length);
|
||||
}
|
||||
}
|
||||
|
||||
SetHandle(buffer);
|
||||
}
|
||||
|
||||
public static string ReadUtf8StringFromPointer(IntPtr lpstr)
|
||||
{
|
||||
if (lpstr == IntPtr.Zero || lpstr == new IntPtr(-1))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var byteCount = 0;
|
||||
|
||||
unsafe
|
||||
{
|
||||
var p = (byte*)lpstr.ToPointer();
|
||||
|
||||
while (*p != 0)
|
||||
{
|
||||
byteCount += 1;
|
||||
p += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (byteCount == 0)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var strBuffer = new byte[byteCount];
|
||||
|
||||
Marshal.Copy(lpstr, strBuffer, 0, byteCount);
|
||||
|
||||
var str = Utf8.GetString(strBuffer);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
if (!IsInvalid)
|
||||
{
|
||||
Marshal.FreeHGlobal(handle);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static readonly UTF8Encoding Utf8;
|
||||
|
||||
}
|
||||
}
|
||||
141
AssetStudio.sln
Normal file
141
AssetStudio.sln
Normal file
@@ -0,0 +1,141 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.31410.357
|
||||
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
|
||||
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
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {3C074481-9CDD-4780-B9F6-57BBC5092EA2}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace SevenZip
|
||||
{
|
||||
class CRC
|
||||
public class CRC
|
||||
{
|
||||
public static readonly uint[] Table;
|
||||
|
||||
16
AssetStudio/AssetStudio.csproj
Normal file
16
AssetStudio/AssetStudio.csproj
Normal file
@@ -0,0 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472;netstandard2.0</TargetFrameworks>
|
||||
<Version>0.16.8.1</Version>
|
||||
<AssemblyVersion>0.16.8.1</AssemblyVersion>
|
||||
<FileVersion>0.16.8.1</FileVersion>
|
||||
<Copyright>Copyright © Perfare 2018-2021</Copyright>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net472|AnyCPU'">
|
||||
<DebugType>none</DebugType>
|
||||
<DebugSymbols>false</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
442
AssetStudio/AssetsManager.cs
Normal file
442
AssetStudio/AssetsManager.cs
Normal file
@@ -0,0 +1,442 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using static AssetStudio.ImportHelper;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class AssetsManager
|
||||
{
|
||||
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)
|
||||
{
|
||||
var path = Path.GetDirectoryName(files[0]);
|
||||
MergeSplitAssets(path);
|
||||
var toReadFile = ProcessingSplitFiles(files.ToList());
|
||||
Load(toReadFile);
|
||||
}
|
||||
|
||||
public void LoadFolder(string path)
|
||||
{
|
||||
MergeSplitAssets(path, true);
|
||||
var files = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories).ToList();
|
||||
var toReadFile = ProcessingSplitFiles(files);
|
||||
Load(toReadFile);
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
ReadAssets();
|
||||
ProcessAssets();
|
||||
}
|
||||
|
||||
private void LoadFile(string fullName)
|
||||
{
|
||||
var reader = new FileReader(fullName);
|
||||
LoadFile(reader);
|
||||
}
|
||||
|
||||
private void LoadFile(FileReader reader)
|
||||
{
|
||||
switch (reader.FileType)
|
||||
{
|
||||
case FileType.AssetsFile:
|
||||
LoadAssetsFile(reader);
|
||||
break;
|
||||
case FileType.BundleFile:
|
||||
LoadBundleFile(reader);
|
||||
break;
|
||||
case FileType.WebFile:
|
||||
LoadWebFile(reader);
|
||||
break;
|
||||
case FileType.GZipFile:
|
||||
LoadFile(DecompressGZip(reader));
|
||||
break;
|
||||
case FileType.BrotliFile:
|
||||
LoadFile(DecompressBrotli(reader));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadAssetsFile(FileReader reader)
|
||||
{
|
||||
if (!assetsFileListHash.Contains(reader.FileName))
|
||||
{
|
||||
Logger.Info($"Loading {reader.FileName}");
|
||||
try
|
||||
{
|
||||
var assetsFile = new SerializedFile(reader, this);
|
||||
CheckStrippedVersion(assetsFile);
|
||||
assetsFileList.Add(assetsFile);
|
||||
assetsFileListHash.Add(assetsFile.fileName);
|
||||
|
||||
foreach (var sharedFile in assetsFile.m_Externals)
|
||||
{
|
||||
var sharedFileName = sharedFile.fileName;
|
||||
|
||||
if (!importFilesHash.Contains(sharedFileName))
|
||||
{
|
||||
var sharedFilePath = Path.Combine(Path.GetDirectoryName(reader.FullPath), sharedFileName);
|
||||
if (!File.Exists(sharedFilePath))
|
||||
{
|
||||
var findFiles = Directory.GetFiles(Path.GetDirectoryName(reader.FullPath), sharedFileName, SearchOption.AllDirectories);
|
||||
if (findFiles.Length > 0)
|
||||
{
|
||||
sharedFilePath = findFiles[0];
|
||||
}
|
||||
}
|
||||
|
||||
if (File.Exists(sharedFilePath))
|
||||
{
|
||||
importFiles.Add(sharedFilePath);
|
||||
importFilesHash.Add(sharedFileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error($"Error while reading assets file {reader.FileName}", e);
|
||||
reader.Dispose();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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.kUnknown_7)
|
||||
{
|
||||
assetsFile.SetVersion(unityVersion);
|
||||
}
|
||||
CheckStrippedVersion(assetsFile);
|
||||
assetsFileList.Add(assetsFile);
|
||||
assetsFileListHash.Add(assetsFile.fileName);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error($"Error while reading assets file {reader.FileName} from {Path.GetFileName(originalPath)}", e);
|
||||
resourceFileReaders.Add(reader.FileName, reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadBundleFile(FileReader reader, string originalPath = null)
|
||||
{
|
||||
Logger.Info("Loading " + reader.FileName);
|
||||
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 if (!resourceFileReaders.ContainsKey(file.fileName))
|
||||
{
|
||||
resourceFileReaders.Add(file.fileName, subReader);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var str = $"Error while reading bundle file {reader.FileName}";
|
||||
if (originalPath != null)
|
||||
{
|
||||
str += $" from {Path.GetFileName(originalPath)}";
|
||||
}
|
||||
Logger.Error(str, e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
reader.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadWebFile(FileReader reader)
|
||||
{
|
||||
Logger.Info("Loading " + reader.FileName);
|
||||
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.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.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:
|
||||
obj = new MeshRenderer(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:
|
||||
obj = new Shader(objectReader);
|
||||
break;
|
||||
case ClassIDType.SkinnedMeshRenderer:
|
||||
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($"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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
271
AssetStudio/Brotli/BitReader.cs
Normal file
271
AssetStudio/Brotli/BitReader.cs
Normal file
@@ -0,0 +1,271 @@
|
||||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>Bit reading helpers.</summary>
|
||||
internal sealed class BitReader
|
||||
{
|
||||
/// <summary>
|
||||
/// Input byte buffer, consist of a ring-buffer and a "slack" region where bytes from the start of
|
||||
/// the ring-buffer are copied.
|
||||
/// </summary>
|
||||
private const int Capacity = 1024;
|
||||
|
||||
private const int Slack = 16;
|
||||
|
||||
private const int IntBufferSize = Capacity + Slack;
|
||||
|
||||
private const int ByteReadSize = Capacity << 2;
|
||||
|
||||
private const int ByteBufferSize = IntBufferSize << 2;
|
||||
|
||||
private readonly byte[] byteBuffer = new byte[ByteBufferSize];
|
||||
|
||||
private readonly int[] intBuffer = new int[IntBufferSize];
|
||||
|
||||
private readonly Org.Brotli.Dec.IntReader intReader = new Org.Brotli.Dec.IntReader();
|
||||
|
||||
private System.IO.Stream input;
|
||||
|
||||
/// <summary>Input stream is finished.</summary>
|
||||
private bool endOfStreamReached;
|
||||
|
||||
/// <summary>Pre-fetched bits.</summary>
|
||||
internal long accumulator;
|
||||
|
||||
/// <summary>Current bit-reading position in accumulator.</summary>
|
||||
internal int bitOffset;
|
||||
|
||||
/// <summary>Offset of next item in intBuffer.</summary>
|
||||
private int intOffset;
|
||||
|
||||
private int tailBytes = 0;
|
||||
|
||||
/* Number of bytes in unfinished "int" item. */
|
||||
/// <summary>Fills up the input buffer.</summary>
|
||||
/// <remarks>
|
||||
/// Fills up the input buffer.
|
||||
/// <p> No-op if there are at least 36 bytes present after current position.
|
||||
/// <p> After encountering the end of the input stream, 64 additional zero bytes are copied to the
|
||||
/// buffer.
|
||||
/// </remarks>
|
||||
internal static void ReadMoreInput(Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
// TODO: Split to check and read; move read outside of decoding loop.
|
||||
if (br.intOffset <= Capacity - 9)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (br.endOfStreamReached)
|
||||
{
|
||||
if (IntAvailable(br) >= -2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("No more input");
|
||||
}
|
||||
int readOffset = br.intOffset << 2;
|
||||
int bytesRead = ByteReadSize - readOffset;
|
||||
System.Array.Copy(br.byteBuffer, readOffset, br.byteBuffer, 0, bytesRead);
|
||||
br.intOffset = 0;
|
||||
try
|
||||
{
|
||||
while (bytesRead < ByteReadSize)
|
||||
{
|
||||
int len = br.input.Read(br.byteBuffer, bytesRead, ByteReadSize - bytesRead);
|
||||
// EOF is -1 in Java, but 0 in C#.
|
||||
if (len <= 0)
|
||||
{
|
||||
br.endOfStreamReached = true;
|
||||
br.tailBytes = bytesRead;
|
||||
bytesRead += 3;
|
||||
break;
|
||||
}
|
||||
bytesRead += len;
|
||||
}
|
||||
}
|
||||
catch (System.IO.IOException e)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Failed to read input", e);
|
||||
}
|
||||
Org.Brotli.Dec.IntReader.Convert(br.intReader, bytesRead >> 2);
|
||||
}
|
||||
|
||||
internal static void CheckHealth(Org.Brotli.Dec.BitReader br, bool endOfStream)
|
||||
{
|
||||
if (!br.endOfStreamReached)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int byteOffset = (br.intOffset << 2) + ((br.bitOffset + 7) >> 3) - 8;
|
||||
if (byteOffset > br.tailBytes)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Read after end");
|
||||
}
|
||||
if (endOfStream && (byteOffset != br.tailBytes))
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Unused bytes after end");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Advances the Read buffer by 5 bytes to make room for reading next 24 bits.</summary>
|
||||
internal static void FillBitWindow(Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
if (br.bitOffset >= 32)
|
||||
{
|
||||
br.accumulator = ((long)br.intBuffer[br.intOffset++] << 32) | ((long)(((ulong)br.accumulator) >> 32));
|
||||
br.bitOffset -= 32;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Reads the specified number of bits from Read Buffer.</summary>
|
||||
internal static int ReadBits(Org.Brotli.Dec.BitReader br, int n)
|
||||
{
|
||||
FillBitWindow(br);
|
||||
int val = (int)((long)(((ulong)br.accumulator) >> br.bitOffset)) & ((1 << n) - 1);
|
||||
br.bitOffset += n;
|
||||
return val;
|
||||
}
|
||||
|
||||
/// <summary>Initialize bit reader.</summary>
|
||||
/// <remarks>
|
||||
/// Initialize bit reader.
|
||||
/// <p> Initialisation turns bit reader to a ready state. Also a number of bytes is prefetched to
|
||||
/// accumulator. Because of that this method may block until enough data could be read from input.
|
||||
/// </remarks>
|
||||
/// <param name="br">BitReader POJO</param>
|
||||
/// <param name="input">data source</param>
|
||||
internal static void Init(Org.Brotli.Dec.BitReader br, System.IO.Stream input)
|
||||
{
|
||||
if (br.input != null)
|
||||
{
|
||||
throw new System.InvalidOperationException("Bit reader already has associated input stream");
|
||||
}
|
||||
Org.Brotli.Dec.IntReader.Init(br.intReader, br.byteBuffer, br.intBuffer);
|
||||
br.input = input;
|
||||
br.accumulator = 0;
|
||||
br.bitOffset = 64;
|
||||
br.intOffset = Capacity;
|
||||
br.endOfStreamReached = false;
|
||||
Prepare(br);
|
||||
}
|
||||
|
||||
private static void Prepare(Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
ReadMoreInput(br);
|
||||
CheckHealth(br, false);
|
||||
FillBitWindow(br);
|
||||
FillBitWindow(br);
|
||||
}
|
||||
|
||||
internal static void Reload(Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
if (br.bitOffset == 64)
|
||||
{
|
||||
Prepare(br);
|
||||
}
|
||||
}
|
||||
|
||||
/// <exception cref="System.IO.IOException"/>
|
||||
internal static void Close(Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
System.IO.Stream @is = br.input;
|
||||
br.input = null;
|
||||
if (@is != null)
|
||||
{
|
||||
@is.Close();
|
||||
}
|
||||
}
|
||||
|
||||
internal static void JumpToByteBoundary(Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
int padding = (64 - br.bitOffset) & 7;
|
||||
if (padding != 0)
|
||||
{
|
||||
int paddingBits = Org.Brotli.Dec.BitReader.ReadBits(br, padding);
|
||||
if (paddingBits != 0)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Corrupted padding bits");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static int IntAvailable(Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
int limit = Capacity;
|
||||
if (br.endOfStreamReached)
|
||||
{
|
||||
limit = (br.tailBytes + 3) >> 2;
|
||||
}
|
||||
return limit - br.intOffset;
|
||||
}
|
||||
|
||||
internal static void CopyBytes(Org.Brotli.Dec.BitReader br, byte[] data, int offset, int length)
|
||||
{
|
||||
if ((br.bitOffset & 7) != 0)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Unaligned copyBytes");
|
||||
}
|
||||
// Drain accumulator.
|
||||
while ((br.bitOffset != 64) && (length != 0))
|
||||
{
|
||||
data[offset++] = unchecked((byte)((long)(((ulong)br.accumulator) >> br.bitOffset)));
|
||||
br.bitOffset += 8;
|
||||
length--;
|
||||
}
|
||||
if (length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Get data from shadow buffer with "sizeof(int)" granularity.
|
||||
int copyInts = System.Math.Min(IntAvailable(br), length >> 2);
|
||||
if (copyInts > 0)
|
||||
{
|
||||
int readOffset = br.intOffset << 2;
|
||||
System.Array.Copy(br.byteBuffer, readOffset, data, offset, copyInts << 2);
|
||||
offset += copyInts << 2;
|
||||
length -= copyInts << 2;
|
||||
br.intOffset += copyInts;
|
||||
}
|
||||
if (length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Read tail bytes.
|
||||
if (IntAvailable(br) > 0)
|
||||
{
|
||||
// length = 1..3
|
||||
FillBitWindow(br);
|
||||
while (length != 0)
|
||||
{
|
||||
data[offset++] = unchecked((byte)((long)(((ulong)br.accumulator) >> br.bitOffset)));
|
||||
br.bitOffset += 8;
|
||||
length--;
|
||||
}
|
||||
CheckHealth(br, false);
|
||||
return;
|
||||
}
|
||||
// Now it is possible to copy bytes directly.
|
||||
try
|
||||
{
|
||||
while (length > 0)
|
||||
{
|
||||
int len = br.input.Read(data, offset, length);
|
||||
if (len == -1)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Unexpected end of input");
|
||||
}
|
||||
offset += len;
|
||||
length -= len;
|
||||
}
|
||||
}
|
||||
catch (System.IO.IOException e)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Failed to read input", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
223
AssetStudio/Brotli/BrotliInputStream.cs
Normal file
223
AssetStudio/Brotli/BrotliInputStream.cs
Normal file
@@ -0,0 +1,223 @@
|
||||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="System.IO.Stream"/>
|
||||
/// decorator that decompresses brotli data.
|
||||
/// <p> Not thread-safe.
|
||||
/// </summary>
|
||||
public class BrotliInputStream : System.IO.Stream
|
||||
{
|
||||
public const int DefaultInternalBufferSize = 16384;
|
||||
|
||||
/// <summary>Internal buffer used for efficient byte-by-byte reading.</summary>
|
||||
private byte[] buffer;
|
||||
|
||||
/// <summary>Number of decoded but still unused bytes in internal buffer.</summary>
|
||||
private int remainingBufferBytes;
|
||||
|
||||
/// <summary>Next unused byte offset.</summary>
|
||||
private int bufferOffset;
|
||||
|
||||
/// <summary>Decoder state.</summary>
|
||||
private readonly Org.Brotli.Dec.State state = new Org.Brotli.Dec.State();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a
|
||||
/// <see cref="System.IO.Stream"/>
|
||||
/// wrapper that decompresses brotli data.
|
||||
/// <p> For byte-by-byte reading (
|
||||
/// <see cref="ReadByte()"/>
|
||||
/// ) internal buffer with
|
||||
/// <see cref="DefaultInternalBufferSize"/>
|
||||
/// size is allocated and used.
|
||||
/// <p> Will block the thread until first kilobyte of data of source is available.
|
||||
/// </summary>
|
||||
/// <param name="source">underlying data source</param>
|
||||
/// <exception cref="System.IO.IOException">in case of corrupted data or source stream problems</exception>
|
||||
public BrotliInputStream(System.IO.Stream source)
|
||||
: this(source, DefaultInternalBufferSize, null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a
|
||||
/// <see cref="System.IO.Stream"/>
|
||||
/// wrapper that decompresses brotli data.
|
||||
/// <p> For byte-by-byte reading (
|
||||
/// <see cref="ReadByte()"/>
|
||||
/// ) internal buffer of specified size is
|
||||
/// allocated and used.
|
||||
/// <p> Will block the thread until first kilobyte of data of source is available.
|
||||
/// </summary>
|
||||
/// <param name="source">compressed data source</param>
|
||||
/// <param name="byteReadBufferSize">
|
||||
/// size of internal buffer used in case of
|
||||
/// byte-by-byte reading
|
||||
/// </param>
|
||||
/// <exception cref="System.IO.IOException">in case of corrupted data or source stream problems</exception>
|
||||
public BrotliInputStream(System.IO.Stream source, int byteReadBufferSize)
|
||||
: this(source, byteReadBufferSize, null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a
|
||||
/// <see cref="System.IO.Stream"/>
|
||||
/// wrapper that decompresses brotli data.
|
||||
/// <p> For byte-by-byte reading (
|
||||
/// <see cref="ReadByte()"/>
|
||||
/// ) internal buffer of specified size is
|
||||
/// allocated and used.
|
||||
/// <p> Will block the thread until first kilobyte of data of source is available.
|
||||
/// </summary>
|
||||
/// <param name="source">compressed data source</param>
|
||||
/// <param name="byteReadBufferSize">
|
||||
/// size of internal buffer used in case of
|
||||
/// byte-by-byte reading
|
||||
/// </param>
|
||||
/// <param name="customDictionary">
|
||||
/// custom dictionary data;
|
||||
/// <see langword="null"/>
|
||||
/// if not used
|
||||
/// </param>
|
||||
/// <exception cref="System.IO.IOException">in case of corrupted data or source stream problems</exception>
|
||||
public BrotliInputStream(System.IO.Stream source, int byteReadBufferSize, byte[] customDictionary)
|
||||
{
|
||||
if (byteReadBufferSize <= 0)
|
||||
{
|
||||
throw new System.ArgumentException("Bad buffer size:" + byteReadBufferSize);
|
||||
}
|
||||
else if (source == null)
|
||||
{
|
||||
throw new System.ArgumentException("source is null");
|
||||
}
|
||||
this.buffer = new byte[byteReadBufferSize];
|
||||
this.remainingBufferBytes = 0;
|
||||
this.bufferOffset = 0;
|
||||
try
|
||||
{
|
||||
Org.Brotli.Dec.State.SetInput(state, source);
|
||||
}
|
||||
catch (Org.Brotli.Dec.BrotliRuntimeException ex)
|
||||
{
|
||||
throw new System.IO.IOException("Brotli decoder initialization failed", ex);
|
||||
}
|
||||
if (customDictionary != null)
|
||||
{
|
||||
Org.Brotli.Dec.Decode.SetCustomDictionary(state, customDictionary);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary><inheritDoc/></summary>
|
||||
/// <exception cref="System.IO.IOException"/>
|
||||
public override void Close()
|
||||
{
|
||||
Org.Brotli.Dec.State.Close(state);
|
||||
}
|
||||
|
||||
/// <summary><inheritDoc/></summary>
|
||||
/// <exception cref="System.IO.IOException"/>
|
||||
public override int ReadByte()
|
||||
{
|
||||
if (bufferOffset >= remainingBufferBytes)
|
||||
{
|
||||
remainingBufferBytes = Read(buffer, 0, buffer.Length);
|
||||
bufferOffset = 0;
|
||||
if (remainingBufferBytes == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return buffer[bufferOffset++] & unchecked((int)(0xFF));
|
||||
}
|
||||
|
||||
/// <summary><inheritDoc/></summary>
|
||||
/// <exception cref="System.IO.IOException"/>
|
||||
public override int Read(byte[] destBuffer, int destOffset, int destLen)
|
||||
{
|
||||
if (destOffset < 0)
|
||||
{
|
||||
throw new System.ArgumentException("Bad offset: " + destOffset);
|
||||
}
|
||||
else if (destLen < 0)
|
||||
{
|
||||
throw new System.ArgumentException("Bad length: " + destLen);
|
||||
}
|
||||
else if (destOffset + destLen > destBuffer.Length)
|
||||
{
|
||||
throw new System.ArgumentException("Buffer overflow: " + (destOffset + destLen) + " > " + destBuffer.Length);
|
||||
}
|
||||
else if (destLen == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int copyLen = System.Math.Max(remainingBufferBytes - bufferOffset, 0);
|
||||
if (copyLen != 0)
|
||||
{
|
||||
copyLen = System.Math.Min(copyLen, destLen);
|
||||
System.Array.Copy(buffer, bufferOffset, destBuffer, destOffset, copyLen);
|
||||
bufferOffset += copyLen;
|
||||
destOffset += copyLen;
|
||||
destLen -= copyLen;
|
||||
if (destLen == 0)
|
||||
{
|
||||
return copyLen;
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
state.output = destBuffer;
|
||||
state.outputOffset = destOffset;
|
||||
state.outputLength = destLen;
|
||||
state.outputUsed = 0;
|
||||
Org.Brotli.Dec.Decode.Decompress(state);
|
||||
if (state.outputUsed == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return state.outputUsed + copyLen;
|
||||
}
|
||||
catch (Org.Brotli.Dec.BrotliRuntimeException ex)
|
||||
{
|
||||
throw new System.IO.IOException("Brotli stream decoding failed", ex);
|
||||
}
|
||||
}
|
||||
// <{[INJECTED CODE]}>
|
||||
public override bool CanRead {
|
||||
get {return true;}
|
||||
}
|
||||
|
||||
public override bool CanSeek {
|
||||
get {return false;}
|
||||
}
|
||||
public override long Length {
|
||||
get {throw new System.NotSupportedException();}
|
||||
}
|
||||
public override long Position {
|
||||
get {throw new System.NotSupportedException();}
|
||||
set {throw new System.NotSupportedException();}
|
||||
}
|
||||
public override long Seek(long offset, System.IO.SeekOrigin origin) {
|
||||
throw new System.NotSupportedException();
|
||||
}
|
||||
public override void SetLength(long value){
|
||||
throw new System.NotSupportedException();
|
||||
}
|
||||
|
||||
public override bool CanWrite{get{return false;}}
|
||||
public override System.IAsyncResult BeginWrite(byte[] buffer, int offset,
|
||||
int count, System.AsyncCallback callback, object state) {
|
||||
throw new System.NotSupportedException();
|
||||
}
|
||||
public override void Write(byte[] buffer, int offset, int count) {
|
||||
throw new System.NotSupportedException();
|
||||
}
|
||||
|
||||
public override void Flush() {}
|
||||
}
|
||||
}
|
||||
22
AssetStudio/Brotli/BrotliRuntimeException.cs
Normal file
22
AssetStudio/Brotli/BrotliRuntimeException.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>Unchecked exception used internally.</summary>
|
||||
[System.Serializable]
|
||||
internal class BrotliRuntimeException : System.Exception
|
||||
{
|
||||
internal BrotliRuntimeException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
|
||||
internal BrotliRuntimeException(string message, System.Exception cause)
|
||||
: base(message, cause)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
57
AssetStudio/Brotli/Context.cs
Normal file
57
AssetStudio/Brotli/Context.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>Common context lookup table for all context modes.</summary>
|
||||
internal sealed class Context
|
||||
{
|
||||
internal static readonly int[] Lookup = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 12, 16, 12, 12, 20, 12, 16, 24, 28, 12, 12, 32, 12, 36, 12, 44, 44, 44, 44, 44, 44, 44, 44
|
||||
, 44, 44, 32, 32, 24, 40, 28, 12, 12, 48, 52, 52, 52, 48, 52, 52, 52, 48, 52, 52, 52, 52, 52, 48, 52, 52, 52, 52, 52, 48, 52, 52, 52, 52, 52, 24, 12, 28, 12, 12, 12, 56, 60, 60, 60, 56, 60, 60, 60, 56, 60, 60, 60, 60, 60, 56, 60, 60, 60, 60
|
||||
, 60, 56, 60, 60, 60, 60, 60, 24, 12, 28, 12, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,
|
||||
1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
||||
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
|
||||
40, 40, 40, 40, 40, 40, 40, 40, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 56, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38
|
||||
, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
|
||||
37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35
|
||||
, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
|
||||
34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9,
|
||||
10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24,
|
||||
25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31, 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39,
|
||||
40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51, 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54,
|
||||
55, 55, 55, 55, 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59, 60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
internal static readonly int[] LookupOffsets = new int[] { 1024, 1536, 1280, 1536, 0, 256, 768, 512 };
|
||||
// CONTEXT_UTF8, last byte.
|
||||
// ASCII range.
|
||||
// UTF8 continuation byte range.
|
||||
// UTF8 lead byte range.
|
||||
// CONTEXT_UTF8 second last byte.
|
||||
// ASCII range.
|
||||
// UTF8 continuation byte range.
|
||||
// UTF8 lead byte range.
|
||||
// CONTEXT_SIGNED, second last byte.
|
||||
// CONTEXT_SIGNED, last byte, same as the above values shifted by 3 bits.
|
||||
// CONTEXT_LSB6, last byte.
|
||||
// CONTEXT_MSB6, last byte.
|
||||
// CONTEXT_{M,L}SB6, second last byte,
|
||||
// CONTEXT_LSB6
|
||||
// CONTEXT_MSB6
|
||||
// CONTEXT_UTF8
|
||||
// CONTEXT_SIGNED
|
||||
}
|
||||
}
|
||||
992
AssetStudio/Brotli/Decode.cs
Normal file
992
AssetStudio/Brotli/Decode.cs
Normal file
@@ -0,0 +1,992 @@
|
||||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>API for Brotli decompression.</summary>
|
||||
internal sealed class Decode
|
||||
{
|
||||
private const int DefaultCodeLength = 8;
|
||||
|
||||
private const int CodeLengthRepeatCode = 16;
|
||||
|
||||
private const int NumLiteralCodes = 256;
|
||||
|
||||
private const int NumInsertAndCopyCodes = 704;
|
||||
|
||||
private const int NumBlockLengthCodes = 26;
|
||||
|
||||
private const int LiteralContextBits = 6;
|
||||
|
||||
private const int DistanceContextBits = 2;
|
||||
|
||||
private const int HuffmanTableBits = 8;
|
||||
|
||||
private const int HuffmanTableMask = unchecked((int)(0xFF));
|
||||
|
||||
private const int CodeLengthCodes = 18;
|
||||
|
||||
private static readonly int[] CodeLengthCodeOrder = new int[] { 1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
|
||||
|
||||
private const int NumDistanceShortCodes = 16;
|
||||
|
||||
private static readonly int[] DistanceShortCodeIndexOffset = new int[] { 3, 2, 1, 0, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 };
|
||||
|
||||
private static readonly int[] DistanceShortCodeValueOffset = new int[] { 0, 0, 0, 0, -1, 1, -2, 2, -3, 3, -1, 1, -2, 2, -3, 3 };
|
||||
|
||||
/// <summary>Static Huffman code for the code length code lengths.</summary>
|
||||
private static readonly int[] FixedTable = new int[] { unchecked((int)(0x020000)), unchecked((int)(0x020004)), unchecked((int)(0x020003)), unchecked((int)(0x030002)), unchecked((int)(0x020000)), unchecked((int)(0x020004)), unchecked((int)(0x020003
|
||||
)), unchecked((int)(0x040001)), unchecked((int)(0x020000)), unchecked((int)(0x020004)), unchecked((int)(0x020003)), unchecked((int)(0x030002)), unchecked((int)(0x020000)), unchecked((int)(0x020004)), unchecked((int)(0x020003)), unchecked((int
|
||||
)(0x040005)) };
|
||||
|
||||
/// <summary>Decodes a number in the range [0..255], by reading 1 - 11 bits.</summary>
|
||||
private static int DecodeVarLenUnsignedByte(Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
if (Org.Brotli.Dec.BitReader.ReadBits(br, 1) != 0)
|
||||
{
|
||||
int n = Org.Brotli.Dec.BitReader.ReadBits(br, 3);
|
||||
if (n == 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Org.Brotli.Dec.BitReader.ReadBits(br, n) + (1 << n);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static void DecodeMetaBlockLength(Org.Brotli.Dec.BitReader br, Org.Brotli.Dec.State state)
|
||||
{
|
||||
state.inputEnd = Org.Brotli.Dec.BitReader.ReadBits(br, 1) == 1;
|
||||
state.metaBlockLength = 0;
|
||||
state.isUncompressed = false;
|
||||
state.isMetadata = false;
|
||||
if (state.inputEnd && Org.Brotli.Dec.BitReader.ReadBits(br, 1) != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int sizeNibbles = Org.Brotli.Dec.BitReader.ReadBits(br, 2) + 4;
|
||||
if (sizeNibbles == 7)
|
||||
{
|
||||
state.isMetadata = true;
|
||||
if (Org.Brotli.Dec.BitReader.ReadBits(br, 1) != 0)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Corrupted reserved bit");
|
||||
}
|
||||
int sizeBytes = Org.Brotli.Dec.BitReader.ReadBits(br, 2);
|
||||
if (sizeBytes == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < sizeBytes; i++)
|
||||
{
|
||||
int bits = Org.Brotli.Dec.BitReader.ReadBits(br, 8);
|
||||
if (bits == 0 && i + 1 == sizeBytes && sizeBytes > 1)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Exuberant nibble");
|
||||
}
|
||||
state.metaBlockLength |= bits << (i * 8);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < sizeNibbles; i++)
|
||||
{
|
||||
int bits = Org.Brotli.Dec.BitReader.ReadBits(br, 4);
|
||||
if (bits == 0 && i + 1 == sizeNibbles && sizeNibbles > 4)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Exuberant nibble");
|
||||
}
|
||||
state.metaBlockLength |= bits << (i * 4);
|
||||
}
|
||||
}
|
||||
state.metaBlockLength++;
|
||||
if (!state.inputEnd)
|
||||
{
|
||||
state.isUncompressed = Org.Brotli.Dec.BitReader.ReadBits(br, 1) == 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Decodes the next Huffman code from bit-stream.</summary>
|
||||
private static int ReadSymbol(int[] table, int offset, Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
int val = (int)((long)(((ulong)br.accumulator) >> br.bitOffset));
|
||||
offset += val & HuffmanTableMask;
|
||||
int bits = table[offset] >> 16;
|
||||
int sym = table[offset] & unchecked((int)(0xFFFF));
|
||||
if (bits <= HuffmanTableBits)
|
||||
{
|
||||
br.bitOffset += bits;
|
||||
return sym;
|
||||
}
|
||||
offset += sym;
|
||||
int mask = (1 << bits) - 1;
|
||||
offset += (int)(((uint)(val & mask)) >> HuffmanTableBits);
|
||||
br.bitOffset += ((table[offset] >> 16) + HuffmanTableBits);
|
||||
return table[offset] & unchecked((int)(0xFFFF));
|
||||
}
|
||||
|
||||
private static int ReadBlockLength(int[] table, int offset, Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader.FillBitWindow(br);
|
||||
int code = ReadSymbol(table, offset, br);
|
||||
int n = Org.Brotli.Dec.Prefix.BlockLengthNBits[code];
|
||||
return Org.Brotli.Dec.Prefix.BlockLengthOffset[code] + Org.Brotli.Dec.BitReader.ReadBits(br, n);
|
||||
}
|
||||
|
||||
private static int TranslateShortCodes(int code, int[] ringBuffer, int index)
|
||||
{
|
||||
if (code < NumDistanceShortCodes)
|
||||
{
|
||||
index += DistanceShortCodeIndexOffset[code];
|
||||
index &= 3;
|
||||
return ringBuffer[index] + DistanceShortCodeValueOffset[code];
|
||||
}
|
||||
return code - NumDistanceShortCodes + 1;
|
||||
}
|
||||
|
||||
private static void MoveToFront(int[] v, int index)
|
||||
{
|
||||
int value = v[index];
|
||||
for (; index > 0; index--)
|
||||
{
|
||||
v[index] = v[index - 1];
|
||||
}
|
||||
v[0] = value;
|
||||
}
|
||||
|
||||
private static void InverseMoveToFrontTransform(byte[] v, int vLen)
|
||||
{
|
||||
int[] mtf = new int[256];
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
mtf[i] = i;
|
||||
}
|
||||
for (int i = 0; i < vLen; i++)
|
||||
{
|
||||
int index = v[i] & unchecked((int)(0xFF));
|
||||
v[i] = unchecked((byte)mtf[index]);
|
||||
if (index != 0)
|
||||
{
|
||||
MoveToFront(mtf, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ReadHuffmanCodeLengths(int[] codeLengthCodeLengths, int numSymbols, int[] codeLengths, Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
int symbol = 0;
|
||||
int prevCodeLen = DefaultCodeLength;
|
||||
int repeat = 0;
|
||||
int repeatCodeLen = 0;
|
||||
int space = 32768;
|
||||
int[] table = new int[32];
|
||||
Org.Brotli.Dec.Huffman.BuildHuffmanTable(table, 0, 5, codeLengthCodeLengths, CodeLengthCodes);
|
||||
while (symbol < numSymbols && space > 0)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
Org.Brotli.Dec.BitReader.FillBitWindow(br);
|
||||
int p = (int)(((long)(((ulong)br.accumulator) >> br.bitOffset))) & 31;
|
||||
br.bitOffset += table[p] >> 16;
|
||||
int codeLen = table[p] & unchecked((int)(0xFFFF));
|
||||
if (codeLen < CodeLengthRepeatCode)
|
||||
{
|
||||
repeat = 0;
|
||||
codeLengths[symbol++] = codeLen;
|
||||
if (codeLen != 0)
|
||||
{
|
||||
prevCodeLen = codeLen;
|
||||
space -= 32768 >> codeLen;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int extraBits = codeLen - 14;
|
||||
int newLen = 0;
|
||||
if (codeLen == CodeLengthRepeatCode)
|
||||
{
|
||||
newLen = prevCodeLen;
|
||||
}
|
||||
if (repeatCodeLen != newLen)
|
||||
{
|
||||
repeat = 0;
|
||||
repeatCodeLen = newLen;
|
||||
}
|
||||
int oldRepeat = repeat;
|
||||
if (repeat > 0)
|
||||
{
|
||||
repeat -= 2;
|
||||
repeat <<= extraBits;
|
||||
}
|
||||
repeat += Org.Brotli.Dec.BitReader.ReadBits(br, extraBits) + 3;
|
||||
int repeatDelta = repeat - oldRepeat;
|
||||
if (symbol + repeatDelta > numSymbols)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("symbol + repeatDelta > numSymbols");
|
||||
}
|
||||
// COV_NF_LINE
|
||||
for (int i = 0; i < repeatDelta; i++)
|
||||
{
|
||||
codeLengths[symbol++] = repeatCodeLen;
|
||||
}
|
||||
if (repeatCodeLen != 0)
|
||||
{
|
||||
space -= repeatDelta << (15 - repeatCodeLen);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (space != 0)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Unused space");
|
||||
}
|
||||
// COV_NF_LINE
|
||||
// TODO: Pass max_symbol to Huffman table builder instead?
|
||||
Org.Brotli.Dec.Utils.FillWithZeroes(codeLengths, symbol, numSymbols - symbol);
|
||||
}
|
||||
|
||||
// TODO: Use specialized versions for smaller tables.
|
||||
internal static void ReadHuffmanCode(int alphabetSize, int[] table, int offset, Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
bool ok = true;
|
||||
int simpleCodeOrSkip;
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
// TODO: Avoid allocation.
|
||||
int[] codeLengths = new int[alphabetSize];
|
||||
simpleCodeOrSkip = Org.Brotli.Dec.BitReader.ReadBits(br, 2);
|
||||
if (simpleCodeOrSkip == 1)
|
||||
{
|
||||
// Read symbols, codes & code lengths directly.
|
||||
int maxBitsCounter = alphabetSize - 1;
|
||||
int maxBits = 0;
|
||||
int[] symbols = new int[4];
|
||||
int numSymbols = Org.Brotli.Dec.BitReader.ReadBits(br, 2) + 1;
|
||||
while (maxBitsCounter != 0)
|
||||
{
|
||||
maxBitsCounter >>= 1;
|
||||
maxBits++;
|
||||
}
|
||||
// TODO: uncomment when codeLengths is reused.
|
||||
// Utils.fillWithZeroes(codeLengths, 0, alphabetSize);
|
||||
for (int i = 0; i < numSymbols; i++)
|
||||
{
|
||||
symbols[i] = Org.Brotli.Dec.BitReader.ReadBits(br, maxBits) % alphabetSize;
|
||||
codeLengths[symbols[i]] = 2;
|
||||
}
|
||||
codeLengths[symbols[0]] = 1;
|
||||
switch (numSymbols)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
ok = symbols[0] != symbols[1];
|
||||
codeLengths[symbols[1]] = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
case 3:
|
||||
{
|
||||
ok = symbols[0] != symbols[1] && symbols[0] != symbols[2] && symbols[1] != symbols[2];
|
||||
break;
|
||||
}
|
||||
|
||||
case 4:
|
||||
default:
|
||||
{
|
||||
ok = symbols[0] != symbols[1] && symbols[0] != symbols[2] && symbols[0] != symbols[3] && symbols[1] != symbols[2] && symbols[1] != symbols[3] && symbols[2] != symbols[3];
|
||||
if (Org.Brotli.Dec.BitReader.ReadBits(br, 1) == 1)
|
||||
{
|
||||
codeLengths[symbols[2]] = 3;
|
||||
codeLengths[symbols[3]] = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
codeLengths[symbols[0]] = 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Decode Huffman-coded code lengths.
|
||||
int[] codeLengthCodeLengths = new int[CodeLengthCodes];
|
||||
int space = 32;
|
||||
int numCodes = 0;
|
||||
for (int i = simpleCodeOrSkip; i < CodeLengthCodes && space > 0; i++)
|
||||
{
|
||||
int codeLenIdx = CodeLengthCodeOrder[i];
|
||||
Org.Brotli.Dec.BitReader.FillBitWindow(br);
|
||||
int p = (int)((long)(((ulong)br.accumulator) >> br.bitOffset)) & 15;
|
||||
// TODO: Demultiplex FIXED_TABLE.
|
||||
br.bitOffset += FixedTable[p] >> 16;
|
||||
int v = FixedTable[p] & unchecked((int)(0xFFFF));
|
||||
codeLengthCodeLengths[codeLenIdx] = v;
|
||||
if (v != 0)
|
||||
{
|
||||
space -= (32 >> v);
|
||||
numCodes++;
|
||||
}
|
||||
}
|
||||
ok = (numCodes == 1 || space == 0);
|
||||
ReadHuffmanCodeLengths(codeLengthCodeLengths, alphabetSize, codeLengths, br);
|
||||
}
|
||||
if (!ok)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Can't readHuffmanCode");
|
||||
}
|
||||
// COV_NF_LINE
|
||||
Org.Brotli.Dec.Huffman.BuildHuffmanTable(table, offset, HuffmanTableBits, codeLengths, alphabetSize);
|
||||
}
|
||||
|
||||
private static int DecodeContextMap(int contextMapSize, byte[] contextMap, Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
int numTrees = DecodeVarLenUnsignedByte(br) + 1;
|
||||
if (numTrees == 1)
|
||||
{
|
||||
Org.Brotli.Dec.Utils.FillWithZeroes(contextMap, 0, contextMapSize);
|
||||
return numTrees;
|
||||
}
|
||||
bool useRleForZeros = Org.Brotli.Dec.BitReader.ReadBits(br, 1) == 1;
|
||||
int maxRunLengthPrefix = 0;
|
||||
if (useRleForZeros)
|
||||
{
|
||||
maxRunLengthPrefix = Org.Brotli.Dec.BitReader.ReadBits(br, 4) + 1;
|
||||
}
|
||||
int[] table = new int[Org.Brotli.Dec.Huffman.HuffmanMaxTableSize];
|
||||
ReadHuffmanCode(numTrees + maxRunLengthPrefix, table, 0, br);
|
||||
for (int i = 0; i < contextMapSize; )
|
||||
{
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
Org.Brotli.Dec.BitReader.FillBitWindow(br);
|
||||
int code = ReadSymbol(table, 0, br);
|
||||
if (code == 0)
|
||||
{
|
||||
contextMap[i] = 0;
|
||||
i++;
|
||||
}
|
||||
else if (code <= maxRunLengthPrefix)
|
||||
{
|
||||
int reps = (1 << code) + Org.Brotli.Dec.BitReader.ReadBits(br, code);
|
||||
while (reps != 0)
|
||||
{
|
||||
if (i >= contextMapSize)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Corrupted context map");
|
||||
}
|
||||
// COV_NF_LINE
|
||||
contextMap[i] = 0;
|
||||
i++;
|
||||
reps--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
contextMap[i] = unchecked((byte)(code - maxRunLengthPrefix));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (Org.Brotli.Dec.BitReader.ReadBits(br, 1) == 1)
|
||||
{
|
||||
InverseMoveToFrontTransform(contextMap, contextMapSize);
|
||||
}
|
||||
return numTrees;
|
||||
}
|
||||
|
||||
private static void DecodeBlockTypeAndLength(Org.Brotli.Dec.State state, int treeType)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader br = state.br;
|
||||
int[] ringBuffers = state.blockTypeRb;
|
||||
int offset = treeType * 2;
|
||||
Org.Brotli.Dec.BitReader.FillBitWindow(br);
|
||||
int blockType = ReadSymbol(state.blockTypeTrees, treeType * Org.Brotli.Dec.Huffman.HuffmanMaxTableSize, br);
|
||||
state.blockLength[treeType] = ReadBlockLength(state.blockLenTrees, treeType * Org.Brotli.Dec.Huffman.HuffmanMaxTableSize, br);
|
||||
if (blockType == 1)
|
||||
{
|
||||
blockType = ringBuffers[offset + 1] + 1;
|
||||
}
|
||||
else if (blockType == 0)
|
||||
{
|
||||
blockType = ringBuffers[offset];
|
||||
}
|
||||
else
|
||||
{
|
||||
blockType -= 2;
|
||||
}
|
||||
if (blockType >= state.numBlockTypes[treeType])
|
||||
{
|
||||
blockType -= state.numBlockTypes[treeType];
|
||||
}
|
||||
ringBuffers[offset] = ringBuffers[offset + 1];
|
||||
ringBuffers[offset + 1] = blockType;
|
||||
}
|
||||
|
||||
private static void DecodeLiteralBlockSwitch(Org.Brotli.Dec.State state)
|
||||
{
|
||||
DecodeBlockTypeAndLength(state, 0);
|
||||
int literalBlockType = state.blockTypeRb[1];
|
||||
state.contextMapSlice = literalBlockType << LiteralContextBits;
|
||||
state.literalTreeIndex = state.contextMap[state.contextMapSlice] & unchecked((int)(0xFF));
|
||||
state.literalTree = state.hGroup0.trees[state.literalTreeIndex];
|
||||
int contextMode = state.contextModes[literalBlockType];
|
||||
state.contextLookupOffset1 = Org.Brotli.Dec.Context.LookupOffsets[contextMode];
|
||||
state.contextLookupOffset2 = Org.Brotli.Dec.Context.LookupOffsets[contextMode + 1];
|
||||
}
|
||||
|
||||
private static void DecodeCommandBlockSwitch(Org.Brotli.Dec.State state)
|
||||
{
|
||||
DecodeBlockTypeAndLength(state, 1);
|
||||
state.treeCommandOffset = state.hGroup1.trees[state.blockTypeRb[3]];
|
||||
}
|
||||
|
||||
private static void DecodeDistanceBlockSwitch(Org.Brotli.Dec.State state)
|
||||
{
|
||||
DecodeBlockTypeAndLength(state, 2);
|
||||
state.distContextMapSlice = state.blockTypeRb[5] << DistanceContextBits;
|
||||
}
|
||||
|
||||
private static void MaybeReallocateRingBuffer(Org.Brotli.Dec.State state)
|
||||
{
|
||||
int newSize = state.maxRingBufferSize;
|
||||
if ((long)newSize > state.expectedTotalSize)
|
||||
{
|
||||
/* TODO: Handle 2GB+ cases more gracefully. */
|
||||
int minimalNewSize = (int)state.expectedTotalSize + state.customDictionary.Length;
|
||||
while ((newSize >> 1) > minimalNewSize)
|
||||
{
|
||||
newSize >>= 1;
|
||||
}
|
||||
if (!state.inputEnd && newSize < 16384 && state.maxRingBufferSize >= 16384)
|
||||
{
|
||||
newSize = 16384;
|
||||
}
|
||||
}
|
||||
if (newSize <= state.ringBufferSize)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int ringBufferSizeWithSlack = newSize + Org.Brotli.Dec.Dictionary.MaxTransformedWordLength;
|
||||
byte[] newBuffer = new byte[ringBufferSizeWithSlack];
|
||||
if (state.ringBuffer != null)
|
||||
{
|
||||
System.Array.Copy(state.ringBuffer, 0, newBuffer, 0, state.ringBufferSize);
|
||||
}
|
||||
else if (state.customDictionary.Length != 0)
|
||||
{
|
||||
/* Prepend custom dictionary, if any. */
|
||||
int length = state.customDictionary.Length;
|
||||
int offset = 0;
|
||||
if (length > state.maxBackwardDistance)
|
||||
{
|
||||
offset = length - state.maxBackwardDistance;
|
||||
length = state.maxBackwardDistance;
|
||||
}
|
||||
System.Array.Copy(state.customDictionary, offset, newBuffer, 0, length);
|
||||
state.pos = length;
|
||||
state.bytesToIgnore = length;
|
||||
}
|
||||
state.ringBuffer = newBuffer;
|
||||
state.ringBufferSize = newSize;
|
||||
}
|
||||
|
||||
/// <summary>Reads next metablock header.</summary>
|
||||
/// <param name="state">decoding state</param>
|
||||
private static void ReadMetablockInfo(Org.Brotli.Dec.State state)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader br = state.br;
|
||||
if (state.inputEnd)
|
||||
{
|
||||
state.nextRunningState = Org.Brotli.Dec.RunningState.Finished;
|
||||
state.bytesToWrite = state.pos;
|
||||
state.bytesWritten = 0;
|
||||
state.runningState = Org.Brotli.Dec.RunningState.Write;
|
||||
return;
|
||||
}
|
||||
// TODO: Reset? Do we need this?
|
||||
state.hGroup0.codes = null;
|
||||
state.hGroup0.trees = null;
|
||||
state.hGroup1.codes = null;
|
||||
state.hGroup1.trees = null;
|
||||
state.hGroup2.codes = null;
|
||||
state.hGroup2.trees = null;
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
DecodeMetaBlockLength(br, state);
|
||||
if (state.metaBlockLength == 0 && !state.isMetadata)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (state.isUncompressed || state.isMetadata)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader.JumpToByteBoundary(br);
|
||||
state.runningState = state.isMetadata ? Org.Brotli.Dec.RunningState.ReadMetadata : Org.Brotli.Dec.RunningState.CopyUncompressed;
|
||||
}
|
||||
else
|
||||
{
|
||||
state.runningState = Org.Brotli.Dec.RunningState.CompressedBlockStart;
|
||||
}
|
||||
if (state.isMetadata)
|
||||
{
|
||||
return;
|
||||
}
|
||||
state.expectedTotalSize += state.metaBlockLength;
|
||||
if (state.ringBufferSize < state.maxRingBufferSize)
|
||||
{
|
||||
MaybeReallocateRingBuffer(state);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ReadMetablockHuffmanCodesAndContextMaps(Org.Brotli.Dec.State state)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader br = state.br;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
state.numBlockTypes[i] = DecodeVarLenUnsignedByte(br) + 1;
|
||||
state.blockLength[i] = 1 << 28;
|
||||
if (state.numBlockTypes[i] > 1)
|
||||
{
|
||||
ReadHuffmanCode(state.numBlockTypes[i] + 2, state.blockTypeTrees, i * Org.Brotli.Dec.Huffman.HuffmanMaxTableSize, br);
|
||||
ReadHuffmanCode(NumBlockLengthCodes, state.blockLenTrees, i * Org.Brotli.Dec.Huffman.HuffmanMaxTableSize, br);
|
||||
state.blockLength[i] = ReadBlockLength(state.blockLenTrees, i * Org.Brotli.Dec.Huffman.HuffmanMaxTableSize, br);
|
||||
}
|
||||
}
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
state.distancePostfixBits = Org.Brotli.Dec.BitReader.ReadBits(br, 2);
|
||||
state.numDirectDistanceCodes = NumDistanceShortCodes + (Org.Brotli.Dec.BitReader.ReadBits(br, 4) << state.distancePostfixBits);
|
||||
state.distancePostfixMask = (1 << state.distancePostfixBits) - 1;
|
||||
int numDistanceCodes = state.numDirectDistanceCodes + (48 << state.distancePostfixBits);
|
||||
// TODO: Reuse?
|
||||
state.contextModes = new byte[state.numBlockTypes[0]];
|
||||
for (int i = 0; i < state.numBlockTypes[0]; )
|
||||
{
|
||||
/* Ensure that less than 256 bits read between readMoreInput. */
|
||||
int limit = System.Math.Min(i + 96, state.numBlockTypes[0]);
|
||||
for (; i < limit; ++i)
|
||||
{
|
||||
state.contextModes[i] = unchecked((byte)(Org.Brotli.Dec.BitReader.ReadBits(br, 2) << 1));
|
||||
}
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
}
|
||||
// TODO: Reuse?
|
||||
state.contextMap = new byte[state.numBlockTypes[0] << LiteralContextBits];
|
||||
int numLiteralTrees = DecodeContextMap(state.numBlockTypes[0] << LiteralContextBits, state.contextMap, br);
|
||||
state.trivialLiteralContext = true;
|
||||
for (int j = 0; j < state.numBlockTypes[0] << LiteralContextBits; j++)
|
||||
{
|
||||
if (state.contextMap[j] != j >> LiteralContextBits)
|
||||
{
|
||||
state.trivialLiteralContext = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// TODO: Reuse?
|
||||
state.distContextMap = new byte[state.numBlockTypes[2] << DistanceContextBits];
|
||||
int numDistTrees = DecodeContextMap(state.numBlockTypes[2] << DistanceContextBits, state.distContextMap, br);
|
||||
Org.Brotli.Dec.HuffmanTreeGroup.Init(state.hGroup0, NumLiteralCodes, numLiteralTrees);
|
||||
Org.Brotli.Dec.HuffmanTreeGroup.Init(state.hGroup1, NumInsertAndCopyCodes, state.numBlockTypes[1]);
|
||||
Org.Brotli.Dec.HuffmanTreeGroup.Init(state.hGroup2, numDistanceCodes, numDistTrees);
|
||||
Org.Brotli.Dec.HuffmanTreeGroup.Decode(state.hGroup0, br);
|
||||
Org.Brotli.Dec.HuffmanTreeGroup.Decode(state.hGroup1, br);
|
||||
Org.Brotli.Dec.HuffmanTreeGroup.Decode(state.hGroup2, br);
|
||||
state.contextMapSlice = 0;
|
||||
state.distContextMapSlice = 0;
|
||||
state.contextLookupOffset1 = Org.Brotli.Dec.Context.LookupOffsets[state.contextModes[0]];
|
||||
state.contextLookupOffset2 = Org.Brotli.Dec.Context.LookupOffsets[state.contextModes[0] + 1];
|
||||
state.literalTreeIndex = 0;
|
||||
state.literalTree = state.hGroup0.trees[0];
|
||||
state.treeCommandOffset = state.hGroup1.trees[0];
|
||||
// TODO: == 0?
|
||||
state.blockTypeRb[0] = state.blockTypeRb[2] = state.blockTypeRb[4] = 1;
|
||||
state.blockTypeRb[1] = state.blockTypeRb[3] = state.blockTypeRb[5] = 0;
|
||||
}
|
||||
|
||||
private static void CopyUncompressedData(Org.Brotli.Dec.State state)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader br = state.br;
|
||||
byte[] ringBuffer = state.ringBuffer;
|
||||
// Could happen if block ends at ring buffer end.
|
||||
if (state.metaBlockLength <= 0)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader.Reload(br);
|
||||
state.runningState = Org.Brotli.Dec.RunningState.BlockStart;
|
||||
return;
|
||||
}
|
||||
int chunkLength = System.Math.Min(state.ringBufferSize - state.pos, state.metaBlockLength);
|
||||
Org.Brotli.Dec.BitReader.CopyBytes(br, ringBuffer, state.pos, chunkLength);
|
||||
state.metaBlockLength -= chunkLength;
|
||||
state.pos += chunkLength;
|
||||
if (state.pos == state.ringBufferSize)
|
||||
{
|
||||
state.nextRunningState = Org.Brotli.Dec.RunningState.CopyUncompressed;
|
||||
state.bytesToWrite = state.ringBufferSize;
|
||||
state.bytesWritten = 0;
|
||||
state.runningState = Org.Brotli.Dec.RunningState.Write;
|
||||
return;
|
||||
}
|
||||
Org.Brotli.Dec.BitReader.Reload(br);
|
||||
state.runningState = Org.Brotli.Dec.RunningState.BlockStart;
|
||||
}
|
||||
|
||||
private static bool WriteRingBuffer(Org.Brotli.Dec.State state)
|
||||
{
|
||||
/* Ignore custom dictionary bytes. */
|
||||
if (state.bytesToIgnore != 0)
|
||||
{
|
||||
state.bytesWritten += state.bytesToIgnore;
|
||||
state.bytesToIgnore = 0;
|
||||
}
|
||||
int toWrite = System.Math.Min(state.outputLength - state.outputUsed, state.bytesToWrite - state.bytesWritten);
|
||||
if (toWrite != 0)
|
||||
{
|
||||
System.Array.Copy(state.ringBuffer, state.bytesWritten, state.output, state.outputOffset + state.outputUsed, toWrite);
|
||||
state.outputUsed += toWrite;
|
||||
state.bytesWritten += toWrite;
|
||||
}
|
||||
return state.outputUsed < state.outputLength;
|
||||
}
|
||||
|
||||
internal static void SetCustomDictionary(Org.Brotli.Dec.State state, byte[] data)
|
||||
{
|
||||
state.customDictionary = (data == null) ? new byte[0] : data;
|
||||
}
|
||||
|
||||
/// <summary>Actual decompress implementation.</summary>
|
||||
internal static void Decompress(Org.Brotli.Dec.State state)
|
||||
{
|
||||
if (state.runningState == Org.Brotli.Dec.RunningState.Uninitialized)
|
||||
{
|
||||
throw new System.InvalidOperationException("Can't decompress until initialized");
|
||||
}
|
||||
if (state.runningState == Org.Brotli.Dec.RunningState.Closed)
|
||||
{
|
||||
throw new System.InvalidOperationException("Can't decompress after close");
|
||||
}
|
||||
Org.Brotli.Dec.BitReader br = state.br;
|
||||
int ringBufferMask = state.ringBufferSize - 1;
|
||||
byte[] ringBuffer = state.ringBuffer;
|
||||
while (state.runningState != Org.Brotli.Dec.RunningState.Finished)
|
||||
{
|
||||
switch (state.runningState)
|
||||
{
|
||||
case Org.Brotli.Dec.RunningState.BlockStart:
|
||||
{
|
||||
// TODO: extract cases to methods for the better readability.
|
||||
if (state.metaBlockLength < 0)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Invalid metablock length");
|
||||
}
|
||||
ReadMetablockInfo(state);
|
||||
/* Ring-buffer would be reallocated here. */
|
||||
ringBufferMask = state.ringBufferSize - 1;
|
||||
ringBuffer = state.ringBuffer;
|
||||
continue;
|
||||
}
|
||||
|
||||
case Org.Brotli.Dec.RunningState.CompressedBlockStart:
|
||||
{
|
||||
ReadMetablockHuffmanCodesAndContextMaps(state);
|
||||
state.runningState = Org.Brotli.Dec.RunningState.MainLoop;
|
||||
goto case Org.Brotli.Dec.RunningState.MainLoop;
|
||||
}
|
||||
|
||||
case Org.Brotli.Dec.RunningState.MainLoop:
|
||||
{
|
||||
// Fall through
|
||||
if (state.metaBlockLength <= 0)
|
||||
{
|
||||
state.runningState = Org.Brotli.Dec.RunningState.BlockStart;
|
||||
continue;
|
||||
}
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
if (state.blockLength[1] == 0)
|
||||
{
|
||||
DecodeCommandBlockSwitch(state);
|
||||
}
|
||||
state.blockLength[1]--;
|
||||
Org.Brotli.Dec.BitReader.FillBitWindow(br);
|
||||
int cmdCode = ReadSymbol(state.hGroup1.codes, state.treeCommandOffset, br);
|
||||
int rangeIdx = (int)(((uint)cmdCode) >> 6);
|
||||
state.distanceCode = 0;
|
||||
if (rangeIdx >= 2)
|
||||
{
|
||||
rangeIdx -= 2;
|
||||
state.distanceCode = -1;
|
||||
}
|
||||
int insertCode = Org.Brotli.Dec.Prefix.InsertRangeLut[rangeIdx] + (((int)(((uint)cmdCode) >> 3)) & 7);
|
||||
int copyCode = Org.Brotli.Dec.Prefix.CopyRangeLut[rangeIdx] + (cmdCode & 7);
|
||||
state.insertLength = Org.Brotli.Dec.Prefix.InsertLengthOffset[insertCode] + Org.Brotli.Dec.BitReader.ReadBits(br, Org.Brotli.Dec.Prefix.InsertLengthNBits[insertCode]);
|
||||
state.copyLength = Org.Brotli.Dec.Prefix.CopyLengthOffset[copyCode] + Org.Brotli.Dec.BitReader.ReadBits(br, Org.Brotli.Dec.Prefix.CopyLengthNBits[copyCode]);
|
||||
state.j = 0;
|
||||
state.runningState = Org.Brotli.Dec.RunningState.InsertLoop;
|
||||
goto case Org.Brotli.Dec.RunningState.InsertLoop;
|
||||
}
|
||||
|
||||
case Org.Brotli.Dec.RunningState.InsertLoop:
|
||||
{
|
||||
// Fall through
|
||||
if (state.trivialLiteralContext)
|
||||
{
|
||||
while (state.j < state.insertLength)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
if (state.blockLength[0] == 0)
|
||||
{
|
||||
DecodeLiteralBlockSwitch(state);
|
||||
}
|
||||
state.blockLength[0]--;
|
||||
Org.Brotli.Dec.BitReader.FillBitWindow(br);
|
||||
ringBuffer[state.pos] = unchecked((byte)ReadSymbol(state.hGroup0.codes, state.literalTree, br));
|
||||
state.j++;
|
||||
if (state.pos++ == ringBufferMask)
|
||||
{
|
||||
state.nextRunningState = Org.Brotli.Dec.RunningState.InsertLoop;
|
||||
state.bytesToWrite = state.ringBufferSize;
|
||||
state.bytesWritten = 0;
|
||||
state.runningState = Org.Brotli.Dec.RunningState.Write;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int prevByte1 = ringBuffer[(state.pos - 1) & ringBufferMask] & unchecked((int)(0xFF));
|
||||
int prevByte2 = ringBuffer[(state.pos - 2) & ringBufferMask] & unchecked((int)(0xFF));
|
||||
while (state.j < state.insertLength)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
if (state.blockLength[0] == 0)
|
||||
{
|
||||
DecodeLiteralBlockSwitch(state);
|
||||
}
|
||||
int literalTreeIndex = state.contextMap[state.contextMapSlice + (Org.Brotli.Dec.Context.Lookup[state.contextLookupOffset1 + prevByte1] | Org.Brotli.Dec.Context.Lookup[state.contextLookupOffset2 + prevByte2])] & unchecked((int)(0xFF));
|
||||
state.blockLength[0]--;
|
||||
prevByte2 = prevByte1;
|
||||
Org.Brotli.Dec.BitReader.FillBitWindow(br);
|
||||
prevByte1 = ReadSymbol(state.hGroup0.codes, state.hGroup0.trees[literalTreeIndex], br);
|
||||
ringBuffer[state.pos] = unchecked((byte)prevByte1);
|
||||
state.j++;
|
||||
if (state.pos++ == ringBufferMask)
|
||||
{
|
||||
state.nextRunningState = Org.Brotli.Dec.RunningState.InsertLoop;
|
||||
state.bytesToWrite = state.ringBufferSize;
|
||||
state.bytesWritten = 0;
|
||||
state.runningState = Org.Brotli.Dec.RunningState.Write;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (state.runningState != Org.Brotli.Dec.RunningState.InsertLoop)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
state.metaBlockLength -= state.insertLength;
|
||||
if (state.metaBlockLength <= 0)
|
||||
{
|
||||
state.runningState = Org.Brotli.Dec.RunningState.MainLoop;
|
||||
continue;
|
||||
}
|
||||
if (state.distanceCode < 0)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
if (state.blockLength[2] == 0)
|
||||
{
|
||||
DecodeDistanceBlockSwitch(state);
|
||||
}
|
||||
state.blockLength[2]--;
|
||||
Org.Brotli.Dec.BitReader.FillBitWindow(br);
|
||||
state.distanceCode = ReadSymbol(state.hGroup2.codes, state.hGroup2.trees[state.distContextMap[state.distContextMapSlice + (state.copyLength > 4 ? 3 : state.copyLength - 2)] & unchecked((int)(0xFF))], br);
|
||||
if (state.distanceCode >= state.numDirectDistanceCodes)
|
||||
{
|
||||
state.distanceCode -= state.numDirectDistanceCodes;
|
||||
int postfix = state.distanceCode & state.distancePostfixMask;
|
||||
state.distanceCode = (int)(((uint)state.distanceCode) >> state.distancePostfixBits);
|
||||
int n = ((int)(((uint)state.distanceCode) >> 1)) + 1;
|
||||
int offset = ((2 + (state.distanceCode & 1)) << n) - 4;
|
||||
state.distanceCode = state.numDirectDistanceCodes + postfix + ((offset + Org.Brotli.Dec.BitReader.ReadBits(br, n)) << state.distancePostfixBits);
|
||||
}
|
||||
}
|
||||
// Convert the distance code to the actual distance by possibly looking up past distances
|
||||
// from the ringBuffer.
|
||||
state.distance = TranslateShortCodes(state.distanceCode, state.distRb, state.distRbIdx);
|
||||
if (state.distance < 0)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Negative distance");
|
||||
}
|
||||
// COV_NF_LINE
|
||||
if (state.maxDistance != state.maxBackwardDistance && state.pos < state.maxBackwardDistance)
|
||||
{
|
||||
state.maxDistance = state.pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
state.maxDistance = state.maxBackwardDistance;
|
||||
}
|
||||
state.copyDst = state.pos;
|
||||
if (state.distance > state.maxDistance)
|
||||
{
|
||||
state.runningState = Org.Brotli.Dec.RunningState.Transform;
|
||||
continue;
|
||||
}
|
||||
if (state.distanceCode > 0)
|
||||
{
|
||||
state.distRb[state.distRbIdx & 3] = state.distance;
|
||||
state.distRbIdx++;
|
||||
}
|
||||
if (state.copyLength > state.metaBlockLength)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Invalid backward reference");
|
||||
}
|
||||
// COV_NF_LINE
|
||||
state.j = 0;
|
||||
state.runningState = Org.Brotli.Dec.RunningState.CopyLoop;
|
||||
goto case Org.Brotli.Dec.RunningState.CopyLoop;
|
||||
}
|
||||
|
||||
case Org.Brotli.Dec.RunningState.CopyLoop:
|
||||
{
|
||||
// fall through
|
||||
int src = (state.pos - state.distance) & ringBufferMask;
|
||||
int dst = state.pos;
|
||||
int copyLength = state.copyLength - state.j;
|
||||
if ((src + copyLength < ringBufferMask) && (dst + copyLength < ringBufferMask))
|
||||
{
|
||||
for (int k = 0; k < copyLength; ++k)
|
||||
{
|
||||
ringBuffer[dst++] = ringBuffer[src++];
|
||||
}
|
||||
state.j += copyLength;
|
||||
state.metaBlockLength -= copyLength;
|
||||
state.pos += copyLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; state.j < state.copyLength; )
|
||||
{
|
||||
ringBuffer[state.pos] = ringBuffer[(state.pos - state.distance) & ringBufferMask];
|
||||
state.metaBlockLength--;
|
||||
state.j++;
|
||||
if (state.pos++ == ringBufferMask)
|
||||
{
|
||||
state.nextRunningState = Org.Brotli.Dec.RunningState.CopyLoop;
|
||||
state.bytesToWrite = state.ringBufferSize;
|
||||
state.bytesWritten = 0;
|
||||
state.runningState = Org.Brotli.Dec.RunningState.Write;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (state.runningState == Org.Brotli.Dec.RunningState.CopyLoop)
|
||||
{
|
||||
state.runningState = Org.Brotli.Dec.RunningState.MainLoop;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
case Org.Brotli.Dec.RunningState.Transform:
|
||||
{
|
||||
if (state.copyLength >= Org.Brotli.Dec.Dictionary.MinWordLength && state.copyLength <= Org.Brotli.Dec.Dictionary.MaxWordLength)
|
||||
{
|
||||
int offset = Org.Brotli.Dec.Dictionary.OffsetsByLength[state.copyLength];
|
||||
int wordId = state.distance - state.maxDistance - 1;
|
||||
int shift = Org.Brotli.Dec.Dictionary.SizeBitsByLength[state.copyLength];
|
||||
int mask = (1 << shift) - 1;
|
||||
int wordIdx = wordId & mask;
|
||||
int transformIdx = (int)(((uint)wordId) >> shift);
|
||||
offset += wordIdx * state.copyLength;
|
||||
if (transformIdx < Org.Brotli.Dec.Transform.Transforms.Length)
|
||||
{
|
||||
int len = Org.Brotli.Dec.Transform.TransformDictionaryWord(ringBuffer, state.copyDst, Org.Brotli.Dec.Dictionary.GetData(), offset, state.copyLength, Org.Brotli.Dec.Transform.Transforms[transformIdx]);
|
||||
state.copyDst += len;
|
||||
state.pos += len;
|
||||
state.metaBlockLength -= len;
|
||||
if (state.copyDst >= state.ringBufferSize)
|
||||
{
|
||||
state.nextRunningState = Org.Brotli.Dec.RunningState.CopyWrapBuffer;
|
||||
state.bytesToWrite = state.ringBufferSize;
|
||||
state.bytesWritten = 0;
|
||||
state.runningState = Org.Brotli.Dec.RunningState.Write;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Invalid backward reference");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// COV_NF_LINE
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Invalid backward reference");
|
||||
}
|
||||
// COV_NF_LINE
|
||||
state.runningState = Org.Brotli.Dec.RunningState.MainLoop;
|
||||
continue;
|
||||
}
|
||||
|
||||
case Org.Brotli.Dec.RunningState.CopyWrapBuffer:
|
||||
{
|
||||
System.Array.Copy(ringBuffer, state.ringBufferSize, ringBuffer, 0, state.copyDst - state.ringBufferSize);
|
||||
state.runningState = Org.Brotli.Dec.RunningState.MainLoop;
|
||||
continue;
|
||||
}
|
||||
|
||||
case Org.Brotli.Dec.RunningState.ReadMetadata:
|
||||
{
|
||||
while (state.metaBlockLength > 0)
|
||||
{
|
||||
Org.Brotli.Dec.BitReader.ReadMoreInput(br);
|
||||
// Optimize
|
||||
Org.Brotli.Dec.BitReader.ReadBits(br, 8);
|
||||
state.metaBlockLength--;
|
||||
}
|
||||
state.runningState = Org.Brotli.Dec.RunningState.BlockStart;
|
||||
continue;
|
||||
}
|
||||
|
||||
case Org.Brotli.Dec.RunningState.CopyUncompressed:
|
||||
{
|
||||
CopyUncompressedData(state);
|
||||
continue;
|
||||
}
|
||||
|
||||
case Org.Brotli.Dec.RunningState.Write:
|
||||
{
|
||||
if (!WriteRingBuffer(state))
|
||||
{
|
||||
// Output buffer is full.
|
||||
return;
|
||||
}
|
||||
if (state.pos >= state.maxBackwardDistance)
|
||||
{
|
||||
state.maxDistance = state.maxBackwardDistance;
|
||||
}
|
||||
state.pos &= ringBufferMask;
|
||||
state.runningState = state.nextRunningState;
|
||||
continue;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Unexpected state " + state.runningState);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (state.runningState == Org.Brotli.Dec.RunningState.Finished)
|
||||
{
|
||||
if (state.metaBlockLength < 0)
|
||||
{
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Invalid metablock length");
|
||||
}
|
||||
Org.Brotli.Dec.BitReader.JumpToByteBoundary(br);
|
||||
Org.Brotli.Dec.BitReader.CheckHealth(state.br, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
97
AssetStudio/Brotli/Dictionary.cs
Normal file
97
AssetStudio/Brotli/Dictionary.cs
Normal file
File diff suppressed because one or more lines are too long
149
AssetStudio/Brotli/Huffman.cs
Normal file
149
AssetStudio/Brotli/Huffman.cs
Normal file
@@ -0,0 +1,149 @@
|
||||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>Utilities for building Huffman decoding tables.</summary>
|
||||
internal sealed class Huffman
|
||||
{
|
||||
/// <summary>
|
||||
/// Maximum possible Huffman table size for an alphabet size of 704, max code length 15 and root
|
||||
/// table bits 8.
|
||||
/// </summary>
|
||||
internal const int HuffmanMaxTableSize = 1080;
|
||||
|
||||
private const int MaxLength = 15;
|
||||
|
||||
/// <summary>Returns reverse(reverse(key, len) + 1, len).</summary>
|
||||
/// <remarks>
|
||||
/// Returns reverse(reverse(key, len) + 1, len).
|
||||
/// <p> reverse(key, len) is the bit-wise reversal of the len least significant bits of key.
|
||||
/// </remarks>
|
||||
private static int GetNextKey(int key, int len)
|
||||
{
|
||||
int step = 1 << (len - 1);
|
||||
while ((key & step) != 0)
|
||||
{
|
||||
step >>= 1;
|
||||
}
|
||||
return (key & (step - 1)) + step;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores
|
||||
/// <paramref name="item"/>
|
||||
/// in
|
||||
/// <c>table[0], table[step], table[2 * step] .., table[end]</c>
|
||||
/// .
|
||||
/// <p> Assumes that end is an integer multiple of step.
|
||||
/// </summary>
|
||||
private static void ReplicateValue(int[] table, int offset, int step, int end, int item)
|
||||
{
|
||||
do
|
||||
{
|
||||
end -= step;
|
||||
table[offset + end] = item;
|
||||
}
|
||||
while (end > 0);
|
||||
}
|
||||
|
||||
/// <param name="count">histogram of bit lengths for the remaining symbols,</param>
|
||||
/// <param name="len">code length of the next processed symbol.</param>
|
||||
/// <returns>table width of the next 2nd level table.</returns>
|
||||
private static int NextTableBitSize(int[] count, int len, int rootBits)
|
||||
{
|
||||
int left = 1 << (len - rootBits);
|
||||
while (len < MaxLength)
|
||||
{
|
||||
left -= count[len];
|
||||
if (left <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
len++;
|
||||
left <<= 1;
|
||||
}
|
||||
return len - rootBits;
|
||||
}
|
||||
|
||||
/// <summary>Builds Huffman lookup table assuming code lengths are in symbol order.</summary>
|
||||
internal static void BuildHuffmanTable(int[] rootTable, int tableOffset, int rootBits, int[] codeLengths, int codeLengthsSize)
|
||||
{
|
||||
int key;
|
||||
// Reversed prefix code.
|
||||
int[] sorted = new int[codeLengthsSize];
|
||||
// Symbols sorted by code length.
|
||||
// TODO: fill with zeroes?
|
||||
int[] count = new int[MaxLength + 1];
|
||||
// Number of codes of each length.
|
||||
int[] offset = new int[MaxLength + 1];
|
||||
// Offsets in sorted table for each length.
|
||||
int symbol;
|
||||
// Build histogram of code lengths.
|
||||
for (symbol = 0; symbol < codeLengthsSize; symbol++)
|
||||
{
|
||||
count[codeLengths[symbol]]++;
|
||||
}
|
||||
// Generate offsets into sorted symbol table by code length.
|
||||
offset[1] = 0;
|
||||
for (int len = 1; len < MaxLength; len++)
|
||||
{
|
||||
offset[len + 1] = offset[len] + count[len];
|
||||
}
|
||||
// Sort symbols by length, by symbol order within each length.
|
||||
for (symbol = 0; symbol < codeLengthsSize; symbol++)
|
||||
{
|
||||
if (codeLengths[symbol] != 0)
|
||||
{
|
||||
sorted[offset[codeLengths[symbol]]++] = symbol;
|
||||
}
|
||||
}
|
||||
int tableBits = rootBits;
|
||||
int tableSize = 1 << tableBits;
|
||||
int totalSize = tableSize;
|
||||
// Special case code with only one value.
|
||||
if (offset[MaxLength] == 1)
|
||||
{
|
||||
for (key = 0; key < totalSize; key++)
|
||||
{
|
||||
rootTable[tableOffset + key] = sorted[0];
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Fill in root table.
|
||||
key = 0;
|
||||
symbol = 0;
|
||||
for (int len = 1, step = 2; len <= rootBits; len++, step <<= 1)
|
||||
{
|
||||
for (; count[len] > 0; count[len]--)
|
||||
{
|
||||
ReplicateValue(rootTable, tableOffset + key, step, tableSize, len << 16 | sorted[symbol++]);
|
||||
key = GetNextKey(key, len);
|
||||
}
|
||||
}
|
||||
// Fill in 2nd level tables and add pointers to root table.
|
||||
int mask = totalSize - 1;
|
||||
int low = -1;
|
||||
int currentOffset = tableOffset;
|
||||
for (int len = rootBits + 1, step = 2; len <= MaxLength; len++, step <<= 1)
|
||||
{
|
||||
for (; count[len] > 0; count[len]--)
|
||||
{
|
||||
if ((key & mask) != low)
|
||||
{
|
||||
currentOffset += tableSize;
|
||||
tableBits = NextTableBitSize(count, len, rootBits);
|
||||
tableSize = 1 << tableBits;
|
||||
totalSize += tableSize;
|
||||
low = key & mask;
|
||||
rootTable[tableOffset + low] = (tableBits + rootBits) << 16 | (currentOffset - tableOffset - low);
|
||||
}
|
||||
ReplicateValue(rootTable, currentOffset + (key >> rootBits), step, tableSize, (len - rootBits) << 16 | sorted[symbol++]);
|
||||
key = GetNextKey(key, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
50
AssetStudio/Brotli/HuffmanTreeGroup.cs
Normal file
50
AssetStudio/Brotli/HuffmanTreeGroup.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>Contains a collection of huffman trees with the same alphabet size.</summary>
|
||||
internal sealed class HuffmanTreeGroup
|
||||
{
|
||||
/// <summary>The maximal alphabet size in this group.</summary>
|
||||
private int alphabetSize;
|
||||
|
||||
/// <summary>Storage for Huffman lookup tables.</summary>
|
||||
internal int[] codes;
|
||||
|
||||
/// <summary>
|
||||
/// Offsets of distinct lookup tables in
|
||||
/// <see cref="codes"/>
|
||||
/// storage.
|
||||
/// </summary>
|
||||
internal int[] trees;
|
||||
|
||||
/// <summary>Initializes the Huffman tree group.</summary>
|
||||
/// <param name="group">POJO to be initialised</param>
|
||||
/// <param name="alphabetSize">the maximal alphabet size in this group</param>
|
||||
/// <param name="n">number of Huffman codes</param>
|
||||
internal static void Init(Org.Brotli.Dec.HuffmanTreeGroup group, int alphabetSize, int n)
|
||||
{
|
||||
group.alphabetSize = alphabetSize;
|
||||
group.codes = new int[n * Org.Brotli.Dec.Huffman.HuffmanMaxTableSize];
|
||||
group.trees = new int[n];
|
||||
}
|
||||
|
||||
/// <summary>Decodes Huffman trees from input stream and constructs lookup tables.</summary>
|
||||
/// <param name="group">target POJO</param>
|
||||
/// <param name="br">data source</param>
|
||||
internal static void Decode(Org.Brotli.Dec.HuffmanTreeGroup group, Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
int next = 0;
|
||||
int n = group.trees.Length;
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
group.trees[i] = next;
|
||||
Org.Brotli.Dec.Decode.ReadHuffmanCode(group.alphabetSize, group.codes, next, br);
|
||||
next += Org.Brotli.Dec.Huffman.HuffmanMaxTableSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
36
AssetStudio/Brotli/IntReader.cs
Normal file
36
AssetStudio/Brotli/IntReader.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
/* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>Byte-to-int conversion magic.</summary>
|
||||
internal sealed class IntReader
|
||||
{
|
||||
private byte[] byteBuffer;
|
||||
|
||||
private int[] intBuffer;
|
||||
|
||||
internal static void Init(Org.Brotli.Dec.IntReader ir, byte[] byteBuffer, int[] intBuffer)
|
||||
{
|
||||
ir.byteBuffer = byteBuffer;
|
||||
ir.intBuffer = intBuffer;
|
||||
}
|
||||
|
||||
/// <summary>Translates bytes to ints.</summary>
|
||||
/// <remarks>
|
||||
/// Translates bytes to ints.
|
||||
/// NB: intLen == 4 * byteSize!
|
||||
/// NB: intLen should be less or equal to intBuffer length.
|
||||
/// </remarks>
|
||||
internal static void Convert(Org.Brotli.Dec.IntReader ir, int intLen)
|
||||
{
|
||||
for (int i = 0; i < intLen; ++i)
|
||||
{
|
||||
ir.intBuffer[i] = ((ir.byteBuffer[i * 4] & unchecked((int)(0xFF)))) | ((ir.byteBuffer[(i * 4) + 1] & unchecked((int)(0xFF))) << 8) | ((ir.byteBuffer[(i * 4) + 2] & unchecked((int)(0xFF))) << 16) | ((ir.byteBuffer[(i * 4) + 3] & unchecked((int
|
||||
)(0xFF))) << 24);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
33
AssetStudio/Brotli/Prefix.cs
Normal file
33
AssetStudio/Brotli/Prefix.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>Lookup tables to map prefix codes to value ranges.</summary>
|
||||
/// <remarks>
|
||||
/// Lookup tables to map prefix codes to value ranges.
|
||||
/// <p> This is used during decoding of the block lengths, literal insertion lengths and copy
|
||||
/// lengths.
|
||||
/// <p> Range represents values: [offset, offset + 2 ^ n_bits)
|
||||
/// </remarks>
|
||||
internal sealed class Prefix
|
||||
{
|
||||
internal static readonly int[] BlockLengthOffset = new int[] { 1, 5, 9, 13, 17, 25, 33, 41, 49, 65, 81, 97, 113, 145, 177, 209, 241, 305, 369, 497, 753, 1265, 2289, 4337, 8433, 16625 };
|
||||
|
||||
internal static readonly int[] BlockLengthNBits = new int[] { 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8, 9, 10, 11, 12, 13, 24 };
|
||||
|
||||
internal static readonly int[] InsertLengthOffset = new int[] { 0, 1, 2, 3, 4, 5, 6, 8, 10, 14, 18, 26, 34, 50, 66, 98, 130, 194, 322, 578, 1090, 2114, 6210, 22594 };
|
||||
|
||||
internal static readonly int[] InsertLengthNBits = new int[] { 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 12, 14, 24 };
|
||||
|
||||
internal static readonly int[] CopyLengthOffset = new int[] { 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 18, 22, 30, 38, 54, 70, 102, 134, 198, 326, 582, 1094, 2118 };
|
||||
|
||||
internal static readonly int[] CopyLengthNBits = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 24 };
|
||||
|
||||
internal static readonly int[] InsertRangeLut = new int[] { 0, 0, 8, 8, 0, 16, 8, 16, 16 };
|
||||
|
||||
internal static readonly int[] CopyRangeLut = new int[] { 0, 8, 0, 8, 16, 0, 16, 8, 16 };
|
||||
}
|
||||
}
|
||||
37
AssetStudio/Brotli/RunningState.cs
Normal file
37
AssetStudio/Brotli/RunningState.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>Enumeration of decoding state-machine.</summary>
|
||||
internal sealed class RunningState
|
||||
{
|
||||
internal const int Uninitialized = 0;
|
||||
|
||||
internal const int BlockStart = 1;
|
||||
|
||||
internal const int CompressedBlockStart = 2;
|
||||
|
||||
internal const int MainLoop = 3;
|
||||
|
||||
internal const int ReadMetadata = 4;
|
||||
|
||||
internal const int CopyUncompressed = 5;
|
||||
|
||||
internal const int InsertLoop = 6;
|
||||
|
||||
internal const int CopyLoop = 7;
|
||||
|
||||
internal const int CopyWrapBuffer = 8;
|
||||
|
||||
internal const int Transform = 9;
|
||||
|
||||
internal const int Finished = 10;
|
||||
|
||||
internal const int Closed = 11;
|
||||
|
||||
internal const int Write = 12;
|
||||
}
|
||||
}
|
||||
171
AssetStudio/Brotli/State.cs
Normal file
171
AssetStudio/Brotli/State.cs
Normal file
@@ -0,0 +1,171 @@
|
||||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
internal sealed class State
|
||||
{
|
||||
internal int runningState = Org.Brotli.Dec.RunningState.Uninitialized;
|
||||
|
||||
internal int nextRunningState;
|
||||
|
||||
internal readonly Org.Brotli.Dec.BitReader br = new Org.Brotli.Dec.BitReader();
|
||||
|
||||
internal byte[] ringBuffer;
|
||||
|
||||
internal readonly int[] blockTypeTrees = new int[3 * Org.Brotli.Dec.Huffman.HuffmanMaxTableSize];
|
||||
|
||||
internal readonly int[] blockLenTrees = new int[3 * Org.Brotli.Dec.Huffman.HuffmanMaxTableSize];
|
||||
|
||||
internal int metaBlockLength;
|
||||
|
||||
internal bool inputEnd;
|
||||
|
||||
internal bool isUncompressed;
|
||||
|
||||
internal bool isMetadata;
|
||||
|
||||
internal readonly Org.Brotli.Dec.HuffmanTreeGroup hGroup0 = new Org.Brotli.Dec.HuffmanTreeGroup();
|
||||
|
||||
internal readonly Org.Brotli.Dec.HuffmanTreeGroup hGroup1 = new Org.Brotli.Dec.HuffmanTreeGroup();
|
||||
|
||||
internal readonly Org.Brotli.Dec.HuffmanTreeGroup hGroup2 = new Org.Brotli.Dec.HuffmanTreeGroup();
|
||||
|
||||
internal readonly int[] blockLength = new int[3];
|
||||
|
||||
internal readonly int[] numBlockTypes = new int[3];
|
||||
|
||||
internal readonly int[] blockTypeRb = new int[6];
|
||||
|
||||
internal readonly int[] distRb = new int[] { 16, 15, 11, 4 };
|
||||
|
||||
internal int pos = 0;
|
||||
|
||||
internal int maxDistance = 0;
|
||||
|
||||
internal int distRbIdx = 0;
|
||||
|
||||
internal bool trivialLiteralContext = false;
|
||||
|
||||
internal int literalTreeIndex = 0;
|
||||
|
||||
internal int literalTree;
|
||||
|
||||
internal int j;
|
||||
|
||||
internal int insertLength;
|
||||
|
||||
internal byte[] contextModes;
|
||||
|
||||
internal byte[] contextMap;
|
||||
|
||||
internal int contextMapSlice;
|
||||
|
||||
internal int distContextMapSlice;
|
||||
|
||||
internal int contextLookupOffset1;
|
||||
|
||||
internal int contextLookupOffset2;
|
||||
|
||||
internal int treeCommandOffset;
|
||||
|
||||
internal int distanceCode;
|
||||
|
||||
internal byte[] distContextMap;
|
||||
|
||||
internal int numDirectDistanceCodes;
|
||||
|
||||
internal int distancePostfixMask;
|
||||
|
||||
internal int distancePostfixBits;
|
||||
|
||||
internal int distance;
|
||||
|
||||
internal int copyLength;
|
||||
|
||||
internal int copyDst;
|
||||
|
||||
internal int maxBackwardDistance;
|
||||
|
||||
internal int maxRingBufferSize;
|
||||
|
||||
internal int ringBufferSize = 0;
|
||||
|
||||
internal long expectedTotalSize = 0;
|
||||
|
||||
internal byte[] customDictionary = new byte[0];
|
||||
|
||||
internal int bytesToIgnore = 0;
|
||||
|
||||
internal int outputOffset;
|
||||
|
||||
internal int outputLength;
|
||||
|
||||
internal int outputUsed;
|
||||
|
||||
internal int bytesWritten;
|
||||
|
||||
internal int bytesToWrite;
|
||||
|
||||
internal byte[] output;
|
||||
|
||||
// Current meta-block header information.
|
||||
// TODO: Update to current spec.
|
||||
private static int DecodeWindowBits(Org.Brotli.Dec.BitReader br)
|
||||
{
|
||||
if (Org.Brotli.Dec.BitReader.ReadBits(br, 1) == 0)
|
||||
{
|
||||
return 16;
|
||||
}
|
||||
int n = Org.Brotli.Dec.BitReader.ReadBits(br, 3);
|
||||
if (n != 0)
|
||||
{
|
||||
return 17 + n;
|
||||
}
|
||||
n = Org.Brotli.Dec.BitReader.ReadBits(br, 3);
|
||||
if (n != 0)
|
||||
{
|
||||
return 8 + n;
|
||||
}
|
||||
return 17;
|
||||
}
|
||||
|
||||
/// <summary>Associate input with decoder state.</summary>
|
||||
/// <param name="state">uninitialized state without associated input</param>
|
||||
/// <param name="input">compressed data source</param>
|
||||
internal static void SetInput(Org.Brotli.Dec.State state, System.IO.Stream input)
|
||||
{
|
||||
if (state.runningState != Org.Brotli.Dec.RunningState.Uninitialized)
|
||||
{
|
||||
throw new System.InvalidOperationException("State MUST be uninitialized");
|
||||
}
|
||||
Org.Brotli.Dec.BitReader.Init(state.br, input);
|
||||
int windowBits = DecodeWindowBits(state.br);
|
||||
if (windowBits == 9)
|
||||
{
|
||||
/* Reserved case for future expansion. */
|
||||
throw new Org.Brotli.Dec.BrotliRuntimeException("Invalid 'windowBits' code");
|
||||
}
|
||||
state.maxRingBufferSize = 1 << windowBits;
|
||||
state.maxBackwardDistance = state.maxRingBufferSize - 16;
|
||||
state.runningState = Org.Brotli.Dec.RunningState.BlockStart;
|
||||
}
|
||||
|
||||
/// <exception cref="System.IO.IOException"/>
|
||||
internal static void Close(Org.Brotli.Dec.State state)
|
||||
{
|
||||
if (state.runningState == Org.Brotli.Dec.RunningState.Uninitialized)
|
||||
{
|
||||
throw new System.InvalidOperationException("State MUST be initialized");
|
||||
}
|
||||
if (state.runningState == Org.Brotli.Dec.RunningState.Closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
state.runningState = Org.Brotli.Dec.RunningState.Closed;
|
||||
Org.Brotli.Dec.BitReader.Close(state.br);
|
||||
}
|
||||
}
|
||||
}
|
||||
154
AssetStudio/Brotli/Transform.cs
Normal file
154
AssetStudio/Brotli/Transform.cs
Normal file
@@ -0,0 +1,154 @@
|
||||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>Transformations on dictionary words.</summary>
|
||||
internal sealed class Transform
|
||||
{
|
||||
private readonly byte[] prefix;
|
||||
|
||||
private readonly int type;
|
||||
|
||||
private readonly byte[] suffix;
|
||||
|
||||
internal Transform(string prefix, int type, string suffix)
|
||||
{
|
||||
this.prefix = ReadUniBytes(prefix);
|
||||
this.type = type;
|
||||
this.suffix = ReadUniBytes(suffix);
|
||||
}
|
||||
|
||||
internal static byte[] ReadUniBytes(string uniBytes)
|
||||
{
|
||||
byte[] result = new byte[uniBytes.Length];
|
||||
for (int i = 0; i < result.Length; ++i)
|
||||
{
|
||||
result[i] = unchecked((byte)uniBytes[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static readonly Org.Brotli.Dec.Transform[] Transforms = new Org.Brotli.Dec.Transform[] { new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, string.Empty), new Org.Brotli.Dec.Transform(string.Empty,
|
||||
Org.Brotli.Dec.WordTransformType.Identity, " "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.Identity, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitFirst1, string.Empty), new Org.Brotli.Dec.Transform
|
||||
(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " the "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.Identity
|
||||
, string.Empty), new Org.Brotli.Dec.Transform("s ", Org.Brotli.Dec.WordTransformType.Identity, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " of "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
|
||||
.UppercaseFirst, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " and "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitFirst2, string.Empty), new Org.Brotli.Dec.Transform
|
||||
(string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast1, string.Empty), new Org.Brotli.Dec.Transform(", ", Org.Brotli.Dec.WordTransformType.Identity, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity
|
||||
, ", "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseFirst, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " in "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
|
||||
.Identity, " to "), new Org.Brotli.Dec.Transform("e ", Org.Brotli.Dec.WordTransformType.Identity, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "\""), new Org.Brotli.Dec.Transform(string.Empty,
|
||||
Org.Brotli.Dec.WordTransformType.Identity, "."), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "\">"), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "\n"), new
|
||||
Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast3, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "]"), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
|
||||
.Identity, " for "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitFirst3, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast2, string.Empty), new Org.Brotli.Dec.Transform
|
||||
(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " a "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " that "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseFirst
|
||||
, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, ". "), new Org.Brotli.Dec.Transform(".", Org.Brotli.Dec.WordTransformType.Identity, string.Empty), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType
|
||||
.Identity, ", "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitFirst4, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " with "), new Org.Brotli.Dec.Transform
|
||||
(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "'"), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " from "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity
|
||||
, " by "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitFirst5, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitFirst6, string.Empty), new Org.Brotli.Dec.Transform
|
||||
(" the ", Org.Brotli.Dec.WordTransformType.Identity, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast4, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
|
||||
.Identity, ". The "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " on "), new Org.Brotli.Dec.Transform
|
||||
(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " as "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " is "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast7
|
||||
, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast1, "ing "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "\n\t"), new Org.Brotli.Dec.Transform(string.Empty
|
||||
, Org.Brotli.Dec.WordTransformType.Identity, ":"), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.Identity, ". "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "ed "), new Org.Brotli.Dec.Transform
|
||||
(string.Empty, Org.Brotli.Dec.WordTransformType.OmitFirst9, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitFirst7, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
|
||||
.OmitLast6, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "("), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst, ", "), new Org.Brotli.Dec.Transform
|
||||
(string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast8, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " at "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
|
||||
.Identity, "ly "), new Org.Brotli.Dec.Transform(" the ", Org.Brotli.Dec.WordTransformType.Identity, " of "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast5, string.Empty), new Org.Brotli.Dec.Transform(
|
||||
string.Empty, Org.Brotli.Dec.WordTransformType.OmitLast9, string.Empty), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseFirst, ", "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst
|
||||
, "\""), new Org.Brotli.Dec.Transform(".", Org.Brotli.Dec.WordTransformType.Identity, "("), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
|
||||
.UppercaseFirst, "\">"), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "=\""), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.Identity, "."), new Org.Brotli.Dec.Transform(".com/",
|
||||
Org.Brotli.Dec.WordTransformType.Identity, string.Empty), new Org.Brotli.Dec.Transform(" the ", Org.Brotli.Dec.WordTransformType.Identity, " of the "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst
|
||||
, "'"), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, ". This "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, ","), new Org.Brotli.Dec.Transform(".", Org.Brotli.Dec.WordTransformType
|
||||
.Identity, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst, "("), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst, "."), new Org.Brotli.Dec.Transform
|
||||
(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, " not "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.Identity, "=\""), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "er "
|
||||
), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseAll, " "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "al "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType
|
||||
.UppercaseAll, string.Empty), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "='"), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, "\""), new Org.Brotli.Dec.Transform
|
||||
(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst, ". "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.Identity, "("), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity,
|
||||
"ful "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseFirst, ". "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "ive "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
|
||||
.Identity, "less "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, "'"), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "est "), new Org.Brotli.Dec.Transform
|
||||
(" ", Org.Brotli.Dec.WordTransformType.UppercaseFirst, "."), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, "\">"), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.Identity, "='"
|
||||
), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst, ","), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity, "ize "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType
|
||||
.UppercaseAll, "."), new Org.Brotli.Dec.Transform("\u00c2\u00a0", Org.Brotli.Dec.WordTransformType.Identity, string.Empty), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.Identity, ","), new Org.Brotli.Dec.Transform(string.Empty
|
||||
, Org.Brotli.Dec.WordTransformType.UppercaseFirst, "=\""), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, "=\""), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.Identity
|
||||
, "ous "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, ", "), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseFirst, "='"), new Org.Brotli.Dec.Transform(" ",
|
||||
Org.Brotli.Dec.WordTransformType.UppercaseFirst, ","), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseAll, "=\""), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseAll, ", "), new Org.Brotli.Dec.Transform
|
||||
(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, ","), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, "("), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.
|
||||
UppercaseAll, ". "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseAll, "."), new Org.Brotli.Dec.Transform(string.Empty, Org.Brotli.Dec.WordTransformType.UppercaseAll, "='"), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType
|
||||
.UppercaseAll, ". "), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseFirst, "=\""), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType.UppercaseAll, "='"), new Org.Brotli.Dec.Transform(" ", Org.Brotli.Dec.WordTransformType
|
||||
.UppercaseFirst, "='") };
|
||||
|
||||
internal static int TransformDictionaryWord(byte[] dst, int dstOffset, byte[] word, int wordOffset, int len, Org.Brotli.Dec.Transform transform)
|
||||
{
|
||||
int offset = dstOffset;
|
||||
// Copy prefix.
|
||||
byte[] @string = transform.prefix;
|
||||
int tmp = @string.Length;
|
||||
int i = 0;
|
||||
// In most cases tmp < 10 -> no benefits from System.arrayCopy
|
||||
while (i < tmp)
|
||||
{
|
||||
dst[offset++] = @string[i++];
|
||||
}
|
||||
// Copy trimmed word.
|
||||
int op = transform.type;
|
||||
tmp = Org.Brotli.Dec.WordTransformType.GetOmitFirst(op);
|
||||
if (tmp > len)
|
||||
{
|
||||
tmp = len;
|
||||
}
|
||||
wordOffset += tmp;
|
||||
len -= tmp;
|
||||
len -= Org.Brotli.Dec.WordTransformType.GetOmitLast(op);
|
||||
i = len;
|
||||
while (i > 0)
|
||||
{
|
||||
dst[offset++] = word[wordOffset++];
|
||||
i--;
|
||||
}
|
||||
if (op == Org.Brotli.Dec.WordTransformType.UppercaseAll || op == Org.Brotli.Dec.WordTransformType.UppercaseFirst)
|
||||
{
|
||||
int uppercaseOffset = offset - len;
|
||||
if (op == Org.Brotli.Dec.WordTransformType.UppercaseFirst)
|
||||
{
|
||||
len = 1;
|
||||
}
|
||||
while (len > 0)
|
||||
{
|
||||
tmp = dst[uppercaseOffset] & unchecked((int)(0xFF));
|
||||
if (tmp < unchecked((int)(0xc0)))
|
||||
{
|
||||
if (tmp >= 'a' && tmp <= 'z')
|
||||
{
|
||||
dst[uppercaseOffset] ^= unchecked((byte)32);
|
||||
}
|
||||
uppercaseOffset += 1;
|
||||
len -= 1;
|
||||
}
|
||||
else if (tmp < unchecked((int)(0xe0)))
|
||||
{
|
||||
dst[uppercaseOffset + 1] ^= unchecked((byte)32);
|
||||
uppercaseOffset += 2;
|
||||
len -= 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[uppercaseOffset + 2] ^= unchecked((byte)5);
|
||||
uppercaseOffset += 3;
|
||||
len -= 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Copy suffix.
|
||||
@string = transform.suffix;
|
||||
tmp = @string.Length;
|
||||
i = 0;
|
||||
while (i < tmp)
|
||||
{
|
||||
dst[offset++] = @string[i++];
|
||||
}
|
||||
return offset - dstOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
59
AssetStudio/Brotli/Utils.cs
Normal file
59
AssetStudio/Brotli/Utils.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>A set of utility methods.</summary>
|
||||
internal sealed class Utils
|
||||
{
|
||||
private static readonly byte[] ByteZeroes = new byte[1024];
|
||||
|
||||
private static readonly int[] IntZeroes = new int[1024];
|
||||
|
||||
/// <summary>Fills byte array with zeroes.</summary>
|
||||
/// <remarks>
|
||||
/// Fills byte array with zeroes.
|
||||
/// <p> Current implementation uses
|
||||
/// <see cref="System.Array.Copy(object, int, object, int, int)"/>
|
||||
/// , so it should be used for length not
|
||||
/// less than 16.
|
||||
/// </remarks>
|
||||
/// <param name="dest">array to fill with zeroes</param>
|
||||
/// <param name="offset">the first byte to fill</param>
|
||||
/// <param name="length">number of bytes to change</param>
|
||||
internal static void FillWithZeroes(byte[] dest, int offset, int length)
|
||||
{
|
||||
int cursor = 0;
|
||||
while (cursor < length)
|
||||
{
|
||||
int step = System.Math.Min(cursor + 1024, length) - cursor;
|
||||
System.Array.Copy(ByteZeroes, 0, dest, offset + cursor, step);
|
||||
cursor += step;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Fills int array with zeroes.</summary>
|
||||
/// <remarks>
|
||||
/// Fills int array with zeroes.
|
||||
/// <p> Current implementation uses
|
||||
/// <see cref="System.Array.Copy(object, int, object, int, int)"/>
|
||||
/// , so it should be used for length not
|
||||
/// less than 16.
|
||||
/// </remarks>
|
||||
/// <param name="dest">array to fill with zeroes</param>
|
||||
/// <param name="offset">the first item to fill</param>
|
||||
/// <param name="length">number of item to change</param>
|
||||
internal static void FillWithZeroes(int[] dest, int offset, int length)
|
||||
{
|
||||
int cursor = 0;
|
||||
while (cursor < length)
|
||||
{
|
||||
int step = System.Math.Min(cursor + 1024, length) - cursor;
|
||||
System.Array.Copy(IntZeroes, 0, dest, offset + cursor, step);
|
||||
cursor += step;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
68
AssetStudio/Brotli/WordTransformType.cs
Normal file
68
AssetStudio/Brotli/WordTransformType.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
/* Copyright 2015 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
namespace Org.Brotli.Dec
|
||||
{
|
||||
/// <summary>Enumeration of all possible word transformations.</summary>
|
||||
/// <remarks>
|
||||
/// Enumeration of all possible word transformations.
|
||||
/// <p>There are two simple types of transforms: omit X first/last symbols, two character-case
|
||||
/// transforms and the identity transform.
|
||||
/// </remarks>
|
||||
internal sealed class WordTransformType
|
||||
{
|
||||
internal const int Identity = 0;
|
||||
|
||||
internal const int OmitLast1 = 1;
|
||||
|
||||
internal const int OmitLast2 = 2;
|
||||
|
||||
internal const int OmitLast3 = 3;
|
||||
|
||||
internal const int OmitLast4 = 4;
|
||||
|
||||
internal const int OmitLast5 = 5;
|
||||
|
||||
internal const int OmitLast6 = 6;
|
||||
|
||||
internal const int OmitLast7 = 7;
|
||||
|
||||
internal const int OmitLast8 = 8;
|
||||
|
||||
internal const int OmitLast9 = 9;
|
||||
|
||||
internal const int UppercaseFirst = 10;
|
||||
|
||||
internal const int UppercaseAll = 11;
|
||||
|
||||
internal const int OmitFirst1 = 12;
|
||||
|
||||
internal const int OmitFirst2 = 13;
|
||||
|
||||
internal const int OmitFirst3 = 14;
|
||||
|
||||
internal const int OmitFirst4 = 15;
|
||||
|
||||
internal const int OmitFirst5 = 16;
|
||||
|
||||
internal const int OmitFirst6 = 17;
|
||||
|
||||
internal const int OmitFirst7 = 18;
|
||||
|
||||
internal const int OmitFirst8 = 19;
|
||||
|
||||
internal const int OmitFirst9 = 20;
|
||||
|
||||
internal static int GetOmitFirst(int type)
|
||||
{
|
||||
return type >= OmitFirst1 ? (type - OmitFirst1 + 1) : 0;
|
||||
}
|
||||
|
||||
internal static int GetOmitLast(int type)
|
||||
{
|
||||
return type <= OmitLast9 ? (type - OmitLast1 + 1) : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
53
AssetStudio/BuildTarget.cs
Normal file
53
AssetStudio/BuildTarget.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public enum BuildTarget
|
||||
{
|
||||
NoTarget = -2,
|
||||
DashboardWidget = 1,
|
||||
StandaloneOSX = 2,
|
||||
StandaloneOSXPPC = 3,
|
||||
StandaloneOSXIntel = 4,
|
||||
StandaloneWindows,
|
||||
WebPlayer,
|
||||
WebPlayerStreamed,
|
||||
Wii = 8,
|
||||
iOS = 9,
|
||||
PS3,
|
||||
XBOX360,
|
||||
Android = 13,
|
||||
StandaloneGLESEmu = 14,
|
||||
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,
|
||||
UnknownPlatform = 9999
|
||||
}
|
||||
}
|
||||
20
AssetStudio/BuildType.cs
Normal file
20
AssetStudio/BuildType.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class BuildType
|
||||
{
|
||||
private string buildType;
|
||||
|
||||
public BuildType(string type)
|
||||
{
|
||||
buildType = type;
|
||||
}
|
||||
|
||||
public bool IsAlpha => buildType == "a";
|
||||
public bool IsPatch => buildType == "p";
|
||||
}
|
||||
}
|
||||
314
AssetStudio/BundleFile.cs
Normal file
314
AssetStudio/BundleFile.cs
Normal file
@@ -0,0 +1,314 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Lz4;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
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 uint flags;
|
||||
}
|
||||
|
||||
public class StorageBlock
|
||||
{
|
||||
public uint compressedSize;
|
||||
public uint uncompressedSize;
|
||||
public ushort 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();
|
||||
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":
|
||||
ReadHeader(reader);
|
||||
ReadBlocksInfoAndDirectory(reader);
|
||||
using (var blocksStream = CreateBlocksStream(reader.FullPath))
|
||||
{
|
||||
ReadBlocks(reader, blocksStream);
|
||||
ReadFiles(blocksStream, reader.FullPath);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadHeaderAndBlocksInfo(EndianBinaryReader reader)
|
||||
{
|
||||
var isCompressed = m_Header.signature == "UnityWeb";
|
||||
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(),
|
||||
flags = (ushort)(isCompressed ? 1 : 0)
|
||||
};
|
||||
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)
|
||||
{
|
||||
foreach (var blockInfo in m_BlocksInfo)
|
||||
{
|
||||
var uncompressedBytes = reader.ReadBytes((int)blockInfo.compressedSize);
|
||||
if (blockInfo.flags == 1)
|
||||
{
|
||||
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 ReadHeader(EndianBinaryReader reader)
|
||||
{
|
||||
m_Header.size = reader.ReadInt64();
|
||||
m_Header.compressedBlocksInfoSize = reader.ReadUInt32();
|
||||
m_Header.uncompressedBlocksInfoSize = reader.ReadUInt32();
|
||||
m_Header.flags = reader.ReadUInt32();
|
||||
if (m_Header.signature != "UnityFS")
|
||||
{
|
||||
reader.ReadByte();
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadBlocksInfoAndDirectory(EndianBinaryReader reader)
|
||||
{
|
||||
byte[] blocksInfoBytes;
|
||||
if (m_Header.version >= 7)
|
||||
{
|
||||
reader.AlignStream(16);
|
||||
}
|
||||
if ((m_Header.flags & 0x80) != 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 kArchiveBlocksAndDirectoryInfoCombined
|
||||
{
|
||||
blocksInfoBytes = reader.ReadBytes((int)m_Header.compressedBlocksInfoSize);
|
||||
}
|
||||
var blocksInfoCompressedStream = new MemoryStream(blocksInfoBytes);
|
||||
MemoryStream blocksInfoUncompresseddStream;
|
||||
switch (m_Header.flags & 0x3F) //kArchiveCompressionTypeMask
|
||||
{
|
||||
default: //None
|
||||
{
|
||||
blocksInfoUncompresseddStream = blocksInfoCompressedStream;
|
||||
break;
|
||||
}
|
||||
case 1: //LZMA
|
||||
{
|
||||
blocksInfoUncompresseddStream = new MemoryStream((int)(m_Header.uncompressedBlocksInfoSize));
|
||||
SevenZipHelper.StreamDecompress(blocksInfoCompressedStream, blocksInfoUncompresseddStream, m_Header.compressedBlocksInfoSize, m_Header.uncompressedBlocksInfoSize);
|
||||
blocksInfoUncompresseddStream.Position = 0;
|
||||
blocksInfoCompressedStream.Close();
|
||||
break;
|
||||
}
|
||||
case 2: //LZ4
|
||||
case 3: //LZ4HC
|
||||
{
|
||||
var uncompressedBytes = new byte[m_Header.uncompressedBlocksInfoSize];
|
||||
using (var decoder = new Lz4DecoderStream(blocksInfoCompressedStream))
|
||||
{
|
||||
decoder.Read(uncompressedBytes, 0, uncompressedBytes.Length);
|
||||
}
|
||||
blocksInfoUncompresseddStream = new MemoryStream(uncompressedBytes);
|
||||
break;
|
||||
}
|
||||
}
|
||||
using (var blocksInfoReader = new EndianBinaryReader(blocksInfoUncompresseddStream))
|
||||
{
|
||||
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 = 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)
|
||||
{
|
||||
switch (blockInfo.flags & 0x3F) //kStorageBlockCompressionTypeMask
|
||||
{
|
||||
default: //None
|
||||
{
|
||||
reader.BaseStream.CopyTo(blocksStream, blockInfo.compressedSize);
|
||||
break;
|
||||
}
|
||||
case 1: //LZMA
|
||||
{
|
||||
SevenZipHelper.StreamDecompress(reader.BaseStream, blocksStream, blockInfo.compressedSize, blockInfo.uncompressedSize);
|
||||
break;
|
||||
}
|
||||
case 2: //LZ4
|
||||
case 3: //LZ4HC
|
||||
{
|
||||
var compressedStream = new MemoryStream(reader.ReadBytes((int)blockInfo.compressedSize));
|
||||
using (var lz4Stream = new Lz4DecoderStream(compressedStream))
|
||||
{
|
||||
lz4Stream.CopyTo(blocksStream, blockInfo.uncompressedSize);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
blocksStream.Position = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
379
AssetStudio/ClassIDType.cs
Normal file
379
AssetStudio/ClassIDType.cs
Normal file
@@ -0,0 +1,379 @@
|
||||
// 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,
|
||||
//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,
|
||||
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
|
||||
}
|
||||
}
|
||||
23
AssetStudio/Classes/Animation.cs
Normal file
23
AssetStudio/Classes/Animation.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1049
AssetStudio/Classes/AnimationClip.cs
Normal file
1049
AssetStudio/Classes/AnimationClip.cs
Normal file
File diff suppressed because it is too large
Load Diff
67
AssetStudio/Classes/Animator.cs
Normal file
67
AssetStudio/Classes/Animator.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
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);
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
605
AssetStudio/Classes/AnimatorController.cs
Normal file
605
AssetStudio/Classes/AnimatorController.cs
Normal file
@@ -0,0 +1,605 @@
|
||||
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 KeyValuePair<uint, string>[tosSize];
|
||||
for (int i = 0; i < tosSize; i++)
|
||||
{
|
||||
m_TOS[i] = new KeyValuePair<uint, string>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
37
AssetStudio/Classes/AnimatorOverrideController.cs
Normal file
37
AssetStudio/Classes/AnimatorOverrideController.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
44
AssetStudio/Classes/AssetBundle.cs
Normal file
44
AssetStudio/Classes/AssetBundle.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
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 PPtr<Object>[] m_PreloadTable;
|
||||
public KeyValuePair<string, AssetInfo>[] m_Container;
|
||||
|
||||
public AssetBundle(ObjectReader reader) : base(reader)
|
||||
{
|
||||
var m_PreloadTableSize = reader.ReadInt32();
|
||||
m_PreloadTable = new PPtr<Object>[m_PreloadTableSize];
|
||||
for (int i = 0; i < m_PreloadTableSize; i++)
|
||||
{
|
||||
m_PreloadTable[i] = new PPtr<Object>(reader);
|
||||
}
|
||||
|
||||
var m_ContainerSize = reader.ReadInt32();
|
||||
m_Container = new KeyValuePair<string, AssetInfo>[m_ContainerSize];
|
||||
for (int i = 0; i < m_ContainerSize; i++)
|
||||
{
|
||||
m_Container[i] = new KeyValuePair<string, AssetInfo>(reader.ReadAlignedString(), new AssetInfo(reader));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
125
AssetStudio/Classes/AudioClip.cs
Normal file
125
AssetStudio/Classes/AudioClip.cs
Normal file
@@ -0,0 +1,125 @@
|
||||
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 AudioType 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 = (AudioType)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 AudioType
|
||||
{
|
||||
UNKNOWN,
|
||||
ACC,
|
||||
AIFF,
|
||||
IT = 10,
|
||||
MOD = 12,
|
||||
MPEG,
|
||||
OGGVORBIS,
|
||||
S3M = 17,
|
||||
WAV = 20,
|
||||
XM,
|
||||
XMA,
|
||||
VAG,
|
||||
AUDIOQUEUE
|
||||
}
|
||||
|
||||
public enum AudioCompressionFormat
|
||||
{
|
||||
PCM,
|
||||
Vorbis,
|
||||
ADPCM,
|
||||
MP3,
|
||||
VAG,
|
||||
HEVAG,
|
||||
XMA,
|
||||
AAC,
|
||||
GCADPCM,
|
||||
ATRAC9
|
||||
}
|
||||
}
|
||||
312
AssetStudio/Classes/Avatar.cs
Normal file
312
AssetStudio/Classes/Avatar.cs
Normal file
@@ -0,0 +1,312 @@
|
||||
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 KeyValuePair<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 KeyValuePair<uint, string>[numTOS];
|
||||
for (int i = 0; i < numTOS; i++)
|
||||
{
|
||||
m_TOS[i] = new KeyValuePair<uint, string>(reader.ReadUInt32(), reader.ReadAlignedString());
|
||||
}
|
||||
|
||||
//HumanDescription m_HumanDescription 2019 and up
|
||||
}
|
||||
|
||||
public string FindBonePath(uint hash)
|
||||
{
|
||||
return m_TOS.FirstOrDefault(pair => pair.Key == hash).Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
18
AssetStudio/Classes/Behaviour.cs
Normal file
18
AssetStudio/Classes/Behaviour.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public abstract class Behaviour : Component
|
||||
{
|
||||
public byte m_Enabled;
|
||||
|
||||
protected Behaviour(ObjectReader reader) : base(reader)
|
||||
{
|
||||
m_Enabled = reader.ReadByte();
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
}
|
||||
24
AssetStudio/Classes/BuildSettings.cs
Normal file
24
AssetStudio/Classes/BuildSettings.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public sealed class BuildSettings : Object
|
||||
{
|
||||
public string m_Version;
|
||||
|
||||
public BuildSettings(ObjectReader reader) : base(reader)
|
||||
{
|
||||
var levels = reader.ReadStringArray();
|
||||
|
||||
var hasRenderTexture = reader.ReadBoolean();
|
||||
var hasPROVersion = reader.ReadBoolean();
|
||||
var hasPublishingRights = reader.ReadBoolean();
|
||||
var hasShadows = reader.ReadBoolean();
|
||||
|
||||
m_Version = reader.ReadAlignedString();
|
||||
}
|
||||
}
|
||||
}
|
||||
17
AssetStudio/Classes/Component.cs
Normal file
17
AssetStudio/Classes/Component.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public abstract class Component : EditorExtension
|
||||
{
|
||||
public PPtr<GameObject> m_GameObject;
|
||||
|
||||
protected Component(ObjectReader reader) : base(reader)
|
||||
{
|
||||
m_GameObject = new PPtr<GameObject>(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
19
AssetStudio/Classes/EditorExtension.cs
Normal file
19
AssetStudio/Classes/EditorExtension.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public abstract class EditorExtension : Object
|
||||
{
|
||||
protected EditorExtension(ObjectReader reader) : base(reader)
|
||||
{
|
||||
if (platform == BuildTarget.NoTarget)
|
||||
{
|
||||
var m_PrefabParentObject = new PPtr<EditorExtension>(reader);
|
||||
var m_PrefabInternal = new PPtr<Object>(reader); //PPtr<Prefab>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
121
AssetStudio/Classes/Font.cs
Normal file
121
AssetStudio/Classes/Font.cs
Normal file
@@ -0,0 +1,121 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public sealed class Font : NamedObject
|
||||
{
|
||||
public byte[] m_FontData;
|
||||
|
||||
public Font(ObjectReader reader) : base(reader)
|
||||
{
|
||||
if ((version[0] == 5 && version[1] >= 5) || version[0] > 5)//5.5 and up
|
||||
{
|
||||
var m_LineSpacing = reader.ReadSingle();
|
||||
var m_DefaultMaterial = new PPtr<Material>(reader);
|
||||
var m_FontSize = reader.ReadSingle();
|
||||
var m_Texture = new PPtr<Texture>(reader);
|
||||
int m_AsciiStartOffset = reader.ReadInt32();
|
||||
var m_Tracking = reader.ReadSingle();
|
||||
var m_CharacterSpacing = reader.ReadInt32();
|
||||
var m_CharacterPadding = reader.ReadInt32();
|
||||
var m_ConvertCase = reader.ReadInt32();
|
||||
int m_CharacterRects_size = reader.ReadInt32();
|
||||
for (int i = 0; i < m_CharacterRects_size; i++)
|
||||
{
|
||||
reader.Position += 44;//CharacterInfo data 41
|
||||
}
|
||||
int m_KerningValues_size = reader.ReadInt32();
|
||||
for (int i = 0; i < m_KerningValues_size; i++)
|
||||
{
|
||||
reader.Position += 8;
|
||||
}
|
||||
var m_PixelScale = reader.ReadSingle();
|
||||
int m_FontData_size = reader.ReadInt32();
|
||||
if (m_FontData_size > 0)
|
||||
{
|
||||
m_FontData = reader.ReadBytes(m_FontData_size);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int m_AsciiStartOffset = reader.ReadInt32();
|
||||
|
||||
if (version[0] <= 3)
|
||||
{
|
||||
int m_FontCountX = reader.ReadInt32();
|
||||
int m_FontCountY = reader.ReadInt32();
|
||||
}
|
||||
|
||||
float m_Kerning = reader.ReadSingle();
|
||||
float m_LineSpacing = reader.ReadSingle();
|
||||
|
||||
if (version[0] <= 3)
|
||||
{
|
||||
int m_PerCharacterKerning_size = reader.ReadInt32();
|
||||
for (int i = 0; i < m_PerCharacterKerning_size; i++)
|
||||
{
|
||||
int first = reader.ReadInt32();
|
||||
float second = reader.ReadSingle();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int m_CharacterSpacing = reader.ReadInt32();
|
||||
int m_CharacterPadding = reader.ReadInt32();
|
||||
}
|
||||
|
||||
int m_ConvertCase = reader.ReadInt32();
|
||||
var m_DefaultMaterial = new PPtr<Material>(reader);
|
||||
|
||||
int m_CharacterRects_size = reader.ReadInt32();
|
||||
for (int i = 0; i < m_CharacterRects_size; i++)
|
||||
{
|
||||
int index = reader.ReadInt32();
|
||||
//Rectf uv
|
||||
float uvx = reader.ReadSingle();
|
||||
float uvy = reader.ReadSingle();
|
||||
float uvwidth = reader.ReadSingle();
|
||||
float uvheight = reader.ReadSingle();
|
||||
//Rectf vert
|
||||
float vertx = reader.ReadSingle();
|
||||
float verty = reader.ReadSingle();
|
||||
float vertwidth = reader.ReadSingle();
|
||||
float vertheight = reader.ReadSingle();
|
||||
float width = reader.ReadSingle();
|
||||
|
||||
if (version[0] >= 4)
|
||||
{
|
||||
var flipped = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
|
||||
var m_Texture = new PPtr<Texture>(reader);
|
||||
|
||||
int m_KerningValues_size = reader.ReadInt32();
|
||||
for (int i = 0; i < m_KerningValues_size; i++)
|
||||
{
|
||||
int pairfirst = reader.ReadInt16();
|
||||
int pairsecond = reader.ReadInt16();
|
||||
float second = reader.ReadSingle();
|
||||
}
|
||||
|
||||
if (version[0] <= 3)
|
||||
{
|
||||
var m_GridFont = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
}
|
||||
else { float m_PixelScale = reader.ReadSingle(); }
|
||||
|
||||
int m_FontData_size = reader.ReadInt32();
|
||||
if (m_FontData_size > 0)
|
||||
{
|
||||
m_FontData = reader.ReadBytes(m_FontData_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
37
AssetStudio/Classes/GameObject.cs
Normal file
37
AssetStudio/Classes/GameObject.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
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 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
115
AssetStudio/Classes/Material.cs
Normal file
115
AssetStudio/Classes/Material.cs
Normal file
@@ -0,0 +1,115 @@
|
||||
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
|
||||
{
|
||||
public KeyValuePair<string, UnityTexEnv>[] m_TexEnvs;
|
||||
public KeyValuePair<string, int>[] m_Ints;
|
||||
public KeyValuePair<string, float>[] m_Floats;
|
||||
public KeyValuePair<string, Color>[] m_Colors;
|
||||
|
||||
public UnityPropertySheet(ObjectReader reader)
|
||||
{
|
||||
var version = reader.version;
|
||||
|
||||
int m_TexEnvsSize = reader.ReadInt32();
|
||||
m_TexEnvs = new KeyValuePair<string, UnityTexEnv>[m_TexEnvsSize];
|
||||
for (int i = 0; i < m_TexEnvsSize; i++)
|
||||
{
|
||||
m_TexEnvs[i] = new KeyValuePair<string, UnityTexEnv>(reader.ReadAlignedString(), new UnityTexEnv(reader));
|
||||
}
|
||||
|
||||
if (version[0] >= 2021) //2021.1 and up
|
||||
{
|
||||
int m_IntsSize = reader.ReadInt32();
|
||||
m_Ints = new KeyValuePair<string, int>[m_IntsSize];
|
||||
for (int i = 0; i < m_IntsSize; i++)
|
||||
{
|
||||
m_Ints[i] = new KeyValuePair<string, int>(reader.ReadAlignedString(), reader.ReadInt32());
|
||||
}
|
||||
}
|
||||
|
||||
int m_FloatsSize = reader.ReadInt32();
|
||||
m_Floats = new KeyValuePair<string, float>[m_FloatsSize];
|
||||
for (int i = 0; i < m_FloatsSize; i++)
|
||||
{
|
||||
m_Floats[i] = new KeyValuePair<string, float>(reader.ReadAlignedString(), reader.ReadSingle());
|
||||
}
|
||||
|
||||
int m_ColorsSize = reader.ReadInt32();
|
||||
m_Colors = new KeyValuePair<string, Color>[m_ColorsSize];
|
||||
for (int i = 0; i < m_ColorsSize; i++)
|
||||
{
|
||||
m_Colors[i] = new KeyValuePair<string, Color>(reader.ReadAlignedString(), reader.ReadColor4());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class Material : NamedObject
|
||||
{
|
||||
public PPtr<Shader> m_Shader;
|
||||
public UnityPropertySheet m_SavedProperties;
|
||||
|
||||
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 = a_Stream.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();
|
||||
for (int i = 0; i < stringTagMapSize; i++)
|
||||
{
|
||||
var first = reader.ReadAlignedString();
|
||||
var second = reader.ReadAlignedString();
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
1383
AssetStudio/Classes/Mesh.cs
Normal file
1383
AssetStudio/Classes/Mesh.cs
Normal file
File diff suppressed because it is too large
Load Diff
17
AssetStudio/Classes/MeshFilter.cs
Normal file
17
AssetStudio/Classes/MeshFilter.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public sealed class MeshFilter : Component
|
||||
{
|
||||
public PPtr<Mesh> m_Mesh;
|
||||
|
||||
public MeshFilter(ObjectReader reader) : base(reader)
|
||||
{
|
||||
m_Mesh = new PPtr<Mesh>(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
15
AssetStudio/Classes/MeshRenderer.cs
Normal file
15
AssetStudio/Classes/MeshRenderer.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public sealed class MeshRenderer : Renderer
|
||||
{
|
||||
public MeshRenderer(ObjectReader reader) : base(reader)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
19
AssetStudio/Classes/MonoBehaviour.cs
Normal file
19
AssetStudio/Classes/MonoBehaviour.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public sealed class MonoBehaviour : Behaviour
|
||||
{
|
||||
public PPtr<MonoScript> m_Script;
|
||||
public string m_Name;
|
||||
|
||||
public MonoBehaviour(ObjectReader reader) : base(reader)
|
||||
{
|
||||
m_Script = new PPtr<MonoScript>(reader);
|
||||
m_Name = reader.ReadAlignedString();
|
||||
}
|
||||
}
|
||||
}
|
||||
44
AssetStudio/Classes/MonoScript.cs
Normal file
44
AssetStudio/Classes/MonoScript.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public sealed class MonoScript : NamedObject
|
||||
{
|
||||
public string m_ClassName;
|
||||
public string m_Namespace;
|
||||
public string m_AssemblyName;
|
||||
|
||||
public MonoScript(ObjectReader reader) : base(reader)
|
||||
{
|
||||
if (version[0] > 3 || (version[0] == 3 && version[1] >= 4)) //3.4 and up
|
||||
{
|
||||
var m_ExecutionOrder = reader.ReadInt32();
|
||||
}
|
||||
if (version[0] < 5) //5.0 down
|
||||
{
|
||||
var m_PropertiesHash = reader.ReadUInt32();
|
||||
}
|
||||
else
|
||||
{
|
||||
var m_PropertiesHash = reader.ReadBytes(16);
|
||||
}
|
||||
if (version[0] < 3) //3.0 down
|
||||
{
|
||||
var m_PathName = reader.ReadAlignedString();
|
||||
}
|
||||
m_ClassName = reader.ReadAlignedString();
|
||||
if (version[0] >= 3) //3.0 and up
|
||||
{
|
||||
m_Namespace = reader.ReadAlignedString();
|
||||
}
|
||||
m_AssemblyName = reader.ReadAlignedString();
|
||||
if (version[0] < 2018 || (version[0] == 2018 && version[1] < 2)) //2018.2 down
|
||||
{
|
||||
var m_IsEditorScript = reader.ReadBoolean();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
21
AssetStudio/Classes/MovieTexture.cs
Normal file
21
AssetStudio/Classes/MovieTexture.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public sealed class MovieTexture : Texture
|
||||
{
|
||||
public byte[] m_MovieData;
|
||||
public PPtr<AudioClip> m_AudioClip;
|
||||
|
||||
public MovieTexture(ObjectReader reader) : base(reader)
|
||||
{
|
||||
var m_Loop = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
m_AudioClip = new PPtr<AudioClip>(reader);
|
||||
m_MovieData = reader.ReadUInt8Array();
|
||||
}
|
||||
}
|
||||
}
|
||||
17
AssetStudio/Classes/NamedObject.cs
Normal file
17
AssetStudio/Classes/NamedObject.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class NamedObject : EditorExtension
|
||||
{
|
||||
public string m_Name;
|
||||
|
||||
protected NamedObject(ObjectReader reader) : base(reader)
|
||||
{
|
||||
m_Name = reader.ReadAlignedString();
|
||||
}
|
||||
}
|
||||
}
|
||||
78
AssetStudio/Classes/Object.cs
Normal file
78
AssetStudio/Classes/Object.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using System.Collections.Specialized;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class Object
|
||||
{
|
||||
public SerializedFile assetsFile;
|
||||
public ObjectReader reader;
|
||||
public long m_PathID;
|
||||
public int[] version;
|
||||
protected BuildType buildType;
|
||||
public BuildTarget platform;
|
||||
public ClassIDType type;
|
||||
public SerializedType serializedType;
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
131
AssetStudio/Classes/PPtr.cs
Normal file
131
AssetStudio/Classes/PPtr.cs
Normal file
@@ -0,0 +1,131 @@
|
||||
using System;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public sealed class PPtr<T> 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.kUnknown_14 ? reader.ReadInt32() : reader.ReadInt64();
|
||||
assetsFile = reader.assetsFile;
|
||||
}
|
||||
|
||||
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 bool IsNull => m_PathID == 0 || m_FileID < 0;
|
||||
}
|
||||
}
|
||||
51
AssetStudio/Classes/PlayerSettings.cs
Normal file
51
AssetStudio/Classes/PlayerSettings.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public sealed class PlayerSettings : Object
|
||||
{
|
||||
public string companyName;
|
||||
public string productName;
|
||||
|
||||
public PlayerSettings(ObjectReader reader) : base(reader)
|
||||
{
|
||||
if (version[0] > 5 || (version[0] == 5 && version[1] >= 4)) //5.4.0 nad up
|
||||
{
|
||||
var productGUID = reader.ReadBytes(16);
|
||||
}
|
||||
|
||||
var AndroidProfiler = reader.ReadBoolean();
|
||||
//bool AndroidFilterTouchesWhenObscured 2017.2 and up
|
||||
//bool AndroidEnableSustainedPerformanceMode 2018 and up
|
||||
reader.AlignStream();
|
||||
int defaultScreenOrientation = reader.ReadInt32();
|
||||
int targetDevice = reader.ReadInt32();
|
||||
if (version[0] < 5 || (version[0] == 5 && version[1] < 3)) //5.3 down
|
||||
{
|
||||
if (version[0] < 5) //5.0 down
|
||||
{
|
||||
int targetPlatform = reader.ReadInt32(); //4.0 and up targetGlesGraphics
|
||||
if (version[0] > 4 || (version[0] == 4 && version[1] >= 6)) //4.6 and up
|
||||
{
|
||||
var targetIOSGraphics = reader.ReadInt32();
|
||||
}
|
||||
}
|
||||
int targetResolution = reader.ReadInt32();
|
||||
}
|
||||
else
|
||||
{
|
||||
var useOnDemandResources = reader.ReadBoolean();
|
||||
reader.AlignStream();
|
||||
}
|
||||
if (version[0] > 3 || (version[0] == 3 && version[1] >= 5)) //3.5 and up
|
||||
{
|
||||
var accelerometerFrequency = reader.ReadInt32();
|
||||
}
|
||||
companyName = reader.ReadAlignedString();
|
||||
productName = reader.ReadAlignedString();
|
||||
}
|
||||
}
|
||||
}
|
||||
14
AssetStudio/Classes/RectTransform.cs
Normal file
14
AssetStudio/Classes/RectTransform.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public sealed class RectTransform : Transform
|
||||
{
|
||||
public RectTransform(ObjectReader reader) : base(reader)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
156
AssetStudio/Classes/Renderer.cs
Normal file
156
AssetStudio/Classes/Renderer.cs
Normal file
@@ -0,0 +1,156 @@
|
||||
using System;
|
||||
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 PPtr<Material>[] m_Materials;
|
||||
public StaticBatchInfo m_StaticBatchInfo;
|
||||
public uint[] m_SubsetIndices;
|
||||
|
||||
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
|
||||
{
|
||||
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 (version[0] >= 2021) //2021.1 and up
|
||||
{
|
||||
var m_StaticShadowCaster = 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();
|
||||
}
|
||||
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.ReadUInt16();
|
||||
var m_LightmapIndexDynamic = reader.ReadUInt16();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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 (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.ReadUInt32();
|
||||
}
|
||||
|
||||
//SInt16 m_SortingLayer 5.6 and up
|
||||
var m_SortingOrder = reader.ReadInt16();
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
19
AssetStudio/Classes/ResourceManager.cs
Normal file
19
AssetStudio/Classes/ResourceManager.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class ResourceManager : Object
|
||||
{
|
||||
public KeyValuePair<string, PPtr<Object>>[] m_Container;
|
||||
|
||||
public ResourceManager(ObjectReader reader) : base(reader)
|
||||
{
|
||||
var m_ContainerSize = reader.ReadInt32();
|
||||
m_Container = new KeyValuePair<string, PPtr<Object>>[m_ContainerSize];
|
||||
for (int i = 0; i < m_ContainerSize; i++)
|
||||
{
|
||||
m_Container[i] = new KeyValuePair<string, PPtr<Object>>(reader.ReadAlignedString(), new PPtr<Object>(reader));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
15
AssetStudio/Classes/RuntimeAnimatorController.cs
Normal file
15
AssetStudio/Classes/RuntimeAnimatorController.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
1020
AssetStudio/Classes/Shader.cs
Normal file
1020
AssetStudio/Classes/Shader.cs
Normal file
File diff suppressed because it is too large
Load Diff
40
AssetStudio/Classes/SkinnedMeshRenderer.cs
Normal file
40
AssetStudio/Classes/SkinnedMeshRenderer.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
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 float[] m_BlendShapeWeights;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (version[0] > 4 || (version[0] == 4 && version[1] >= 3)) //4.3 and up
|
||||
{
|
||||
m_BlendShapeWeights = reader.ReadSingleArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
260
AssetStudio/Classes/Sprite.cs
Normal file
260
AssetStudio/Classes/Sprite.cs
Normal file
@@ -0,0 +1,260 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class SecondarySpriteTexture
|
||||
{
|
||||
public PPtr<Texture2D> texture;
|
||||
public string name;
|
||||
|
||||
public SecondarySpriteTexture(ObjectReader reader)
|
||||
{
|
||||
texture = new PPtr<Texture2D>(reader);
|
||||
name = reader.ReadStringToNull();
|
||||
}
|
||||
}
|
||||
|
||||
public enum SpritePackingRotation
|
||||
{
|
||||
kSPRNone = 0,
|
||||
kSPRFlipHorizontal = 1,
|
||||
kSPRFlipVertical = 2,
|
||||
kSPRRotate180 = 3,
|
||||
kSPRRotate90 = 4
|
||||
};
|
||||
|
||||
public enum SpritePackingMode
|
||||
{
|
||||
kSPMTight = 0,
|
||||
kSPMRectangle
|
||||
};
|
||||
|
||||
public enum SpriteMeshType
|
||||
{
|
||||
kSpriteMeshTypeFullRect,
|
||||
kSpriteMeshTypeTight
|
||||
};
|
||||
|
||||
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;
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
74
AssetStudio/Classes/SpriteAtlas.cs
Normal file
74
AssetStudio/Classes/SpriteAtlas.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
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 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);
|
||||
}
|
||||
//string m_Tag
|
||||
//bool m_IsVariant
|
||||
}
|
||||
}
|
||||
}
|
||||
18
AssetStudio/Classes/TextAsset.cs
Normal file
18
AssetStudio/Classes/TextAsset.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public sealed class TextAsset : NamedObject
|
||||
{
|
||||
public byte[] m_Script;
|
||||
|
||||
public TextAsset(ObjectReader reader) : base(reader)
|
||||
{
|
||||
m_Script = reader.ReadUInt8Array();
|
||||
}
|
||||
}
|
||||
}
|
||||
24
AssetStudio/Classes/Texture.cs
Normal file
24
AssetStudio/Classes/Texture.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public abstract class Texture : NamedObject
|
||||
{
|
||||
protected Texture(ObjectReader reader) : base(reader)
|
||||
{
|
||||
if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 3)) //2017.3 and up
|
||||
{
|
||||
var m_ForcedFallbackFormat = reader.ReadInt32();
|
||||
var m_DownscaleFallback = reader.ReadBoolean();
|
||||
if (version[0] > 2020 || (version[0] == 2020 && version[1] >= 2)) //2020.2 and up
|
||||
{
|
||||
var m_IsAlphaChannelOptional = reader.ReadBoolean();
|
||||
}
|
||||
reader.AlignStream();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
216
AssetStudio/Classes/Texture2D.cs
Normal file
216
AssetStudio/Classes/Texture2D.cs
Normal file
@@ -0,0 +1,216 @@
|
||||
using System;
|
||||
|
||||
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,
|
||||
RGB565 = 7,
|
||||
R16 = 9,
|
||||
DXT1,
|
||||
DXT5 = 12,
|
||||
RGBA4444,
|
||||
BGRA32,
|
||||
RHalf,
|
||||
RGHalf,
|
||||
RGBAHalf,
|
||||
RFloat,
|
||||
RGFloat,
|
||||
RGBAFloat,
|
||||
YUY2,
|
||||
RGB9e5Float,
|
||||
BC4 = 26,
|
||||
BC5,
|
||||
BC6H = 24,
|
||||
BC7,
|
||||
DXT1Crunched = 28,
|
||||
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,
|
||||
ASTC_HDR_4x4,
|
||||
ASTC_HDR_5x5,
|
||||
ASTC_HDR_6x6,
|
||||
ASTC_HDR_8x8,
|
||||
ASTC_HDR_10x10,
|
||||
ASTC_HDR_12x12,
|
||||
RG32,
|
||||
RGB48,
|
||||
RGBA64
|
||||
}
|
||||
}
|
||||
31
AssetStudio/Classes/Transform.cs
Normal file
31
AssetStudio/Classes/Transform.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
72
AssetStudio/Classes/VideoClip.cs
Normal file
72
AssetStudio/Classes/VideoClip.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
using System.IO;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class StreamedResource
|
||||
{
|
||||
public string m_Source;
|
||||
public long m_Offset; //ulong
|
||||
public long m_Size; //ulong
|
||||
|
||||
public StreamedResource(BinaryReader reader)
|
||||
{
|
||||
m_Source = reader.ReadAlignedString();
|
||||
m_Offset = reader.ReadInt64();
|
||||
m_Size = reader.ReadInt64();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class VideoClip : NamedObject
|
||||
{
|
||||
public ResourceReader m_VideoData;
|
||||
public string m_OriginalPath;
|
||||
public StreamedResource m_ExternalResources;
|
||||
|
||||
public VideoClip(ObjectReader reader) : base(reader)
|
||||
{
|
||||
m_OriginalPath = reader.ReadAlignedString();
|
||||
var m_ProxyWidth = reader.ReadUInt32();
|
||||
var m_ProxyHeight = reader.ReadUInt32();
|
||||
var Width = reader.ReadUInt32();
|
||||
var Height = reader.ReadUInt32();
|
||||
if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 2)) //2017.2 and up
|
||||
{
|
||||
var m_PixelAspecRatioNum = reader.ReadUInt32();
|
||||
var m_PixelAspecRatioDen = reader.ReadUInt32();
|
||||
}
|
||||
var m_FrameRate = reader.ReadDouble();
|
||||
var m_FrameCount = reader.ReadUInt64();
|
||||
var m_Format = reader.ReadInt32();
|
||||
var m_AudioChannelCount = reader.ReadUInt16Array();
|
||||
reader.AlignStream();
|
||||
var m_AudioSampleRate = reader.ReadUInt32Array();
|
||||
var m_AudioLanguage = reader.ReadStringArray();
|
||||
if (version[0] >= 2020) //2020.1 and up
|
||||
{
|
||||
var m_VideoShadersSize = reader.ReadInt32();
|
||||
var m_VideoShaders = new PPtr<Shader>[m_VideoShadersSize];
|
||||
for (int i = 0; i < m_VideoShadersSize; i++)
|
||||
{
|
||||
m_VideoShaders[i] = new PPtr<Shader>(reader);
|
||||
}
|
||||
}
|
||||
m_ExternalResources = new StreamedResource(reader);
|
||||
var m_HasSplitAlpha = reader.ReadBoolean();
|
||||
if (version[0] >= 2020) //2020.1 and up
|
||||
{
|
||||
var m_sRGB = reader.ReadBoolean();
|
||||
}
|
||||
|
||||
ResourceReader resourceReader;
|
||||
if (!string.IsNullOrEmpty(m_ExternalResources.m_Source))
|
||||
{
|
||||
resourceReader = new ResourceReader(m_ExternalResources.m_Source, assetsFile, m_ExternalResources.m_Offset, m_ExternalResources.m_Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
resourceReader = new ResourceReader(reader, reader.BaseStream.Position, m_ExternalResources.m_Size);
|
||||
}
|
||||
m_VideoData = resourceReader;
|
||||
}
|
||||
}
|
||||
}
|
||||
120
AssetStudio/CommonString.cs
Normal file
120
AssetStudio/CommonString.cs
Normal file
@@ -0,0 +1,120 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public static class CommonString
|
||||
{
|
||||
public static readonly Dictionary<uint, string> StringBuffer = new Dictionary<uint, string>
|
||||
{
|
||||
{0, "AABB"},
|
||||
{5, "AnimationClip"},
|
||||
{19, "AnimationCurve"},
|
||||
{34, "AnimationState"},
|
||||
{49, "Array"},
|
||||
{55, "Base"},
|
||||
{60, "BitField"},
|
||||
{69, "bitset"},
|
||||
{76, "bool"},
|
||||
{81, "char"},
|
||||
{86, "ColorRGBA"},
|
||||
{96, "Component"},
|
||||
{106, "data"},
|
||||
{111, "deque"},
|
||||
{117, "double"},
|
||||
{124, "dynamic_array"},
|
||||
{138, "FastPropertyName"},
|
||||
{155, "first"},
|
||||
{161, "float"},
|
||||
{167, "Font"},
|
||||
{172, "GameObject"},
|
||||
{183, "Generic Mono"},
|
||||
{196, "GradientNEW"},
|
||||
{208, "GUID"},
|
||||
{213, "GUIStyle"},
|
||||
{222, "int"},
|
||||
{226, "list"},
|
||||
{231, "long long"},
|
||||
{241, "map"},
|
||||
{245, "Matrix4x4f"},
|
||||
{256, "MdFour"},
|
||||
{263, "MonoBehaviour"},
|
||||
{277, "MonoScript"},
|
||||
{288, "m_ByteSize"},
|
||||
{299, "m_Curve"},
|
||||
{307, "m_EditorClassIdentifier"},
|
||||
{331, "m_EditorHideFlags"},
|
||||
{349, "m_Enabled"},
|
||||
{359, "m_ExtensionPtr"},
|
||||
{374, "m_GameObject"},
|
||||
{387, "m_Index"},
|
||||
{395, "m_IsArray"},
|
||||
{405, "m_IsStatic"},
|
||||
{416, "m_MetaFlag"},
|
||||
{427, "m_Name"},
|
||||
{434, "m_ObjectHideFlags"},
|
||||
{452, "m_PrefabInternal"},
|
||||
{469, "m_PrefabParentObject"},
|
||||
{490, "m_Script"},
|
||||
{499, "m_StaticEditorFlags"},
|
||||
{519, "m_Type"},
|
||||
{526, "m_Version"},
|
||||
{536, "Object"},
|
||||
{543, "pair"},
|
||||
{548, "PPtr<Component>"},
|
||||
{564, "PPtr<GameObject>"},
|
||||
{581, "PPtr<Material>"},
|
||||
{596, "PPtr<MonoBehaviour>"},
|
||||
{616, "PPtr<MonoScript>"},
|
||||
{633, "PPtr<Object>"},
|
||||
{646, "PPtr<Prefab>"},
|
||||
{659, "PPtr<Sprite>"},
|
||||
{672, "PPtr<TextAsset>"},
|
||||
{688, "PPtr<Texture>"},
|
||||
{702, "PPtr<Texture2D>"},
|
||||
{718, "PPtr<Transform>"},
|
||||
{734, "Prefab"},
|
||||
{741, "Quaternionf"},
|
||||
{753, "Rectf"},
|
||||
{759, "RectInt"},
|
||||
{767, "RectOffset"},
|
||||
{778, "second"},
|
||||
{785, "set"},
|
||||
{789, "short"},
|
||||
{795, "size"},
|
||||
{800, "SInt16"},
|
||||
{807, "SInt32"},
|
||||
{814, "SInt64"},
|
||||
{821, "SInt8"},
|
||||
{827, "staticvector"},
|
||||
{840, "string"},
|
||||
{847, "TextAsset"},
|
||||
{857, "TextMesh"},
|
||||
{866, "Texture"},
|
||||
{874, "Texture2D"},
|
||||
{884, "Transform"},
|
||||
{894, "TypelessData"},
|
||||
{907, "UInt16"},
|
||||
{914, "UInt32"},
|
||||
{921, "UInt64"},
|
||||
{928, "UInt8"},
|
||||
{934, "unsigned int"},
|
||||
{947, "unsigned long long"},
|
||||
{966, "unsigned short"},
|
||||
{981, "vector"},
|
||||
{988, "Vector2f"},
|
||||
{997, "Vector3f"},
|
||||
{1006, "Vector4f"},
|
||||
{1015, "m_ScriptingClassIdentifier"},
|
||||
{1042, "Gradient"},
|
||||
{1051, "Type*"},
|
||||
{1057, "int2_storage"},
|
||||
{1070, "int3_storage"},
|
||||
{1083, "BoundsInt"},
|
||||
{1093, "m_CorrespondingSourceObject"},
|
||||
{1121, "m_PrefabInstance"},
|
||||
{1138, "m_PrefabAsset"},
|
||||
{1152, "FileSize"},
|
||||
{1161, "Hash128"}
|
||||
};
|
||||
}
|
||||
}
|
||||
117
AssetStudio/EndianBinaryReader.cs
Normal file
117
AssetStudio/EndianBinaryReader.cs
Normal file
@@ -0,0 +1,117 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public enum EndianType
|
||||
{
|
||||
LittleEndian,
|
||||
BigEndian
|
||||
}
|
||||
|
||||
public class EndianBinaryReader : BinaryReader
|
||||
{
|
||||
public EndianType endian;
|
||||
|
||||
public EndianBinaryReader(Stream stream, EndianType endian = EndianType.BigEndian) : base(stream)
|
||||
{
|
||||
this.endian = endian;
|
||||
}
|
||||
|
||||
public long Position
|
||||
{
|
||||
get => BaseStream.Position;
|
||||
set => BaseStream.Position = value;
|
||||
}
|
||||
|
||||
public override short ReadInt16()
|
||||
{
|
||||
if (endian == EndianType.BigEndian)
|
||||
{
|
||||
var buff = ReadBytes(2);
|
||||
Array.Reverse(buff);
|
||||
return BitConverter.ToInt16(buff, 0);
|
||||
}
|
||||
return base.ReadInt16();
|
||||
}
|
||||
|
||||
public override int ReadInt32()
|
||||
{
|
||||
if (endian == EndianType.BigEndian)
|
||||
{
|
||||
var buff = ReadBytes(4);
|
||||
Array.Reverse(buff);
|
||||
return BitConverter.ToInt32(buff, 0);
|
||||
}
|
||||
return base.ReadInt32();
|
||||
}
|
||||
|
||||
public override long ReadInt64()
|
||||
{
|
||||
if (endian == EndianType.BigEndian)
|
||||
{
|
||||
var buff = ReadBytes(8);
|
||||
Array.Reverse(buff);
|
||||
return BitConverter.ToInt64(buff, 0);
|
||||
}
|
||||
return base.ReadInt64();
|
||||
}
|
||||
|
||||
public override ushort ReadUInt16()
|
||||
{
|
||||
if (endian == EndianType.BigEndian)
|
||||
{
|
||||
var buff = ReadBytes(2);
|
||||
Array.Reverse(buff);
|
||||
return BitConverter.ToUInt16(buff, 0);
|
||||
}
|
||||
return base.ReadUInt16();
|
||||
}
|
||||
|
||||
public override uint ReadUInt32()
|
||||
{
|
||||
if (endian == EndianType.BigEndian)
|
||||
{
|
||||
var buff = ReadBytes(4);
|
||||
Array.Reverse(buff);
|
||||
return BitConverter.ToUInt32(buff, 0);
|
||||
}
|
||||
return base.ReadUInt32();
|
||||
}
|
||||
|
||||
public override ulong ReadUInt64()
|
||||
{
|
||||
if (endian == EndianType.BigEndian)
|
||||
{
|
||||
var buff = ReadBytes(8);
|
||||
Array.Reverse(buff);
|
||||
return BitConverter.ToUInt64(buff, 0);
|
||||
}
|
||||
return base.ReadUInt64();
|
||||
}
|
||||
|
||||
public override float ReadSingle()
|
||||
{
|
||||
if (endian == EndianType.BigEndian)
|
||||
{
|
||||
var buff = ReadBytes(4);
|
||||
Array.Reverse(buff);
|
||||
return BitConverter.ToSingle(buff, 0);
|
||||
}
|
||||
return base.ReadSingle();
|
||||
}
|
||||
|
||||
public override double ReadDouble()
|
||||
{
|
||||
if (endian == EndianType.BigEndian)
|
||||
{
|
||||
var buff = ReadBytes(8);
|
||||
Array.Reverse(buff);
|
||||
return BitConverter.ToUInt64(buff, 0);
|
||||
}
|
||||
return base.ReadDouble();
|
||||
}
|
||||
}
|
||||
}
|
||||
165
AssetStudio/Extensions/BinaryReaderExtensions.cs
Normal file
165
AssetStudio/Extensions/BinaryReaderExtensions.cs
Normal file
@@ -0,0 +1,165 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
private static T[] ReadArray<T>(Func<T> del, int length)
|
||||
{
|
||||
var array = new T[length];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
array[i] = del();
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
public static bool[] ReadBooleanArray(this BinaryReader reader)
|
||||
{
|
||||
return ReadArray(reader.ReadBoolean, reader.ReadInt32());
|
||||
}
|
||||
|
||||
public static byte[] ReadUInt8Array(this BinaryReader reader)
|
||||
{
|
||||
return reader.ReadBytes(reader.ReadInt32());
|
||||
}
|
||||
|
||||
public static ushort[] ReadUInt16Array(this BinaryReader reader)
|
||||
{
|
||||
return ReadArray(reader.ReadUInt16, reader.ReadInt32());
|
||||
}
|
||||
|
||||
public static int[] ReadInt32Array(this BinaryReader reader)
|
||||
{
|
||||
return ReadArray(reader.ReadInt32, reader.ReadInt32());
|
||||
}
|
||||
|
||||
public static int[] ReadInt32Array(this BinaryReader reader, int length)
|
||||
{
|
||||
return ReadArray(reader.ReadInt32, length);
|
||||
}
|
||||
|
||||
public static uint[] ReadUInt32Array(this BinaryReader reader)
|
||||
{
|
||||
return ReadArray(reader.ReadUInt32, reader.ReadInt32());
|
||||
}
|
||||
|
||||
public static uint[][] ReadUInt32ArrayArray(this BinaryReader reader)
|
||||
{
|
||||
return ReadArray(reader.ReadUInt32Array, reader.ReadInt32());
|
||||
}
|
||||
|
||||
public static uint[] ReadUInt32Array(this BinaryReader reader, int length)
|
||||
{
|
||||
return ReadArray(reader.ReadUInt32, length);
|
||||
}
|
||||
|
||||
public static float[] ReadSingleArray(this BinaryReader reader)
|
||||
{
|
||||
return ReadArray(reader.ReadSingle, reader.ReadInt32());
|
||||
}
|
||||
|
||||
public static float[] ReadSingleArray(this BinaryReader reader, int length)
|
||||
{
|
||||
return ReadArray(reader.ReadSingle, length);
|
||||
}
|
||||
|
||||
public static string[] ReadStringArray(this BinaryReader reader)
|
||||
{
|
||||
return ReadArray(reader.ReadAlignedString, reader.ReadInt32());
|
||||
}
|
||||
|
||||
public static Vector2[] ReadVector2Array(this BinaryReader reader)
|
||||
{
|
||||
return ReadArray(reader.ReadVector2, reader.ReadInt32());
|
||||
}
|
||||
|
||||
public static Vector4[] ReadVector4Array(this BinaryReader reader)
|
||||
{
|
||||
return ReadArray(reader.ReadVector4, reader.ReadInt32());
|
||||
}
|
||||
|
||||
public static Matrix4x4[] ReadMatrixArray(this BinaryReader reader)
|
||||
{
|
||||
return ReadArray(reader.ReadMatrix, reader.ReadInt32());
|
||||
}
|
||||
}
|
||||
}
|
||||
27
AssetStudio/Extensions/BinaryWriterExtensions.cs
Normal file
27
AssetStudio/Extensions/BinaryWriterExtensions.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public static class BinaryWriterExtensions
|
||||
{
|
||||
public static void AlignStream(this BinaryWriter writer, int alignment)
|
||||
{
|
||||
var pos = writer.BaseStream.Position;
|
||||
var mod = pos % alignment;
|
||||
if (mod != 0)
|
||||
{
|
||||
writer.Write(new byte[alignment - mod]);
|
||||
}
|
||||
}
|
||||
|
||||
public static void WriteAlignedString(this BinaryWriter writer, string str)
|
||||
{
|
||||
var bytes = Encoding.UTF8.GetBytes(str);
|
||||
writer.Write(bytes.Length);
|
||||
writer.Write(bytes);
|
||||
writer.AlignStream(4);
|
||||
}
|
||||
}
|
||||
}
|
||||
24
AssetStudio/Extensions/StreamExtensions.cs
Normal file
24
AssetStudio/Extensions/StreamExtensions.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System.IO;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public static class StreamExtensions
|
||||
{
|
||||
private const int BufferSize = 81920;
|
||||
|
||||
public static void CopyTo(this Stream source, Stream destination, long size)
|
||||
{
|
||||
var buffer = new byte[BufferSize];
|
||||
for (var left = size; left > 0; left -= BufferSize)
|
||||
{
|
||||
int toRead = BufferSize < left ? BufferSize : (int)left;
|
||||
int read = source.Read(buffer, 0, toRead);
|
||||
destination.Write(buffer, 0, read);
|
||||
if (read != toRead)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
17
AssetStudio/FileIdentifier.cs
Normal file
17
AssetStudio/FileIdentifier.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class FileIdentifier
|
||||
{
|
||||
public Guid guid;
|
||||
public int type; //enum { kNonAssetType = 0, kDeprecatedCachedAssetType = 1, kSerializedAssetType = 2, kMetaAssetType = 3 };
|
||||
public string pathName;
|
||||
|
||||
//custom
|
||||
public string fileName;
|
||||
}
|
||||
}
|
||||
100
AssetStudio/FileReader.cs
Normal file
100
AssetStudio/FileReader.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class FileReader : EndianBinaryReader
|
||||
{
|
||||
public string FullPath;
|
||||
public string FileName;
|
||||
public FileType FileType;
|
||||
|
||||
private static readonly byte[] gzipMagic = { 0x1f, 0x8b };
|
||||
private static readonly byte[] brotliMagic = { 0x62, 0x72, 0x6F, 0x74, 0x6C, 0x69 };
|
||||
|
||||
public FileReader(string path) : this(path, File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { }
|
||||
|
||||
public FileReader(string path, Stream stream) : base(stream, EndianType.BigEndian)
|
||||
{
|
||||
FullPath = Path.GetFullPath(path);
|
||||
FileName = Path.GetFileName(path);
|
||||
FileType = CheckFileType();
|
||||
}
|
||||
|
||||
private FileType CheckFileType()
|
||||
{
|
||||
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:
|
||||
{
|
||||
var 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;
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
18
AssetStudio/FileType.cs
Normal file
18
AssetStudio/FileType.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public enum FileType
|
||||
{
|
||||
AssetsFile,
|
||||
BundleFile,
|
||||
WebFile,
|
||||
ResourceFile,
|
||||
GZipFile,
|
||||
BrotliFile
|
||||
}
|
||||
}
|
||||
324
AssetStudio/IImported.cs
Normal file
324
AssetStudio/IImported.cs
Normal file
@@ -0,0 +1,324 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public interface IImported
|
||||
{
|
||||
ImportedFrame RootFrame { get; }
|
||||
List<ImportedMesh> MeshList { get; }
|
||||
List<ImportedMaterial> MaterialList { get; }
|
||||
List<ImportedTexture> TextureList { get; }
|
||||
List<ImportedKeyframedAnimation> AnimationList { get; }
|
||||
List<ImportedMorph> MorphList { get; }
|
||||
}
|
||||
|
||||
public class ImportedFrame
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public Vector3 LocalRotation { get; set; }
|
||||
public Vector3 LocalPosition { get; set; }
|
||||
public Vector3 LocalScale { get; set; }
|
||||
public ImportedFrame Parent { get; set; }
|
||||
|
||||
private List<ImportedFrame> children;
|
||||
|
||||
public ImportedFrame this[int i] => children[i];
|
||||
|
||||
public int Count => children.Count;
|
||||
|
||||
public string Path
|
||||
{
|
||||
get
|
||||
{
|
||||
var frame = this;
|
||||
var path = frame.Name;
|
||||
while (frame.Parent != null)
|
||||
{
|
||||
frame = frame.Parent;
|
||||
path = frame.Name + "/" + path;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
public ImportedFrame(int childrenCount = 0)
|
||||
{
|
||||
children = new List<ImportedFrame>(childrenCount);
|
||||
}
|
||||
|
||||
public void AddChild(ImportedFrame obj)
|
||||
{
|
||||
children.Add(obj);
|
||||
obj.Parent?.Remove(obj);
|
||||
obj.Parent = this;
|
||||
}
|
||||
|
||||
public void Remove(ImportedFrame frame)
|
||||
{
|
||||
children.Remove(frame);
|
||||
}
|
||||
|
||||
public ImportedFrame FindFrameByPath(string path)
|
||||
{
|
||||
var name = path.Substring(path.LastIndexOf('/') + 1);
|
||||
foreach (var frame in FindChilds(name))
|
||||
{
|
||||
if (frame.Path.EndsWith(path, StringComparison.Ordinal))
|
||||
{
|
||||
return frame;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ImportedFrame FindFrame(string name)
|
||||
{
|
||||
if (Name == name)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
foreach (var child in children)
|
||||
{
|
||||
var frame = child.FindFrame(name);
|
||||
if (frame != null)
|
||||
{
|
||||
return frame;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ImportedFrame FindChild(string name, bool recursive = true)
|
||||
{
|
||||
foreach (var child in children)
|
||||
{
|
||||
if (recursive)
|
||||
{
|
||||
var frame = child.FindFrame(name);
|
||||
if (frame != null)
|
||||
{
|
||||
return frame;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (child.Name == name)
|
||||
{
|
||||
return child;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public IEnumerable<ImportedFrame> FindChilds(string name)
|
||||
{
|
||||
if (Name == name)
|
||||
{
|
||||
yield return this;
|
||||
}
|
||||
foreach (var child in children)
|
||||
{
|
||||
foreach (var item in child.FindChilds(name))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ImportedMesh
|
||||
{
|
||||
public string Path { get; set; }
|
||||
public List<ImportedVertex> VertexList { get; set; }
|
||||
public List<ImportedSubmesh> SubmeshList { get; set; }
|
||||
public List<ImportedBone> BoneList { get; set; }
|
||||
public bool hasNormal { get; set; }
|
||||
public bool[] hasUV { get; set; }
|
||||
public bool hasTangent { get; set; }
|
||||
public bool hasColor { get; set; }
|
||||
}
|
||||
|
||||
public class ImportedSubmesh
|
||||
{
|
||||
public List<ImportedFace> FaceList { get; set; }
|
||||
public string Material { get; set; }
|
||||
public int BaseVertex { get; set; }
|
||||
}
|
||||
|
||||
public class ImportedVertex
|
||||
{
|
||||
public Vector3 Vertex { get; set; }
|
||||
public Vector3 Normal { get; set; }
|
||||
public float[][] UV { get; set; }
|
||||
public Vector4 Tangent { get; set; }
|
||||
public Color Color { get; set; }
|
||||
public float[] Weights { get; set; }
|
||||
public int[] BoneIndices { get; set; }
|
||||
}
|
||||
|
||||
public class ImportedFace
|
||||
{
|
||||
public int[] VertexIndices { get; set; }
|
||||
}
|
||||
|
||||
public class ImportedBone
|
||||
{
|
||||
public string Path { get; set; }
|
||||
public Matrix4x4 Matrix { get; set; }
|
||||
}
|
||||
|
||||
public class ImportedMaterial
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public Color Diffuse { get; set; }
|
||||
public Color Ambient { get; set; }
|
||||
public Color Specular { get; set; }
|
||||
public Color Emissive { get; set; }
|
||||
public Color Reflection { get; set; }
|
||||
public float Shininess { get; set; }
|
||||
public float Transparency { get; set; }
|
||||
public List<ImportedMaterialTexture> Textures { get; set; }
|
||||
}
|
||||
|
||||
public class ImportedMaterialTexture
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public int Dest { get; set; }
|
||||
public Vector2 Offset { get; set; }
|
||||
public Vector2 Scale { get; set; }
|
||||
}
|
||||
|
||||
public class ImportedTexture
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public byte[] Data { get; set; }
|
||||
|
||||
public ImportedTexture(MemoryStream stream, string name)
|
||||
{
|
||||
Name = name;
|
||||
Data = stream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public class ImportedKeyframedAnimation
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public float SampleRate { get; set; }
|
||||
public List<ImportedAnimationKeyframedTrack> TrackList { get; set; }
|
||||
|
||||
public ImportedAnimationKeyframedTrack FindTrack(string path)
|
||||
{
|
||||
var track = TrackList.Find(x => x.Path == path);
|
||||
if (track == null)
|
||||
{
|
||||
track = new ImportedAnimationKeyframedTrack { Path = path };
|
||||
TrackList.Add(track);
|
||||
}
|
||||
|
||||
return track;
|
||||
}
|
||||
}
|
||||
|
||||
public class ImportedAnimationKeyframedTrack
|
||||
{
|
||||
public string Path { get; set; }
|
||||
public List<ImportedKeyframe<Vector3>> Scalings = new List<ImportedKeyframe<Vector3>>();
|
||||
public List<ImportedKeyframe<Vector3>> Rotations = new List<ImportedKeyframe<Vector3>>();
|
||||
public List<ImportedKeyframe<Vector3>> Translations = new List<ImportedKeyframe<Vector3>>();
|
||||
public ImportedBlendShape BlendShape;
|
||||
}
|
||||
|
||||
public class ImportedKeyframe<T>
|
||||
{
|
||||
public float time { get; set; }
|
||||
public T value { get; set; }
|
||||
|
||||
public ImportedKeyframe(float time, T value)
|
||||
{
|
||||
this.time = time;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
public class ImportedBlendShape
|
||||
{
|
||||
public string ChannelName;
|
||||
public List<ImportedKeyframe<float>> Keyframes = new List<ImportedKeyframe<float>>();
|
||||
}
|
||||
|
||||
public class ImportedMorph
|
||||
{
|
||||
public string Path { get; set; }
|
||||
public List<ImportedMorphChannel> Channels { get; set; }
|
||||
}
|
||||
|
||||
public class ImportedMorphChannel
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public List<ImportedMorphKeyframe> KeyframeList { get; set; }
|
||||
}
|
||||
|
||||
public class ImportedMorphKeyframe
|
||||
{
|
||||
public bool hasNormals { get; set; }
|
||||
public bool hasTangents { get; set; }
|
||||
public float Weight { get; set; }
|
||||
public List<ImportedMorphVertex> VertexList { get; set; }
|
||||
}
|
||||
|
||||
public class ImportedMorphVertex
|
||||
{
|
||||
public uint Index { get; set; }
|
||||
public ImportedVertex Vertex { get; set; }
|
||||
}
|
||||
|
||||
public static class ImportedHelpers
|
||||
{
|
||||
public static ImportedMesh FindMesh(string path, List<ImportedMesh> importedMeshList)
|
||||
{
|
||||
foreach (var mesh in importedMeshList)
|
||||
{
|
||||
if (mesh.Path == path)
|
||||
{
|
||||
return mesh;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ImportedMaterial FindMaterial(string name, List<ImportedMaterial> importedMats)
|
||||
{
|
||||
foreach (var mat in importedMats)
|
||||
{
|
||||
if (mat.Name == name)
|
||||
{
|
||||
return mat;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ImportedTexture FindTexture(string name, List<ImportedTexture> importedTextureList)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach (var tex in importedTextureList)
|
||||
{
|
||||
if (tex.Name == name)
|
||||
{
|
||||
return tex;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
26
AssetStudio/ILogger.cs
Normal file
26
AssetStudio/ILogger.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public enum LoggerEvent
|
||||
{
|
||||
Verbose,
|
||||
Debug,
|
||||
Info,
|
||||
Warning,
|
||||
Error,
|
||||
}
|
||||
|
||||
public interface ILogger
|
||||
{
|
||||
void Log(LoggerEvent loggerEvent, string message);
|
||||
}
|
||||
|
||||
public sealed class DummyLogger : ILogger
|
||||
{
|
||||
public void Log(LoggerEvent loggerEvent, string message) { }
|
||||
}
|
||||
}
|
||||
17
AssetStudio/IProgress.cs
Normal file
17
AssetStudio/IProgress.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public interface IProgress
|
||||
{
|
||||
void Report(int value);
|
||||
}
|
||||
|
||||
public sealed class DummyProgress : IProgress
|
||||
{
|
||||
public void Report(int value) { }
|
||||
}
|
||||
}
|
||||
82
AssetStudio/ImportHelper.cs
Normal file
82
AssetStudio/ImportHelper.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
using Org.Brotli.Dec;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public static class ImportHelper
|
||||
{
|
||||
public static void MergeSplitAssets(string path, bool allDirectories = false)
|
||||
{
|
||||
var splitFiles = Directory.GetFiles(path, "*.split0", allDirectories ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
|
||||
foreach (var splitFile in splitFiles)
|
||||
{
|
||||
var destFile = Path.GetFileNameWithoutExtension(splitFile);
|
||||
var destPath = Path.GetDirectoryName(splitFile);
|
||||
var destFull = Path.Combine(destPath, destFile);
|
||||
if (!File.Exists(destFull))
|
||||
{
|
||||
var splitParts = Directory.GetFiles(destPath, destFile + ".split*");
|
||||
using (var destStream = File.Create(destFull))
|
||||
{
|
||||
for (int i = 0; i < splitParts.Length; i++)
|
||||
{
|
||||
var splitPart = destFull + ".split" + i;
|
||||
using (var sourceStream = File.OpenRead(splitPart))
|
||||
{
|
||||
sourceStream.CopyTo(destStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string[] ProcessingSplitFiles(List<string> selectFile)
|
||||
{
|
||||
var splitFiles = selectFile.Where(x => x.Contains(".split"))
|
||||
.Select(x => Path.Combine(Path.GetDirectoryName(x), Path.GetFileNameWithoutExtension(x)))
|
||||
.Distinct()
|
||||
.ToList();
|
||||
selectFile.RemoveAll(x => x.Contains(".split"));
|
||||
foreach (var file in splitFiles)
|
||||
{
|
||||
if (File.Exists(file))
|
||||
{
|
||||
selectFile.Add(file);
|
||||
}
|
||||
}
|
||||
return selectFile.Distinct().ToArray();
|
||||
}
|
||||
|
||||
public static FileReader DecompressGZip(FileReader reader)
|
||||
{
|
||||
using (reader)
|
||||
{
|
||||
var stream = new MemoryStream();
|
||||
using (var gs = new GZipStream(reader.BaseStream, CompressionMode.Decompress))
|
||||
{
|
||||
gs.CopyTo(stream);
|
||||
}
|
||||
stream.Position = 0;
|
||||
return new FileReader(reader.FullPath, stream);
|
||||
}
|
||||
}
|
||||
|
||||
public static FileReader DecompressBrotli(FileReader reader)
|
||||
{
|
||||
using (reader)
|
||||
{
|
||||
var stream = new MemoryStream();
|
||||
using (var brotliStream = new BrotliInputStream(reader.BaseStream))
|
||||
{
|
||||
brotliStream.CopyTo(stream);
|
||||
}
|
||||
stream.Position = 0;
|
||||
return new FileReader(reader.FullPath, stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
13
AssetStudio/LocalSerializedObjectIdentifier.cs
Normal file
13
AssetStudio/LocalSerializedObjectIdentifier.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public class LocalSerializedObjectIdentifier
|
||||
{
|
||||
public int localSerializedFileIndex;
|
||||
public long localIdentifierInFile;
|
||||
}
|
||||
}
|
||||
26
AssetStudio/Logger.cs
Normal file
26
AssetStudio/Logger.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
public static class Logger
|
||||
{
|
||||
public static ILogger Default = new DummyLogger();
|
||||
|
||||
public static void Verbose(string message) => Default.Log(LoggerEvent.Verbose, message);
|
||||
public static void Debug(string message) => Default.Log(LoggerEvent.Debug, message);
|
||||
public static void Info(string message) => Default.Log(LoggerEvent.Info, message);
|
||||
public static void Warning(string message) => Default.Log(LoggerEvent.Warning, message);
|
||||
public static void Error(string message) => Default.Log(LoggerEvent.Error, message);
|
||||
|
||||
public static void Error(string message, Exception e)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine(message);
|
||||
sb.AppendLine(e.ToString());
|
||||
Default.Log(LoggerEvent.Error, sb.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
540
AssetStudio/Lz4DecoderStream.cs
Normal file
540
AssetStudio/Lz4DecoderStream.cs
Normal file
@@ -0,0 +1,540 @@
|
||||
#define CHECK_ARGS
|
||||
#define CHECK_EOF
|
||||
//#define LOCAL_SHADOW
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Lz4
|
||||
{
|
||||
public class Lz4DecoderStream : Stream
|
||||
{
|
||||
public Lz4DecoderStream(Stream input, long inputLength = long.MaxValue)
|
||||
{
|
||||
Reset(input, inputLength);
|
||||
}
|
||||
|
||||
private void Reset(Stream input, long inputLength = long.MaxValue)
|
||||
{
|
||||
this.inputLength = inputLength;
|
||||
this.input = input;
|
||||
|
||||
phase = DecodePhase.ReadToken;
|
||||
|
||||
decodeBufferPos = 0;
|
||||
|
||||
litLen = 0;
|
||||
matLen = 0;
|
||||
matDst = 0;
|
||||
|
||||
inBufPos = DecBufLen;
|
||||
inBufEnd = DecBufLen;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (disposing && input != null)
|
||||
{
|
||||
input.Close();
|
||||
}
|
||||
input = null;
|
||||
decodeBuffer = null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
|
||||
private long inputLength;
|
||||
private Stream input;
|
||||
|
||||
//because we might not be able to match back across invocations,
|
||||
//we have to keep the last window's worth of bytes around for reuse
|
||||
//we use a circular buffer for this - every time we write into this
|
||||
//buffer, we also write the same into our output buffer
|
||||
|
||||
private const int DecBufLen = 0x10000;
|
||||
private const int DecBufMask = 0xFFFF;
|
||||
|
||||
private const int InBufLen = 128;
|
||||
|
||||
private byte[] decodeBuffer = new byte[DecBufLen + InBufLen];
|
||||
private int decodeBufferPos, inBufPos, inBufEnd;
|
||||
|
||||
//we keep track of which phase we're in so that we can jump right back
|
||||
//into the correct part of decoding
|
||||
|
||||
private DecodePhase phase;
|
||||
|
||||
private enum DecodePhase
|
||||
{
|
||||
ReadToken,
|
||||
ReadExLiteralLength,
|
||||
CopyLiteral,
|
||||
ReadOffset,
|
||||
ReadExMatchLength,
|
||||
CopyMatch,
|
||||
}
|
||||
|
||||
//state within interruptable phases and across phase boundaries is
|
||||
//kept here - again, so that we can punt out and restart freely
|
||||
|
||||
private int litLen, matLen, matDst;
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
#if CHECK_ARGS
|
||||
if (buffer == null)
|
||||
throw new ArgumentNullException("buffer");
|
||||
if (offset < 0 || count < 0 || buffer.Length - count < offset)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
if (input == null)
|
||||
throw new InvalidOperationException();
|
||||
#endif
|
||||
int nRead, nToRead = count;
|
||||
|
||||
var decBuf = decodeBuffer;
|
||||
|
||||
//the stringy gotos are obnoxious, but their purpose is to
|
||||
//make it *blindingly* obvious how the state machine transitions
|
||||
//back and forth as it reads - remember, we can yield out of
|
||||
//this routine in several places, and we must be able to re-enter
|
||||
//and pick up where we left off!
|
||||
|
||||
#if LOCAL_SHADOW
|
||||
var phase = this.phase;
|
||||
var inBufPos = this.inBufPos;
|
||||
var inBufEnd = this.inBufEnd;
|
||||
#endif
|
||||
switch (phase)
|
||||
{
|
||||
case DecodePhase.ReadToken:
|
||||
goto readToken;
|
||||
|
||||
case DecodePhase.ReadExLiteralLength:
|
||||
goto readExLiteralLength;
|
||||
|
||||
case DecodePhase.CopyLiteral:
|
||||
goto copyLiteral;
|
||||
|
||||
case DecodePhase.ReadOffset:
|
||||
goto readOffset;
|
||||
|
||||
case DecodePhase.ReadExMatchLength:
|
||||
goto readExMatchLength;
|
||||
|
||||
case DecodePhase.CopyMatch:
|
||||
goto copyMatch;
|
||||
}
|
||||
|
||||
readToken:
|
||||
int tok;
|
||||
if (inBufPos < inBufEnd)
|
||||
{
|
||||
tok = decBuf[inBufPos++];
|
||||
}
|
||||
else
|
||||
{
|
||||
#if LOCAL_SHADOW
|
||||
this.inBufPos = inBufPos;
|
||||
#endif
|
||||
|
||||
tok = ReadByteCore();
|
||||
#if LOCAL_SHADOW
|
||||
inBufPos = this.inBufPos;
|
||||
inBufEnd = this.inBufEnd;
|
||||
#endif
|
||||
#if CHECK_EOF
|
||||
if (tok == -1)
|
||||
goto finish;
|
||||
#endif
|
||||
}
|
||||
|
||||
litLen = tok >> 4;
|
||||
matLen = (tok & 0xF) + 4;
|
||||
|
||||
switch (litLen)
|
||||
{
|
||||
case 0:
|
||||
phase = DecodePhase.ReadOffset;
|
||||
goto readOffset;
|
||||
|
||||
case 0xF:
|
||||
phase = DecodePhase.ReadExLiteralLength;
|
||||
goto readExLiteralLength;
|
||||
|
||||
default:
|
||||
phase = DecodePhase.CopyLiteral;
|
||||
goto copyLiteral;
|
||||
}
|
||||
|
||||
readExLiteralLength:
|
||||
int exLitLen;
|
||||
if (inBufPos < inBufEnd)
|
||||
{
|
||||
exLitLen = decBuf[inBufPos++];
|
||||
}
|
||||
else
|
||||
{
|
||||
#if LOCAL_SHADOW
|
||||
this.inBufPos = inBufPos;
|
||||
#endif
|
||||
exLitLen = ReadByteCore();
|
||||
#if LOCAL_SHADOW
|
||||
inBufPos = this.inBufPos;
|
||||
inBufEnd = this.inBufEnd;
|
||||
#endif
|
||||
|
||||
#if CHECK_EOF
|
||||
if (exLitLen == -1)
|
||||
goto finish;
|
||||
#endif
|
||||
}
|
||||
|
||||
litLen += exLitLen;
|
||||
if (exLitLen == 255)
|
||||
goto readExLiteralLength;
|
||||
|
||||
phase = DecodePhase.CopyLiteral;
|
||||
goto copyLiteral;
|
||||
|
||||
copyLiteral:
|
||||
int nReadLit = litLen < nToRead ? litLen : nToRead;
|
||||
if (nReadLit != 0)
|
||||
{
|
||||
if (inBufPos + nReadLit <= inBufEnd)
|
||||
{
|
||||
int ofs = offset;
|
||||
|
||||
for (int c = nReadLit; c-- != 0;)
|
||||
buffer[ofs++] = decBuf[inBufPos++];
|
||||
|
||||
nRead = nReadLit;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if LOCAL_SHADOW
|
||||
this.inBufPos = inBufPos;
|
||||
#endif
|
||||
nRead = ReadCore(buffer, offset, nReadLit);
|
||||
#if LOCAL_SHADOW
|
||||
inBufPos = this.inBufPos;
|
||||
inBufEnd = this.inBufEnd;
|
||||
#endif
|
||||
#if CHECK_EOF
|
||||
if (nRead == 0)
|
||||
goto finish;
|
||||
#endif
|
||||
}
|
||||
|
||||
offset += nRead;
|
||||
nToRead -= nRead;
|
||||
|
||||
litLen -= nRead;
|
||||
|
||||
if (litLen != 0)
|
||||
goto copyLiteral;
|
||||
}
|
||||
|
||||
if (nToRead == 0)
|
||||
goto finish;
|
||||
|
||||
phase = DecodePhase.ReadOffset;
|
||||
goto readOffset;
|
||||
|
||||
readOffset:
|
||||
if (inBufPos + 1 < inBufEnd)
|
||||
{
|
||||
matDst = (decBuf[inBufPos + 1] << 8) | decBuf[inBufPos];
|
||||
inBufPos += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if LOCAL_SHADOW
|
||||
this.inBufPos = inBufPos;
|
||||
#endif
|
||||
matDst = ReadOffsetCore();
|
||||
#if LOCAL_SHADOW
|
||||
inBufPos = this.inBufPos;
|
||||
inBufEnd = this.inBufEnd;
|
||||
#endif
|
||||
#if CHECK_EOF
|
||||
if (matDst == -1)
|
||||
goto finish;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (matLen == 15 + 4)
|
||||
{
|
||||
phase = DecodePhase.ReadExMatchLength;
|
||||
goto readExMatchLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
phase = DecodePhase.CopyMatch;
|
||||
goto copyMatch;
|
||||
}
|
||||
|
||||
readExMatchLength:
|
||||
int exMatLen;
|
||||
if (inBufPos < inBufEnd)
|
||||
{
|
||||
exMatLen = decBuf[inBufPos++];
|
||||
}
|
||||
else
|
||||
{
|
||||
#if LOCAL_SHADOW
|
||||
this.inBufPos = inBufPos;
|
||||
#endif
|
||||
exMatLen = ReadByteCore();
|
||||
#if LOCAL_SHADOW
|
||||
inBufPos = this.inBufPos;
|
||||
inBufEnd = this.inBufEnd;
|
||||
#endif
|
||||
#if CHECK_EOF
|
||||
if (exMatLen == -1)
|
||||
goto finish;
|
||||
#endif
|
||||
}
|
||||
|
||||
matLen += exMatLen;
|
||||
if (exMatLen == 255)
|
||||
goto readExMatchLength;
|
||||
|
||||
phase = DecodePhase.CopyMatch;
|
||||
goto copyMatch;
|
||||
|
||||
copyMatch:
|
||||
int nCpyMat = matLen < nToRead ? matLen : nToRead;
|
||||
if (nCpyMat != 0)
|
||||
{
|
||||
nRead = count - nToRead;
|
||||
|
||||
int bufDst = matDst - nRead;
|
||||
if (bufDst > 0)
|
||||
{
|
||||
//offset is fairly far back, we need to pull from the buffer
|
||||
|
||||
int bufSrc = decodeBufferPos - bufDst;
|
||||
if (bufSrc < 0)
|
||||
bufSrc += DecBufLen;
|
||||
int bufCnt = bufDst < nCpyMat ? bufDst : nCpyMat;
|
||||
|
||||
for (int c = bufCnt; c-- != 0;)
|
||||
buffer[offset++] = decBuf[bufSrc++ & DecBufMask];
|
||||
}
|
||||
else
|
||||
{
|
||||
bufDst = 0;
|
||||
}
|
||||
|
||||
int sOfs = offset - matDst;
|
||||
for (int i = bufDst; i < nCpyMat; i++)
|
||||
buffer[offset++] = buffer[sOfs++];
|
||||
|
||||
nToRead -= nCpyMat;
|
||||
matLen -= nCpyMat;
|
||||
}
|
||||
|
||||
if (nToRead == 0)
|
||||
goto finish;
|
||||
|
||||
phase = DecodePhase.ReadToken;
|
||||
goto readToken;
|
||||
|
||||
finish:
|
||||
nRead = count - nToRead;
|
||||
|
||||
int nToBuf = nRead < DecBufLen ? nRead : DecBufLen;
|
||||
int repPos = offset - nToBuf;
|
||||
|
||||
if (nToBuf == DecBufLen)
|
||||
{
|
||||
Buffer.BlockCopy(buffer, repPos, decBuf, 0, DecBufLen);
|
||||
decodeBufferPos = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int decPos = decodeBufferPos;
|
||||
|
||||
while (nToBuf-- != 0)
|
||||
decBuf[decPos++ & DecBufMask] = buffer[repPos++];
|
||||
|
||||
decodeBufferPos = decPos & DecBufMask;
|
||||
}
|
||||
|
||||
#if LOCAL_SHADOW
|
||||
this.phase = phase;
|
||||
this.inBufPos = inBufPos;
|
||||
#endif
|
||||
return nRead;
|
||||
}
|
||||
|
||||
private int ReadByteCore()
|
||||
{
|
||||
var buf = decodeBuffer;
|
||||
|
||||
if (inBufPos == inBufEnd)
|
||||
{
|
||||
int nRead = input.Read(buf, DecBufLen,
|
||||
InBufLen < inputLength ? InBufLen : (int)inputLength);
|
||||
|
||||
#if CHECK_EOF
|
||||
if (nRead == 0)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
inputLength -= nRead;
|
||||
|
||||
inBufPos = DecBufLen;
|
||||
inBufEnd = DecBufLen + nRead;
|
||||
}
|
||||
|
||||
return buf[inBufPos++];
|
||||
}
|
||||
|
||||
private int ReadOffsetCore()
|
||||
{
|
||||
var buf = decodeBuffer;
|
||||
|
||||
if (inBufPos == inBufEnd)
|
||||
{
|
||||
int nRead = input.Read(buf, DecBufLen,
|
||||
InBufLen < inputLength ? InBufLen : (int)inputLength);
|
||||
|
||||
#if CHECK_EOF
|
||||
if (nRead == 0)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
inputLength -= nRead;
|
||||
|
||||
inBufPos = DecBufLen;
|
||||
inBufEnd = DecBufLen + nRead;
|
||||
}
|
||||
|
||||
if (inBufEnd - inBufPos == 1)
|
||||
{
|
||||
buf[DecBufLen] = buf[inBufPos];
|
||||
|
||||
int nRead = input.Read(buf, DecBufLen + 1,
|
||||
InBufLen - 1 < inputLength ? InBufLen - 1 : (int)inputLength);
|
||||
|
||||
#if CHECK_EOF
|
||||
if (nRead == 0)
|
||||
{
|
||||
inBufPos = DecBufLen;
|
||||
inBufEnd = DecBufLen + 1;
|
||||
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
inputLength -= nRead;
|
||||
|
||||
inBufPos = DecBufLen;
|
||||
inBufEnd = DecBufLen + nRead + 1;
|
||||
}
|
||||
|
||||
int ret = (buf[inBufPos + 1] << 8) | buf[inBufPos];
|
||||
inBufPos += 2;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private int ReadCore(byte[] buffer, int offset, int count)
|
||||
{
|
||||
int nToRead = count;
|
||||
|
||||
var buf = decodeBuffer;
|
||||
int inBufLen = inBufEnd - inBufPos;
|
||||
|
||||
int fromBuf = nToRead < inBufLen ? nToRead : inBufLen;
|
||||
if (fromBuf != 0)
|
||||
{
|
||||
var bufPos = inBufPos;
|
||||
|
||||
for (int c = fromBuf; c-- != 0;)
|
||||
buffer[offset++] = buf[bufPos++];
|
||||
|
||||
inBufPos = bufPos;
|
||||
nToRead -= fromBuf;
|
||||
}
|
||||
|
||||
if (nToRead != 0)
|
||||
{
|
||||
int nRead;
|
||||
|
||||
if (nToRead >= InBufLen)
|
||||
{
|
||||
nRead = input.Read(buffer, offset,
|
||||
nToRead < inputLength ? nToRead : (int)inputLength);
|
||||
nToRead -= nRead;
|
||||
}
|
||||
else
|
||||
{
|
||||
nRead = input.Read(buf, DecBufLen,
|
||||
InBufLen < inputLength ? InBufLen : (int)inputLength);
|
||||
|
||||
inBufPos = DecBufLen;
|
||||
inBufEnd = DecBufLen + nRead;
|
||||
|
||||
fromBuf = nToRead < nRead ? nToRead : nRead;
|
||||
|
||||
var bufPos = inBufPos;
|
||||
|
||||
for (int c = fromBuf; c-- != 0;)
|
||||
buffer[offset++] = buf[bufPos++];
|
||||
|
||||
inBufPos = bufPos;
|
||||
nToRead -= fromBuf;
|
||||
}
|
||||
|
||||
inputLength -= nRead;
|
||||
}
|
||||
|
||||
return count - nToRead;
|
||||
}
|
||||
|
||||
#region Stream internals
|
||||
|
||||
public override bool CanRead => true;
|
||||
|
||||
public override bool CanSeek => false;
|
||||
|
||||
public override bool CanWrite => false;
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
}
|
||||
|
||||
public override long Length => throw new NotSupportedException();
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get => throw new NotSupportedException();
|
||||
set => throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
84
AssetStudio/Math/Color.cs
Normal file
84
AssetStudio/Math/Color.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
public struct Color : IEquatable<Color>
|
||||
{
|
||||
public float R;
|
||||
public float G;
|
||||
public float B;
|
||||
public float A;
|
||||
|
||||
public Color(float r, float g, float b, float a)
|
||||
{
|
||||
R = r;
|
||||
G = g;
|
||||
B = b;
|
||||
A = a;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return ((Vector4)this).GetHashCode();
|
||||
}
|
||||
|
||||
public override bool Equals(object other)
|
||||
{
|
||||
if (!(other is Color))
|
||||
return false;
|
||||
return Equals((Color)other);
|
||||
}
|
||||
|
||||
public bool Equals(Color other)
|
||||
{
|
||||
return R.Equals(other.R) && G.Equals(other.G) && B.Equals(other.B) && A.Equals(other.A);
|
||||
}
|
||||
|
||||
public static Color operator +(Color a, Color b)
|
||||
{
|
||||
return new Color(a.R + b.R, a.G + b.G, a.B + b.B, a.A + b.A);
|
||||
}
|
||||
|
||||
public static Color operator -(Color a, Color b)
|
||||
{
|
||||
return new Color(a.R - b.R, a.G - b.G, a.B - b.B, a.A - b.A);
|
||||
}
|
||||
|
||||
public static Color operator *(Color a, Color b)
|
||||
{
|
||||
return new Color(a.R * b.R, a.G * b.G, a.B * b.B, a.A * b.A);
|
||||
}
|
||||
|
||||
public static Color operator *(Color a, float b)
|
||||
{
|
||||
return new Color(a.R * b, a.G * b, a.B * b, a.A * b);
|
||||
}
|
||||
|
||||
public static Color operator *(float b, Color a)
|
||||
{
|
||||
return new Color(a.R * b, a.G * b, a.B * b, a.A * b);
|
||||
}
|
||||
|
||||
public static Color operator /(Color a, float b)
|
||||
{
|
||||
return new Color(a.R / b, a.G / b, a.B / b, a.A / b);
|
||||
}
|
||||
|
||||
public static bool operator ==(Color lhs, Color rhs)
|
||||
{
|
||||
return (Vector4)lhs == (Vector4)rhs;
|
||||
}
|
||||
|
||||
public static bool operator !=(Color lhs, Color rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
public static implicit operator Vector4(Color c)
|
||||
{
|
||||
return new Vector4(c.R, c.G, c.B, c.A);
|
||||
}
|
||||
}
|
||||
}
|
||||
888
AssetStudio/Math/Half.cs
Normal file
888
AssetStudio/Math/Half.cs
Normal file
@@ -0,0 +1,888 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a half-precision floating point number.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Note:
|
||||
/// Half is not fast enought and precision is also very bad,
|
||||
/// so is should not be used for matemathical computation (use Single instead).
|
||||
/// The main advantage of Half type is lower memory cost: two bytes per number.
|
||||
/// Half is typically used in graphical applications.
|
||||
///
|
||||
/// Note:
|
||||
/// All functions, where is used conversion half->float/float->half,
|
||||
/// are approx. ten times slower than float->double/double->float, i.e. ~3ns on 2GHz CPU.
|
||||
///
|
||||
/// References:
|
||||
/// - Fast Half Float Conversions, Jeroen van der Zijp, link: http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf
|
||||
/// - IEEE 754 revision, link: http://grouper.ieee.org/groups/754/
|
||||
/// </remarks>
|
||||
[Serializable]
|
||||
public struct Half : IComparable, IFormattable, IConvertible, IComparable<Half>, IEquatable<Half>
|
||||
{
|
||||
/// <summary>
|
||||
/// Internal representation of the half-precision floating-point number.
|
||||
/// </summary>
|
||||
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
|
||||
internal ushort value;
|
||||
|
||||
#region Constants
|
||||
/// <summary>
|
||||
/// Represents the smallest positive System.Half value greater than zero. This field is constant.
|
||||
/// </summary>
|
||||
public static readonly Half Epsilon = Half.ToHalf(0x0001);
|
||||
/// <summary>
|
||||
/// Represents the largest possible value of System.Half. This field is constant.
|
||||
/// </summary>
|
||||
public static readonly Half MaxValue = Half.ToHalf(0x7bff);
|
||||
/// <summary>
|
||||
/// Represents the smallest possible value of System.Half. This field is constant.
|
||||
/// </summary>
|
||||
public static readonly Half MinValue = Half.ToHalf(0xfbff);
|
||||
/// <summary>
|
||||
/// Represents not a number (NaN). This field is constant.
|
||||
/// </summary>
|
||||
public static readonly Half NaN = Half.ToHalf(0xfe00);
|
||||
/// <summary>
|
||||
/// Represents negative infinity. This field is constant.
|
||||
/// </summary>
|
||||
public static readonly Half NegativeInfinity = Half.ToHalf(0xfc00);
|
||||
/// <summary>
|
||||
/// Represents positive infinity. This field is constant.
|
||||
/// </summary>
|
||||
public static readonly Half PositiveInfinity = Half.ToHalf(0x7c00);
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Initializes a new instance of System.Half to the value of the specified single-precision floating-point number.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to represent as a System.Half.</param>
|
||||
public Half(float value) { this = HalfHelper.SingleToHalf(value); }
|
||||
/// <summary>
|
||||
/// Initializes a new instance of System.Half to the value of the specified 32-bit signed integer.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to represent as a System.Half.</param>
|
||||
public Half(int value) : this((float)value) { }
|
||||
/// <summary>
|
||||
/// Initializes a new instance of System.Half to the value of the specified 64-bit signed integer.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to represent as a System.Half.</param>
|
||||
public Half(long value) : this((float)value) { }
|
||||
/// <summary>
|
||||
/// Initializes a new instance of System.Half to the value of the specified double-precision floating-point number.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to represent as a System.Half.</param>
|
||||
public Half(double value) : this((float)value) { }
|
||||
/// <summary>
|
||||
/// Initializes a new instance of System.Half to the value of the specified decimal number.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to represent as a System.Half.</param>
|
||||
public Half(decimal value) : this((float)value) { }
|
||||
/// <summary>
|
||||
/// Initializes a new instance of System.Half to the value of the specified 32-bit unsigned integer.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to represent as a System.Half.</param>
|
||||
public Half(uint value) : this((float)value) { }
|
||||
/// <summary>
|
||||
/// Initializes a new instance of System.Half to the value of the specified 64-bit unsigned integer.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to represent as a System.Half.</param>
|
||||
public Half(ulong value) : this((float)value) { }
|
||||
#endregion
|
||||
|
||||
#region Numeric operators
|
||||
|
||||
/// <summary>
|
||||
/// Returns the result of multiplying the specified System.Half value by negative one.
|
||||
/// </summary>
|
||||
/// <param name="half">A System.Half.</param>
|
||||
/// <returns>A System.Half with the value of half, but the opposite sign. -or- Zero, if half is zero.</returns>
|
||||
public static Half Negate(Half half) { return -half; }
|
||||
/// <summary>
|
||||
/// Adds two specified System.Half values.
|
||||
/// </summary>
|
||||
/// <param name="half1">A System.Half.</param>
|
||||
/// <param name="half2">A System.Half.</param>
|
||||
/// <returns>A System.Half value that is the sum of half1 and half2.</returns>
|
||||
public static Half Add(Half half1, Half half2) { return half1 + half2; }
|
||||
/// <summary>
|
||||
/// Subtracts one specified System.Half value from another.
|
||||
/// </summary>
|
||||
/// <param name="half1">A System.Half (the minuend).</param>
|
||||
/// <param name="half2">A System.Half (the subtrahend).</param>
|
||||
/// <returns>The System.Half result of subtracting half2 from half1.</returns>
|
||||
public static Half Subtract(Half half1, Half half2) { return half1 - half2; }
|
||||
/// <summary>
|
||||
/// Multiplies two specified System.Half values.
|
||||
/// </summary>
|
||||
/// <param name="half1">A System.Half (the multiplicand).</param>
|
||||
/// <param name="half2">A System.Half (the multiplier).</param>
|
||||
/// <returns>A System.Half that is the result of multiplying half1 and half2.</returns>
|
||||
public static Half Multiply(Half half1, Half half2) { return half1 * half2; }
|
||||
/// <summary>
|
||||
/// Divides two specified System.Half values.
|
||||
/// </summary>
|
||||
/// <param name="half1">A System.Half (the dividend).</param>
|
||||
/// <param name="half2">A System.Half (the divisor).</param>
|
||||
/// <returns>The System.Half that is the result of dividing half1 by half2.</returns>
|
||||
/// <exception cref="System.DivideByZeroException">half2 is zero.</exception>
|
||||
public static Half Divide(Half half1, Half half2) { return half1 / half2; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value of the System.Half operand (the sign of the operand is unchanged).
|
||||
/// </summary>
|
||||
/// <param name="half">The System.Half operand.</param>
|
||||
/// <returns>The value of the operand, half.</returns>
|
||||
public static Half operator +(Half half) { return half; }
|
||||
/// <summary>
|
||||
/// Negates the value of the specified System.Half operand.
|
||||
/// </summary>
|
||||
/// <param name="half">The System.Half operand.</param>
|
||||
/// <returns>The result of half multiplied by negative one (-1).</returns>
|
||||
public static Half operator -(Half half) { return HalfHelper.Negate(half); }
|
||||
/// <summary>
|
||||
/// Increments the System.Half operand by 1.
|
||||
/// </summary>
|
||||
/// <param name="half">The System.Half operand.</param>
|
||||
/// <returns>The value of half incremented by 1.</returns>
|
||||
public static Half operator ++(Half half) { return (Half)(half + 1f); }
|
||||
/// <summary>
|
||||
/// Decrements the System.Half operand by one.
|
||||
/// </summary>
|
||||
/// <param name="half">The System.Half operand.</param>
|
||||
/// <returns>The value of half decremented by 1.</returns>
|
||||
public static Half operator --(Half half) { return (Half)(half - 1f); }
|
||||
/// <summary>
|
||||
/// Adds two specified System.Half values.
|
||||
/// </summary>
|
||||
/// <param name="half1">A System.Half.</param>
|
||||
/// <param name="half2">A System.Half.</param>
|
||||
/// <returns>The System.Half result of adding half1 and half2.</returns>
|
||||
public static Half operator +(Half half1, Half half2) { return (Half)((float)half1 + (float)half2); }
|
||||
/// <summary>
|
||||
/// Subtracts two specified System.Half values.
|
||||
/// </summary>
|
||||
/// <param name="half1">A System.Half.</param>
|
||||
/// <param name="half2">A System.Half.</param>
|
||||
/// <returns>The System.Half result of subtracting half1 and half2.</returns>
|
||||
public static Half operator -(Half half1, Half half2) { return (Half)((float)half1 - (float)half2); }
|
||||
/// <summary>
|
||||
/// Multiplies two specified System.Half values.
|
||||
/// </summary>
|
||||
/// <param name="half1">A System.Half.</param>
|
||||
/// <param name="half2">A System.Half.</param>
|
||||
/// <returns>The System.Half result of multiplying half1 by half2.</returns>
|
||||
public static Half operator *(Half half1, Half half2) { return (Half)((float)half1 * (float)half2); }
|
||||
/// <summary>
|
||||
/// Divides two specified System.Half values.
|
||||
/// </summary>
|
||||
/// <param name="half1">A System.Half (the dividend).</param>
|
||||
/// <param name="half2">A System.Half (the divisor).</param>
|
||||
/// <returns>The System.Half result of half1 by half2.</returns>
|
||||
public static Half operator /(Half half1, Half half2) { return (Half)((float)half1 / (float)half2); }
|
||||
/// <summary>
|
||||
/// Returns a value indicating whether two instances of System.Half are equal.
|
||||
/// </summary>
|
||||
/// <param name="half1">A System.Half.</param>
|
||||
/// <param name="half2">A System.Half.</param>
|
||||
/// <returns>true if half1 and half2 are equal; otherwise, false.</returns>
|
||||
public static bool operator ==(Half half1, Half half2) { return (!IsNaN(half1) && (half1.value == half2.value)); }
|
||||
/// <summary>
|
||||
/// Returns a value indicating whether two instances of System.Half are not equal.
|
||||
/// </summary>
|
||||
/// <param name="half1">A System.Half.</param>
|
||||
/// <param name="half2">A System.Half.</param>
|
||||
/// <returns>true if half1 and half2 are not equal; otherwise, false.</returns>
|
||||
public static bool operator !=(Half half1, Half half2) { return !(half1.value == half2.value); }
|
||||
/// <summary>
|
||||
/// Returns a value indicating whether a specified System.Half is less than another specified System.Half.
|
||||
/// </summary>
|
||||
/// <param name="half1">A System.Half.</param>
|
||||
/// <param name="half2">A System.Half.</param>
|
||||
/// <returns>true if half1 is less than half1; otherwise, false.</returns>
|
||||
public static bool operator <(Half half1, Half half2) { return (float)half1 < (float)half2; }
|
||||
/// <summary>
|
||||
/// Returns a value indicating whether a specified System.Half is greater than another specified System.Half.
|
||||
/// </summary>
|
||||
/// <param name="half1">A System.Half.</param>
|
||||
/// <param name="half2">A System.Half.</param>
|
||||
/// <returns>true if half1 is greater than half2; otherwise, false.</returns>
|
||||
public static bool operator >(Half half1, Half half2) { return (float)half1 > (float)half2; }
|
||||
/// <summary>
|
||||
/// Returns a value indicating whether a specified System.Half is less than or equal to another specified System.Half.
|
||||
/// </summary>
|
||||
/// <param name="half1">A System.Half.</param>
|
||||
/// <param name="half2">A System.Half.</param>
|
||||
/// <returns>true if half1 is less than or equal to half2; otherwise, false.</returns>
|
||||
public static bool operator <=(Half half1, Half half2) { return (half1 == half2) || (half1 < half2); }
|
||||
/// <summary>
|
||||
/// Returns a value indicating whether a specified System.Half is greater than or equal to another specified System.Half.
|
||||
/// </summary>
|
||||
/// <param name="half1">A System.Half.</param>
|
||||
/// <param name="half2">A System.Half.</param>
|
||||
/// <returns>true if half1 is greater than or equal to half2; otherwise, false.</returns>
|
||||
public static bool operator >=(Half half1, Half half2) { return (half1 == half2) || (half1 > half2); }
|
||||
#endregion
|
||||
|
||||
#region Type casting operators
|
||||
/// <summary>
|
||||
/// Converts an 8-bit unsigned integer to a System.Half.
|
||||
/// </summary>
|
||||
/// <param name="value">An 8-bit unsigned integer.</param>
|
||||
/// <returns>A System.Half that represents the converted 8-bit unsigned integer.</returns>
|
||||
public static implicit operator Half(byte value) { return new Half((float)value); }
|
||||
/// <summary>
|
||||
/// Converts a 16-bit signed integer to a System.Half.
|
||||
/// </summary>
|
||||
/// <param name="value">A 16-bit signed integer.</param>
|
||||
/// <returns>A System.Half that represents the converted 16-bit signed integer.</returns>
|
||||
public static implicit operator Half(short value) { return new Half((float)value); }
|
||||
/// <summary>
|
||||
/// Converts a Unicode character to a System.Half.
|
||||
/// </summary>
|
||||
/// <param name="value">A Unicode character.</param>
|
||||
/// <returns>A System.Half that represents the converted Unicode character.</returns>
|
||||
public static implicit operator Half(char value) { return new Half((float)value); }
|
||||
/// <summary>
|
||||
/// Converts a 32-bit signed integer to a System.Half.
|
||||
/// </summary>
|
||||
/// <param name="value">A 32-bit signed integer.</param>
|
||||
/// <returns>A System.Half that represents the converted 32-bit signed integer.</returns>
|
||||
public static implicit operator Half(int value) { return new Half((float)value); }
|
||||
/// <summary>
|
||||
/// Converts a 64-bit signed integer to a System.Half.
|
||||
/// </summary>
|
||||
/// <param name="value">A 64-bit signed integer.</param>
|
||||
/// <returns>A System.Half that represents the converted 64-bit signed integer.</returns>
|
||||
public static implicit operator Half(long value) { return new Half((float)value); }
|
||||
/// <summary>
|
||||
/// Converts a single-precision floating-point number to a System.Half.
|
||||
/// </summary>
|
||||
/// <param name="value">A single-precision floating-point number.</param>
|
||||
/// <returns>A System.Half that represents the converted single-precision floating point number.</returns>
|
||||
public static explicit operator Half(float value) { return new Half((float)value); }
|
||||
/// <summary>
|
||||
/// Converts a double-precision floating-point number to a System.Half.
|
||||
/// </summary>
|
||||
/// <param name="value">A double-precision floating-point number.</param>
|
||||
/// <returns>A System.Half that represents the converted double-precision floating point number.</returns>
|
||||
public static explicit operator Half(double value) { return new Half((float)value); }
|
||||
/// <summary>
|
||||
/// Converts a decimal number to a System.Half.
|
||||
/// </summary>
|
||||
/// <param name="value">decimal number</param>
|
||||
/// <returns>A System.Half that represents the converted decimal number.</returns>
|
||||
public static explicit operator Half(decimal value) { return new Half((float)value); }
|
||||
/// <summary>
|
||||
/// Converts a System.Half to an 8-bit unsigned integer.
|
||||
/// </summary>
|
||||
/// <param name="value">A System.Half to convert.</param>
|
||||
/// <returns>An 8-bit unsigned integer that represents the converted System.Half.</returns>
|
||||
public static explicit operator byte(Half value) { return (byte)(float)value; }
|
||||
/// <summary>
|
||||
/// Converts a System.Half to a Unicode character.
|
||||
/// </summary>
|
||||
/// <param name="value">A System.Half to convert.</param>
|
||||
/// <returns>A Unicode character that represents the converted System.Half.</returns>
|
||||
public static explicit operator char(Half value) { return (char)(float)value; }
|
||||
/// <summary>
|
||||
/// Converts a System.Half to a 16-bit signed integer.
|
||||
/// </summary>
|
||||
/// <param name="value">A System.Half to convert.</param>
|
||||
/// <returns>A 16-bit signed integer that represents the converted System.Half.</returns>
|
||||
public static explicit operator short(Half value) { return (short)(float)value; }
|
||||
/// <summary>
|
||||
/// Converts a System.Half to a 32-bit signed integer.
|
||||
/// </summary>
|
||||
/// <param name="value">A System.Half to convert.</param>
|
||||
/// <returns>A 32-bit signed integer that represents the converted System.Half.</returns>
|
||||
public static explicit operator int(Half value) { return (int)(float)value; }
|
||||
/// <summary>
|
||||
/// Converts a System.Half to a 64-bit signed integer.
|
||||
/// </summary>
|
||||
/// <param name="value">A System.Half to convert.</param>
|
||||
/// <returns>A 64-bit signed integer that represents the converted System.Half.</returns>
|
||||
public static explicit operator long(Half value) { return (long)(float)value; }
|
||||
/// <summary>
|
||||
/// Converts a System.Half to a single-precision floating-point number.
|
||||
/// </summary>
|
||||
/// <param name="value">A System.Half to convert.</param>
|
||||
/// <returns>A single-precision floating-point number that represents the converted System.Half.</returns>
|
||||
public static implicit operator float(Half value) { return (float)HalfHelper.HalfToSingle(value); }
|
||||
/// <summary>
|
||||
/// Converts a System.Half to a double-precision floating-point number.
|
||||
/// </summary>
|
||||
/// <param name="value">A System.Half to convert.</param>
|
||||
/// <returns>A double-precision floating-point number that represents the converted System.Half.</returns>
|
||||
public static implicit operator double(Half value) { return (double)(float)value; }
|
||||
/// <summary>
|
||||
/// Converts a System.Half to a decimal number.
|
||||
/// </summary>
|
||||
/// <param name="value">A System.Half to convert.</param>
|
||||
/// <returns>A decimal number that represents the converted System.Half.</returns>
|
||||
public static explicit operator decimal(Half value) { return (decimal)(float)value; }
|
||||
/// <summary>
|
||||
/// Converts an 8-bit signed integer to a System.Half.
|
||||
/// </summary>
|
||||
/// <param name="value">An 8-bit signed integer.</param>
|
||||
/// <returns>A System.Half that represents the converted 8-bit signed integer.</returns>
|
||||
public static implicit operator Half(sbyte value) { return new Half((float)value); }
|
||||
/// <summary>
|
||||
/// Converts a 16-bit unsigned integer to a System.Half.
|
||||
/// </summary>
|
||||
/// <param name="value">A 16-bit unsigned integer.</param>
|
||||
/// <returns>A System.Half that represents the converted 16-bit unsigned integer.</returns>
|
||||
public static implicit operator Half(ushort value) { return new Half((float)value); }
|
||||
/// <summary>
|
||||
/// Converts a 32-bit unsigned integer to a System.Half.
|
||||
/// </summary>
|
||||
/// <param name="value">A 32-bit unsigned integer.</param>
|
||||
/// <returns>A System.Half that represents the converted 32-bit unsigned integer.</returns>
|
||||
public static implicit operator Half(uint value) { return new Half((float)value); }
|
||||
/// <summary>
|
||||
/// Converts a 64-bit unsigned integer to a System.Half.
|
||||
/// </summary>
|
||||
/// <param name="value">A 64-bit unsigned integer.</param>
|
||||
/// <returns>A System.Half that represents the converted 64-bit unsigned integer.</returns>
|
||||
public static implicit operator Half(ulong value) { return new Half((float)value); }
|
||||
/// <summary>
|
||||
/// Converts a System.Half to an 8-bit signed integer.
|
||||
/// </summary>
|
||||
/// <param name="value">A System.Half to convert.</param>
|
||||
/// <returns>An 8-bit signed integer that represents the converted System.Half.</returns>
|
||||
public static explicit operator sbyte(Half value) { return (sbyte)(float)value; }
|
||||
/// <summary>
|
||||
/// Converts a System.Half to a 16-bit unsigned integer.
|
||||
/// </summary>
|
||||
/// <param name="value">A System.Half to convert.</param>
|
||||
/// <returns>A 16-bit unsigned integer that represents the converted System.Half.</returns>
|
||||
public static explicit operator ushort(Half value) { return (ushort)(float)value; }
|
||||
/// <summary>
|
||||
/// Converts a System.Half to a 32-bit unsigned integer.
|
||||
/// </summary>
|
||||
/// <param name="value">A System.Half to convert.</param>
|
||||
/// <returns>A 32-bit unsigned integer that represents the converted System.Half.</returns>
|
||||
public static explicit operator uint(Half value) { return (uint)(float)value; }
|
||||
/// <summary>
|
||||
/// Converts a System.Half to a 64-bit unsigned integer.
|
||||
/// </summary>
|
||||
/// <param name="value">A System.Half to convert.</param>
|
||||
/// <returns>A 64-bit unsigned integer that represents the converted System.Half.</returns>
|
||||
public static explicit operator ulong(Half value) { return (ulong)(float)value; }
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Compares this instance to a specified System.Half object.
|
||||
/// </summary>
|
||||
/// <param name="other">A System.Half object.</param>
|
||||
/// <returns>
|
||||
/// A signed number indicating the relative values of this instance and value.
|
||||
/// Return Value Meaning Less than zero This instance is less than value. Zero
|
||||
/// This instance is equal to value. Greater than zero This instance is greater than value.
|
||||
/// </returns>
|
||||
public int CompareTo(Half other)
|
||||
{
|
||||
int result = 0;
|
||||
if (this < other)
|
||||
{
|
||||
result = -1;
|
||||
}
|
||||
else if (this > other)
|
||||
{
|
||||
result = 1;
|
||||
}
|
||||
else if (this != other)
|
||||
{
|
||||
if (!IsNaN(this))
|
||||
{
|
||||
result = 1;
|
||||
}
|
||||
else if (!IsNaN(other))
|
||||
{
|
||||
result = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
/// <summary>
|
||||
/// Compares this instance to a specified System.Object.
|
||||
/// </summary>
|
||||
/// <param name="obj">An System.Object or null.</param>
|
||||
/// <returns>
|
||||
/// A signed number indicating the relative values of this instance and value.
|
||||
/// Return Value Meaning Less than zero This instance is less than value. Zero
|
||||
/// This instance is equal to value. Greater than zero This instance is greater
|
||||
/// than value. -or- value is null.
|
||||
/// </returns>
|
||||
/// <exception cref="System.ArgumentException">value is not a System.Half</exception>
|
||||
public int CompareTo(object obj)
|
||||
{
|
||||
int result = 0;
|
||||
if (obj == null)
|
||||
{
|
||||
result = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (obj is Half)
|
||||
{
|
||||
result = CompareTo((Half)obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException("Object must be of type Half.");
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a value indicating whether this instance and a specified System.Half object represent the same value.
|
||||
/// </summary>
|
||||
/// <param name="other">A System.Half object to compare to this instance.</param>
|
||||
/// <returns>true if value is equal to this instance; otherwise, false.</returns>
|
||||
public bool Equals(Half other)
|
||||
{
|
||||
return ((other == this) || (IsNaN(other) && IsNaN(this)));
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a value indicating whether this instance and a specified System.Object
|
||||
/// represent the same type and value.
|
||||
/// </summary>
|
||||
/// <param name="obj">An System.Object.</param>
|
||||
/// <returns>true if value is a System.Half and equal to this instance; otherwise, false.</returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
bool result = false;
|
||||
if (obj is Half)
|
||||
{
|
||||
Half half = (Half)obj;
|
||||
if ((half == this) || (IsNaN(half) && IsNaN(this)))
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns the hash code for this instance.
|
||||
/// </summary>
|
||||
/// <returns>A 32-bit signed integer hash code.</returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return value.GetHashCode();
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns the System.TypeCode for value type System.Half.
|
||||
/// </summary>
|
||||
/// <returns>The enumerated constant (TypeCode)255.</returns>
|
||||
public TypeCode GetTypeCode()
|
||||
{
|
||||
return (TypeCode)255;
|
||||
}
|
||||
|
||||
#region BitConverter & Math methods for Half
|
||||
/// <summary>
|
||||
/// Returns the specified half-precision floating point value as an array of bytes.
|
||||
/// </summary>
|
||||
/// <param name="value">The number to convert.</param>
|
||||
/// <returns>An array of bytes with length 2.</returns>
|
||||
public static byte[] GetBytes(Half value)
|
||||
{
|
||||
return BitConverter.GetBytes(value.value);
|
||||
}
|
||||
/// <summary>
|
||||
/// Converts the value of a specified instance of System.Half to its equivalent binary representation.
|
||||
/// </summary>
|
||||
/// <param name="value">A System.Half value.</param>
|
||||
/// <returns>A 16-bit unsigned integer that contain the binary representation of value.</returns>
|
||||
public static ushort GetBits(Half value)
|
||||
{
|
||||
return value.value;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a half-precision floating point number converted from two bytes
|
||||
/// at a specified position in a byte array.
|
||||
/// </summary>
|
||||
/// <param name="value">An array of bytes.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <returns>A half-precision floating point number formed by two bytes beginning at startIndex.</returns>
|
||||
/// <exception cref="System.ArgumentException">
|
||||
/// startIndex is greater than or equal to the length of value minus 1, and is
|
||||
/// less than or equal to the length of value minus 1.
|
||||
/// </exception>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">startIndex is less than zero or greater than the length of value minus 1.</exception>
|
||||
public static Half ToHalf(byte[] value, int startIndex)
|
||||
{
|
||||
return Half.ToHalf((ushort)BitConverter.ToInt16(value, startIndex));
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a half-precision floating point number converted from its binary representation.
|
||||
/// </summary>
|
||||
/// <param name="bits">Binary representation of System.Half value</param>
|
||||
/// <returns>A half-precision floating point number formed by its binary representation.</returns>
|
||||
public static Half ToHalf(ushort bits)
|
||||
{
|
||||
return new Half { value = bits };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a value indicating the sign of a half-precision floating-point number.
|
||||
/// </summary>
|
||||
/// <param name="value">A signed number.</param>
|
||||
/// <returns>
|
||||
/// A number indicating the sign of value. Number Description -1 value is less
|
||||
/// than zero. 0 value is equal to zero. 1 value is greater than zero.
|
||||
/// </returns>
|
||||
/// <exception cref="System.ArithmeticException">value is equal to System.Half.NaN.</exception>
|
||||
public static int Sign(Half value)
|
||||
{
|
||||
if (value < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else if (value > 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (value != 0)
|
||||
{
|
||||
throw new ArithmeticException("Function does not accept floating point Not-a-Number values.");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns the absolute value of a half-precision floating-point number.
|
||||
/// </summary>
|
||||
/// <param name="value">A number in the range System.Half.MinValue ≤ value ≤ System.Half.MaxValue.</param>
|
||||
/// <returns>A half-precision floating-point number, x, such that 0 ≤ x ≤System.Half.MaxValue.</returns>
|
||||
public static Half Abs(Half value)
|
||||
{
|
||||
return HalfHelper.Abs(value);
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns the larger of two half-precision floating-point numbers.
|
||||
/// </summary>
|
||||
/// <param name="value1">The first of two half-precision floating-point numbers to compare.</param>
|
||||
/// <param name="value2">The second of two half-precision floating-point numbers to compare.</param>
|
||||
/// <returns>
|
||||
/// Parameter value1 or value2, whichever is larger. If value1, or value2, or both val1
|
||||
/// and value2 are equal to System.Half.NaN, System.Half.NaN is returned.
|
||||
/// </returns>
|
||||
public static Half Max(Half value1, Half value2)
|
||||
{
|
||||
return (value1 < value2) ? value2 : value1;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns the smaller of two half-precision floating-point numbers.
|
||||
/// </summary>
|
||||
/// <param name="value1">The first of two half-precision floating-point numbers to compare.</param>
|
||||
/// <param name="value2">The second of two half-precision floating-point numbers to compare.</param>
|
||||
/// <returns>
|
||||
/// Parameter value1 or value2, whichever is smaller. If value1, or value2, or both val1
|
||||
/// and value2 are equal to System.Half.NaN, System.Half.NaN is returned.
|
||||
/// </returns>
|
||||
public static Half Min(Half value1, Half value2)
|
||||
{
|
||||
return (value1 < value2) ? value1 : value2;
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Returns a value indicating whether the specified number evaluates to not a number (System.Half.NaN).
|
||||
/// </summary>
|
||||
/// <param name="half">A half-precision floating-point number.</param>
|
||||
/// <returns>true if value evaluates to not a number (System.Half.NaN); otherwise, false.</returns>
|
||||
public static bool IsNaN(Half half)
|
||||
{
|
||||
return HalfHelper.IsNaN(half);
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a value indicating whether the specified number evaluates to negative or positive infinity.
|
||||
/// </summary>
|
||||
/// <param name="half">A half-precision floating-point number.</param>
|
||||
/// <returns>true if half evaluates to System.Half.PositiveInfinity or System.Half.NegativeInfinity; otherwise, false.</returns>
|
||||
public static bool IsInfinity(Half half)
|
||||
{
|
||||
return HalfHelper.IsInfinity(half);
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a value indicating whether the specified number evaluates to negative infinity.
|
||||
/// </summary>
|
||||
/// <param name="half">A half-precision floating-point number.</param>
|
||||
/// <returns>true if half evaluates to System.Half.NegativeInfinity; otherwise, false.</returns>
|
||||
public static bool IsNegativeInfinity(Half half)
|
||||
{
|
||||
return HalfHelper.IsNegativeInfinity(half);
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a value indicating whether the specified number evaluates to positive infinity.
|
||||
/// </summary>
|
||||
/// <param name="half">A half-precision floating-point number.</param>
|
||||
/// <returns>true if half evaluates to System.Half.PositiveInfinity; otherwise, false.</returns>
|
||||
public static bool IsPositiveInfinity(Half half)
|
||||
{
|
||||
return HalfHelper.IsPositiveInfinity(half);
|
||||
}
|
||||
|
||||
#region String operations (Parse and ToString)
|
||||
/// <summary>
|
||||
/// Converts the string representation of a number to its System.Half equivalent.
|
||||
/// </summary>
|
||||
/// <param name="value">The string representation of the number to convert.</param>
|
||||
/// <returns>The System.Half number equivalent to the number contained in value.</returns>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.FormatException">value is not in the correct format.</exception>
|
||||
/// <exception cref="System.OverflowException">value represents a number less than System.Half.MinValue or greater than System.Half.MaxValue.</exception>
|
||||
public static Half Parse(string value)
|
||||
{
|
||||
return (Half)float.Parse(value, CultureInfo.InvariantCulture);
|
||||
}
|
||||
/// <summary>
|
||||
/// Converts the string representation of a number to its System.Half equivalent
|
||||
/// using the specified culture-specific format information.
|
||||
/// </summary>
|
||||
/// <param name="value">The string representation of the number to convert.</param>
|
||||
/// <param name="provider">An System.IFormatProvider that supplies culture-specific parsing information about value.</param>
|
||||
/// <returns>The System.Half number equivalent to the number contained in s as specified by provider.</returns>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.FormatException">value is not in the correct format.</exception>
|
||||
/// <exception cref="System.OverflowException">value represents a number less than System.Half.MinValue or greater than System.Half.MaxValue.</exception>
|
||||
public static Half Parse(string value, IFormatProvider provider)
|
||||
{
|
||||
return (Half)float.Parse(value, provider);
|
||||
}
|
||||
/// <summary>
|
||||
/// Converts the string representation of a number in a specified style to its System.Half equivalent.
|
||||
/// </summary>
|
||||
/// <param name="value">The string representation of the number to convert.</param>
|
||||
/// <param name="style">
|
||||
/// A bitwise combination of System.Globalization.NumberStyles values that indicates
|
||||
/// the style elements that can be present in value. A typical value to specify is
|
||||
/// System.Globalization.NumberStyles.Number.
|
||||
/// </param>
|
||||
/// <returns>The System.Half number equivalent to the number contained in s as specified by style.</returns>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentException">
|
||||
/// style is not a System.Globalization.NumberStyles value. -or- style is the
|
||||
/// System.Globalization.NumberStyles.AllowHexSpecifier value.
|
||||
/// </exception>
|
||||
/// <exception cref="System.FormatException">value is not in the correct format.</exception>
|
||||
/// <exception cref="System.OverflowException">value represents a number less than System.Half.MinValue or greater than System.Half.MaxValue.</exception>
|
||||
public static Half Parse(string value, NumberStyles style)
|
||||
{
|
||||
return (Half)float.Parse(value, style, CultureInfo.InvariantCulture);
|
||||
}
|
||||
/// <summary>
|
||||
/// Converts the string representation of a number to its System.Half equivalent
|
||||
/// using the specified style and culture-specific format.
|
||||
/// </summary>
|
||||
/// <param name="value">The string representation of the number to convert.</param>
|
||||
/// <param name="style">
|
||||
/// A bitwise combination of System.Globalization.NumberStyles values that indicates
|
||||
/// the style elements that can be present in value. A typical value to specify is
|
||||
/// System.Globalization.NumberStyles.Number.
|
||||
/// </param>
|
||||
/// <param name="provider">An System.IFormatProvider object that supplies culture-specific information about the format of value.</param>
|
||||
/// <returns>The System.Half number equivalent to the number contained in s as specified by style and provider.</returns>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentException">
|
||||
/// style is not a System.Globalization.NumberStyles value. -or- style is the
|
||||
/// System.Globalization.NumberStyles.AllowHexSpecifier value.
|
||||
/// </exception>
|
||||
/// <exception cref="System.FormatException">value is not in the correct format.</exception>
|
||||
/// <exception cref="System.OverflowException">value represents a number less than System.Half.MinValue or greater than System.Half.MaxValue.</exception>
|
||||
public static Half Parse(string value, NumberStyles style, IFormatProvider provider)
|
||||
{
|
||||
return (Half)float.Parse(value, style, provider);
|
||||
}
|
||||
/// <summary>
|
||||
/// Converts the string representation of a number to its System.Half equivalent.
|
||||
/// A return value indicates whether the conversion succeeded or failed.
|
||||
/// </summary>
|
||||
/// <param name="value">The string representation of the number to convert.</param>
|
||||
/// <param name="result">
|
||||
/// When this method returns, contains the System.Half number that is equivalent
|
||||
/// to the numeric value contained in value, if the conversion succeeded, or is zero
|
||||
/// if the conversion failed. The conversion fails if the s parameter is null,
|
||||
/// is not a number in a valid format, or represents a number less than System.Half.MinValue
|
||||
/// or greater than System.Half.MaxValue. This parameter is passed uninitialized.
|
||||
/// </param>
|
||||
/// <returns>true if s was converted successfully; otherwise, false.</returns>
|
||||
public static bool TryParse(string value, out Half result)
|
||||
{
|
||||
float f;
|
||||
if (float.TryParse(value, out f))
|
||||
{
|
||||
result = (Half)f;
|
||||
return true;
|
||||
}
|
||||
|
||||
result = new Half();
|
||||
return false;
|
||||
}
|
||||
/// <summary>
|
||||
/// Converts the string representation of a number to its System.Half equivalent
|
||||
/// using the specified style and culture-specific format. A return value indicates
|
||||
/// whether the conversion succeeded or failed.
|
||||
/// </summary>
|
||||
/// <param name="value">The string representation of the number to convert.</param>
|
||||
/// <param name="style">
|
||||
/// A bitwise combination of System.Globalization.NumberStyles values that indicates
|
||||
/// the permitted format of value. A typical value to specify is System.Globalization.NumberStyles.Number.
|
||||
/// </param>
|
||||
/// <param name="provider">An System.IFormatProvider object that supplies culture-specific parsing information about value.</param>
|
||||
/// <param name="result">
|
||||
/// When this method returns, contains the System.Half number that is equivalent
|
||||
/// to the numeric value contained in value, if the conversion succeeded, or is zero
|
||||
/// if the conversion failed. The conversion fails if the s parameter is null,
|
||||
/// is not in a format compliant with style, or represents a number less than
|
||||
/// System.Half.MinValue or greater than System.Half.MaxValue. This parameter is passed uninitialized.
|
||||
/// </param>
|
||||
/// <returns>true if s was converted successfully; otherwise, false.</returns>
|
||||
/// <exception cref="System.ArgumentException">
|
||||
/// style is not a System.Globalization.NumberStyles value. -or- style
|
||||
/// is the System.Globalization.NumberStyles.AllowHexSpecifier value.
|
||||
/// </exception>
|
||||
public static bool TryParse(string value, NumberStyles style, IFormatProvider provider, out Half result)
|
||||
{
|
||||
bool parseResult = false;
|
||||
float f;
|
||||
if (float.TryParse(value, style, provider, out f))
|
||||
{
|
||||
result = (Half)f;
|
||||
parseResult = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = new Half();
|
||||
}
|
||||
|
||||
return parseResult;
|
||||
}
|
||||
/// <summary>
|
||||
/// Converts the numeric value of this instance to its equivalent string representation.
|
||||
/// </summary>
|
||||
/// <returns>A string that represents the value of this instance.</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return ((float)this).ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
/// <summary>
|
||||
/// Converts the numeric value of this instance to its equivalent string representation
|
||||
/// using the specified culture-specific format information.
|
||||
/// </summary>
|
||||
/// <param name="formatProvider">An System.IFormatProvider that supplies culture-specific formatting information.</param>
|
||||
/// <returns>The string representation of the value of this instance as specified by provider.</returns>
|
||||
public string ToString(IFormatProvider formatProvider)
|
||||
{
|
||||
return ((float)this).ToString(formatProvider);
|
||||
}
|
||||
/// <summary>
|
||||
/// Converts the numeric value of this instance to its equivalent string representation, using the specified format.
|
||||
/// </summary>
|
||||
/// <param name="format">A numeric format string.</param>
|
||||
/// <returns>The string representation of the value of this instance as specified by format.</returns>
|
||||
public string ToString(string format)
|
||||
{
|
||||
return ((float)this).ToString(format, CultureInfo.InvariantCulture);
|
||||
}
|
||||
/// <summary>
|
||||
/// Converts the numeric value of this instance to its equivalent string representation
|
||||
/// using the specified format and culture-specific format information.
|
||||
/// </summary>
|
||||
/// <param name="format">A numeric format string.</param>
|
||||
/// <param name="formatProvider">An System.IFormatProvider that supplies culture-specific formatting information.</param>
|
||||
/// <returns>The string representation of the value of this instance as specified by format and provider.</returns>
|
||||
/// <exception cref="System.FormatException">format is invalid.</exception>
|
||||
public string ToString(string format, IFormatProvider formatProvider)
|
||||
{
|
||||
return ((float)this).ToString(format, formatProvider);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IConvertible Members
|
||||
float IConvertible.ToSingle(IFormatProvider provider)
|
||||
{
|
||||
return (float)this;
|
||||
}
|
||||
TypeCode IConvertible.GetTypeCode()
|
||||
{
|
||||
return GetTypeCode();
|
||||
}
|
||||
bool IConvertible.ToBoolean(IFormatProvider provider)
|
||||
{
|
||||
return Convert.ToBoolean((float)this);
|
||||
}
|
||||
byte IConvertible.ToByte(IFormatProvider provider)
|
||||
{
|
||||
return Convert.ToByte((float)this);
|
||||
}
|
||||
char IConvertible.ToChar(IFormatProvider provider)
|
||||
{
|
||||
throw new InvalidCastException(string.Format(CultureInfo.CurrentCulture, "Invalid cast from '{0}' to '{1}'.", "Half", "Char"));
|
||||
}
|
||||
DateTime IConvertible.ToDateTime(IFormatProvider provider)
|
||||
{
|
||||
throw new InvalidCastException(string.Format(CultureInfo.CurrentCulture, "Invalid cast from '{0}' to '{1}'.", "Half", "DateTime"));
|
||||
}
|
||||
decimal IConvertible.ToDecimal(IFormatProvider provider)
|
||||
{
|
||||
return Convert.ToDecimal((float)this);
|
||||
}
|
||||
double IConvertible.ToDouble(IFormatProvider provider)
|
||||
{
|
||||
return Convert.ToDouble((float)this);
|
||||
}
|
||||
short IConvertible.ToInt16(IFormatProvider provider)
|
||||
{
|
||||
return Convert.ToInt16((float)this);
|
||||
}
|
||||
int IConvertible.ToInt32(IFormatProvider provider)
|
||||
{
|
||||
return Convert.ToInt32((float)this);
|
||||
}
|
||||
long IConvertible.ToInt64(IFormatProvider provider)
|
||||
{
|
||||
return Convert.ToInt64((float)this);
|
||||
}
|
||||
sbyte IConvertible.ToSByte(IFormatProvider provider)
|
||||
{
|
||||
return Convert.ToSByte((float)this);
|
||||
}
|
||||
string IConvertible.ToString(IFormatProvider provider)
|
||||
{
|
||||
return Convert.ToString((float)this, CultureInfo.InvariantCulture);
|
||||
}
|
||||
object IConvertible.ToType(Type conversionType, IFormatProvider provider)
|
||||
{
|
||||
return (((float)this) as IConvertible).ToType(conversionType, provider);
|
||||
}
|
||||
ushort IConvertible.ToUInt16(IFormatProvider provider)
|
||||
{
|
||||
return Convert.ToUInt16((float)this);
|
||||
}
|
||||
uint IConvertible.ToUInt32(IFormatProvider provider)
|
||||
{
|
||||
return Convert.ToUInt32((float)this);
|
||||
}
|
||||
ulong IConvertible.ToUInt64(IFormatProvider provider)
|
||||
{
|
||||
return Convert.ToUInt64((float)this);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
212
AssetStudio/Math/HalfHelper.cs
Normal file
212
AssetStudio/Math/HalfHelper.cs
Normal file
@@ -0,0 +1,212 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class for Half conversions and some low level operations.
|
||||
/// This class is internally used in the Half class.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// References:
|
||||
/// - Fast Half Float Conversions, Jeroen van der Zijp, link: http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf
|
||||
/// </remarks>
|
||||
[ComVisible(false)]
|
||||
internal static class HalfHelper
|
||||
{
|
||||
private static uint[] mantissaTable = GenerateMantissaTable();
|
||||
private static uint[] exponentTable = GenerateExponentTable();
|
||||
private static ushort[] offsetTable = GenerateOffsetTable();
|
||||
private static ushort[] baseTable = GenerateBaseTable();
|
||||
private static sbyte[] shiftTable = GenerateShiftTable();
|
||||
|
||||
// Transforms the subnormal representation to a normalized one.
|
||||
private static uint ConvertMantissa(int i)
|
||||
{
|
||||
uint m = (uint)(i << 13); // Zero pad mantissa bits
|
||||
uint e = 0; // Zero exponent
|
||||
|
||||
// While not normalized
|
||||
while ((m & 0x00800000) == 0)
|
||||
{
|
||||
e -= 0x00800000; // Decrement exponent (1<<23)
|
||||
m <<= 1; // Shift mantissa
|
||||
}
|
||||
m &= unchecked((uint)~0x00800000); // Clear leading 1 bit
|
||||
e += 0x38800000; // Adjust bias ((127-14)<<23)
|
||||
return m | e; // Return combined number
|
||||
}
|
||||
|
||||
private static uint[] GenerateMantissaTable()
|
||||
{
|
||||
uint[] mantissaTable = new uint[2048];
|
||||
mantissaTable[0] = 0;
|
||||
for (int i = 1; i < 1024; i++)
|
||||
{
|
||||
mantissaTable[i] = ConvertMantissa(i);
|
||||
}
|
||||
for (int i = 1024; i < 2048; i++)
|
||||
{
|
||||
mantissaTable[i] = (uint)(0x38000000 + ((i - 1024) << 13));
|
||||
}
|
||||
|
||||
return mantissaTable;
|
||||
}
|
||||
private static uint[] GenerateExponentTable()
|
||||
{
|
||||
uint[] exponentTable = new uint[64];
|
||||
exponentTable[0] = 0;
|
||||
for (int i = 1; i < 31; i++)
|
||||
{
|
||||
exponentTable[i] = (uint)(i << 23);
|
||||
}
|
||||
exponentTable[31] = 0x47800000;
|
||||
exponentTable[32] = 0x80000000;
|
||||
for (int i = 33; i < 63; i++)
|
||||
{
|
||||
exponentTable[i] = (uint)(0x80000000 + ((i - 32) << 23));
|
||||
}
|
||||
exponentTable[63] = 0xc7800000;
|
||||
|
||||
return exponentTable;
|
||||
}
|
||||
private static ushort[] GenerateOffsetTable()
|
||||
{
|
||||
ushort[] offsetTable = new ushort[64];
|
||||
offsetTable[0] = 0;
|
||||
for (int i = 1; i < 32; i++)
|
||||
{
|
||||
offsetTable[i] = 1024;
|
||||
}
|
||||
offsetTable[32] = 0;
|
||||
for (int i = 33; i < 64; i++)
|
||||
{
|
||||
offsetTable[i] = 1024;
|
||||
}
|
||||
|
||||
return offsetTable;
|
||||
}
|
||||
private static ushort[] GenerateBaseTable()
|
||||
{
|
||||
ushort[] baseTable = new ushort[512];
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
sbyte e = (sbyte)(127 - i);
|
||||
if (e > 24)
|
||||
{ // Very small numbers map to zero
|
||||
baseTable[i | 0x000] = 0x0000;
|
||||
baseTable[i | 0x100] = 0x8000;
|
||||
}
|
||||
else if (e > 14)
|
||||
{ // Small numbers map to denorms
|
||||
baseTable[i | 0x000] = (ushort)(0x0400 >> (18 + e));
|
||||
baseTable[i | 0x100] = (ushort)((0x0400 >> (18 + e)) | 0x8000);
|
||||
}
|
||||
else if (e >= -15)
|
||||
{ // Normal numbers just lose precision
|
||||
baseTable[i | 0x000] = (ushort)((15 - e) << 10);
|
||||
baseTable[i | 0x100] = (ushort)(((15 - e) << 10) | 0x8000);
|
||||
}
|
||||
else if (e > -128)
|
||||
{ // Large numbers map to Infinity
|
||||
baseTable[i | 0x000] = 0x7c00;
|
||||
baseTable[i | 0x100] = 0xfc00;
|
||||
}
|
||||
else
|
||||
{ // Infinity and NaN's stay Infinity and NaN's
|
||||
baseTable[i | 0x000] = 0x7c00;
|
||||
baseTable[i | 0x100] = 0xfc00;
|
||||
}
|
||||
}
|
||||
|
||||
return baseTable;
|
||||
}
|
||||
private static sbyte[] GenerateShiftTable()
|
||||
{
|
||||
sbyte[] shiftTable = new sbyte[512];
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
sbyte e = (sbyte)(127 - i);
|
||||
if (e > 24)
|
||||
{ // Very small numbers map to zero
|
||||
shiftTable[i | 0x000] = 24;
|
||||
shiftTable[i | 0x100] = 24;
|
||||
}
|
||||
else if (e > 14)
|
||||
{ // Small numbers map to denorms
|
||||
shiftTable[i | 0x000] = (sbyte)(e - 1);
|
||||
shiftTable[i | 0x100] = (sbyte)(e - 1);
|
||||
}
|
||||
else if (e >= -15)
|
||||
{ // Normal numbers just lose precision
|
||||
shiftTable[i | 0x000] = 13;
|
||||
shiftTable[i | 0x100] = 13;
|
||||
}
|
||||
else if (e > -128)
|
||||
{ // Large numbers map to Infinity
|
||||
shiftTable[i | 0x000] = 24;
|
||||
shiftTable[i | 0x100] = 24;
|
||||
}
|
||||
else
|
||||
{ // Infinity and NaN's stay Infinity and NaN's
|
||||
shiftTable[i | 0x000] = 13;
|
||||
shiftTable[i | 0x100] = 13;
|
||||
}
|
||||
}
|
||||
|
||||
return shiftTable;
|
||||
}
|
||||
|
||||
/*public static unsafe float HalfToSingle(Half half)
|
||||
{
|
||||
uint result = mantissaTable[offsetTable[half.value >> 10] + (half.value & 0x3ff)] + exponentTable[half.value >> 10];
|
||||
return *((float*)&result);
|
||||
}
|
||||
public static unsafe Half SingleToHalf(float single)
|
||||
{
|
||||
uint value = *((uint*)&single);
|
||||
|
||||
ushort result = (ushort)(baseTable[(value >> 23) & 0x1ff] + ((value & 0x007fffff) >> shiftTable[value >> 23]));
|
||||
return Half.ToHalf(result);
|
||||
}*/
|
||||
public static float HalfToSingle(Half half)
|
||||
{
|
||||
uint result = mantissaTable[offsetTable[half.value >> 10] + (half.value & 0x3ff)] + exponentTable[half.value >> 10];
|
||||
byte[] uintBytes = BitConverter.GetBytes(result);
|
||||
return BitConverter.ToSingle(uintBytes, 0);
|
||||
}
|
||||
public static Half SingleToHalf(float single)
|
||||
{
|
||||
byte[] singleBytes = BitConverter.GetBytes(single);
|
||||
uint value = BitConverter.ToUInt32(singleBytes, 0);
|
||||
ushort result = (ushort)(baseTable[(value >> 23) & 0x1ff] + ((value & 0x007fffff) >> shiftTable[value >> 23]));
|
||||
return Half.ToHalf(result);
|
||||
}
|
||||
|
||||
public static Half Negate(Half half)
|
||||
{
|
||||
return Half.ToHalf((ushort)(half.value ^ 0x8000));
|
||||
}
|
||||
public static Half Abs(Half half)
|
||||
{
|
||||
return Half.ToHalf((ushort)(half.value & 0x7fff));
|
||||
}
|
||||
|
||||
public static bool IsNaN(Half half)
|
||||
{
|
||||
return ((half.value & 0x7fff) > 0x7c00);
|
||||
}
|
||||
public static bool IsInfinity(Half half)
|
||||
{
|
||||
return ((half.value & 0x7fff) == 0x7c00);
|
||||
}
|
||||
public static bool IsPositiveInfinity(Half half)
|
||||
{
|
||||
return (half.value == 0x7c00);
|
||||
}
|
||||
public static bool IsNegativeInfinity(Half half)
|
||||
{
|
||||
return (half.value == 0xfc00);
|
||||
}
|
||||
}
|
||||
}
|
||||
241
AssetStudio/Math/Matrix4x4.cs
Normal file
241
AssetStudio/Math/Matrix4x4.cs
Normal file
@@ -0,0 +1,241 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
public struct Matrix4x4 : IEquatable<Matrix4x4>
|
||||
{
|
||||
public float M00;
|
||||
public float M10;
|
||||
public float M20;
|
||||
public float M30;
|
||||
|
||||
public float M01;
|
||||
public float M11;
|
||||
public float M21;
|
||||
public float M31;
|
||||
|
||||
public float M02;
|
||||
public float M12;
|
||||
public float M22;
|
||||
public float M32;
|
||||
|
||||
public float M03;
|
||||
public float M13;
|
||||
public float M23;
|
||||
public float M33;
|
||||
|
||||
public Matrix4x4(float[] values)
|
||||
{
|
||||
if (values == null)
|
||||
throw new ArgumentNullException(nameof(values));
|
||||
if (values.Length != 16)
|
||||
throw new ArgumentOutOfRangeException(nameof(values), "There must be sixteen and only sixteen input values for Matrix.");
|
||||
|
||||
M00 = values[0];
|
||||
M10 = values[1];
|
||||
M20 = values[2];
|
||||
M30 = values[3];
|
||||
|
||||
M01 = values[4];
|
||||
M11 = values[5];
|
||||
M21 = values[6];
|
||||
M31 = values[7];
|
||||
|
||||
M02 = values[8];
|
||||
M12 = values[9];
|
||||
M22 = values[10];
|
||||
M32 = values[11];
|
||||
|
||||
M03 = values[12];
|
||||
M13 = values[13];
|
||||
M23 = values[14];
|
||||
M33 = values[15];
|
||||
}
|
||||
|
||||
public float this[int row, int column]
|
||||
{
|
||||
get => this[row + column * 4];
|
||||
|
||||
set => this[row + column * 4] = value;
|
||||
}
|
||||
|
||||
public float this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0: return M00;
|
||||
case 1: return M10;
|
||||
case 2: return M20;
|
||||
case 3: return M30;
|
||||
case 4: return M01;
|
||||
case 5: return M11;
|
||||
case 6: return M21;
|
||||
case 7: return M31;
|
||||
case 8: return M02;
|
||||
case 9: return M12;
|
||||
case 10: return M22;
|
||||
case 11: return M32;
|
||||
case 12: return M03;
|
||||
case 13: return M13;
|
||||
case 14: return M23;
|
||||
case 15: return M33;
|
||||
default: throw new ArgumentOutOfRangeException(nameof(index), "Invalid Matrix4x4 index!");
|
||||
}
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0: M00 = value; break;
|
||||
case 1: M10 = value; break;
|
||||
case 2: M20 = value; break;
|
||||
case 3: M30 = value; break;
|
||||
case 4: M01 = value; break;
|
||||
case 5: M11 = value; break;
|
||||
case 6: M21 = value; break;
|
||||
case 7: M31 = value; break;
|
||||
case 8: M02 = value; break;
|
||||
case 9: M12 = value; break;
|
||||
case 10: M22 = value; break;
|
||||
case 11: M32 = value; break;
|
||||
case 12: M03 = value; break;
|
||||
case 13: M13 = value; break;
|
||||
case 14: M23 = value; break;
|
||||
case 15: M33 = value; break;
|
||||
default: throw new ArgumentOutOfRangeException(nameof(index), "Invalid Matrix4x4 index!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return GetColumn(0).GetHashCode() ^ (GetColumn(1).GetHashCode() << 2) ^ (GetColumn(2).GetHashCode() >> 2) ^ (GetColumn(3).GetHashCode() >> 1);
|
||||
}
|
||||
|
||||
public override bool Equals(object other)
|
||||
{
|
||||
if (!(other is Matrix4x4))
|
||||
return false;
|
||||
return Equals((Matrix4x4)other);
|
||||
}
|
||||
|
||||
public bool Equals(Matrix4x4 other)
|
||||
{
|
||||
return GetColumn(0).Equals(other.GetColumn(0))
|
||||
&& GetColumn(1).Equals(other.GetColumn(1))
|
||||
&& GetColumn(2).Equals(other.GetColumn(2))
|
||||
&& GetColumn(3).Equals(other.GetColumn(3));
|
||||
}
|
||||
|
||||
public Vector4 GetColumn(int index)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0: return new Vector4(M00, M10, M20, M30);
|
||||
case 1: return new Vector4(M01, M11, M21, M31);
|
||||
case 2: return new Vector4(M02, M12, M22, M32);
|
||||
case 3: return new Vector4(M03, M13, M23, M33);
|
||||
default: throw new IndexOutOfRangeException("Invalid column index!");
|
||||
}
|
||||
}
|
||||
|
||||
public Vector4 GetRow(int index)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0: return new Vector4(M00, M01, M02, M03);
|
||||
case 1: return new Vector4(M10, M11, M12, M13);
|
||||
case 2: return new Vector4(M20, M21, M22, M23);
|
||||
case 3: return new Vector4(M30, M31, M32, M33);
|
||||
default: throw new IndexOutOfRangeException("Invalid row index!");
|
||||
}
|
||||
}
|
||||
|
||||
public static Matrix4x4 operator *(Matrix4x4 lhs, Matrix4x4 rhs)
|
||||
{
|
||||
Matrix4x4 res;
|
||||
res.M00 = lhs.M00 * rhs.M00 + lhs.M01 * rhs.M10 + lhs.M02 * rhs.M20 + lhs.M03 * rhs.M30;
|
||||
res.M01 = lhs.M00 * rhs.M01 + lhs.M01 * rhs.M11 + lhs.M02 * rhs.M21 + lhs.M03 * rhs.M31;
|
||||
res.M02 = lhs.M00 * rhs.M02 + lhs.M01 * rhs.M12 + lhs.M02 * rhs.M22 + lhs.M03 * rhs.M32;
|
||||
res.M03 = lhs.M00 * rhs.M03 + lhs.M01 * rhs.M13 + lhs.M02 * rhs.M23 + lhs.M03 * rhs.M33;
|
||||
|
||||
res.M10 = lhs.M10 * rhs.M00 + lhs.M11 * rhs.M10 + lhs.M12 * rhs.M20 + lhs.M13 * rhs.M30;
|
||||
res.M11 = lhs.M10 * rhs.M01 + lhs.M11 * rhs.M11 + lhs.M12 * rhs.M21 + lhs.M13 * rhs.M31;
|
||||
res.M12 = lhs.M10 * rhs.M02 + lhs.M11 * rhs.M12 + lhs.M12 * rhs.M22 + lhs.M13 * rhs.M32;
|
||||
res.M13 = lhs.M10 * rhs.M03 + lhs.M11 * rhs.M13 + lhs.M12 * rhs.M23 + lhs.M13 * rhs.M33;
|
||||
|
||||
res.M20 = lhs.M20 * rhs.M00 + lhs.M21 * rhs.M10 + lhs.M22 * rhs.M20 + lhs.M23 * rhs.M30;
|
||||
res.M21 = lhs.M20 * rhs.M01 + lhs.M21 * rhs.M11 + lhs.M22 * rhs.M21 + lhs.M23 * rhs.M31;
|
||||
res.M22 = lhs.M20 * rhs.M02 + lhs.M21 * rhs.M12 + lhs.M22 * rhs.M22 + lhs.M23 * rhs.M32;
|
||||
res.M23 = lhs.M20 * rhs.M03 + lhs.M21 * rhs.M13 + lhs.M22 * rhs.M23 + lhs.M23 * rhs.M33;
|
||||
|
||||
res.M30 = lhs.M30 * rhs.M00 + lhs.M31 * rhs.M10 + lhs.M32 * rhs.M20 + lhs.M33 * rhs.M30;
|
||||
res.M31 = lhs.M30 * rhs.M01 + lhs.M31 * rhs.M11 + lhs.M32 * rhs.M21 + lhs.M33 * rhs.M31;
|
||||
res.M32 = lhs.M30 * rhs.M02 + lhs.M31 * rhs.M12 + lhs.M32 * rhs.M22 + lhs.M33 * rhs.M32;
|
||||
res.M33 = lhs.M30 * rhs.M03 + lhs.M31 * rhs.M13 + lhs.M32 * rhs.M23 + lhs.M33 * rhs.M33;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public static bool operator ==(Matrix4x4 lhs, Matrix4x4 rhs)
|
||||
{
|
||||
return lhs.GetColumn(0) == rhs.GetColumn(0)
|
||||
&& lhs.GetColumn(1) == rhs.GetColumn(1)
|
||||
&& lhs.GetColumn(2) == rhs.GetColumn(2)
|
||||
&& lhs.GetColumn(3) == rhs.GetColumn(3);
|
||||
}
|
||||
|
||||
public static bool operator !=(Matrix4x4 lhs, Matrix4x4 rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
public static Matrix4x4 Scale(Vector3 vector)
|
||||
{
|
||||
Matrix4x4 m;
|
||||
m.M00 = vector.X; m.M01 = 0F; m.M02 = 0F; m.M03 = 0F;
|
||||
m.M10 = 0F; m.M11 = vector.Y; m.M12 = 0F; m.M13 = 0F;
|
||||
m.M20 = 0F; m.M21 = 0F; m.M22 = vector.Z; m.M23 = 0F;
|
||||
m.M30 = 0F; m.M31 = 0F; m.M32 = 0F; m.M33 = 1F;
|
||||
return m;
|
||||
}
|
||||
|
||||
public static Matrix4x4 Translate(Vector3 vector)
|
||||
{
|
||||
Matrix4x4 m;
|
||||
m.M00 = 1F; m.M01 = 0F; m.M02 = 0F; m.M03 = vector.X;
|
||||
m.M10 = 0F; m.M11 = 1F; m.M12 = 0F; m.M13 = vector.Y;
|
||||
m.M20 = 0F; m.M21 = 0F; m.M22 = 1F; m.M23 = vector.Z;
|
||||
m.M30 = 0F; m.M31 = 0F; m.M32 = 0F; m.M33 = 1F;
|
||||
return m;
|
||||
}
|
||||
|
||||
public static Matrix4x4 Rotate(Quaternion q)
|
||||
{
|
||||
float x = q.X * 2.0F;
|
||||
float y = q.Y * 2.0F;
|
||||
float z = q.Z * 2.0F;
|
||||
float xx = q.X * x;
|
||||
float yy = q.Y * y;
|
||||
float zz = q.Z * z;
|
||||
float xy = q.X * y;
|
||||
float xz = q.X * z;
|
||||
float yz = q.Y * z;
|
||||
float wx = q.W * x;
|
||||
float wy = q.W * y;
|
||||
float wz = q.W * z;
|
||||
|
||||
Matrix4x4 m;
|
||||
m.M00 = 1.0f - (yy + zz); m.M10 = xy + wz; m.M20 = xz - wy; m.M30 = 0.0F;
|
||||
m.M01 = xy - wz; m.M11 = 1.0f - (xx + zz); m.M21 = yz + wx; m.M31 = 0.0F;
|
||||
m.M02 = xz + wy; m.M12 = yz - wx; m.M22 = 1.0f - (xx + yy); m.M32 = 0.0F;
|
||||
m.M03 = 0.0F; m.M13 = 0.0F; m.M23 = 0.0F; m.M33 = 1.0F;
|
||||
return m;
|
||||
}
|
||||
}
|
||||
}
|
||||
88
AssetStudio/Math/Quaternion.cs
Normal file
88
AssetStudio/Math/Quaternion.cs
Normal file
@@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
public struct Quaternion : IEquatable<Quaternion>
|
||||
{
|
||||
public float X;
|
||||
public float Y;
|
||||
public float Z;
|
||||
public float W;
|
||||
|
||||
public Quaternion(float x, float y, float z, float w)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
Z = z;
|
||||
W = w;
|
||||
}
|
||||
|
||||
public float this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0: return X;
|
||||
case 1: return Y;
|
||||
case 2: return Z;
|
||||
case 3: return W;
|
||||
default: throw new ArgumentOutOfRangeException(nameof(index), "Invalid Quaternion index!");
|
||||
}
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0: X = value; break;
|
||||
case 1: Y = value; break;
|
||||
case 2: Z = value; break;
|
||||
case 3: W = value; break;
|
||||
default: throw new ArgumentOutOfRangeException(nameof(index), "Invalid Quaternion index!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return X.GetHashCode() ^ (Y.GetHashCode() << 2) ^ (Z.GetHashCode() >> 2) ^ (W.GetHashCode() >> 1);
|
||||
}
|
||||
|
||||
public override bool Equals(object other)
|
||||
{
|
||||
if (!(other is Quaternion))
|
||||
return false;
|
||||
return Equals((Quaternion)other);
|
||||
}
|
||||
|
||||
public bool Equals(Quaternion other)
|
||||
{
|
||||
return X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z) && W.Equals(other.W);
|
||||
}
|
||||
|
||||
public static float Dot(Quaternion a, Quaternion b)
|
||||
{
|
||||
return a.X * b.X + a.Y * b.Y + a.Z * b.Z + a.W * b.W;
|
||||
}
|
||||
|
||||
private static bool IsEqualUsingDot(float dot)
|
||||
{
|
||||
return dot > 1.0f - kEpsilon;
|
||||
}
|
||||
|
||||
public static bool operator ==(Quaternion lhs, Quaternion rhs)
|
||||
{
|
||||
return IsEqualUsingDot(Dot(lhs, rhs));
|
||||
}
|
||||
|
||||
public static bool operator !=(Quaternion lhs, Quaternion rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
private const float kEpsilon = 0.000001F;
|
||||
}
|
||||
}
|
||||
148
AssetStudio/Math/Vector2.cs
Normal file
148
AssetStudio/Math/Vector2.cs
Normal file
@@ -0,0 +1,148 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace AssetStudio
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
public struct Vector2 : IEquatable<Vector2>
|
||||
{
|
||||
public float X;
|
||||
public float Y;
|
||||
|
||||
public Vector2(float x, float y)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
}
|
||||
|
||||
public float this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0: return X;
|
||||
case 1: return Y;
|
||||
default: throw new ArgumentOutOfRangeException(nameof(index), "Invalid Vector2 index!");
|
||||
}
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0: X = value; break;
|
||||
case 1: Y = value; break;
|
||||
default: throw new ArgumentOutOfRangeException(nameof(index), "Invalid Vector2 index!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return X.GetHashCode() ^ (Y.GetHashCode() << 2);
|
||||
}
|
||||
|
||||
public override bool Equals(object other)
|
||||
{
|
||||
if (!(other is Vector2))
|
||||
return false;
|
||||
return Equals((Vector2)other);
|
||||
}
|
||||
|
||||
public bool Equals(Vector2 other)
|
||||
{
|
||||
return X.Equals(other.X) && Y.Equals(other.Y);
|
||||
}
|
||||
|
||||
public void Normalize()
|
||||
{
|
||||
var length = Length();
|
||||
if (length > kEpsilon)
|
||||
{
|
||||
var invNorm = 1.0f / length;
|
||||
X *= invNorm;
|
||||
Y *= invNorm;
|
||||
}
|
||||
else
|
||||
{
|
||||
X = 0;
|
||||
Y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public float Length()
|
||||
{
|
||||
return (float)Math.Sqrt(LengthSquared());
|
||||
}
|
||||
|
||||
public float LengthSquared()
|
||||
{
|
||||
return X * X + Y * Y;
|
||||
}
|
||||
|
||||
public static Vector2 Zero => new Vector2();
|
||||
|
||||
public static Vector2 operator +(Vector2 a, Vector2 b)
|
||||
{
|
||||
return new Vector2(a.X + b.X, a.Y + b.Y);
|
||||
}
|
||||
|
||||
public static Vector2 operator -(Vector2 a, Vector2 b)
|
||||
{
|
||||
return new Vector2(a.X - b.X, a.Y - b.Y);
|
||||
}
|
||||
|
||||
public static Vector2 operator *(Vector2 a, Vector2 b)
|
||||
{
|
||||
return new Vector2(a.X * b.X, a.Y * b.Y);
|
||||
}
|
||||
|
||||
public static Vector2 operator /(Vector2 a, Vector2 b)
|
||||
{
|
||||
return new Vector2(a.X / b.X, a.Y / b.Y);
|
||||
}
|
||||
|
||||
public static Vector2 operator -(Vector2 a)
|
||||
{
|
||||
return new Vector2(-a.X, -a.Y);
|
||||
}
|
||||
|
||||
public static Vector2 operator *(Vector2 a, float d)
|
||||
{
|
||||
return new Vector2(a.X * d, a.Y * d);
|
||||
}
|
||||
|
||||
public static Vector2 operator *(float d, Vector2 a)
|
||||
{
|
||||
return new Vector2(a.X * d, a.Y * d);
|
||||
}
|
||||
|
||||
public static Vector2 operator /(Vector2 a, float d)
|
||||
{
|
||||
return new Vector2(a.X / d, a.Y / d);
|
||||
}
|
||||
|
||||
public static bool operator ==(Vector2 lhs, Vector2 rhs)
|
||||
{
|
||||
return (lhs - rhs).LengthSquared() < kEpsilon * kEpsilon;
|
||||
}
|
||||
|
||||
public static bool operator !=(Vector2 lhs, Vector2 rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
public static implicit operator Vector3(Vector2 v)
|
||||
{
|
||||
return new Vector3(v.X, v.Y, 0);
|
||||
}
|
||||
|
||||
public static implicit operator Vector4(Vector2 v)
|
||||
{
|
||||
return new Vector4(v.X, v.Y, 0.0F, 0.0F);
|
||||
}
|
||||
|
||||
private const float kEpsilon = 0.00001F;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user