Compare commits
539 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
91a79f78cc | ||
|
|
8d5e5812ec | ||
|
|
622323117a | ||
|
|
2fdbe74a4a | ||
|
|
13af32ed2d | ||
|
|
dd00cee809 | ||
|
|
34cafac121 | ||
|
|
4bf4c12159 | ||
|
|
754c563515 | ||
|
|
ea1a829957 | ||
|
|
ccb956a834 | ||
|
|
ba83aa5247 | ||
|
|
324e84eafc | ||
|
|
e290f2aca9 | ||
|
|
b13001ac90 | ||
|
|
1e24a2cc81 | ||
|
|
631dbdfa53 | ||
|
|
fbf295f2a8 | ||
|
|
00c84fd622 | ||
|
|
a8cee21ae8 | ||
|
|
48d7c3e692 | ||
|
|
c7291b567f | ||
|
|
ecb0e528c2 | ||
|
|
2de65b22ec | ||
|
|
a01d07ce41 | ||
|
|
348bf2a299 | ||
|
|
37c81d78ce | ||
|
|
33052d2e11 | ||
|
|
4603ebd7cf | ||
|
|
00f0a8a828 | ||
|
|
367e4e012e | ||
|
|
3bf4e8b0e5 | ||
|
|
39a5a75333 | ||
|
|
20f4dcd798 | ||
|
|
8398156122 | ||
|
|
8136ba1d34 | ||
|
|
2c18b939e7 | ||
|
|
01d2b95417 | ||
|
|
8cfb82e03d | ||
|
|
2d8d34bab8 | ||
|
|
6e772cb6b7 | ||
|
|
32ce8e350f | ||
|
|
73ab1a368a | ||
|
|
d9aa25c4af | ||
|
|
d18cfb6968 | ||
|
|
924e448270 | ||
|
|
4dc402fd16 | ||
|
|
8b802028e9 | ||
|
|
f6a20c873a | ||
|
|
4e4422466c | ||
|
|
3bf032d2e0 | ||
|
|
3d378b28c9 | ||
|
|
1f7ca563bf | ||
|
|
f6a0ff580c | ||
|
|
b9e858a6d5 | ||
|
|
f88eeec7ee | ||
|
|
9c6c55fe75 | ||
|
|
e6f2932ef1 | ||
|
|
8c1f9539c7 | ||
|
|
21379d133d | ||
|
|
6e58c8fc2f | ||
|
|
10db1eec7d | ||
|
|
d267ad19f5 | ||
|
|
99d2885f9c | ||
|
|
0545bfe642 | ||
|
|
7e408d2c2e | ||
|
|
512b9bae61 | ||
|
|
0f10bf9375 | ||
|
|
63468fa91e | ||
|
|
d9f6e13bdf | ||
|
|
e512636ad6 | ||
|
|
f2769e689f | ||
|
|
9898a03417 | ||
|
|
7174f1fe22 | ||
|
|
4480eb83d7 | ||
|
|
5ee673175c | ||
|
|
86885f999c | ||
|
|
2e4e0a6b99 | ||
|
|
338b50c694 | ||
|
|
20b57db193 | ||
|
|
7b61cff46d | ||
|
|
25728f9486 | ||
|
|
8e215f13af | ||
|
|
a71607aae3 | ||
|
|
2ae9bf95a4 | ||
|
|
08cf71cb02 | ||
|
|
8f3fa82f64 | ||
|
|
e40bee38af | ||
|
|
2799108c7d | ||
|
|
e1be487b6b | ||
|
|
383d6e2439 | ||
|
|
3452b73eb0 | ||
|
|
9dc45d3024 | ||
|
|
dc0a8a1e3d | ||
|
|
cf2102e182 | ||
|
|
6db6760a0a | ||
|
|
cdd0142759 | ||
|
|
4fbf77e661 | ||
|
|
8d31623138 | ||
|
|
acd14a2179 | ||
|
|
f09124f611 | ||
|
|
ead2e4eaf7 | ||
|
|
63ccc50de3 | ||
|
|
a753c24d9d | ||
|
|
d4bf2e0796 | ||
|
|
2472cd5d1b | ||
|
|
7bfe92eb9c | ||
|
|
990d413673 | ||
|
|
b4f677f81b | ||
|
|
59dfc3f05e | ||
|
|
3d409fc1d4 | ||
|
|
ab437b460f | ||
|
|
ff46687106 | ||
|
|
d7f099dc05 | ||
|
|
415156256a | ||
|
|
c799f53687 | ||
|
|
15ff5e65b1 | ||
|
|
a3769f0bad | ||
|
|
8a668620de | ||
|
|
935634c9e2 | ||
|
|
d13e227eb9 | ||
|
|
b977dbd183 | ||
|
|
15399a2969 | ||
|
|
bc3cc77a0a | ||
|
|
dcd6d9bf7b | ||
|
|
ddcb00676a | ||
|
|
73f9207839 | ||
|
|
bccbca87fa | ||
|
|
a24fec5558 | ||
|
|
c26ba7dcab | ||
|
|
cadcd2d53c | ||
|
|
7eca939c06 | ||
|
|
975567cdd4 | ||
|
|
2df2d491ae | ||
|
|
9b4852f393 | ||
|
|
f3d0abb65e | ||
|
|
9a5ae3bf51 | ||
|
|
d11783ebfc | ||
|
|
f5eebe6743 | ||
|
|
b8c7bdb1ba | ||
|
|
87bbe47e7e | ||
|
|
1ff6475fdb | ||
|
|
2f044a8d94 | ||
|
|
a1a54665d9 | ||
|
|
6e73c2d50c | ||
|
|
53f690c554 | ||
|
|
eebd333e11 | ||
|
|
3b65f1bdf2 | ||
|
|
a9444c05bf | ||
|
|
9a957138b5 | ||
|
|
a94e3bd012 | ||
|
|
b80cfab4fb | ||
|
|
da6233c10d | ||
|
|
43e925ae23 | ||
|
|
cd7c65ef4a | ||
|
|
fd7f466578 | ||
|
|
3a84ccd30f | ||
|
|
7fdd451cd1 | ||
|
|
59d5b12e80 | ||
|
|
d81513a95f | ||
|
|
23d577336f | ||
|
|
b9646c1140 | ||
|
|
7d103dfcea | ||
|
|
df1bad5380 | ||
|
|
6a41e543ee | ||
|
|
06e94e9648 | ||
|
|
096da843d1 | ||
|
|
ba6da187f3 | ||
|
|
11cc55dd71 | ||
|
|
e82dbce63c | ||
|
|
4677ab9637 | ||
|
|
b77e6e8077 | ||
|
|
3416060d4b | ||
|
|
ce7ed928c4 | ||
|
|
b7c7eff1b5 | ||
|
|
64b5471ea4 | ||
|
|
ef2d880039 | ||
|
|
a577d329ec | ||
|
|
80fc72e8b0 | ||
|
|
0a3fbfe39a | ||
|
|
4f430055f3 | ||
|
|
67832954e4 | ||
|
|
333de659ed | ||
|
|
0374410315 | ||
|
|
296a25d26f | ||
|
|
0e141ae95c | ||
|
|
fc1c89c710 | ||
|
|
422ceb9a25 | ||
|
|
14a494cc24 | ||
|
|
0da6a4aee7 | ||
|
|
00618f8081 | ||
|
|
d525f9bee3 | ||
|
|
ab7d2bb3b8 | ||
|
|
e2f35a0314 | ||
|
|
e4c409ab19 | ||
|
|
48c28e046d | ||
|
|
0f45fb5788 | ||
|
|
8d4303b166 | ||
|
|
857a55f133 | ||
|
|
b513834076 | ||
|
|
2131034ad9 | ||
|
|
4a53b0ff74 | ||
|
|
f7ff77b11d | ||
|
|
e06fe64311 | ||
|
|
e416d47df4 | ||
|
|
51a0d00b93 | ||
|
|
ae16506d87 | ||
|
|
75c128534e | ||
|
|
e0b7ff743c | ||
|
|
84314df7cb | ||
|
|
1545a92c27 | ||
|
|
b62c548193 | ||
|
|
d92098571e | ||
|
|
1eb340aaea | ||
|
|
6211ea3c77 | ||
|
|
3d91f1f3f4 | ||
| 365aac8cfa | |||
|
|
abd1a6a051 | ||
| b80a11093a | |||
|
|
d129c7ba62 | ||
|
|
46606f529d | ||
|
|
034234a134 | ||
|
|
c197edaee6 | ||
|
|
32991d0273 | ||
|
|
c4826bf1f3 | ||
|
|
1afbe28cc9 | ||
|
|
d28aba759f | ||
|
|
80c0fb2f23 | ||
|
|
99c2b0ab3b | ||
|
|
9f46d1ea9c | ||
|
|
d4c36cab72 | ||
|
|
5ec26d101c | ||
|
|
c5732b0899 | ||
|
|
fb442b39fa | ||
|
|
afb0430f30 | ||
|
|
7bb6d0ab89 | ||
|
|
9d85b77ef0 | ||
|
|
2b55752eb3 | ||
|
|
c45df3444c | ||
|
|
cc30cda7cc | ||
|
|
de0ee2e438 | ||
|
|
1000b0cafa | ||
|
|
9a10f4a9e7 | ||
|
|
6cb52df017 | ||
|
|
e1f8897150 | ||
|
|
aa8a6d18ae | ||
|
|
d70b54480d | ||
|
|
d2eb7b9795 | ||
|
|
e7aca45a9f | ||
|
|
7752d3ada5 | ||
|
|
4cfd3da983 | ||
|
|
1ea1ae3199 | ||
|
|
2b29b121e0 | ||
|
|
5c9868c435 | ||
|
|
6c0a111c09 | ||
|
|
4cbf8ca553 | ||
|
|
5aefd3e4e1 | ||
|
|
8bb5287605 | ||
|
|
0c2478cc70 | ||
|
|
06cda8303d | ||
|
|
3c45b639cb | ||
|
|
aa77115da8 | ||
|
|
5c42895bb2 | ||
|
|
67668ccc27 | ||
|
|
cdf01bb966 | ||
|
|
178665610c | ||
|
|
13a7b65f6d | ||
|
|
26ba52bcd2 | ||
|
|
9e4d14f686 | ||
|
|
5ecabfee07 | ||
|
|
caa9fe276e | ||
|
|
80f1a65a71 | ||
|
|
2adf0cc1e8 | ||
|
|
1ca6766402 | ||
|
|
08b6e1d6d9 | ||
|
|
efd06290d8 | ||
|
|
2f4bc7bb05 | ||
|
|
147e4bb079 | ||
|
|
749084539e | ||
|
|
87add0fa93 | ||
|
|
98039b533f | ||
|
|
1d2d68ed54 | ||
|
|
18c9457948 | ||
|
|
bb3683d8fb | ||
|
|
6dd8a4a24c | ||
|
|
a2acf1dd90 | ||
|
|
b34959ba1d | ||
|
|
2b40623f83 | ||
|
|
faa73b7697 | ||
|
|
d40b2326f7 | ||
|
|
57c6c18d8b | ||
|
|
f4b2aaf84e | ||
|
|
f253b75a45 | ||
|
|
b15886e089 | ||
|
|
e78778e82c | ||
|
|
d957774436 | ||
|
|
1722cbf067 | ||
|
|
c394b38c76 | ||
|
|
baafe8b4e5 | ||
|
|
78247fafab | ||
|
|
f7055fbc10 | ||
|
|
54a46e8a3e | ||
|
|
3ffcec4a71 | ||
|
|
3af6532904 | ||
|
|
f879005e76 | ||
|
|
af3f28752a | ||
|
|
240a643111 | ||
|
|
bf951db63c | ||
|
|
54b54a2367 | ||
|
|
5a9855a9f6 | ||
|
|
3e3553b2ce | ||
|
|
e90788e232 | ||
|
|
c7ed43cf8d | ||
|
|
a8ca882e07 | ||
|
|
0e48faf7a3 | ||
|
|
51e12e9683 | ||
|
|
0ec4548a6b | ||
|
|
c72d51ad1e | ||
|
|
1747f8f8be | ||
|
|
6fbd17291a | ||
|
|
e1ec4b8878 | ||
|
|
1d08ae6af6 | ||
|
|
c596b3a828 | ||
|
|
846c689088 | ||
|
|
84dc8358a7 | ||
|
|
86092b18a2 | ||
|
|
c968117ed1 | ||
|
|
ef884f4be7 | ||
|
|
5bf97fcf1a | ||
|
|
c0967ce23e | ||
|
|
de0e4c5aae | ||
|
|
01094b8d9e | ||
|
|
7af197ad80 | ||
|
|
136a49801e | ||
|
|
d603742172 | ||
|
|
cdf8ac1ffc | ||
|
|
8d5c2c7ea1 | ||
|
|
d075ad4c24 | ||
|
|
4e1c18fff2 | ||
|
|
a2e9683ba3 | ||
|
|
f7444171e3 | ||
|
|
fdea13bf84 | ||
|
|
a06df405fc | ||
|
|
70515d28d4 | ||
|
|
37c25d3baf | ||
|
|
75802ffa8e | ||
|
|
5a35d4f4d8 | ||
|
|
9958f33b60 | ||
|
|
c1e9b308a1 | ||
|
|
6ef4fe82da | ||
|
|
8f287ceeec | ||
|
|
12b4a77f1f | ||
|
|
38dd74b188 | ||
|
|
e3db1e11cc | ||
|
|
0d9d2fccfb | ||
|
|
c84463e3c2 | ||
|
|
619cfad47c | ||
|
|
17408d5d4e | ||
|
|
04daaeaf7f | ||
|
|
92456f1da6 | ||
|
|
38909a69a6 | ||
|
|
26a1629dee | ||
|
|
cc5c1854e2 | ||
|
|
fccad08fb0 | ||
|
|
0d156994b4 | ||
|
|
dd1eb94beb | ||
|
|
b53f169a4f | ||
|
|
ce9bcefb88 | ||
|
|
ab60c56e88 | ||
|
|
32e4815cbe | ||
|
|
a8ee358150 | ||
|
|
302350fe2c | ||
|
|
2f323046d3 | ||
|
|
3dad8bfb5c | ||
|
|
f8624c8997 | ||
|
|
9d8e214ae3 | ||
|
|
15bbbec1db | ||
|
|
00a3dfb958 | ||
|
|
12c9e79bf2 | ||
|
|
39cd33efd4 | ||
|
|
ce5c98b78d | ||
|
|
053c440415 | ||
|
|
d477865e9a | ||
|
|
a7e0859b8d | ||
|
|
ed593d3ae1 | ||
|
|
d973d2bee5 | ||
|
|
90c3d3bef3 | ||
|
|
d583b9ce08 | ||
|
|
46792b3dc6 | ||
|
|
1739a4686e | ||
|
|
28257af738 | ||
|
|
50fb3d2557 | ||
|
|
3f0d4641b1 | ||
|
|
b2fcdd1762 | ||
|
|
99706b868b | ||
|
|
dfe3311323 | ||
|
|
6a04ed7431 | ||
|
|
32ab5c7451 | ||
|
|
b6403208f1 | ||
|
|
fcaa1eacaf | ||
|
|
97c4fbddde | ||
|
|
ed9e7ee558 | ||
|
|
618c304a87 | ||
|
|
cc311c2a1a | ||
|
|
fda7f55231 | ||
|
|
fe5724ef82 | ||
|
|
1a0ba48b51 | ||
|
|
713d55b4eb | ||
|
|
59d6d6907a | ||
|
|
020178f780 | ||
|
|
a2242fe018 | ||
|
|
ef6d1007e6 | ||
|
|
9971facf90 | ||
|
|
3a0070612a | ||
|
|
8f415d4fe6 | ||
|
|
f438e6c063 | ||
|
|
1e086cf00a | ||
|
|
d166e3329a | ||
|
|
4db49c0896 | ||
|
|
12806268d4 | ||
|
|
39d37640cc | ||
|
|
d771df9b09 | ||
|
|
44af7bf03c | ||
|
|
07e473bad0 | ||
|
|
19d417e84b | ||
|
|
c898f62d69 | ||
|
|
d69f6eef40 | ||
|
|
affd9fe889 | ||
|
|
90ebbd86ee | ||
|
|
50a1aa3bbc | ||
|
|
270dacf1e5 | ||
|
|
4a4df3c2a4 | ||
|
|
4d7598e805 | ||
|
|
94d407ffb7 | ||
|
|
3291e52cc6 | ||
|
|
f576af8f11 | ||
|
|
eee7231737 | ||
|
|
e7455256a7 | ||
|
|
2a026947c4 | ||
|
|
12795451e6 | ||
|
|
c9802401fb | ||
|
|
5a12e3c967 | ||
|
|
a02e3714d0 | ||
|
|
84f99dc919 | ||
|
|
163f46b4cf | ||
|
|
7b1d269986 | ||
|
|
386d0793aa | ||
|
|
dc3360a97d | ||
|
|
6ab9a9b350 | ||
|
|
e3f971f62c | ||
|
|
3a718acb50 | ||
|
|
2e09f532b9 | ||
|
|
c39185e35c | ||
|
|
eee271278a | ||
|
|
e7077aae63 | ||
|
|
78a6efd02f | ||
|
|
73b3cc9e75 | ||
|
|
ef6f75c8a8 | ||
|
|
3bed978b89 | ||
|
|
dcab86b1ed | ||
|
|
7cf9ac8d4c | ||
|
|
e63cf8554e | ||
|
|
d7e4dfda41 | ||
|
|
9c92fcd854 | ||
|
|
7768c5f7f5 | ||
|
|
58e87e8787 | ||
|
|
b176bc3d00 | ||
|
|
3c13462618 | ||
|
|
68a41d4582 | ||
|
|
60e93e0ab3 | ||
|
|
9fb5c62b75 | ||
|
|
352e51170d | ||
|
|
fc64762bfe | ||
|
|
fe34c63697 | ||
|
|
02d96741e8 | ||
|
|
d8b27a31d2 | ||
|
|
4fcd3a4c60 | ||
|
|
fd1868ed46 | ||
|
|
7250e1f460 | ||
|
|
1e0a490a69 | ||
|
|
bfedb389b8 | ||
|
|
0a2fdd0b74 | ||
|
|
a2959f9b29 | ||
|
|
cd99390ba7 | ||
|
|
388e2dfc52 | ||
|
|
47e09afa73 | ||
|
|
cdef686ec4 | ||
|
|
be21cf40cb | ||
|
|
4eb817375c | ||
|
|
5a623c18d0 | ||
|
|
63ca1074fc | ||
|
|
9a70b774ab | ||
|
|
ea385c2853 | ||
|
|
f9604bc858 | ||
|
|
65a37363e6 | ||
|
|
2879a89594 | ||
|
|
6bc88394cd | ||
|
|
f17d56c603 | ||
|
|
2253db1abb | ||
|
|
c362953775 | ||
|
|
6ea2989d69 | ||
|
|
ea90db4fe6 | ||
|
|
2b1a18be6a | ||
|
|
40ad7470aa | ||
|
|
89d1d0944a | ||
|
|
73e13263fc | ||
|
|
60ddd31101 | ||
|
|
ee4a680d6d | ||
|
|
2f61367fcb | ||
|
|
c7b1c97d68 | ||
|
|
ed30f6b861 | ||
|
|
5ea8c5f09a | ||
|
|
d1cf5ecc52 | ||
|
|
a85abf0ecd | ||
|
|
caca3dd489 | ||
|
|
39853c77fe | ||
|
|
f149b66322 | ||
|
|
0ea4a7ad6f | ||
|
|
729a6bac7c | ||
|
|
be8aa3691e | ||
|
|
cfa0638b94 | ||
|
|
ff1a25b41f | ||
|
|
a0cfb65b56 | ||
|
|
77428c0515 | ||
|
|
34d6ae6658 | ||
|
|
f339360fbc | ||
|
|
f23c38cc3c | ||
|
|
fdf1559f09 | ||
|
|
556e33d56f | ||
|
|
c980d53543 | ||
|
|
c8cfc1c5fc | ||
|
|
a7904ca74e | ||
|
|
6cc3d71acf | ||
|
|
23827f4ffa | ||
|
|
67050e6a67 | ||
|
|
0943608bd8 | ||
|
|
f1aa61bf3b | ||
|
|
691a16e9ad | ||
|
|
0a3a307d39 |
13
.gitignore
vendored
13
.gitignore
vendored
@ -1,6 +1,10 @@
|
|||||||
/build/
|
/build/
|
||||||
/data/dlls/
|
/data/dlls/
|
||||||
/data/fastfiles/
|
/data/fastfiles/
|
||||||
|
/releases/
|
||||||
|
|
||||||
|
.vscode/*
|
||||||
|
.qmake.stash
|
||||||
|
|
||||||
# Ignore Qt Creator user files
|
# Ignore Qt Creator user files
|
||||||
*.pro.user
|
*.pro.user
|
||||||
@ -10,3 +14,12 @@
|
|||||||
*.creator.user
|
*.creator.user
|
||||||
*.creator.user.*
|
*.creator.user.*
|
||||||
*.creator.*
|
*.creator.*
|
||||||
|
*.ps1
|
||||||
|
version.txt
|
||||||
|
*.autosave
|
||||||
|
*.XMODEL_EXPORT
|
||||||
|
data/obj/*
|
||||||
|
libs/*/release/*
|
||||||
|
libs/*/debug/*
|
||||||
|
.git.stash
|
||||||
|
*Makefile*
|
||||||
|
|||||||
@ -2,9 +2,9 @@ TEMPLATE = subdirs
|
|||||||
|
|
||||||
SUBDIRS += libs \
|
SUBDIRS += libs \
|
||||||
app \
|
app \
|
||||||
tools \
|
#tools \
|
||||||
tests
|
#tests
|
||||||
|
|
||||||
tests.depends = libs
|
#tests.depends = libs
|
||||||
app.depends = libs
|
app.depends = libs
|
||||||
tools.depends = libs
|
#tools.depends = libs
|
||||||
|
|||||||
36
ai-commit.sh
Normal file
36
ai-commit.sh
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# 1. Stage everything
|
||||||
|
git add -A
|
||||||
|
|
||||||
|
# 2. Get list of staged files
|
||||||
|
FILES=$(git diff --cached --name-only)
|
||||||
|
|
||||||
|
if [ -z "$FILES" ]; then
|
||||||
|
echo "No changes to commit."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 3. Loop file by file
|
||||||
|
for FILE in $FILES; do
|
||||||
|
# Get diff for this file
|
||||||
|
DIFF=$(git diff --cached -- "$FILE")
|
||||||
|
|
||||||
|
if [ -z "$DIFF" ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ask Ollama for a commit message describing this file change
|
||||||
|
MSG=$(echo "$DIFF" | ollama run gemma3 \
|
||||||
|
"You are a commit bot. Write a SHORT, clear, concise Git commit message for changes in file: $FILE.
|
||||||
|
Only output the commit message, nothing else.
|
||||||
|
Diff:
|
||||||
|
$DIFF")
|
||||||
|
|
||||||
|
# Commit just this file with its message
|
||||||
|
git commit -m "$MSG" -- "$FILE"
|
||||||
|
|
||||||
|
echo "✅ Committed $FILE with message:"
|
||||||
|
echo "$MSG"
|
||||||
|
done
|
||||||
77
app/app.pro
77
app/app.pro
@ -6,63 +6,9 @@ SUBDIRS += app
|
|||||||
|
|
||||||
CONFIG += c++17
|
CONFIG += c++17
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += $$files($$PWD/*.cpp)
|
||||||
aboutdialog.cpp \
|
HEADERS += $$files($$PWD/*.h)
|
||||||
ddsviewer.cpp \
|
FORMS += $$files($$PWD/*.ui)
|
||||||
fastfileviewer.cpp \
|
|
||||||
imagewidget.cpp \
|
|
||||||
iwiviewer.cpp \
|
|
||||||
localstringviewer.cpp \
|
|
||||||
main.cpp \
|
|
||||||
mainwindow.cpp \
|
|
||||||
materialviewer.cpp \
|
|
||||||
preferenceeditor.cpp \
|
|
||||||
soundviewer.cpp \
|
|
||||||
stringtableviewer.cpp \
|
|
||||||
rumblegraphviewer.cpp \
|
|
||||||
rumblefileviewer.cpp \
|
|
||||||
techsetviewer.cpp \
|
|
||||||
xtreewidget.cpp \
|
|
||||||
xtreewidgetitem.cpp \
|
|
||||||
zonefileviewer.cpp
|
|
||||||
|
|
||||||
HEADERS += \
|
|
||||||
aboutdialog.h \
|
|
||||||
d3dbsp_structs.h \
|
|
||||||
ddsviewer.h \
|
|
||||||
fastfileviewer.h \
|
|
||||||
imagewidget.h \
|
|
||||||
iwiviewer.h \
|
|
||||||
localstringviewer.h \
|
|
||||||
mainwindow.h \
|
|
||||||
materialviewer.h \
|
|
||||||
preferenceeditor.h \
|
|
||||||
soundviewer.h \
|
|
||||||
stringtableviewer.h \
|
|
||||||
rumblegraphviewer.h \
|
|
||||||
rumblefileviewer.h \
|
|
||||||
techsetviewer.h \
|
|
||||||
xtreewidget.h \
|
|
||||||
xtreewidgetitem.h \
|
|
||||||
zonefileviewer.h
|
|
||||||
|
|
||||||
FORMS += \
|
|
||||||
aboutdialog.ui \
|
|
||||||
ddsviewer.ui \
|
|
||||||
fastfileviewer.ui \
|
|
||||||
imagewidget.ui \
|
|
||||||
iwiviewer.ui \
|
|
||||||
localstringviewer.ui \
|
|
||||||
mainwindow.ui \
|
|
||||||
materialviewer.ui \
|
|
||||||
modelviewer.ui \
|
|
||||||
preferenceeditor.ui \
|
|
||||||
soundviewer.ui \
|
|
||||||
stringtableviewer.ui \
|
|
||||||
rumblegraphviewer.ui \
|
|
||||||
rumblefileviewer.ui \
|
|
||||||
techsetviewer.ui \
|
|
||||||
zonefileviewer.ui
|
|
||||||
|
|
||||||
RESOURCES += ../data/data.qrc
|
RESOURCES += ../data/data.qrc
|
||||||
|
|
||||||
@ -71,6 +17,7 @@ LIBS += \
|
|||||||
-L$$PWD/../third_party/zlib/lib/ -lzlib \
|
-L$$PWD/../third_party/zlib/lib/ -lzlib \
|
||||||
-L$$PWD/../third_party/xbox_sdk/lib -lxcompress64 \
|
-L$$PWD/../third_party/xbox_sdk/lib -lxcompress64 \
|
||||||
-L$$OUT_PWD/../libs/ -lcore \
|
-L$$OUT_PWD/../libs/ -lcore \
|
||||||
|
-L$$OUT_PWD/../libs/ -lxassets\
|
||||||
-L$$OUT_PWD/../libs/ -lcompression \
|
-L$$OUT_PWD/../libs/ -lcompression \
|
||||||
-L$$OUT_PWD/../libs/ -lencryption \
|
-L$$OUT_PWD/../libs/ -lencryption \
|
||||||
-L$$OUT_PWD/../libs/ -lfastfile \
|
-L$$OUT_PWD/../libs/ -lfastfile \
|
||||||
@ -90,6 +37,7 @@ INCLUDEPATH += \
|
|||||||
$$PWD/../libs/ddsfile \
|
$$PWD/../libs/ddsfile \
|
||||||
$$PWD/../libs/ipakfile \
|
$$PWD/../libs/ipakfile \
|
||||||
$$PWD/../libs/iwifile \
|
$$PWD/../libs/iwifile \
|
||||||
|
$$PWD/../libs/xassets \
|
||||||
$$PWD/../libs/zonefile
|
$$PWD/../libs/zonefile
|
||||||
|
|
||||||
DEPENDPATH += \
|
DEPENDPATH += \
|
||||||
@ -103,16 +51,11 @@ DEPENDPATH += \
|
|||||||
$$PWD/../libs/ddsfile \
|
$$PWD/../libs/ddsfile \
|
||||||
$$PWD/../libs/ipakfile \
|
$$PWD/../libs/ipakfile \
|
||||||
$$PWD/../libs/iwifile \
|
$$PWD/../libs/iwifile \
|
||||||
|
$$PWD/../libs/xassets \
|
||||||
$$PWD/../libs/zonefile
|
$$PWD/../libs/zonefile
|
||||||
|
|
||||||
# Copy DLLs to Debug folder
|
|
||||||
QMAKE_POST_LINK += xcopy /Y /E /I \"G:/Projects/Qt/XPlor/third_party/devil_sdk/lib\\*.dll\" \"$$OUT_PWD/debug/\" $$escape_expand(\\n\\t)
|
|
||||||
QMAKE_POST_LINK += xcopy /Y /E /I \"G:/Projects/Qt/XPlor/third_party/zlib/lib\\*.dll\" \"$$OUT_PWD/debug/\" $$escape_expand(\\n\\t)
|
|
||||||
QMAKE_POST_LINK += xcopy /Y /E /I \"G:/Projects/Qt/XPlor/third_party/xna/lib\\*.dll\" \"$$OUT_PWD/debug/\" $$escape_expand(\\n\\t)
|
|
||||||
QMAKE_POST_LINK += xcopy /Y /E /I \"$$PWD/../third_party/xbox_sdk/lib\\*.dll\" \"$$OUT_PWD/debug/\" $$escape_expand(\\n\\t)
|
|
||||||
|
|
||||||
# Copy DLLs to Release folder
|
win32 {
|
||||||
QMAKE_POST_LINK += xcopy /Y /E /I \"G:/Projects/Qt/XPlor/third_party/devil_sdk/lib\\*.dll\" \"$$OUT_PWD/release/\" $$escape_expand(\\n\\t)
|
QMAKE_POST_LINK =
|
||||||
QMAKE_POST_LINK += xcopy /Y /E /I \"G:/Projects/Qt/XPlor/third_party/zlib/lib\\*.dll\" \"$$OUT_PWD/release/\" $$escape_expand(\\n\\t)
|
QMAKE_POST_LINK += for /D %%G in (\"$$PWD/../third_party/*/lib\") do copy /Y \"%%~G\*.dll\" \"$$OUT_PWD/$$DESTDIR/\" >NUL $$escape_expand(\\n\\t)
|
||||||
QMAKE_POST_LINK += xcopy /Y /E /I \"G:/Projects/Qt/XPlor/third_party/xna/lib\\*.dll\" \"$$OUT_PWD/release/\" $$escape_expand(\\n\\t)
|
}
|
||||||
QMAKE_POST_LINK += xcopy /Y /E /I \"$$PWD/../third_party/xbox_sdk/lib\\*.dll\" \"$$OUT_PWD/release/\" $$escape_expand(\\n\\t)
|
|
||||||
|
|||||||
@ -14,8 +14,8 @@ DDSViewer::~DDSViewer() {
|
|||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DDSViewer::SetDDSFile(std::shared_ptr<DDSFile> aDDSFile) {
|
void DDSViewer::SetDDSFile(const DDSFile* aDDSFile) {
|
||||||
mDDSFile.swap(aDDSFile);
|
mDDSFile = aDDSFile;
|
||||||
|
|
||||||
ui->label_Title->setText(mDDSFile->fileStem + ".dds");
|
ui->label_Title->setText(mDDSFile->fileStem + ".dds");
|
||||||
|
|
||||||
|
|||||||
@ -16,14 +16,14 @@ public:
|
|||||||
explicit DDSViewer(QWidget *parent = nullptr);
|
explicit DDSViewer(QWidget *parent = nullptr);
|
||||||
~DDSViewer();
|
~DDSViewer();
|
||||||
|
|
||||||
void SetDDSFile(std::shared_ptr<DDSFile> aDDSFile);
|
void SetDDSFile(const DDSFile *aDDSFile);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void MipmapIndexChanged(int aMipmapIndex);
|
void MipmapIndexChanged(int aMipmapIndex);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::DDSViewer *ui;
|
Ui::DDSViewer *ui;
|
||||||
std::shared_ptr<DDSFile> mDDSFile;
|
const DDSFile* mDDSFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DDSVIEWER_H
|
#endif // DDSVIEWER_H
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
#include "fastfileviewer.h"
|
#include "fastfileviewer.h"
|
||||||
#include "asset_structs.h"
|
|
||||||
#include "ui_fastfileviewer.h"
|
#include "ui_fastfileviewer.h"
|
||||||
|
|
||||||
FastFileViewer::FastFileViewer(QWidget *parent)
|
FastFileViewer::FastFileViewer(QWidget *parent)
|
||||||
@ -15,8 +14,8 @@ FastFileViewer::~FastFileViewer()
|
|||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FastFileViewer::SetFastFile(std::shared_ptr<FastFile> aFastFile) {
|
void FastFileViewer::SetFastFile(const FastFile* aFastFile) {
|
||||||
mFastFile.swap(aFastFile);
|
mFastFile = aFastFile;
|
||||||
|
|
||||||
ui->label_Title->setText(mFastFile->GetStem());
|
ui->label_Title->setText(mFastFile->GetStem());
|
||||||
ui->comboBox_Company->setCurrentIndex(mFastFile->GetCompany());
|
ui->comboBox_Company->setCurrentIndex(mFastFile->GetCompany());
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
#ifndef FASTFILEVIEWER_H
|
#ifndef FASTFILEVIEWER_H
|
||||||
#define FASTFILEVIEWER_H
|
#define FASTFILEVIEWER_H
|
||||||
|
|
||||||
#include "asset_structs.h"
|
|
||||||
#include "fastfile.h"
|
#include "fastfile.h"
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
@ -17,10 +16,10 @@ public:
|
|||||||
explicit FastFileViewer(QWidget *parent = nullptr);
|
explicit FastFileViewer(QWidget *parent = nullptr);
|
||||||
~FastFileViewer();
|
~FastFileViewer();
|
||||||
|
|
||||||
void SetFastFile(std::shared_ptr<FastFile> aFastFile);
|
void SetFastFile(const FastFile *aFastFile);
|
||||||
private:
|
private:
|
||||||
Ui::FFViewer *ui;
|
Ui::FFViewer *ui;
|
||||||
std::shared_ptr<FastFile> mFastFile;
|
const FastFile* mFastFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // FASTFILEVIEWER_H
|
#endif // FASTFILEVIEWER_H
|
||||||
|
|||||||
@ -13,16 +13,16 @@ ImageWidget::~ImageWidget()
|
|||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageWidget::SetImage(std::shared_ptr<Image> aImage)
|
void ImageWidget::SetImage(std::shared_ptr<QImage> aImage)
|
||||||
{
|
{
|
||||||
mImage = aImage;
|
mImage = aImage;
|
||||||
|
|
||||||
ui->lineEdit_Name->setText(aImage->name);
|
//ui->lineEdit_Name->setText(aImage->name);
|
||||||
ui->lineEdit_Role->setText(aImage->materialName);
|
//ui->lineEdit_Role->setText(aImage->materialName);
|
||||||
ui->comboBox_Compression->setCurrentIndex(aImage->compression);
|
//ui->comboBox_Compression->setCurrentIndex(aImage->compression);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Image> ImageWidget::GetImage()
|
std::shared_ptr<QImage> ImageWidget::GetImage()
|
||||||
{
|
{
|
||||||
return mImage;
|
return mImage;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,6 @@
|
|||||||
#include "enums.h"
|
#include "enums.h"
|
||||||
#include "dds_structs.h"
|
#include "dds_structs.h"
|
||||||
#include "d3dbsp_structs.h"
|
#include "d3dbsp_structs.h"
|
||||||
#include "asset_structs.h"
|
|
||||||
#include "ipak_structs.h"
|
#include "ipak_structs.h"
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
@ -21,11 +20,11 @@ public:
|
|||||||
explicit ImageWidget(QWidget *parent = nullptr);
|
explicit ImageWidget(QWidget *parent = nullptr);
|
||||||
~ImageWidget();
|
~ImageWidget();
|
||||||
|
|
||||||
void SetImage(std::shared_ptr<Image> aImage);
|
void SetImage(std::shared_ptr<QImage> aImage);
|
||||||
std::shared_ptr<Image> GetImage();
|
std::shared_ptr<QImage> GetImage();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<Image> mImage;
|
std::shared_ptr<QImage> mImage;
|
||||||
Ui::ImageWidget *ui;
|
Ui::ImageWidget *ui;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -14,8 +14,8 @@ IWIViewer::~IWIViewer()
|
|||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IWIViewer::SetIWIFile(std::shared_ptr<IWIFile> aIWIFile) {
|
void IWIViewer::SetIWIFile(const IWIFile* aIWIFile) {
|
||||||
mIWIFile.swap(aIWIFile);
|
mIWIFile = aIWIFile;
|
||||||
|
|
||||||
ui->label_Title->setText(mIWIFile->fileStem + ".iwi");
|
ui->label_Title->setText(mIWIFile->fileStem + ".iwi");
|
||||||
|
|
||||||
|
|||||||
@ -18,10 +18,10 @@ public:
|
|||||||
|
|
||||||
void MipmapIndexChanged(int aMipmapIndex);
|
void MipmapIndexChanged(int aMipmapIndex);
|
||||||
|
|
||||||
void SetIWIFile(std::shared_ptr<IWIFile> aIWIFile);
|
void SetIWIFile(const IWIFile *aIWIFile);
|
||||||
private:
|
private:
|
||||||
Ui::IWIViewer *ui;
|
Ui::IWIViewer *ui;
|
||||||
std::shared_ptr<IWIFile> mIWIFile;
|
const IWIFile* mIWIFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // IWIVIEWER_H
|
#endif // IWIVIEWER_H
|
||||||
|
|||||||
@ -37,26 +37,22 @@ void LocalStringViewer::SetFileNotes(const QString aFileNotes) {
|
|||||||
ui->plainTextEdit_FileNotes->setPlainText(mFileNotes);
|
ui->plainTextEdit_FileNotes->setPlainText(mFileNotes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalStringViewer::AddLocalString(LocalString aLocalString) {
|
void LocalStringViewer::AddLocalString(XLocalizeEntry aLocalString) {
|
||||||
mLocalStrings.append(aLocalString);
|
mLocalStrings.append(aLocalString);
|
||||||
|
ui->tableWidget_Strings->setRowCount(mLocalStrings.size());
|
||||||
ui->tableWidget_Strings->setRowCount(mLocalStrings.size());
|
ui->groupBox_LocalStrViewer->setTitle(QString("Entries (%1)").arg(mLocalStrings.size()));
|
||||||
|
QTableWidgetItem *aliasItem = new QTableWidgetItem(aLocalString.GetValue()->GetString());
|
||||||
ui->groupBox_LocalStrViewer->setTitle(QString("Entries (%1)").arg(mLocalStrings.size()));
|
QTableWidgetItem *stringItem = new QTableWidgetItem(aLocalString.GetName()->GetString());
|
||||||
|
ui->tableWidget_Strings->setItem(mLocalStrings.size() - 1, 0, aliasItem);
|
||||||
QTableWidgetItem *aliasItem = new QTableWidgetItem(aLocalString.alias);
|
ui->tableWidget_Strings->setItem(mLocalStrings.size() - 1, 1, stringItem);
|
||||||
QTableWidgetItem *stringItem = new QTableWidgetItem(aLocalString.string);
|
|
||||||
|
|
||||||
ui->tableWidget_Strings->setItem(mLocalStrings.size() - 1, 0, aliasItem);
|
|
||||||
ui->tableWidget_Strings->setItem(mLocalStrings.size() - 1, 1, stringItem);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalStringViewer::SetZoneFile(std::shared_ptr<ZoneFile> aZoneFile) {
|
void LocalStringViewer::SetZoneFile(const ZoneFile* aZoneFile) {
|
||||||
mLocalStrings.clear();
|
mLocalStrings.clear();
|
||||||
ui->tableWidget_Strings->clear();
|
ui->tableWidget_Strings->clear();
|
||||||
|
|
||||||
ui->label_Title->setText(aZoneFile->GetStem().section('.', 0, 0) + ".str");
|
ui->label_Title->setText(aZoneFile->GetStem().section('.', 0, 0) + ".str");
|
||||||
for (const LocalString &localStr : aZoneFile->GetAssetMap().localStrings) {
|
// for (const LocalString &localStr : aZoneFile->GetAssetMap().localStrings) {
|
||||||
AddLocalString(localStr);
|
// AddLocalString(localStr);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
#ifndef LOCALSTRINGVIEWER_H
|
#ifndef LOCALSTRINGVIEWER_H
|
||||||
#define LOCALSTRINGVIEWER_H
|
#define LOCALSTRINGVIEWER_H
|
||||||
|
|
||||||
#include "asset_structs.h"
|
#include "xlocalizeentry.h"
|
||||||
#include "zonefile.h"
|
#include "zonefile.h"
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
@ -20,15 +20,15 @@ public:
|
|||||||
void SetVersion(quint32 aVersion);
|
void SetVersion(quint32 aVersion);
|
||||||
void SetConfigPath(const QString aConfigPath);
|
void SetConfigPath(const QString aConfigPath);
|
||||||
void SetFileNotes(const QString aFileNotes);
|
void SetFileNotes(const QString aFileNotes);
|
||||||
void AddLocalString(LocalString aLocalString);
|
void AddLocalString(XLocalizeEntry aLocalString);
|
||||||
void SetZoneFile(std::shared_ptr<ZoneFile> aZoneFile);
|
void SetZoneFile(const ZoneFile *aZoneFile);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::LocalStringViewer *ui;
|
Ui::LocalStringViewer *ui;
|
||||||
quint32 mVersion;
|
quint32 mVersion;
|
||||||
QString mConfigPath;
|
QString mConfigPath;
|
||||||
QString mFileNotes;
|
QString mFileNotes;
|
||||||
QVector<LocalString> mLocalStrings;
|
QVector<XLocalizeEntry> mLocalStrings;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // LOCALSTRINGVIEWER_H
|
#endif // LOCALSTRINGVIEWER_H
|
||||||
|
|||||||
@ -1,4 +1,7 @@
|
|||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
|
#include "qtimer.h"
|
||||||
|
#include "ui_mainwindow.h"
|
||||||
|
|
||||||
#include "aboutdialog.h"
|
#include "aboutdialog.h"
|
||||||
#include "fastfile.h"
|
#include "fastfile.h"
|
||||||
#include "highlighter_gsc.h"
|
#include "highlighter_gsc.h"
|
||||||
@ -7,12 +10,10 @@
|
|||||||
#include "highlighter_rumble.h"
|
#include "highlighter_rumble.h"
|
||||||
#include "materialviewer.h"
|
#include "materialviewer.h"
|
||||||
#include "preferenceeditor.h"
|
#include "preferenceeditor.h"
|
||||||
#include "rumblefileviewer.h"
|
#include "reportissuedialog.h"
|
||||||
#include "rumblegraphviewer.h"
|
#include "rumblegraphviewer.h"
|
||||||
#include "soundviewer.h"
|
|
||||||
#include "stringtableviewer.h"
|
#include "stringtableviewer.h"
|
||||||
#include "techsetviewer.h"
|
#include "techsetviewer.h"
|
||||||
#include "ui_mainwindow.h"
|
|
||||||
#include "fastfile_factory.h"
|
#include "fastfile_factory.h"
|
||||||
#include "iwifile.h"
|
#include "iwifile.h"
|
||||||
#include "ddsfile.h"
|
#include "ddsfile.h"
|
||||||
@ -22,13 +23,11 @@
|
|||||||
#include "ipak_structs.h"
|
#include "ipak_structs.h"
|
||||||
#include "iwiviewer.h"
|
#include "iwiviewer.h"
|
||||||
#include "localstringviewer.h"
|
#include "localstringviewer.h"
|
||||||
#include "imagewidget.h"
|
|
||||||
#include "xtreewidget.h"
|
|
||||||
#include "zonefileviewer.h"
|
#include "zonefileviewer.h"
|
||||||
#include "techsetviewer.h"
|
#include "techsetviewer.h"
|
||||||
#include "logmanager.h"
|
#include "logmanager.h"
|
||||||
|
|
||||||
#include <qmath.h>
|
#include <QtMath>
|
||||||
|
|
||||||
MainWindow::MainWindow(QWidget *parent)
|
MainWindow::MainWindow(QWidget *parent)
|
||||||
: QMainWindow(parent), ui(new Ui::MainWindow) {
|
: QMainWindow(parent), ui(new Ui::MainWindow) {
|
||||||
@ -36,10 +35,12 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
|
|
||||||
setAcceptDrops(true);
|
setAcceptDrops(true);
|
||||||
|
|
||||||
|
XAsset::SetDebug(true);
|
||||||
|
|
||||||
mTypeMap = QMap<QString, int>();
|
mTypeMap = QMap<QString, int>();
|
||||||
mTypeOrder = QStringList();
|
mTypeOrder = QStringList();
|
||||||
mRawFileMap = QMap<QString, QString>();
|
mRawFileMap = QMap<QString, QString>();
|
||||||
mImageMap = QMap<QString, Image>();
|
//mImageMap = QMap<QString, Image>();
|
||||||
mTreeMap = QMap<QString, QTreeWidgetItem *>();
|
mTreeMap = QMap<QString, QTreeWidgetItem *>();
|
||||||
mStrTableMap = QMap<QString, QVector<QPair<QString, QString>>>();
|
mStrTableMap = QMap<QString, QVector<QPair<QString, QString>>>();
|
||||||
mBSPVersion = 0;
|
mBSPVersion = 0;
|
||||||
@ -49,13 +50,23 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
mTreeWidget = new XTreeWidget(this);
|
mTreeWidget = new XTreeWidget(this);
|
||||||
mLogWidget = new QPlainTextEdit(this);
|
mLogWidget = new QPlainTextEdit(this);
|
||||||
|
|
||||||
//ModelViewer *mModelViewer = new ModelViewer(container);
|
|
||||||
//mModelViewer->setAcceptDrops(false);
|
|
||||||
|
|
||||||
mProgressBar = new QProgressBar(this);
|
mProgressBar = new QProgressBar(this);
|
||||||
mProgressBar->setMaximum(100); // Default max value
|
mProgressBar->setMaximum(100); // Default max value
|
||||||
mProgressBar->setVisible(false); // Initially hidden
|
mProgressBar->setVisible(false); // Initially hidden
|
||||||
|
|
||||||
|
connect(ui->actionRun_Tests, &QAction::triggered, this, [](bool checked) {
|
||||||
|
Q_UNUSED(checked);
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(ui->actionReport_Issue, &QAction::triggered, this, [this](bool checked) {
|
||||||
|
Q_UNUSED(checked);
|
||||||
|
|
||||||
|
ReportIssueDialog issueDialog("https://git.redline.llc", "njohnson", "XPlor", "4738c4d2efd123efac1506c68c59b285c646df9f", this);
|
||||||
|
if (issueDialog.exec() == QDialog::Accepted) {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
connect(&StatusBarManager::instance(), &StatusBarManager::statusUpdated,
|
connect(&StatusBarManager::instance(), &StatusBarManager::statusUpdated,
|
||||||
this, &MainWindow::HandleStatusUpdate);
|
this, &MainWindow::HandleStatusUpdate);
|
||||||
|
|
||||||
@ -148,7 +159,7 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
ui->tabWidget->clear();
|
ui->tabWidget->clear();
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(mTreeWidget, &XTreeWidget::RawFileSelected, this, [this](std::shared_ptr<RawFile> rawFile, const QString aParentName) {
|
connect(mTreeWidget, &XTreeWidget::RawFileSelected, this, [this](const XRawFile* rawFile, const QString aParentName) {
|
||||||
QTabWidget *rawTabWidget = new QTabWidget(this);
|
QTabWidget *rawTabWidget = new QTabWidget(this);
|
||||||
rawTabWidget->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
|
rawTabWidget->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
|
||||||
|
|
||||||
@ -157,13 +168,13 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
scriptEditor->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
|
scriptEditor->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
|
||||||
scriptEditor->setFont(QFont("Consolas"));
|
scriptEditor->setFont(QFont("Consolas"));
|
||||||
|
|
||||||
if (rawFile->contents.isEmpty()) {
|
// if (rawFile->contents.isEmpty()) {
|
||||||
scriptEditor->setPlainText("EMPTY");
|
// scriptEditor->setPlainText("EMPTY");
|
||||||
} else {
|
// } else {
|
||||||
scriptEditor->setPlainText(rawFile->contents);
|
// scriptEditor->setPlainText(rawFile->contents);
|
||||||
}
|
// }
|
||||||
|
|
||||||
QString fileStem = rawFile->path.split('/').last();
|
QString fileStem;// = rawFile->path.split('/').last();
|
||||||
for (int i = 0; i < ui->tabWidget->count(); i++) {
|
for (int i = 0; i < ui->tabWidget->count(); i++) {
|
||||||
if (ui->tabWidget->tabText(i) == fileStem) {
|
if (ui->tabWidget->tabText(i) == fileStem) {
|
||||||
delete scriptEditor;
|
delete scriptEditor;
|
||||||
@ -175,7 +186,7 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
QFontMetrics metrics(scriptEditor->font());
|
QFontMetrics metrics(scriptEditor->font());
|
||||||
scriptEditor->setTabStopDistance(tabStopSpaces * metrics.horizontalAdvance(' '));
|
scriptEditor->setTabStopDistance(tabStopSpaces * metrics.horizontalAdvance(' '));
|
||||||
|
|
||||||
QSyntaxHighlighter *highlighter;
|
QSyntaxHighlighter *highlighter = nullptr;
|
||||||
if (fileStem.contains(".gsc")) {
|
if (fileStem.contains(".gsc")) {
|
||||||
highlighter = new Highlighter_GSC(scriptEditor->document());
|
highlighter = new Highlighter_GSC(scriptEditor->document());
|
||||||
} else if (fileStem.contains(".cfg")) {
|
} else if (fileStem.contains(".cfg")) {
|
||||||
@ -191,12 +202,12 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
rawTabWidget->addTab(scriptEditor, "Text Editor");
|
rawTabWidget->addTab(scriptEditor, "Text Editor");
|
||||||
|
|
||||||
ui->tabWidget->addTab(rawTabWidget, fileStem);
|
ui->tabWidget->addTab(rawTabWidget, fileStem);
|
||||||
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, ZoneFile::AssetTypeToIcon(ASSET_RUMBLE));
|
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, Utils::CreateAssetIcon(ASSET_TYPE_RUMBLE));
|
||||||
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
|
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
|
||||||
return;
|
return;
|
||||||
} else if (fileStem.contains(".shock")) {
|
} else if (fileStem.contains(".shock")) {
|
||||||
highlighter = new Highlighter_Shock(scriptEditor->document());
|
highlighter = new Highlighter_Shock(scriptEditor->document());
|
||||||
} else if (rawFile->contents.left(6) == "RUMBLE") {
|
} /*else if (rawFile->contents.left(6) == "RUMBLE") {
|
||||||
RumbleFileViewer *rmbFileViewer = new RumbleFileViewer(this);
|
RumbleFileViewer *rmbFileViewer = new RumbleFileViewer(this);
|
||||||
rmbFileViewer->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
|
rmbFileViewer->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
|
||||||
rmbFileViewer->SetRumbleFile(rawFile);
|
rmbFileViewer->SetRumbleFile(rawFile);
|
||||||
@ -205,59 +216,61 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
rawTabWidget->addTab(scriptEditor, "Text Editor");
|
rawTabWidget->addTab(scriptEditor, "Text Editor");
|
||||||
|
|
||||||
ui->tabWidget->addTab(rawTabWidget, fileStem);
|
ui->tabWidget->addTab(rawTabWidget, fileStem);
|
||||||
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, ZoneFile::AssetTypeToIcon(ASSET_RUMBLE));
|
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, Utils::CreateAssetIcon(ASSET_TYPE_RUMBLE));
|
||||||
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
|
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
|
||||||
return;
|
return;
|
||||||
|
}*/ else {
|
||||||
|
delete highlighter;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->tabWidget->addTab(scriptEditor, fileStem);
|
ui->tabWidget->addTab(scriptEditor, fileStem);
|
||||||
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, ZoneFile::AssetTypeToIcon(ASSET_RAW_FILE));
|
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, Utils::CreateAssetIcon(ASSET_TYPE_RAWFILE));
|
||||||
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
|
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(mTreeWidget, &XTreeWidget::ImageSelected, this, [this](std::shared_ptr<Image> image, const QString aParentName) {
|
// connect(mTreeWidget, &XTreeWidget::ImageSelected, this, [this](std::shared_ptr<Image> image, const QString aParentName) {
|
||||||
ImageWidget *mImageWidget = new ImageWidget(this);
|
// ImageWidget *mImageWidget = new ImageWidget(this);
|
||||||
mImageWidget->setAcceptDrops(false);
|
// mImageWidget->setAcceptDrops(false);
|
||||||
mImageWidget->SetImage(image);
|
// mImageWidget->SetImage(image);
|
||||||
mImageWidget->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
|
// mImageWidget->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
|
||||||
|
|
||||||
QString fileStem = image->materialName;
|
// QString fileStem = image->materialName;
|
||||||
for (int i = 0; i < ui->tabWidget->count(); i++) {
|
// for (int i = 0; i < ui->tabWidget->count(); i++) {
|
||||||
if (ui->tabWidget->tabText(i) == fileStem) {
|
// if (ui->tabWidget->tabText(i) == fileStem) {
|
||||||
delete mImageWidget;
|
// delete mImageWidget;
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
ui->tabWidget->addTab(mImageWidget, fileStem);
|
// ui->tabWidget->addTab(mImageWidget, fileStem);
|
||||||
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, ZoneFile::AssetTypeToIcon(ASSET_IMAGE));
|
// ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, Utils::CreateAssetIcon(ASSET_TYPE_IMAGE));
|
||||||
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
|
// ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
|
||||||
});
|
// });
|
||||||
|
|
||||||
connect(mTreeWidget, &XTreeWidget::MenuSelected, this, [](std::shared_ptr<Menu> menu, const QString aParentName) {
|
// connect(mTreeWidget, &XTreeWidget::MenuSelected, this, [](std::shared_ptr<Menu> menu, const QString aParentName) {
|
||||||
Q_UNUSED(menu);
|
// Q_UNUSED(menu);
|
||||||
});
|
// });
|
||||||
|
|
||||||
connect(mTreeWidget, &XTreeWidget::MaterialSelected, this, [this](std::shared_ptr<Material> material, const QString aParentName) {
|
connect(mTreeWidget, &XTreeWidget::MaterialSelected, this, [this](const XMaterial* material, const QString aParentName) {
|
||||||
MaterialViewer *matViewer = new MaterialViewer(this);
|
MaterialViewer *matViewer = new MaterialViewer(this);
|
||||||
matViewer->setAcceptDrops(false);
|
matViewer->setAcceptDrops(false);
|
||||||
matViewer->SetMaterial(material);
|
matViewer->SetMaterial(material);
|
||||||
matViewer->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
|
matViewer->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
|
||||||
|
|
||||||
QString fileStem = material->name;
|
// QString fileStem = material->name;
|
||||||
for (int i = 0; i < ui->tabWidget->count(); i++) {
|
// for (int i = 0; i < ui->tabWidget->count(); i++) {
|
||||||
if (ui->tabWidget->tabText(i) == fileStem) {
|
// if (ui->tabWidget->tabText(i) == fileStem) {
|
||||||
delete matViewer;
|
// delete matViewer;
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
ui->tabWidget->addTab(matViewer, fileStem);
|
//ui->tabWidget->addTab(matViewer, fileStem);
|
||||||
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, ZoneFile::AssetTypeToIcon(ASSET_MATERIAL));
|
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, Utils::CreateAssetIcon(ASSET_TYPE_MATERIAL));
|
||||||
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
|
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(mTreeWidget, &XTreeWidget::DDSFileSelected, this, [this](std::shared_ptr<DDSFile> ddsFile, const QString aParentName) {
|
connect(mTreeWidget, &XTreeWidget::DDSFileSelected, this, [this](const DDSFile* ddsFile, const QString aParentName) {
|
||||||
DDSViewer *ddsViewer = new DDSViewer(this);
|
DDSViewer *ddsViewer = new DDSViewer(this);
|
||||||
ddsViewer->setAcceptDrops(false);
|
ddsViewer->setAcceptDrops(false);
|
||||||
ddsViewer->SetDDSFile(ddsFile);
|
ddsViewer->SetDDSFile(ddsFile);
|
||||||
@ -272,11 +285,11 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ui->tabWidget->addTab(ddsViewer, fileStem);
|
ui->tabWidget->addTab(ddsViewer, fileStem);
|
||||||
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, ZoneFile::AssetTypeToIcon(ASSET_IMAGE));
|
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, Utils::CreateAssetIcon(ASSET_TYPE_IMAGE));
|
||||||
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
|
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(mTreeWidget, &XTreeWidget::IWIFileSelected, this, [this](std::shared_ptr<IWIFile> iwiFile, const QString aParentName) {
|
connect(mTreeWidget, &XTreeWidget::IWIFileSelected, this, [this](const IWIFile* iwiFile, const QString aParentName) {
|
||||||
IWIViewer *iwiViewer = new IWIViewer(this);
|
IWIViewer *iwiViewer = new IWIViewer(this);
|
||||||
iwiViewer->setAcceptDrops(false);
|
iwiViewer->setAcceptDrops(false);
|
||||||
iwiViewer->SetIWIFile(iwiFile);
|
iwiViewer->SetIWIFile(iwiFile);
|
||||||
@ -291,11 +304,11 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ui->tabWidget->addTab(iwiViewer, fileStem);
|
ui->tabWidget->addTab(iwiViewer, fileStem);
|
||||||
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, ZoneFile::AssetTypeToIcon(ASSET_IMAGE));
|
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, Utils::CreateAssetIcon(ASSET_TYPE_IMAGE));
|
||||||
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
|
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(mTreeWidget, &XTreeWidget::FastFileSelected, this, [this](std::shared_ptr<FastFile> aFastFile, const QString aParentName) {
|
connect(mTreeWidget, &XTreeWidget::FastFileSelected, this, [this](const FastFile* aFastFile, const QString aParentName) {
|
||||||
FastFileViewer *fastFileViewer = new FastFileViewer(this);
|
FastFileViewer *fastFileViewer = new FastFileViewer(this);
|
||||||
fastFileViewer->setAcceptDrops(false);
|
fastFileViewer->setAcceptDrops(false);
|
||||||
fastFileViewer->SetFastFile(aFastFile);
|
fastFileViewer->SetFastFile(aFastFile);
|
||||||
@ -310,11 +323,11 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ui->tabWidget->addTab(fastFileViewer, fileStem);
|
ui->tabWidget->addTab(fastFileViewer, fileStem);
|
||||||
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, ZoneFile::AssetTypeToIcon(ASSET_FAST_FILE));
|
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, Utils::CreateAssetIcon("FF"));
|
||||||
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
|
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(mTreeWidget, &XTreeWidget::ZoneFileSelected, this, [this](std::shared_ptr<ZoneFile> aZoneFile, const QString aParentName) {
|
connect(mTreeWidget, &XTreeWidget::ZoneFileSelected, this, [this](const ZoneFile* aZoneFile, const QString aParentName) {
|
||||||
ZoneFileViewer *zoneFileViewer = new ZoneFileViewer(this);
|
ZoneFileViewer *zoneFileViewer = new ZoneFileViewer(this);
|
||||||
zoneFileViewer->setAcceptDrops(false);
|
zoneFileViewer->setAcceptDrops(false);
|
||||||
zoneFileViewer->SetZoneFile(aZoneFile);
|
zoneFileViewer->SetZoneFile(aZoneFile);
|
||||||
@ -341,11 +354,11 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
scrollArea->setWidget(containerWidget);
|
scrollArea->setWidget(containerWidget);
|
||||||
|
|
||||||
ui->tabWidget->addTab(scrollArea, fileStem);
|
ui->tabWidget->addTab(scrollArea, fileStem);
|
||||||
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, ZoneFile::AssetTypeToIcon(ASSET_ZONE_FILE));
|
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, Utils::CreateAssetIcon("ZF"));
|
||||||
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
|
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(mTreeWidget, &XTreeWidget::LocalStringSelected, this, [this](std::shared_ptr<ZoneFile> aZoneFile, const QString aParentName) {
|
connect(mTreeWidget, &XTreeWidget::LocalStringSelected, this, [this](const ZoneFile* aZoneFile, const QString aParentName) {
|
||||||
LocalStringViewer *localStrViewer = new LocalStringViewer(this);
|
LocalStringViewer *localStrViewer = new LocalStringViewer(this);
|
||||||
localStrViewer->setAcceptDrops(false);
|
localStrViewer->setAcceptDrops(false);
|
||||||
localStrViewer->SetZoneFile(aZoneFile);
|
localStrViewer->SetZoneFile(aZoneFile);
|
||||||
@ -360,17 +373,17 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ui->tabWidget->addTab(localStrViewer, fileStem);
|
ui->tabWidget->addTab(localStrViewer, fileStem);
|
||||||
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, ZoneFile::AssetTypeToIcon(ASSET_LOCAL_STRING));
|
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, Utils::CreateAssetIcon(ASSET_TYPE_LOCALIZE_ENTRY));
|
||||||
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
|
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(mTreeWidget, &XTreeWidget::TechSetSelected, this, [this](std::shared_ptr<TechSet> aTechSet, const QString aParentName) {
|
connect(mTreeWidget, &XTreeWidget::TechSetSelected, this, [this](const XMaterialTechniqueSet* aTechSet, const QString aParentName) {
|
||||||
TechSetViewer *techSetViewer = new TechSetViewer(this);
|
TechSetViewer *techSetViewer = new TechSetViewer(this);
|
||||||
techSetViewer->setAcceptDrops(false);
|
techSetViewer->setAcceptDrops(false);
|
||||||
techSetViewer->SetTechSet(aTechSet);
|
techSetViewer->SetTechSet(aTechSet);
|
||||||
techSetViewer->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
|
techSetViewer->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
|
||||||
|
|
||||||
QString fileStem = aTechSet->name;
|
QString fileStem = aTechSet->GetName();
|
||||||
for (int i = 0; i < ui->tabWidget->count(); i++) {
|
for (int i = 0; i < ui->tabWidget->count(); i++) {
|
||||||
if (ui->tabWidget->tabText(i) == fileStem) {
|
if (ui->tabWidget->tabText(i) == fileStem) {
|
||||||
delete techSetViewer;
|
delete techSetViewer;
|
||||||
@ -378,18 +391,18 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->tabWidget->addTab(techSetViewer, aTechSet->name);
|
ui->tabWidget->addTab(techSetViewer, aTechSet->GetName());
|
||||||
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, ZoneFile::AssetTypeToIcon(ASSET_TECH_SET));
|
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, Utils::CreateAssetIcon(ASSET_TYPE_TECHNIQUE_SET));
|
||||||
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
|
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(mTreeWidget, &XTreeWidget::StrTableSelected, this, [this](std::shared_ptr<StringTable> aStrTable, const QString aParentName) {
|
connect(mTreeWidget, &XTreeWidget::StrTableSelected, this, [this](const XStringTable* aStrTable, const QString aParentName) {
|
||||||
StringTableViewer *strTableViewer = new StringTableViewer(this);
|
StringTableViewer *strTableViewer = new StringTableViewer(this);
|
||||||
strTableViewer->setAcceptDrops(false);
|
strTableViewer->setAcceptDrops(false);
|
||||||
strTableViewer->SetStringTable(aStrTable);
|
strTableViewer->SetStringTable(aStrTable);
|
||||||
strTableViewer->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
|
strTableViewer->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
|
||||||
|
|
||||||
QString fileStem = aStrTable->name;
|
QString fileStem = aStrTable->GetName()->GetString();
|
||||||
for (int i = 0; i < ui->tabWidget->count(); i++) {
|
for (int i = 0; i < ui->tabWidget->count(); i++) {
|
||||||
if (ui->tabWidget->tabText(i) == fileStem) {
|
if (ui->tabWidget->tabText(i) == fileStem) {
|
||||||
delete strTableViewer;
|
delete strTableViewer;
|
||||||
@ -398,28 +411,28 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ui->tabWidget->addTab(strTableViewer, fileStem);
|
ui->tabWidget->addTab(strTableViewer, fileStem);
|
||||||
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, ZoneFile::AssetTypeToIcon(ASSET_STRING_TABLE));
|
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, Utils::CreateAssetIcon(ASSET_TYPE_STRINGTABLE));
|
||||||
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
|
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(mTreeWidget, &XTreeWidget::SoundSelected, this, [this](std::shared_ptr<Sound> aSound, const QString aParentName) {
|
// connect(mTreeWidget, &XTreeWidget::SoundSelected, this, [this](std::shared_ptr<Sound> aSound, const QString aParentName) {
|
||||||
SoundViewer *soundViewer = new SoundViewer(this);
|
// SoundViewer *soundViewer = new SoundViewer(this);
|
||||||
soundViewer->setAcceptDrops(false);
|
// soundViewer->setAcceptDrops(false);
|
||||||
soundViewer->SetSound(aSound);
|
// soundViewer->SetSound(aSound);
|
||||||
soundViewer->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
|
// soundViewer->setProperty("PARENT_NAME", QVariant::fromValue(aParentName));
|
||||||
|
|
||||||
QString fileStem = aSound->path.split('/').last();
|
// QString fileStem = aSound->path.split('/').last();
|
||||||
for (int i = 0; i < ui->tabWidget->count(); i++) {
|
// for (int i = 0; i < ui->tabWidget->count(); i++) {
|
||||||
if (ui->tabWidget->tabText(i) == fileStem) {
|
// if (ui->tabWidget->tabText(i) == fileStem) {
|
||||||
delete soundViewer;
|
// delete soundViewer;
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
ui->tabWidget->addTab(soundViewer, fileStem);
|
// ui->tabWidget->addTab(soundViewer, fileStem);
|
||||||
ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, ZoneFile::AssetTypeToIcon(ASSET_SOUND));
|
// ui->tabWidget->setTabIcon(ui->tabWidget->count() - 1, Utils::CreateAssetIcon(ASSET_TYPE_SOUND));
|
||||||
ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
|
// ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
|
||||||
});
|
// });
|
||||||
|
|
||||||
connect(mTreeWidget, &XTreeWidget::ItemSelected, this, [this](const QString itemText) {
|
connect(mTreeWidget, &XTreeWidget::ItemSelected, this, [this](const QString itemText) {
|
||||||
for (int i = 0; i < ui->tabWidget->count(); i++) {
|
for (int i = 0; i < ui->tabWidget->count(); i++) {
|
||||||
@ -520,7 +533,22 @@ bool MainWindow::OpenFastFile(const QString aFastFilePath) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<FastFile> fastFile = FastFileFactory::Create(aFastFilePath);
|
FastFile* fastFile = FastFile::Open(aFastFilePath);
|
||||||
|
fastFile->SetStem(fastFileStem);
|
||||||
|
mTreeWidget->AddFastFile(fastFile);
|
||||||
|
|
||||||
|
// Open zone file after decompressing ff and writing
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MainWindow::OpenFastFile(const QByteArray& aFastFileData, const QString aFastFilePath) {
|
||||||
|
const QString fastFileStem = aFastFilePath.section("/", -1, -1);
|
||||||
|
if (mTreeWidget->HasFastFile(fastFileStem)) {
|
||||||
|
LogManager::instance().addError("Can't add duplicate file!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FastFile* fastFile = FastFile::Open(aFastFileData);
|
||||||
fastFile->SetStem(fastFileStem);
|
fastFile->SetStem(fastFileStem);
|
||||||
mTreeWidget->AddFastFile(fastFile);
|
mTreeWidget->AddFastFile(fastFile);
|
||||||
|
|
||||||
@ -535,11 +563,13 @@ bool MainWindow::OpenFastFile(const QString aFastFilePath) {
|
|||||||
and opens the selected file.
|
and opens the selected file.
|
||||||
*/
|
*/
|
||||||
bool MainWindow::OpenFastFile() {
|
bool MainWindow::OpenFastFile() {
|
||||||
const QString fastFileName = Utils::GetOpenFastFileName();
|
// Open file dialog to steam apps
|
||||||
if (!OpenFastFile(fastFileName)) {
|
const QString steamPath = "C:/Program Files (x86)/Steam/steamapps/common/Call of Duty World at War/zone/english/";
|
||||||
qDebug() << "Failed to open Fast file!";
|
|
||||||
return false;
|
QFileDialog::getOpenFileContent(tr("Fast File (*.ff);;All Files (*.*)"), [this](const QString &fileName, const QByteArray &data){
|
||||||
}
|
OpenFastFile(data, fileName);
|
||||||
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -553,19 +583,25 @@ bool MainWindow::OpenZoneFile(const QString aZoneFilePath, bool fromFF) {
|
|||||||
Q_UNUSED(aZoneFilePath);
|
Q_UNUSED(aZoneFilePath);
|
||||||
Q_UNUSED(fromFF);
|
Q_UNUSED(fromFF);
|
||||||
|
|
||||||
//ZoneFile zoneFile;
|
// ZoneFile* zoneFile = ZoneFile::Create();
|
||||||
//if (!zoneFile.Load(aZoneFilePath)) {
|
// if (!zoneFile.Load(aZoneFilePath)) {
|
||||||
// qDebug() << "Error: Failed to load zone file!";
|
// qDebug() << "Error: Failed to load zone file!";
|
||||||
// return false;
|
// return false;
|
||||||
//}
|
// }
|
||||||
//mTreeWidget->AddZoneFile(std::make_shared<ZoneFile>(zoneFile));
|
// mTreeWidget->AddZoneFile(std::make_shared<ZoneFile>(zoneFile));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MainWindow::OpenZoneFile() {
|
bool MainWindow::OpenZoneFile() {
|
||||||
const QString zoneFileName = Utils::GetOpenZoneFileName();
|
// Open file dialog to steam apps
|
||||||
if (!OpenZoneFile(zoneFileName)) {
|
const QString steamPath = "C:/Program Files (x86)/Steam/steamapps/common/Call of Duty World at War/zone/english/";
|
||||||
|
const QString zoneFilePath = QFileDialog::getOpenFileName(this, "Open Zone File", steamPath, "Zone File (*.zone);;All Files (*.*)");
|
||||||
|
if (zoneFilePath.isNull()) {
|
||||||
|
// User pressed cancel
|
||||||
|
return false;
|
||||||
|
} else if (!QFile::exists(zoneFilePath)) {
|
||||||
|
QMessageBox::warning(this, "Warning!", QString("%1 does not exist!.").arg(zoneFilePath));
|
||||||
qDebug() << "Failed to open Zone file!";
|
qDebug() << "Failed to open Zone file!";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -637,7 +673,7 @@ quint32 DXT3 = 0x33545844; // 'DXT3'
|
|||||||
quint32 DXT5 = 0x35545844; // 'DXT5'
|
quint32 DXT5 = 0x35545844; // 'DXT5'
|
||||||
|
|
||||||
int MainWindow::LoadFile_IWI(const QString aFilePath) {
|
int MainWindow::LoadFile_IWI(const QString aFilePath) {
|
||||||
mTreeWidget->AddIWIFile(std::make_shared<IWIFile>(aFilePath));
|
mTreeWidget->AddIWIFile(new IWIFile(aFilePath));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -648,7 +684,7 @@ int MainWindow::LoadFile_DDSFiles(const QStringList aFilePaths) {
|
|||||||
qDebug() << "Error: Invalid filename " << filePath;
|
qDebug() << "Error: Invalid filename " << filePath;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
mTreeWidget->AddDDSFile(std::make_shared<DDSFile>(filePath));
|
mTreeWidget->AddDDSFile(new DDSFile(filePath));
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -680,7 +716,7 @@ int MainWindow::LoadFile_DDS(const QString aFilePath) {
|
|||||||
qDebug() << "Error: Invalid filename " << aFilePath;
|
qDebug() << "Error: Invalid filename " << aFilePath;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
mTreeWidget->AddDDSFile(std::make_shared<DDSFile>(aFilePath));
|
mTreeWidget->AddDDSFile(new DDSFile(aFilePath));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -753,7 +789,7 @@ int MainWindow::LoadFile_IPAK(const QString aFilePath) {
|
|||||||
|
|
||||||
QVector<IPAKIndexEntry> entries = QVector<IPAKIndexEntry>();
|
QVector<IPAKIndexEntry> entries = QVector<IPAKIndexEntry>();
|
||||||
QVector<IPAKSection> sections = QVector<IPAKSection>(header.sectionCount);
|
QVector<IPAKSection> sections = QVector<IPAKSection>(header.sectionCount);
|
||||||
for (uint i = 0; i < header.sectionCount; i++) {
|
for (quint32 i = 0; i < header.sectionCount; i++) {
|
||||||
IPAKSection currentSection;
|
IPAKSection currentSection;
|
||||||
stream >> currentSection;
|
stream >> currentSection;
|
||||||
sections << currentSection;
|
sections << currentSection;
|
||||||
@ -775,7 +811,7 @@ int MainWindow::LoadFile_IPAK(const QString aFilePath) {
|
|||||||
<< " - Count: " << chunkHeader.count << "\n"
|
<< " - Count: " << chunkHeader.count << "\n"
|
||||||
<< " - Offset: " << chunkHeader.offset;
|
<< " - Offset: " << chunkHeader.offset;
|
||||||
|
|
||||||
for (uint j = 0; j < 31; j++) {
|
for (quint32 j = 0; j < 31; j++) {
|
||||||
IPAKDataChunkCommand command;
|
IPAKDataChunkCommand command;
|
||||||
stream >> command;
|
stream >> command;
|
||||||
if (!command.size) { continue; }
|
if (!command.size) { continue; }
|
||||||
@ -785,7 +821,7 @@ int MainWindow::LoadFile_IPAK(const QString aFilePath) {
|
|||||||
<< " - Compressed: " << command.compressed;
|
<< " - Compressed: " << command.compressed;
|
||||||
|
|
||||||
}
|
}
|
||||||
for (uint j = 0; j < chunkHeader.count; j++) {
|
for (quint32 j = 0; j < chunkHeader.count; j++) {
|
||||||
auto command = chunkHeader.commands[j];
|
auto command = chunkHeader.commands[j];
|
||||||
|
|
||||||
qDebug() << "Reading from " << stream.device()->pos();
|
qDebug() << "Reading from " << stream.device()->pos();
|
||||||
@ -810,7 +846,7 @@ int MainWindow::LoadFile_IPAK(const QString aFilePath) {
|
|||||||
stream.skipRawData(sizeof(quint32) * (31 - chunkHeader.count));
|
stream.skipRawData(sizeof(quint32) * (31 - chunkHeader.count));
|
||||||
qDebug() << stream.device()->pos();
|
qDebug() << stream.device()->pos();
|
||||||
} else if (sectionType == "Index") {
|
} else if (sectionType == "Index") {
|
||||||
for (uint j = 0; j < currentSection.itemCount; j++) {
|
for (quint32 j = 0; j < currentSection.itemCount; j++) {
|
||||||
IPAKIndexEntry entry;
|
IPAKIndexEntry entry;
|
||||||
stream >> entry;
|
stream >> entry;
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
#define MAINWINDOW_H
|
#define MAINWINDOW_H
|
||||||
|
|
||||||
#include "d3dbsp_structs.h"
|
#include "d3dbsp_structs.h"
|
||||||
#include "asset_structs.h"
|
|
||||||
#include "xtreewidget.h"
|
#include "xtreewidget.h"
|
||||||
|
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
@ -16,7 +15,6 @@
|
|||||||
#include <QPlainTextEdit>
|
#include <QPlainTextEdit>
|
||||||
#include <QMimeData>
|
#include <QMimeData>
|
||||||
#include <QProgressBar>
|
#include <QProgressBar>
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
@ -35,6 +33,7 @@ public:
|
|||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
bool OpenFastFile(const QString aFastFilePath);
|
bool OpenFastFile(const QString aFastFilePath);
|
||||||
|
bool OpenFastFile(const QByteArray& aFastFileData, const QString aFastFilePath);
|
||||||
bool OpenFastFile();
|
bool OpenFastFile();
|
||||||
|
|
||||||
bool OpenZoneFile(const QString aZoneFilePath, bool fromFF = false);
|
bool OpenZoneFile(const QString aZoneFilePath, bool fromFF = false);
|
||||||
@ -64,7 +63,7 @@ private:
|
|||||||
quint32 mTagCount;
|
quint32 mTagCount;
|
||||||
quint32 mRecordCount;
|
quint32 mRecordCount;
|
||||||
QMap<QString, QString> mRawFileMap;
|
QMap<QString, QString> mRawFileMap;
|
||||||
QMap<QString, Image> mImageMap;
|
//QMap<QString, Image> mImageMap;
|
||||||
QMap<QString, QTreeWidgetItem*> mTreeMap;
|
QMap<QString, QTreeWidgetItem*> mTreeMap;
|
||||||
QMap<QString, QVector<QPair<QString, QString>>> mStrTableMap;
|
QMap<QString, QVector<QPair<QString, QString>>> mStrTableMap;
|
||||||
XTreeWidget *mTreeWidget;
|
XTreeWidget *mTreeWidget;
|
||||||
|
|||||||
@ -50,7 +50,7 @@
|
|||||||
<height>21</height>
|
<height>21</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QMenu" name="menuFile">
|
<widget class="QMenu" name="MenuDef">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>File</string>
|
<string>File</string>
|
||||||
</property>
|
</property>
|
||||||
@ -117,9 +117,17 @@
|
|||||||
</property>
|
</property>
|
||||||
<addaction name="actionAbout"/>
|
<addaction name="actionAbout"/>
|
||||||
<addaction name="actionCheck_for_Updates"/>
|
<addaction name="actionCheck_for_Updates"/>
|
||||||
|
<addaction name="actionReport_Issue"/>
|
||||||
</widget>
|
</widget>
|
||||||
<addaction name="menuFile"/>
|
<widget class="QMenu" name="menuTools">
|
||||||
|
<property name="title">
|
||||||
|
<string>Tools</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionRun_Tests"/>
|
||||||
|
</widget>
|
||||||
|
<addaction name="MenuDef"/>
|
||||||
<addaction name="menuEdit"/>
|
<addaction name="menuEdit"/>
|
||||||
|
<addaction name="menuTools"/>
|
||||||
<addaction name="menuHelp"/>
|
<addaction name="menuHelp"/>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QToolBar" name="toolBar">
|
<widget class="QToolBar" name="toolBar">
|
||||||
@ -353,6 +361,16 @@
|
|||||||
<string>Preferences...</string>
|
<string>Preferences...</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionReport_Issue">
|
||||||
|
<property name="text">
|
||||||
|
<string>Report Issue</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionRun_Tests">
|
||||||
|
<property name="text">
|
||||||
|
<string>Run Tests</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="../data/data.qrc"/>
|
<include location="../data/data.qrc"/>
|
||||||
|
|||||||
@ -3,33 +3,41 @@
|
|||||||
|
|
||||||
MaterialViewer::MaterialViewer(QWidget *parent)
|
MaterialViewer::MaterialViewer(QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
, ui(new Ui::MaterialViewer) {
|
, ui(new Ui::MaterialViewer)
|
||||||
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
MaterialViewer::~MaterialViewer() {
|
MaterialViewer::~MaterialViewer()
|
||||||
|
{
|
||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ToHexStr(quint32 in) {
|
QString ToHexStr(quint32 in)
|
||||||
|
{
|
||||||
return QString("%1").arg(in, 8, 16, QChar('0')).toUpper();
|
return QString("%1").arg(in, 8, 16, QChar('0')).toUpper();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaterialViewer::SetMaterial(std::shared_ptr<Material> aMaterial) {
|
void MaterialViewer::SetMaterial(const XMaterial* aMaterial)
|
||||||
ui->lineEdit_NamePtr->setText(ToHexStr(aMaterial->namePtr));
|
{
|
||||||
ui->lineEdit_Name->setText(aMaterial->name);
|
Q_UNUSED(aMaterial);
|
||||||
ui->lineEdit_RefPtr->setText(ToHexStr(aMaterial->refNamePtr));
|
|
||||||
ui->lineEdit_RefName->setText(aMaterial->refName);
|
// TODO: Fill in MaterialViewer::SetMaterial
|
||||||
QString unknownStr = "";
|
|
||||||
foreach (quint32 unknownPtr, aMaterial->pointers) {
|
// ui->lineEdit_NamePtr->setText(ToHexStr(aMaterial->namePtr));
|
||||||
unknownStr += ToHexStr(unknownPtr) + "\n";
|
// ui->lineEdit_Name->setText(aMaterial->name);
|
||||||
}
|
// ui->lineEdit_RefPtr->setText(ToHexStr(aMaterial->refNamePtr));
|
||||||
ui->lineEdit_Unknowns->setText(unknownStr);
|
// ui->lineEdit_RefName->setText(aMaterial->refName);
|
||||||
ui->lineEdit_StateA->setText(ToHexStr(aMaterial->stateBits[0]));
|
// QString unknownStr = "";
|
||||||
ui->lineEdit_StateA->setText(ToHexStr(aMaterial->stateBits[1]));
|
// foreach (quint32 unknownPtr, aMaterial->pointers) {
|
||||||
ui->spinBox_TextureCount->setValue(aMaterial->textureCount);
|
// unknownStr += ToHexStr(unknownPtr) + "\n";
|
||||||
ui->spinBox_ConstCount->setValue(aMaterial->constCount);
|
// }
|
||||||
ui->lineEdit_TechSetPtr->setText(ToHexStr(aMaterial->techSetPtr));
|
// ui->lineEdit_Unknowns->setText(unknownStr);
|
||||||
ui->lineEdit_TexturePtr->setText(ToHexStr(aMaterial->texturePtr));
|
// ui->lineEdit_StateA->setText(ToHexStr(aMaterial->stateBits[0]));
|
||||||
ui->lineEdit_ConstantPtr->setText(ToHexStr(aMaterial->constPtr));
|
// ui->lineEdit_StateA->setText(ToHexStr(aMaterial->stateBits[1]));
|
||||||
|
// ui->spinBox_TextureCount->setValue(aMaterial->textureCount);
|
||||||
|
// ui->spinBox_ConstCount->setValue(aMaterial->constCount);
|
||||||
|
// ui->lineEdit_TechSetPtr->setText(ToHexStr(aMaterial->techSetPtr));
|
||||||
|
// ui->lineEdit_TexturePtr->setText(ToHexStr(aMaterial->texturePtr));
|
||||||
|
// ui->lineEdit_ConstantPtr->setText(ToHexStr(aMaterial->constPtr));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
#ifndef MATERIALVIEWER_H
|
#ifndef MATERIALVIEWER_H
|
||||||
#define MATERIALVIEWER_H
|
#define MATERIALVIEWER_H
|
||||||
|
|
||||||
#include "asset_structs.h"
|
#include "xmaterial.h"
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QScrollArea>
|
#include <QScrollArea>
|
||||||
@ -18,7 +18,7 @@ public:
|
|||||||
explicit MaterialViewer(QWidget *parent = nullptr);
|
explicit MaterialViewer(QWidget *parent = nullptr);
|
||||||
~MaterialViewer();
|
~MaterialViewer();
|
||||||
|
|
||||||
void SetMaterial(std::shared_ptr<Material> aMaterial);
|
void SetMaterial(const XMaterial *aMaterial);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::MaterialViewer *ui;
|
Ui::MaterialViewer *ui;
|
||||||
|
|||||||
103
app/reportissuedialog.cpp
Normal file
103
app/reportissuedialog.cpp
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
#include "reportissuedialog.h"
|
||||||
|
#include "qjsonarray.h"
|
||||||
|
#include "ui_reportissuedialog.h"
|
||||||
|
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QNetworkRequest>
|
||||||
|
|
||||||
|
ReportIssueDialog::ReportIssueDialog(const QString &giteaBaseUrl,
|
||||||
|
const QString &repoOwner,
|
||||||
|
const QString &repoName,
|
||||||
|
const QString &accessToken,
|
||||||
|
QWidget *parent) :
|
||||||
|
QDialog(parent),
|
||||||
|
ui(new Ui::ReportIssueDialog),
|
||||||
|
networkManager(new QNetworkAccessManager(this)),
|
||||||
|
giteaBaseUrl(giteaBaseUrl),
|
||||||
|
repoOwner(repoOwner),
|
||||||
|
repoName(repoName),
|
||||||
|
accessToken(accessToken)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
connect(networkManager, &QNetworkAccessManager::finished, this, &ReportIssueDialog::onNetworkReplyFinished);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReportIssueDialog::~ReportIssueDialog()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReportIssueDialog::on_buttonSend_clicked()
|
||||||
|
{
|
||||||
|
QString title = ui->lineEditSummary->text().trimmed();
|
||||||
|
QString details = ui->textEditDetails->toPlainText().trimmed();
|
||||||
|
QString contact = ui->lineEditContact->text().trimmed();
|
||||||
|
|
||||||
|
if (title.isEmpty()) {
|
||||||
|
QMessageBox::warning(this, tr("Input Error"), tr("Please enter a summary/title for the issue."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString body = details;
|
||||||
|
if (!contact.isEmpty()) {
|
||||||
|
body += QString("\n\nContact info:\n%1").arg(contact);
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->buttonSend->setEnabled(false);
|
||||||
|
sendIssueReport(title, body, contact);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReportIssueDialog::on_buttonCancel_clicked()
|
||||||
|
{
|
||||||
|
reject();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReportIssueDialog::sendIssueReport(const QString &title, const QString &body, const QString &/*contact*/)
|
||||||
|
{
|
||||||
|
// Compose URL: e.g. https://gitea.example.com/api/v1/repos/{owner}/{repo}/issues
|
||||||
|
QUrl url(QString("%1/api/v1/repos/%2/%3/issues").arg(giteaBaseUrl).arg(repoOwner).arg(repoName));
|
||||||
|
|
||||||
|
QNetworkRequest request(url);
|
||||||
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||||
|
|
||||||
|
if (!accessToken.isEmpty()) {
|
||||||
|
request.setRawHeader("Authorization", "token " + accessToken.toUtf8());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compose JSON body
|
||||||
|
QJsonObject json;
|
||||||
|
json["title"] = title;
|
||||||
|
json["body"] = body;
|
||||||
|
json["labels"] = QJsonArray{12};
|
||||||
|
|
||||||
|
QJsonDocument doc(json);
|
||||||
|
QByteArray data = doc.toJson();
|
||||||
|
|
||||||
|
networkManager->post(request, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReportIssueDialog::onNetworkReplyFinished(QNetworkReply *reply)
|
||||||
|
{
|
||||||
|
ui->buttonSend->setEnabled(true);
|
||||||
|
|
||||||
|
QByteArray responseData = reply->readAll();
|
||||||
|
QString responseStr = QString::fromUtf8(responseData);
|
||||||
|
|
||||||
|
if (reply->error() != QNetworkReply::NoError) {
|
||||||
|
QString errorStr = reply->errorString();
|
||||||
|
if (errorStr.isEmpty()) errorStr = "Unknown network error";
|
||||||
|
QMessageBox::critical(this, tr("Error"), tr("Failed to send issue report:\n%1\nResponse:\n%2").arg(errorStr).arg(responseStr));
|
||||||
|
} else {
|
||||||
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
if (status == 201) {
|
||||||
|
QMessageBox::information(this, tr("Success"), tr("Issue reported successfully!"));
|
||||||
|
accept();
|
||||||
|
} else {
|
||||||
|
QMessageBox::warning(this, tr("Failed"), tr("Unexpected response from server (%1):\n%2").arg(status).arg(responseStr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reply->deleteLater();
|
||||||
|
}
|
||||||
43
app/reportissuedialog.h
Normal file
43
app/reportissuedialog.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#ifndef REPORTISSUEDIALOG_H
|
||||||
|
#define REPORTISSUEDIALOG_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class ReportIssueDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ReportIssueDialog : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ReportIssueDialog(const QString &giteaBaseUrl,
|
||||||
|
const QString &repoOwner,
|
||||||
|
const QString &repoName,
|
||||||
|
const QString &accessToken,
|
||||||
|
QWidget *parent = nullptr);
|
||||||
|
~ReportIssueDialog();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void on_buttonSend_clicked();
|
||||||
|
void on_buttonCancel_clicked();
|
||||||
|
|
||||||
|
void onNetworkReplyFinished(QNetworkReply *reply);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::ReportIssueDialog *ui;
|
||||||
|
|
||||||
|
QNetworkAccessManager *networkManager;
|
||||||
|
|
||||||
|
QString giteaBaseUrl;
|
||||||
|
QString repoOwner;
|
||||||
|
QString repoName;
|
||||||
|
QString accessToken;
|
||||||
|
|
||||||
|
void sendIssueReport(const QString &title, const QString &body, const QString &contact);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // REPORTISSUEDIALOG_H
|
||||||
84
app/reportissuedialog.ui
Normal file
84
app/reportissuedialog.ui
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>ReportIssueDialog</class>
|
||||||
|
<widget class="QDialog" name="ReportIssueDialog">
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Report a Problem</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="labelInstructions">
|
||||||
|
<property name="text">
|
||||||
|
<string>Please describe the problem you encountered. We’ll use this info to help fix it.</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="labelSummary">
|
||||||
|
<property name="text">
|
||||||
|
<string>Summary (short title):</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="lineEditSummary" />
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="labelDetails">
|
||||||
|
<property name="text">
|
||||||
|
<string>Details (what happened?):</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTextEdit" name="textEditDetails" />
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="labelContact">
|
||||||
|
<property name="text">
|
||||||
|
<string>Your contact (email or name, optional):</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="lineEditContact" />
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="buttonLayout">
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Expanding</enum>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="buttonSend">
|
||||||
|
<property name="text">
|
||||||
|
<string>Send Report</string>
|
||||||
|
</property>
|
||||||
|
<property name="default">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="buttonCancel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Cancel</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
@ -18,41 +18,41 @@ RumbleFileViewer::~RumbleFileViewer() {
|
|||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RumbleFileViewer::SetRumbleFile(std::shared_ptr<RawFile> aRumbleFile) {
|
void RumbleFileViewer::SetRumbleFile(XRawFile *aRumbleFile) {
|
||||||
mRumbleFile = aRumbleFile;
|
mRumbleFile = aRumbleFile;
|
||||||
|
|
||||||
ui->tableWidget_Properties->clear();
|
ui->tableWidget_Properties->clear();
|
||||||
|
|
||||||
const QString magic = aRumbleFile->contents.left(6);
|
// const QString magic = aRumbleFile->contents.left(6);
|
||||||
if (magic != "RUMBLE") {
|
// if (magic != "RUMBLE") {
|
||||||
qDebug() << "Rumble file has invalid magic: " << magic;
|
// qDebug() << "Rumble file has invalid magic: " << magic;
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
int firstIndex = 0;
|
// int firstIndex = 0;
|
||||||
int secondIndex = 0;
|
// int secondIndex = 0;
|
||||||
int thirdIndex = 0;
|
// int thirdIndex = 0;
|
||||||
|
|
||||||
int startIndex = 0;
|
// int startIndex = 0;
|
||||||
for (int i = 0; i < aRumbleFile->contents.count("\\") / 2; i++) {
|
// for (int i = 0; i < aRumbleFile->contents.count("\\") / 2; i++) {
|
||||||
ui->tableWidget_Properties->setRowCount(i + 1);
|
// ui->tableWidget_Properties->setRowCount(i + 1);
|
||||||
ui->spinBox_Entries->setValue(i + 1);
|
// ui->spinBox_Entries->setValue(i + 1);
|
||||||
|
|
||||||
firstIndex = aRumbleFile->contents.indexOf("\\", startIndex);
|
// firstIndex = aRumbleFile->contents.indexOf("\\", startIndex);
|
||||||
secondIndex = aRumbleFile->contents.indexOf("\\", firstIndex + 1);
|
// secondIndex = aRumbleFile->contents.indexOf("\\", firstIndex + 1);
|
||||||
thirdIndex = aRumbleFile->contents.indexOf("\\", secondIndex + 1);
|
// thirdIndex = aRumbleFile->contents.indexOf("\\", secondIndex + 1);
|
||||||
if (thirdIndex == -1) {
|
// if (thirdIndex == -1) {
|
||||||
thirdIndex = aRumbleFile->contents.size();
|
// thirdIndex = aRumbleFile->contents.size();
|
||||||
}
|
// }
|
||||||
|
|
||||||
const QString keyStr = aRumbleFile->contents.mid(firstIndex + 1, secondIndex - firstIndex - 1);
|
// const QString keyStr = aRumbleFile->contents.mid(firstIndex + 1, secondIndex - firstIndex - 1);
|
||||||
QTableWidgetItem *keyItem = new QTableWidgetItem(keyStr);
|
// QTableWidgetItem *keyItem = new QTableWidgetItem(keyStr);
|
||||||
ui->tableWidget_Properties->setItem(i, 0, keyItem);
|
// ui->tableWidget_Properties->setItem(i, 0, keyItem);
|
||||||
|
|
||||||
const QString valStr = aRumbleFile->contents.mid(secondIndex + 1, thirdIndex - secondIndex - 1);
|
// const QString valStr = aRumbleFile->contents.mid(secondIndex + 1, thirdIndex - secondIndex - 1);
|
||||||
QTableWidgetItem *valueItem = new QTableWidgetItem(valStr);
|
// QTableWidgetItem *valueItem = new QTableWidgetItem(valStr);
|
||||||
ui->tableWidget_Properties->setItem(i, 1, valueItem);
|
// ui->tableWidget_Properties->setItem(i, 1, valueItem);
|
||||||
|
|
||||||
startIndex = thirdIndex;
|
// startIndex = thirdIndex;
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
#ifndef RUMBLEFILEVIEWER_H
|
#ifndef RUMBLEFILEVIEWER_H
|
||||||
#define RUMBLEFILEVIEWER_H
|
#define RUMBLEFILEVIEWER_H
|
||||||
|
|
||||||
#include "asset_structs.h"
|
#include "xrawfile.h"
|
||||||
#include "zonefile.h"
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
@ -17,12 +17,12 @@ public:
|
|||||||
explicit RumbleFileViewer(QWidget *parent = nullptr);
|
explicit RumbleFileViewer(QWidget *parent = nullptr);
|
||||||
~RumbleFileViewer();
|
~RumbleFileViewer();
|
||||||
|
|
||||||
void SetRumbleFile(std::shared_ptr<RawFile> aRumbleFile);
|
void SetRumbleFile(XRawFile* aRumbleFile);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::RumbleFileViewer *ui;
|
Ui::RumbleFileViewer *ui;
|
||||||
quint32 mPropertyCount;
|
quint32 mPropertyCount;
|
||||||
std::shared_ptr<RawFile> mRumbleFile;
|
XRawFile* mRumbleFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // RUMBLEFILEVIEWER_H
|
#endif // RUMBLEFILEVIEWER_H
|
||||||
|
|||||||
@ -19,10 +19,10 @@ RumbleGraphViewer::~RumbleGraphViewer() {
|
|||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RumbleGraphViewer::SetRumbleGraphFile(const std::shared_ptr<RawFile> aRawFile) {
|
void RumbleGraphViewer::SetRumbleGraphFile(const XRawFile* aRawFile) {
|
||||||
mRumbleGraphFile = aRawFile;
|
mRumbleGraphFile = aRawFile;
|
||||||
|
|
||||||
QDataStream rawFileStream(mRumbleGraphFile->contents.toLatin1());
|
XDataStream rawFileStream;//(mRumbleGraphFile->contents.toLatin1());
|
||||||
|
|
||||||
QByteArray magic(15, Qt::Uninitialized);
|
QByteArray magic(15, Qt::Uninitialized);
|
||||||
rawFileStream.readRawData(magic.data(), 15);
|
rawFileStream.readRawData(magic.data(), 15);
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
#ifndef RUMBLEGRAPHVIEWER_H
|
#ifndef RUMBLEGRAPHVIEWER_H
|
||||||
#define RUMBLEGRAPHVIEWER_H
|
#define RUMBLEGRAPHVIEWER_H
|
||||||
|
|
||||||
#include "asset_structs.h"
|
#include "xrawfile.h"
|
||||||
#include "zonefile.h"
|
#include "zonefile.h"
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
@ -18,13 +18,13 @@ public:
|
|||||||
~RumbleGraphViewer();
|
~RumbleGraphViewer();
|
||||||
|
|
||||||
void SetEntryCount(quint32 aCount);
|
void SetEntryCount(quint32 aCount);
|
||||||
void SetRumbleGraphFile(const std::shared_ptr<RawFile> aRawFile);
|
void SetRumbleGraphFile(const XRawFile *aRawFile);
|
||||||
void SetZoneFile(std::shared_ptr<ZoneFile> aZoneFile);
|
void SetZoneFile(ZoneFile* aZoneFile);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::RumbleGraphViewer *ui;
|
Ui::RumbleGraphViewer *ui;
|
||||||
quint32 mEntryCount;
|
quint32 mEntryCount;
|
||||||
std::shared_ptr<RawFile> mRumbleGraphFile;
|
const XRawFile* mRumbleGraphFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // RUMBLEGRAPHVIEWER_H
|
#endif // RUMBLEGRAPHVIEWER_H
|
||||||
|
|||||||
@ -61,17 +61,17 @@ SoundViewer::~SoundViewer()
|
|||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundViewer::SetSound(std::shared_ptr<Sound> aSound)
|
// void SoundViewer::SetSound(std::shared_ptr<Sound> aSound)
|
||||||
{
|
// {
|
||||||
buffer->setData(aSound->data);
|
// buffer->setData(aSound->data);
|
||||||
if (!buffer->open(QIODevice::ReadOnly)) {
|
// if (!buffer->open(QIODevice::ReadOnly)) {
|
||||||
qWarning() << "Failed to open QBuffer.";
|
// qWarning() << "Failed to open QBuffer.";
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
ui->groupBox->setTitle(aSound->path);
|
// ui->groupBox->setTitle(aSound->path);
|
||||||
player->setSourceDevice(buffer);
|
// player->setSourceDevice(buffer);
|
||||||
}
|
// }
|
||||||
|
|
||||||
void SoundViewer::SetOutput(QAudioOutput *aOutput) {
|
void SoundViewer::SetOutput(QAudioOutput *aOutput) {
|
||||||
if (!aOutput) { return; }
|
if (!aOutput) { return; }
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
#ifndef SOUNDVIEWER_H
|
#ifndef SOUNDVIEWER_H
|
||||||
#define SOUNDVIEWER_H
|
#define SOUNDVIEWER_H
|
||||||
|
|
||||||
#include "asset_structs.h"
|
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QMediaPlayer>
|
#include <QMediaPlayer>
|
||||||
#include <QBuffer>
|
#include <QBuffer>
|
||||||
@ -22,7 +20,7 @@ public:
|
|||||||
explicit SoundViewer(QWidget *parent = nullptr);
|
explicit SoundViewer(QWidget *parent = nullptr);
|
||||||
~SoundViewer();
|
~SoundViewer();
|
||||||
|
|
||||||
void SetSound(std::shared_ptr<Sound> aSound);
|
//void SetSound(std::shared_ptr<Sound> aSound);
|
||||||
|
|
||||||
void SetOutput(QAudioOutput *aOutput);
|
void SetOutput(QAudioOutput *aOutput);
|
||||||
private:
|
private:
|
||||||
|
|||||||
@ -13,22 +13,21 @@ StringTableViewer::~StringTableViewer()
|
|||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StringTableViewer::SetStringTable(std::shared_ptr<StringTable> aStringTable) {
|
void StringTableViewer::SetStringTable(const XStringTable *aStringTable) {
|
||||||
ui->tableWidget_Strings->clear();
|
ui->tableWidget_Strings->clear();
|
||||||
|
|
||||||
ui->tableWidget_Strings->setRowCount(aStringTable->rowCount);
|
ui->tableWidget_Strings->setRowCount(aStringTable->GetRowCount());
|
||||||
ui->tableWidget_Strings->setColumnCount(aStringTable->columnCount);
|
ui->tableWidget_Strings->setColumnCount(aStringTable->GetColumnCount());
|
||||||
|
|
||||||
int currentIndex = 0;
|
int currentIndex = 0;
|
||||||
for (const QString &key : aStringTable->content.keys()) {
|
for (auto value : *aStringTable->GetValues()) {
|
||||||
const QString value = aStringTable->content[key];
|
|
||||||
|
|
||||||
QTableWidgetItem *tableKeyItem = new QTableWidgetItem();
|
QTableWidgetItem *tableKeyItem = new QTableWidgetItem();
|
||||||
tableKeyItem->setText(key);
|
tableKeyItem->setText(value->GetName());
|
||||||
ui->tableWidget_Strings->setItem(currentIndex, 0, tableKeyItem);
|
ui->tableWidget_Strings->setItem(currentIndex, 0, tableKeyItem);
|
||||||
|
|
||||||
QTableWidgetItem *tableValItem = new QTableWidgetItem();
|
QTableWidgetItem *tableValItem = new QTableWidgetItem();
|
||||||
tableValItem->setText(value);
|
tableValItem->setText(value->GetString());
|
||||||
ui->tableWidget_Strings->setItem(currentIndex, 1, tableValItem);
|
ui->tableWidget_Strings->setItem(currentIndex, 1, tableValItem);
|
||||||
|
|
||||||
currentIndex++;
|
currentIndex++;
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
#ifndef STRINGTABLEVIEWER_H
|
#ifndef STRINGTABLEVIEWER_H
|
||||||
#define STRINGTABLEVIEWER_H
|
#define STRINGTABLEVIEWER_H
|
||||||
|
|
||||||
#include "asset_structs.h"
|
#include "xstringtable.h"
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
@ -16,7 +17,7 @@ public:
|
|||||||
explicit StringTableViewer(QWidget *parent = nullptr);
|
explicit StringTableViewer(QWidget *parent = nullptr);
|
||||||
~StringTableViewer();
|
~StringTableViewer();
|
||||||
|
|
||||||
void SetStringTable(std::shared_ptr<StringTable> aStringTable);
|
void SetStringTable(const XStringTable *aStringTable);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::StringTableViewer *ui;
|
Ui::StringTableViewer *ui;
|
||||||
|
|||||||
@ -13,13 +13,13 @@ TechSetViewer::~TechSetViewer()
|
|||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TechSetViewer::SetTechSet(std::shared_ptr<TechSet> aTechSet) {
|
void TechSetViewer::SetTechSet(const XMaterialTechniqueSet* aTechSet) {
|
||||||
ui->listWidget_Ptrs->clear();
|
//ui->listWidget_Ptrs->clear();
|
||||||
ui->label_Title->setText(aTechSet->name);
|
ui->label_Title->setText(aTechSet->GetName());
|
||||||
|
|
||||||
int ptrIndex = 1;
|
// int ptrIndex = 1;
|
||||||
for (auto ptr : aTechSet->pointers) {
|
//for (auto ptr : aTechSet->pointers) {
|
||||||
ui->listWidget_Ptrs->addItem(QString("Pointer %1: %2").arg(ptrIndex).arg(ptr));
|
// ui->listWidget_Ptrs->addItem(QString("Pointer %1: %2").arg(ptrIndex).arg(ptr));
|
||||||
ptrIndex++;
|
// ptrIndex++;
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
#ifndef TECHSETVIEWER_H
|
#ifndef TECHSETVIEWER_H
|
||||||
#define TECHSETVIEWER_H
|
#define TECHSETVIEWER_H
|
||||||
|
|
||||||
#include "asset_structs.h"
|
#include "xmaterialtechniqueset.h"
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
@ -16,7 +17,7 @@ public:
|
|||||||
explicit TechSetViewer(QWidget *parent = nullptr);
|
explicit TechSetViewer(QWidget *parent = nullptr);
|
||||||
~TechSetViewer();
|
~TechSetViewer();
|
||||||
|
|
||||||
void SetTechSet(std::shared_ptr<TechSet> aTechSet);
|
void SetTechSet(const XMaterialTechniqueSet *aTechSet);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::TechSetViewer *ui;
|
Ui::TechSetViewer *ui;
|
||||||
|
|||||||
@ -6,14 +6,14 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>961</width>
|
<width>880</width>
|
||||||
<height>756</height>
|
<height>559</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Form</string>
|
<string>Form</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label_Title">
|
<widget class="QLabel" name="label_Title">
|
||||||
<property name="font">
|
<property name="font">
|
||||||
@ -29,47 +29,121 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="groupBox">
|
<widget class="QGroupBox" name="groupBox">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Unknown Pointers:</string>
|
<string>Set Parameters</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QListWidget" name="listWidget_Ptrs"/>
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Name:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="lineEdit_Name">
|
||||||
|
<property name="placeholderText">
|
||||||
|
<string>Technique set name</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>World Vertex Format:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="spinBox_WorldVertFormat"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="listWidget_Techniques"/>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer name="horizontalSpacer">
|
<widget class="QGroupBox" name="groupBox_2">
|
||||||
<property name="orientation">
|
<property name="title">
|
||||||
<enum>Qt::Orientation::Horizontal</enum>
|
<string>Current Technique</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeHint" stdset="0">
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
<size>
|
<item>
|
||||||
<width>40</width>
|
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||||
<height>20</height>
|
<item>
|
||||||
</size>
|
<widget class="QLabel" name="label_4">
|
||||||
</property>
|
<property name="text">
|
||||||
</spacer>
|
<string>Name:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="lineEdit_TechniqueName">
|
||||||
|
<property name="placeholderText">
|
||||||
|
<string>Technique set name</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="text">
|
||||||
|
<string>Flags:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="spinBox_Flags"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_6">
|
||||||
|
<property name="text">
|
||||||
|
<string>Pass Count:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="spinBox_PassCount"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox_3">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string>Material Pass</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<spacer name="verticalSpacer">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Orientation::Vertical</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>20</width>
|
|
||||||
<height>363</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
|
|||||||
@ -5,10 +5,10 @@
|
|||||||
|
|
||||||
XTreeWidget::XTreeWidget(QWidget *parent)
|
XTreeWidget::XTreeWidget(QWidget *parent)
|
||||||
: QTreeWidget(parent) {
|
: QTreeWidget(parent) {
|
||||||
mFastFiles = QMap<QString, std::shared_ptr<FastFile>>();
|
mFastFiles = QMap<QString, const FastFile*>();
|
||||||
mZoneFiles = QMap<QString, std::shared_ptr<ZoneFile>>();
|
mZoneFiles = QMap<QString, const ZoneFile*>();
|
||||||
mDDSFiles = QMap<QString, std::shared_ptr<DDSFile>>();
|
mDDSFiles = QMap<QString, const DDSFile*>();
|
||||||
mIWIFiles = QMap<QString, std::shared_ptr<IWIFile>>();
|
mIWIFiles = QMap<QString, const IWIFile*>();
|
||||||
|
|
||||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
setSelectionMode(QTreeWidget::SingleSelection);
|
setSelectionMode(QTreeWidget::SingleSelection);
|
||||||
@ -37,7 +37,7 @@ XTreeWidget::~XTreeWidget() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void XTreeWidget::AddFastFile(std::shared_ptr<FastFile> aFastFile) {
|
void XTreeWidget::AddFastFile(FastFile* aFastFile) {
|
||||||
XTreeWidgetItem *fastFileItem = new XTreeWidgetItem(this);
|
XTreeWidgetItem *fastFileItem = new XTreeWidgetItem(this);
|
||||||
fastFileItem->setText(0, aFastFile->GetStem());
|
fastFileItem->setText(0, aFastFile->GetStem());
|
||||||
fastFileItem->setIcon(0, Utils::CreateAssetIcon("FF"));
|
fastFileItem->setIcon(0, Utils::CreateAssetIcon("FF"));
|
||||||
@ -83,211 +83,189 @@ void XTreeWidget::AddFastFile(std::shared_ptr<FastFile> aFastFile) {
|
|||||||
sortByColumn(0, Qt::AscendingOrder);
|
sortByColumn(0, Qt::AscendingOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
void XTreeWidget::AddZoneFile(std::shared_ptr<ZoneFile> aZoneFile, XTreeWidgetItem *aParentItem) {
|
void XTreeWidget::AddZoneFile(const ZoneFile* aZoneFile, XTreeWidgetItem *aParentItem) {
|
||||||
XTreeWidgetItem *zoneItem;
|
XTreeWidgetItem *zoneItem;
|
||||||
if (aParentItem != nullptr) {
|
if (aParentItem != nullptr) {
|
||||||
zoneItem = new XTreeWidgetItem(aParentItem);
|
zoneItem = new XTreeWidgetItem(aParentItem);
|
||||||
} else {
|
} else {
|
||||||
zoneItem = new XTreeWidgetItem(this);
|
zoneItem = new XTreeWidgetItem(this);
|
||||||
}
|
}
|
||||||
zoneItem->setIcon(0, ZoneFile::AssetTypeToIcon(ASSET_ZONE_FILE));
|
zoneItem->setIcon(0, Utils::CreateAssetIcon("ZF"));
|
||||||
zoneItem->setText(0, aZoneFile->GetBaseStem() + ".zone");
|
zoneItem->setText(0, aZoneFile->GetBaseStem() + ".zone");
|
||||||
|
|
||||||
auto assetMap = aZoneFile->GetAssetMap();
|
XAssetList assetList = aZoneFile->GetAssetList();
|
||||||
|
QVector<XAsset*> localizeEntries;
|
||||||
if (!assetMap.localStrings.isEmpty()) {
|
for (int i = 0; i < assetList.Size(); i++)
|
||||||
QIcon localStrIcon = ZoneFile::AssetTypeToIcon(ASSET_LOCAL_STRING);
|
{
|
||||||
|
XAsset *currentAsset = assetList.GetAsset(i);
|
||||||
XTreeWidgetItem *localStrRoot = new XTreeWidgetItem(zoneItem);
|
if (currentAsset->GetType() == ASSET_TYPE_LOCALIZE_ENTRY)
|
||||||
localStrRoot->setText(0, "String Files");
|
{
|
||||||
localStrRoot->setIcon(0, localStrIcon);
|
localizeEntries.append(currentAsset);
|
||||||
localStrRoot->SetCategory(CATEGORY_TYPE);
|
} else if (currentAsset->GetType() == ASSET_TYPE_LOCALIZE_ENTRY)
|
||||||
|
{
|
||||||
XTreeWidgetItem *localStrItem = new XTreeWidgetItem(localStrRoot);
|
localizeEntries.append(currentAsset);
|
||||||
localStrItem->setText(0, aZoneFile->GetStem().section('.', 0, 0) + ".str");
|
|
||||||
localStrItem->setIcon(0, localStrIcon);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!assetMap.techSets.isEmpty()) {
|
|
||||||
QIcon techSetIcon = ZoneFile::AssetTypeToIcon(ASSET_TECH_SET);
|
|
||||||
|
|
||||||
XTreeWidgetItem *techSetRoot = new XTreeWidgetItem(zoneItem);
|
|
||||||
techSetRoot->setText(0, "Tech Sets");
|
|
||||||
techSetRoot->setIcon(0, techSetIcon);
|
|
||||||
techSetRoot->SetCategory(CATEGORY_TYPE);
|
|
||||||
|
|
||||||
for (TechSet techSet : assetMap.techSets) {
|
|
||||||
XTreeWidgetItem *techSetItem = new XTreeWidgetItem(techSetRoot);
|
|
||||||
techSetItem->setText(0, techSet.name);
|
|
||||||
techSetItem->setIcon(0, techSetIcon);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!assetMap.rawFiles.isEmpty()) {
|
|
||||||
QIcon rawFileIcon = ZoneFile::AssetTypeToIcon(ASSET_RAW_FILE);
|
|
||||||
|
|
||||||
XTreeWidgetItem *rawFileRoot = new XTreeWidgetItem(zoneItem);
|
// if (!assetMap.localizeEntries.isEmpty()) {
|
||||||
rawFileRoot->setText(0, "Raw Files");
|
// QIcon localStrIcon = Utils::CreateAssetIcon(ASSET_TYPE_LOCALIZE_ENTRY);
|
||||||
rawFileRoot->setIcon(0, rawFileIcon);
|
|
||||||
rawFileRoot->SetCategory(CATEGORY_TYPE);
|
|
||||||
for (RawFile rawFile : assetMap.rawFiles) {
|
|
||||||
if (!rawFile.length) { continue; }
|
|
||||||
|
|
||||||
XTreeWidgetItem *tempItem = rawFileRoot;
|
// XTreeWidgetItem *localStrRoot = new XTreeWidgetItem(zoneItem);
|
||||||
const QStringList pathParts = rawFile.path.split('/');
|
// localStrRoot->setText(0, "String Files");
|
||||||
for (const QString &pathPart : pathParts) {
|
// localStrRoot->setIcon(0, localStrIcon);
|
||||||
bool childFound = false;
|
// localStrRoot->SetCategory(CATEGORY_TYPE);
|
||||||
for (int i = 0; i < tempItem->childCount(); i++) {
|
|
||||||
QTreeWidgetItem *rawChildItem = tempItem->child(i);
|
|
||||||
XTreeWidgetItem *childItem = dynamic_cast<XTreeWidgetItem*>(rawChildItem);
|
|
||||||
if (childItem->text(0) == pathPart) {
|
|
||||||
tempItem = childItem;
|
|
||||||
|
|
||||||
childFound = true;
|
// XTreeWidgetItem *localStrItem = new XTreeWidgetItem(localStrRoot);
|
||||||
break;
|
// localStrItem->setText(0, aZoneFile->GetStem().section('.', 0, 0) + ".str");
|
||||||
}
|
// localStrItem->setIcon(0, localStrIcon);
|
||||||
}
|
// }
|
||||||
|
|
||||||
const QString rawFileStr = QString("%1 [%2-%3]").arg(pathPart).arg(rawFile.startPos).arg(rawFile.endPos);
|
// if (!assetMap.techSets.isEmpty()) {
|
||||||
//rawFileStr = pathPart;
|
// QIcon techSetIcon = Utils::CreateAssetIcon(ASSET_TYPE_TECHNIQUE_SET);
|
||||||
if (pathPart == pathParts.last()) {
|
|
||||||
XTreeWidgetItem *rawFileItem = new XTreeWidgetItem(tempItem);
|
|
||||||
rawFileItem->setText(0, rawFileStr);
|
|
||||||
|
|
||||||
tempItem = rawFileItem;
|
// XTreeWidgetItem *techSetRoot = new XTreeWidgetItem(zoneItem);
|
||||||
} else if (!childFound) {
|
// techSetRoot->setText(0, "Tech Sets");
|
||||||
tempItem = new XTreeWidgetItem(tempItem);
|
// techSetRoot->setIcon(0, techSetIcon);
|
||||||
tempItem->setText(0, rawFileStr);
|
// techSetRoot->SetCategory(CATEGORY_TYPE);
|
||||||
}
|
|
||||||
|
|
||||||
}
|
// for (auto techSet : assetMap.techSets) {
|
||||||
tempItem->setIcon(0, rawFileIcon);
|
// XTreeWidgetItem *techSetItem = new XTreeWidgetItem(techSetRoot);
|
||||||
}
|
// techSetItem->setText(0, techSet.name);
|
||||||
}
|
// techSetItem->setIcon(0, techSetIcon);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
if (!assetMap.menuFiles.isEmpty()) {
|
// if (!assetMap.rawFiles.isEmpty()) {
|
||||||
QIcon menuFileIcon = ZoneFile::AssetTypeToIcon(ASSET_MENU);
|
// QIcon rawFileIcon = Utils::CreateAssetIcon(ASSET_TYPE_RAWFILE);
|
||||||
|
|
||||||
XTreeWidgetItem *menuRoot = new XTreeWidgetItem(zoneItem);
|
// XTreeWidgetItem *rawFileRoot = new XTreeWidgetItem(zoneItem);
|
||||||
menuRoot->setText(0, "Menu Files");
|
// rawFileRoot->setText(0, "Raw Files");
|
||||||
menuRoot->setIcon(0, menuFileIcon);
|
// rawFileRoot->setIcon(0, rawFileIcon);
|
||||||
menuRoot->SetCategory(CATEGORY_TYPE);
|
// rawFileRoot->SetCategory(CATEGORY_TYPE);
|
||||||
|
// for (auto rawFile : assetMap.rawFiles) {
|
||||||
|
// if (!rawFile.length) { continue; }
|
||||||
|
|
||||||
int menuIndex = 1;
|
// XTreeWidgetItem *tempItem = rawFileRoot;
|
||||||
for (MenuFile menuFile : assetMap.menuFiles) {
|
// // const QStringList pathParts = rawFile->path.split('/');
|
||||||
XTreeWidgetItem *menuFileRoot = new XTreeWidgetItem(menuRoot);
|
// // for (const QString &pathPart : pathParts) {
|
||||||
menuFileRoot->setText(0, QString("Menu %1").arg(menuIndex));
|
// // bool childFound = false;
|
||||||
for (Menu menu : menuFile.menuDefs) {
|
// // for (int i = 0; i < tempItem->childCount(); i++) {
|
||||||
XTreeWidgetItem *menuItem = new XTreeWidgetItem(menuFileRoot);
|
// // QTreeWidgetItem *rawChildItem = tempItem->child(i);
|
||||||
menuItem->setText(0, menu.filePath);
|
// // XTreeWidgetItem *childItem = dynamic_cast<XTreeWidgetItem*>(rawChildItem);
|
||||||
menuItem->setIcon(0, menuFileIcon);
|
// // if (childItem->text(0) == pathPart) {
|
||||||
}
|
// // tempItem = childItem;
|
||||||
menuIndex++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!assetMap.images.isEmpty()) {
|
// // childFound = true;
|
||||||
QIcon imageIcon = ZoneFile::AssetTypeToIcon(ASSET_IMAGE);
|
// // break;
|
||||||
|
// // }
|
||||||
|
// // }
|
||||||
|
|
||||||
XTreeWidgetItem *imageRoot = new XTreeWidgetItem(zoneItem);
|
// // const QString rawFileStr = pathPart;// = QString("%1 [%2-%3]").arg(pathPart).arg(rawFile.startPos).arg(rawFile.endPos);
|
||||||
imageRoot->setText(0, "Images");
|
// // if (pathPart == pathParts.last()) {
|
||||||
imageRoot->setIcon(0, imageIcon);
|
// // XTreeWidgetItem *rawFileItem = new XTreeWidgetItem(tempItem);
|
||||||
imageRoot->SetCategory(CATEGORY_TYPE);
|
// // rawFileItem->setText(0, rawFileStr);
|
||||||
|
|
||||||
for (Image image : assetMap.images) {
|
// // tempItem = rawFileItem;
|
||||||
XTreeWidgetItem *imageItem = new XTreeWidgetItem(imageRoot);
|
// // } else if (!childFound) {
|
||||||
imageItem->setText(0, image.materialName);
|
// // tempItem = new XTreeWidgetItem(tempItem);
|
||||||
imageItem->setIcon(0, imageIcon);
|
// // tempItem->setText(0, rawFileStr);
|
||||||
}
|
// // }
|
||||||
}
|
|
||||||
|
|
||||||
if (!assetMap.models.isEmpty()) {
|
// // }
|
||||||
QIcon modelIcon = ZoneFile::AssetTypeToIcon(ASSET_MODEL);
|
// tempItem->setIcon(0, rawFileIcon);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
XTreeWidgetItem *modelsRoot = new XTreeWidgetItem(zoneItem);
|
// if (!assetMap.menuDefinitions.isEmpty()) {
|
||||||
modelsRoot->setText(0, "Models");
|
// // QIcon MenuDefIcon = Utils::CreateAssetIcon(ASSET_TYPE_MENU);
|
||||||
modelsRoot->setIcon(0, modelIcon);
|
|
||||||
modelsRoot->SetCategory(CATEGORY_TYPE);
|
|
||||||
|
|
||||||
for (Model model: assetMap.models) {
|
// // XTreeWidgetItem *menuRoot = new XTreeWidgetItem(zoneItem);
|
||||||
XTreeWidgetItem *modelItem = new XTreeWidgetItem(modelsRoot);
|
// // menuRoot->setText(0, "Menu Files");
|
||||||
modelItem->setText(0, model.modelName);
|
// // menuRoot->setIcon(0, MenuDefIcon);
|
||||||
modelItem->setIcon(0, modelIcon);
|
// // menuRoot->SetCategory(CATEGORY_TYPE);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!assetMap.materials.isEmpty()) {
|
// // int menuIndex = 1;
|
||||||
QIcon materialIcon = ZoneFile::AssetTypeToIcon(ASSET_MATERIAL);
|
// // for (MenuDef menuDef : assetMap.menuDefinitions) {
|
||||||
|
// // XTreeWidgetItem *MenuDefRoot = new XTreeWidgetItem(menuRoot);
|
||||||
|
// // MenuDefRoot->setText(0, QString("Menu %1").arg(menuIndex));
|
||||||
|
// // for (Menu menu : menuDef.men) {
|
||||||
|
// // XTreeWidgetItem *menuItem = new XTreeWidgetItem(MenuDefRoot);
|
||||||
|
// // menuItem->setText(0, menu.filePath);
|
||||||
|
// // menuItem->setIcon(0, MenuDefIcon);
|
||||||
|
// // }
|
||||||
|
// // menuIndex++;
|
||||||
|
// // }
|
||||||
|
// }
|
||||||
|
|
||||||
XTreeWidgetItem *materialsRoot = new XTreeWidgetItem(zoneItem);
|
// if (!assetMap.images.isEmpty()) {
|
||||||
materialsRoot->setText(0, "Materials");
|
// // QIcon imageIcon = Utils::CreateAssetIcon(ASSET_TYPE_IMAGE);
|
||||||
materialsRoot->setIcon(0, materialIcon);
|
|
||||||
materialsRoot->SetCategory(CATEGORY_TYPE);
|
|
||||||
|
|
||||||
for (Material material: assetMap.materials) {
|
// // XTreeWidgetItem *imageRoot = new XTreeWidgetItem(zoneItem);
|
||||||
XTreeWidgetItem *materialItem = new XTreeWidgetItem(materialsRoot);
|
// // imageRoot->setText(0, "Images");
|
||||||
materialItem->setText(0, material.name);
|
// // imageRoot->setIcon(0, imageIcon);
|
||||||
materialItem->setIcon(0, materialIcon);
|
// // imageRoot->SetCategory(CATEGORY_TYPE);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!assetMap.stringTables.isEmpty()) {
|
// // for (Image image : assetMap.images) {
|
||||||
QIcon stringTableIcon = ZoneFile::AssetTypeToIcon(ASSET_STRING_TABLE);
|
// // XTreeWidgetItem *imageItem = new XTreeWidgetItem(imageRoot);
|
||||||
|
// // imageItem->setText(0, image.materialName);
|
||||||
|
// // imageItem->setIcon(0, imageIcon);
|
||||||
|
// // }
|
||||||
|
// }
|
||||||
|
|
||||||
XTreeWidgetItem *strTableRoot = new XTreeWidgetItem(zoneItem);
|
// if (!assetMap.models.isEmpty()) {
|
||||||
strTableRoot->setText(0, "String Tables");
|
// QIcon modelIcon = Utils::CreateAssetIcon(ASSET_TYPE_XMODEL);
|
||||||
strTableRoot->setIcon(0, stringTableIcon);
|
|
||||||
strTableRoot->SetCategory(CATEGORY_TYPE);
|
|
||||||
|
|
||||||
for (StringTable strTable: assetMap.stringTables) {
|
// XTreeWidgetItem *modelsRoot = new XTreeWidgetItem(zoneItem);
|
||||||
XTreeWidgetItem *modelItem = new XTreeWidgetItem(strTableRoot);
|
// modelsRoot->setText(0, "Models");
|
||||||
modelItem->setText(0, strTable.name);
|
// modelsRoot->setIcon(0, modelIcon);
|
||||||
modelItem->setIcon(0, stringTableIcon);
|
// modelsRoot->SetCategory(CATEGORY_TYPE);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!assetMap.sounds.isEmpty()) {
|
// for (auto model: assetMap.models) {
|
||||||
QIcon soundIcon = ZoneFile::AssetTypeToIcon(ASSET_SOUND);
|
// XTreeWidgetItem *modelItem = new XTreeWidgetItem(modelsRoot);
|
||||||
|
// modelItem->setText(0, model.name);
|
||||||
|
// modelItem->setIcon(0, modelIcon);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
XTreeWidgetItem *soundsRoot = new XTreeWidgetItem(zoneItem);
|
// if (!assetMap.materials.isEmpty()) {
|
||||||
soundsRoot->setText(0, "Sounds");
|
// QIcon materialIcon = Utils::CreateAssetIcon(ASSET_TYPE_MATERIAL);
|
||||||
soundsRoot->setIcon(0, soundIcon);
|
|
||||||
soundsRoot->SetCategory(CATEGORY_TYPE);
|
|
||||||
for (SoundAsset soundAsset : assetMap.sounds) {
|
|
||||||
for (Sound sound : soundAsset.sounds) {
|
|
||||||
XTreeWidgetItem *tempItem = soundsRoot;
|
|
||||||
|
|
||||||
if (!sound.dataLength) { continue; }
|
// XTreeWidgetItem *materialsRoot = new XTreeWidgetItem(zoneItem);
|
||||||
|
// materialsRoot->setText(0, "Materials");
|
||||||
|
// materialsRoot->setIcon(0, materialIcon);
|
||||||
|
// materialsRoot->SetCategory(CATEGORY_TYPE);
|
||||||
|
|
||||||
for (const QString &pathPart : sound.path.split('/')) {
|
// for (auto material: assetMap.materials) {
|
||||||
if (pathPart.isEmpty()) { continue; }
|
// XTreeWidgetItem *materialItem = new XTreeWidgetItem(materialsRoot);
|
||||||
|
// //materialItem->setText(0, material.name);
|
||||||
|
// materialItem->setIcon(0, materialIcon);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
bool childFound = false;
|
// if (!assetMap.stringTables.isEmpty()) {
|
||||||
for (int i = 0; i < tempItem->childCount(); i++) {
|
// QIcon stringTableIcon = Utils::CreateAssetIcon(ASSET_TYPE_STRINGTABLE);
|
||||||
XTreeWidgetItem *childItem = dynamic_cast<XTreeWidgetItem*>(tempItem->child(i));
|
|
||||||
if (childItem->text(0) == pathPart) {
|
|
||||||
tempItem = childItem;
|
|
||||||
|
|
||||||
childFound = true;
|
// XTreeWidgetItem *strTableRoot = new XTreeWidgetItem(zoneItem);
|
||||||
break;
|
// strTableRoot->setText(0, "String Tables");
|
||||||
}
|
// strTableRoot->setIcon(0, stringTableIcon);
|
||||||
}
|
// strTableRoot->SetCategory(CATEGORY_TYPE);
|
||||||
|
|
||||||
if (pathPart.contains(".wav")) {
|
// for (auto strTable: assetMap.stringTables) {
|
||||||
XTreeWidgetItem *soundItem = new XTreeWidgetItem(tempItem);
|
// XTreeWidgetItem *modelItem = new XTreeWidgetItem(strTableRoot);
|
||||||
soundItem->setText(0, pathPart);
|
// modelItem->setText(0, strTable.name);
|
||||||
|
// modelItem->setIcon(0, stringTableIcon);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
tempItem = soundItem;
|
// if (!assetMap.sounds.isEmpty()) {
|
||||||
} else if (!childFound) {
|
// QIcon soundIcon = Utils::CreateAssetIcon(ASSET_TYPE_SOUND);
|
||||||
tempItem = new XTreeWidgetItem(tempItem);
|
|
||||||
tempItem->setText(0, pathPart);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
// XTreeWidgetItem *soundsRoot = new XTreeWidgetItem(zoneItem);
|
||||||
tempItem->setIcon(0, soundIcon);
|
// soundsRoot->setText(0, "Sounds");
|
||||||
}
|
// soundsRoot->setIcon(0, soundIcon);
|
||||||
}
|
// soundsRoot->SetCategory(CATEGORY_TYPE);
|
||||||
}
|
// }
|
||||||
|
|
||||||
mZoneFiles[aZoneFile->GetBaseStem() + ".zone"] = aZoneFile;
|
mZoneFiles[aZoneFile->GetBaseStem() + ".zone"] = aZoneFile;
|
||||||
}
|
}
|
||||||
@ -324,7 +302,7 @@ void XTreeWidget::PrepareContextMenu(const QPoint &pos) {
|
|||||||
QMenu *exportSubmenu = new QMenu("Export...", this);
|
QMenu *exportSubmenu = new QMenu("Export...", this);
|
||||||
contextMenu->addMenu(exportSubmenu);
|
contextMenu->addMenu(exportSubmenu);
|
||||||
|
|
||||||
std::shared_ptr<DDSFile> ddsFile = mDDSFiles[fileStem];
|
const DDSFile* ddsFile = mDDSFiles[fileStem];
|
||||||
|
|
||||||
QAction *exportIWIAction = new QAction("Export as IWI");
|
QAction *exportIWIAction = new QAction("Export as IWI");
|
||||||
exportSubmenu->addAction(exportIWIAction);
|
exportSubmenu->addAction(exportIWIAction);
|
||||||
@ -368,7 +346,7 @@ void XTreeWidget::PrepareContextMenu(const QPoint &pos) {
|
|||||||
QMenu *exportSubmenu = new QMenu("Export...", this);
|
QMenu *exportSubmenu = new QMenu("Export...", this);
|
||||||
contextMenu->addMenu(exportSubmenu);
|
contextMenu->addMenu(exportSubmenu);
|
||||||
|
|
||||||
std::shared_ptr<IWIFile> iwiFile = mIWIFiles[fileStem];
|
const IWIFile* iwiFile = mIWIFiles[fileStem];
|
||||||
|
|
||||||
QAction *exportDDSAction = new QAction("Export as DDS");
|
QAction *exportDDSAction = new QAction("Export as DDS");
|
||||||
exportSubmenu->addAction(exportDDSAction);
|
exportSubmenu->addAction(exportDDSAction);
|
||||||
@ -497,7 +475,7 @@ void XTreeWidget::PrepareContextMenu(const QPoint &pos) {
|
|||||||
QMenu *exportSubmenu = new QMenu("Export...", this);
|
QMenu *exportSubmenu = new QMenu("Export...", this);
|
||||||
contextMenu->addMenu(exportSubmenu);
|
contextMenu->addMenu(exportSubmenu);
|
||||||
|
|
||||||
std::shared_ptr<FastFile> fastFile = mFastFiles[fileStem];
|
const FastFile* fastFile = mFastFiles[fileStem];
|
||||||
|
|
||||||
QAction *exportFastFileAction = new QAction("Export Fast File");
|
QAction *exportFastFileAction = new QAction("Export Fast File");
|
||||||
exportSubmenu->addAction(exportFastFileAction);
|
exportSubmenu->addAction(exportFastFileAction);
|
||||||
@ -512,13 +490,13 @@ void XTreeWidget::PrepareContextMenu(const QPoint &pos) {
|
|||||||
});
|
});
|
||||||
QAction *exportZoneFileAction = new QAction("Export Zone File");
|
QAction *exportZoneFileAction = new QAction("Export Zone File");
|
||||||
exportSubmenu->addAction(exportZoneFileAction);
|
exportSubmenu->addAction(exportZoneFileAction);
|
||||||
connect(exportZoneFileAction, &QAction::triggered, this, [fastFile](bool checked) {
|
connect(exportZoneFileAction, &QAction::triggered, this, [](bool checked) {
|
||||||
Q_UNUSED(checked);
|
Q_UNUSED(checked);
|
||||||
|
|
||||||
const QString zoneFilePath = QFileDialog::getSaveFileName(
|
// const QString zoneFilePath = QFileDialog::getSaveFileName(
|
||||||
nullptr, "Export Zone File...", QDir::currentPath(),
|
// nullptr, "Export Zone File...", QDir::currentPath(),
|
||||||
"Zone File (*.zone);;All Files(*.*)");
|
// "Zone File (*.zone);;All Files(*.*)");
|
||||||
fastFile->GetZoneFile()->SaveZoneFile(zoneFilePath);
|
//fastFile->GetZoneFile()->SaveZoneFile(zoneFilePath);
|
||||||
});
|
});
|
||||||
} else if (activeText.contains(".zone")) {
|
} else if (activeText.contains(".zone")) {
|
||||||
const QString fileStem = activeText;
|
const QString fileStem = activeText;
|
||||||
@ -530,7 +508,7 @@ void XTreeWidget::PrepareContextMenu(const QPoint &pos) {
|
|||||||
QMenu *exportSubmenu = new QMenu("Export...", this);
|
QMenu *exportSubmenu = new QMenu("Export...", this);
|
||||||
contextMenu->addMenu(exportSubmenu);
|
contextMenu->addMenu(exportSubmenu);
|
||||||
|
|
||||||
std::shared_ptr<ZoneFile> zoneFile = mZoneFiles[fileStem];
|
//const ZoneFile* zoneFile = mZoneFiles[fileStem];
|
||||||
|
|
||||||
QAction *exportZoneFileAction = new QAction("Export Zone File");
|
QAction *exportZoneFileAction = new QAction("Export Zone File");
|
||||||
exportSubmenu->addAction(exportZoneFileAction);
|
exportSubmenu->addAction(exportZoneFileAction);
|
||||||
@ -552,41 +530,41 @@ void XTreeWidget::PrepareContextMenu(const QPoint &pos) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (parentItem && parentItem != invisibleRootItem() && parentItem->text(0).contains(".zone")) {
|
if (parentItem && parentItem != invisibleRootItem() && parentItem->text(0).contains(".zone")) {
|
||||||
const QString fileStem = parentItem->text(0).section('.', 0, 0);
|
//const QString fileStem = parentItem->text(0).section('.', 0, 0);
|
||||||
QVector<SoundAsset> soundAssets = mZoneFiles[fileStem]->GetAssetMap().sounds;
|
// QVector<LoadedSound> LoadedSounds = mZoneFiles[fileStem]->GetAssetMap().sounds;
|
||||||
for (SoundAsset soundAsset : soundAssets) {
|
// for (LoadedSound LoadedSound : LoadedSounds) {
|
||||||
for (Sound sound : soundAsset.sounds) {
|
// for (Sound sound : LoadedSound.sounds) {
|
||||||
if (sound.path.contains(activeText)) {
|
// if (sound.path.contains(activeText)) {
|
||||||
QMenu *exportSubmenu = new QMenu("Export...", this);
|
// QMenu *exportSubmenu = new QMenu("Export...", this);
|
||||||
contextMenu->addMenu(exportSubmenu);
|
// contextMenu->addMenu(exportSubmenu);
|
||||||
|
|
||||||
QAction *exportWAVAction = new QAction("Export as WAV File");
|
// QAction *exportWAVAction = new QAction("Export as WAV File");
|
||||||
exportSubmenu->addAction(exportWAVAction);
|
// exportSubmenu->addAction(exportWAVAction);
|
||||||
connect(exportWAVAction, &QAction::triggered, this, [sound](bool checked) {
|
// connect(exportWAVAction, &QAction::triggered, this, [sound](bool checked) {
|
||||||
Q_UNUSED(checked);
|
// Q_UNUSED(checked);
|
||||||
|
|
||||||
QDir dir = QDir::currentPath();
|
// QDir dir = QDir::currentPath();
|
||||||
if (!dir.exists("exports/")) {
|
// if (!dir.exists("exports/")) {
|
||||||
dir.mkdir("exports/");
|
// dir.mkdir("exports/");
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (!dir.exists("exports/sounds/")) {
|
// if (!dir.exists("exports/sounds/")) {
|
||||||
dir.mkdir("exports/sounds/");
|
// dir.mkdir("exports/sounds/");
|
||||||
}
|
// }
|
||||||
|
|
||||||
const QString fileName = "exports/sounds/" + sound.path.split('/').last();
|
// const QString fileName = "exports/sounds/" + sound.path.split('/').last();
|
||||||
QFile wavFile(fileName);
|
// QFile wavFile(fileName);
|
||||||
if (!wavFile.open(QIODevice::WriteOnly)) {
|
// if (!wavFile.open(QIODevice::WriteOnly)) {
|
||||||
qDebug() << "Failed to write wav file!";
|
// qDebug() << "Failed to write wav file!";
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
wavFile.write(sound.data);
|
// wavFile.write(sound.data);
|
||||||
wavFile.close();
|
// wavFile.close();
|
||||||
});
|
// });
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
} else if (activeItem && activeText == "Sounds") {
|
} else if (activeItem && activeText == "Sounds") {
|
||||||
XTreeWidgetItem *parentItem = dynamic_cast<XTreeWidgetItem*>(activeItem->parent());
|
XTreeWidgetItem *parentItem = dynamic_cast<XTreeWidgetItem*>(activeItem->parent());
|
||||||
@ -599,39 +577,39 @@ void XTreeWidget::PrepareContextMenu(const QPoint &pos) {
|
|||||||
}
|
}
|
||||||
if (parentItem && parentItem != invisibleRootItem() && parentItem->text(0).contains(".zone")) {
|
if (parentItem && parentItem != invisibleRootItem() && parentItem->text(0).contains(".zone")) {
|
||||||
const QString fileStem = parentItem->text(0).section('.', 0, 0);
|
const QString fileStem = parentItem->text(0).section('.', 0, 0);
|
||||||
auto zoneFile = mZoneFiles[fileStem];
|
//auto zoneFile = mZoneFiles[fileStem];
|
||||||
|
|
||||||
QMenu *exportSubmenu = new QMenu("Export...", this);
|
QMenu *exportSubmenu = new QMenu("Export...", this);
|
||||||
contextMenu->addMenu(exportSubmenu);
|
contextMenu->addMenu(exportSubmenu);
|
||||||
|
|
||||||
QAction *exportAllWAVAction = new QAction("Export ALL as WAV Files");
|
QAction *exportAllWAVAction = new QAction("Export ALL as WAV Files");
|
||||||
exportSubmenu->addAction(exportAllWAVAction);
|
exportSubmenu->addAction(exportAllWAVAction);
|
||||||
connect(exportAllWAVAction, &QAction::triggered, this, [zoneFile](bool checked) {
|
connect(exportAllWAVAction, &QAction::triggered, this, [](bool checked) {
|
||||||
Q_UNUSED(checked);
|
Q_UNUSED(checked);
|
||||||
|
|
||||||
for (SoundAsset soundAsset : zoneFile->GetAssetMap().sounds) {
|
// for (LoadedSound LoadedSound : zoneFile->GetAssetMap().sounds) {
|
||||||
for (Sound sound : soundAsset.sounds) {
|
// for (Sound sound : LoadedSound.sounds) {
|
||||||
if (!sound.dataLength) { continue; }
|
// if (!sound.dataLength) { continue; }
|
||||||
|
|
||||||
QDir dir = QDir::currentPath();
|
// QDir dir = QDir::currentPath();
|
||||||
if (!dir.exists("exports/")) {
|
// if (!dir.exists("exports/")) {
|
||||||
dir.mkdir("exports/");
|
// dir.mkdir("exports/");
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (!dir.exists("exports/sounds/")) {
|
// if (!dir.exists("exports/sounds/")) {
|
||||||
dir.mkdir("exports/sounds/");
|
// dir.mkdir("exports/sounds/");
|
||||||
}
|
// }
|
||||||
|
|
||||||
const QString fileName = "exports/sounds/" + sound.path.split('/').last();
|
// const QString fileName = "exports/sounds/" + sound.path.split('/').last();
|
||||||
QFile wavFile(fileName);
|
// QFile wavFile(fileName);
|
||||||
if (!wavFile.open(QIODevice::WriteOnly)) {
|
// if (!wavFile.open(QIODevice::WriteOnly)) {
|
||||||
qDebug() << "Failed to write wav file!";
|
// qDebug() << "Failed to write wav file!";
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
wavFile.write(sound.data);
|
// wavFile.write(sound.data);
|
||||||
wavFile.close();
|
// wavFile.close();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -653,20 +631,19 @@ void XTreeWidget::ItemSelectionChanged() {
|
|||||||
|
|
||||||
XTreeWidgetItem *parentItem = dynamic_cast<XTreeWidgetItem*>(selectedItem->parent());
|
XTreeWidgetItem *parentItem = dynamic_cast<XTreeWidgetItem*>(selectedItem->parent());
|
||||||
|
|
||||||
if (selectedText.contains(".dds")) {
|
/*if (selectedText.contains(".dds")) {
|
||||||
if (!mDDSFiles.contains(selectedText)) {
|
if (!mDDSFiles.contains(selectedText)) {
|
||||||
LogManager::instance().addError("Could not find " + selectedText + " in DDS map!");
|
LogManager::instance().addError("Could not find " + selectedText + " in DDS map!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::shared_ptr<DDSFile> ddsFile = mDDSFiles[selectedText];
|
emit DDSFileSelected(mDDSFiles[selectedText], selectedText);
|
||||||
emit DDSFileSelected(ddsFile, selectedText);
|
|
||||||
} else if (selectedText.contains(".iwi")) {
|
} else if (selectedText.contains(".iwi")) {
|
||||||
if (!mIWIFiles.contains(selectedText)) {
|
if (!mIWIFiles.contains(selectedText)) {
|
||||||
LogManager::instance().addError("Could not find " + selectedText + " in IWI map!");
|
LogManager::instance().addError("Could not find " + selectedText + " in IWI map!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
emit IWIFileSelected(mIWIFiles[selectedText], selectedText);
|
emit IWIFileSelected(mIWIFiles[selectedText], selectedText);
|
||||||
} else if (selectedText.contains(".ff")) {
|
} else */if (selectedText.contains(".ff")) {
|
||||||
if (!mFastFiles.contains(selectedText)) {
|
if (!mFastFiles.contains(selectedText)) {
|
||||||
LogManager::instance().addError("Could not find " + selectedText + " in Fast File map!");
|
LogManager::instance().addError("Could not find " + selectedText + " in Fast File map!");
|
||||||
return;
|
return;
|
||||||
@ -688,34 +665,22 @@ void XTreeWidget::ItemSelectionChanged() {
|
|||||||
XTreeWidgetItem *grandpaItem = dynamic_cast<XTreeWidgetItem*>(parentItem->parent());
|
XTreeWidgetItem *grandpaItem = dynamic_cast<XTreeWidgetItem*>(parentItem->parent());
|
||||||
if (grandpaItem && grandpaItem->text(0).contains(".zone")) {
|
if (grandpaItem && grandpaItem->text(0).contains(".zone")) {
|
||||||
const QString fileStem = grandpaItem->text(0).section('.', 0, 0);
|
const QString fileStem = grandpaItem->text(0).section('.', 0, 0);
|
||||||
QVector<Image> images = mZoneFiles[fileStem]->GetAssetMap().images;
|
// QVector<Image> images = mZoneFiles[fileStem]->GetAssetMap().images;
|
||||||
for (Image image : images) {
|
// for (Image image : images) {
|
||||||
if (image.materialName == selectedText) {
|
// if (image.materialName == selectedText) {
|
||||||
emit ImageSelected(std::make_shared<Image>(image), fileStem);
|
// emit ImageSelected(std::make_shared<Image>(image), fileStem);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
} else if (parentItem && (parentItem->text(0) == "Tech Sets")) {
|
} /*else if (parentItem && (parentItem->text(0) == "Tech Sets")) {
|
||||||
XTreeWidgetItem *grandpaItem = dynamic_cast<XTreeWidgetItem*>(parentItem->parent());
|
XTreeWidgetItem *grandpaItem = dynamic_cast<XTreeWidgetItem*>(parentItem->parent());
|
||||||
if (grandpaItem && grandpaItem->text(0).contains(".zone")) {
|
if (grandpaItem && grandpaItem->text(0).contains(".zone")) {
|
||||||
const QString fileStem = grandpaItem->text(0).section('.', 0, 0);
|
const QString fileStem = grandpaItem->text(0).section('.', 0, 0);
|
||||||
auto techsets = mZoneFiles[fileStem]->GetAssetMap().techSets;
|
auto techsets = mZoneFiles[fileStem]->GetAssetList().techSets;
|
||||||
for (auto techset : techsets) {
|
for (auto techset : techsets) {
|
||||||
if (techset.name == selectedText) {
|
if (techset.name == selectedText) {
|
||||||
emit TechSetSelected(std::make_shared<TechSet>(techset), fileStem);
|
emit TechSetSelected(new MaterialTechSet(techset), fileStem);
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (parentItem && (parentItem->text(0) == "Tech Sets")) {
|
|
||||||
XTreeWidgetItem *grandpaItem = dynamic_cast<XTreeWidgetItem*>(parentItem->parent());
|
|
||||||
if (grandpaItem && grandpaItem->text(0).contains(".zone")) {
|
|
||||||
const QString fileStem = grandpaItem->text(0).section('.', 0, 0);
|
|
||||||
auto techsets = mZoneFiles[fileStem]->GetAssetMap().techSets;
|
|
||||||
for (auto techset : techsets) {
|
|
||||||
if (techset.name == selectedText) {
|
|
||||||
emit TechSetSelected(std::make_shared<TechSet>(techset), fileStem);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -724,12 +689,12 @@ void XTreeWidget::ItemSelectionChanged() {
|
|||||||
XTreeWidgetItem *grandpaItem = dynamic_cast<XTreeWidgetItem*>(parentItem->parent());
|
XTreeWidgetItem *grandpaItem = dynamic_cast<XTreeWidgetItem*>(parentItem->parent());
|
||||||
if (grandpaItem && grandpaItem->text(0).contains(".zone")) {
|
if (grandpaItem && grandpaItem->text(0).contains(".zone")) {
|
||||||
const QString fileStem = grandpaItem->text(0).section('.', 0, 0);
|
const QString fileStem = grandpaItem->text(0).section('.', 0, 0);
|
||||||
QVector<Material> materials = mZoneFiles[fileStem]->GetAssetMap().materials;
|
auto materials = mZoneFiles[fileStem]->GetAssetMap().materials;
|
||||||
for (Material material : materials) {
|
for (auto material : materials) {
|
||||||
if (material.name == selectedText) {
|
// if (material.name == selectedText) {
|
||||||
emit MaterialSelected(std::make_shared<Material>(material), fileStem);
|
// emit MaterialSelected(std::make_shared<Material>(material), fileStem);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (parentItem && selectedText.contains(".wav")) {
|
} else if (parentItem && selectedText.contains(".wav")) {
|
||||||
@ -743,15 +708,15 @@ void XTreeWidget::ItemSelectionChanged() {
|
|||||||
}
|
}
|
||||||
if (grandpaItem && grandpaItem != invisibleRootItem() && grandpaItem->text(0).contains(".zone")) {
|
if (grandpaItem && grandpaItem != invisibleRootItem() && grandpaItem->text(0).contains(".zone")) {
|
||||||
const QString fileStem = grandpaItem->text(0).section('.', 0, 0);
|
const QString fileStem = grandpaItem->text(0).section('.', 0, 0);
|
||||||
QVector<SoundAsset> soundAssets = mZoneFiles[fileStem]->GetAssetMap().sounds;
|
// QVector<LoadedSound> LoadedSounds = mZoneFiles[fileStem]->GetAssetMap().sounds;
|
||||||
for (SoundAsset soundAsset : soundAssets) {
|
// for (LoadedSound LoadedSound : LoadedSounds) {
|
||||||
for (Sound sound : soundAsset.sounds) {
|
// for (Sound sound : LoadedSound.sounds) {
|
||||||
if (sound.path.contains(selectedText)) {
|
// if (sound.path.contains(selectedText)) {
|
||||||
emit SoundSelected(std::make_shared<Sound>(sound), fileStem);
|
// emit SoundSelected(std::make_shared<Sound>(sound), fileStem);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
} else if (selectedItem->GetCategory() != CATEGORY_TYPE) {
|
} else if (selectedItem->GetCategory() != CATEGORY_TYPE) {
|
||||||
XTreeWidgetItem *zoneRoot = selectedItem;
|
XTreeWidgetItem *zoneRoot = selectedItem;
|
||||||
@ -772,17 +737,17 @@ void XTreeWidget::ItemSelectionChanged() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<RawFile> rawFiles = mZoneFiles[fileStem]->GetAssetMap().rawFiles;
|
auto rawFiles = mZoneFiles[fileStem]->GetAssetMap().rawFiles;
|
||||||
for (RawFile rawFile : rawFiles) {
|
for (auto rawFile : rawFiles) {
|
||||||
if (rawFile.path.split('/').last() == selectedText) {
|
//if (rawFile->path.split('/').last() == selectedText) {
|
||||||
emit RawFileSelected(std::make_shared<RawFile>(rawFile), fileStem);
|
// emit RawFileSelected(std::make_shared<RawFile>(rawFile), fileStem);
|
||||||
return;
|
// return;
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<ZoneFile> XTreeWidget::FindZoneFile(const QString aStem) {
|
const ZoneFile* XTreeWidget::FindZoneFile(const QString aStem) {
|
||||||
foreach (auto zoneFile, mZoneFiles) {
|
foreach (auto zoneFile, mZoneFiles) {
|
||||||
if (zoneFile->GetStem() == aStem) {
|
if (zoneFile->GetStem() == aStem) {
|
||||||
return zoneFile;
|
return zoneFile;
|
||||||
@ -791,7 +756,7 @@ std::shared_ptr<ZoneFile> XTreeWidget::FindZoneFile(const QString aStem) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<FastFile> XTreeWidget::FindFastFile(const QString aStem) {
|
const FastFile *XTreeWidget::FindFastFile(const QString aStem) {
|
||||||
foreach (auto fastFile, mFastFiles) {
|
foreach (auto fastFile, mFastFiles) {
|
||||||
if (fastFile->GetStem() == aStem) {
|
if (fastFile->GetStem() == aStem) {
|
||||||
return fastFile;
|
return fastFile;
|
||||||
@ -808,7 +773,7 @@ bool XTreeWidget::HasFastFile(const QString aStem) {
|
|||||||
return FindFastFile(aStem) != nullptr;
|
return FindFastFile(aStem) != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void XTreeWidget::AddIWIFile(std::shared_ptr<IWIFile> aIWIFile) {
|
void XTreeWidget::AddIWIFile(IWIFile* aIWIFile) {
|
||||||
const QString iwiFileName = QString(aIWIFile->fileStem + ".iwi");
|
const QString iwiFileName = QString(aIWIFile->fileStem + ".iwi");
|
||||||
|
|
||||||
for (int i = 0; i < invisibleRootItem()->childCount(); i++) {
|
for (int i = 0; i < invisibleRootItem()->childCount(); i++) {
|
||||||
@ -819,12 +784,12 @@ void XTreeWidget::AddIWIFile(std::shared_ptr<IWIFile> aIWIFile) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
XTreeWidgetItem *iwiItem = new XTreeWidgetItem(this);
|
XTreeWidgetItem *iwiItem = new XTreeWidgetItem(this);
|
||||||
iwiItem->setIcon(0, ZoneFile::AssetTypeToIcon(ASSET_IMAGE));
|
iwiItem->setIcon(0, Utils::CreateAssetIcon(ASSET_TYPE_IMAGE));
|
||||||
iwiItem->setText(0, iwiFileName);
|
iwiItem->setText(0, iwiFileName);
|
||||||
mIWIFiles[aIWIFile->fileStem.section(".", 0, 0)] = aIWIFile;
|
mIWIFiles[aIWIFile->fileStem.section(".", 0, 0)] = aIWIFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
void XTreeWidget::AddDDSFile(std::shared_ptr<DDSFile> aDDSFile) {
|
void XTreeWidget::AddDDSFile(DDSFile* aDDSFile) {
|
||||||
const QString ddsFileName = QString(aDDSFile->fileStem + ".dds");
|
const QString ddsFileName = QString(aDDSFile->fileStem + ".dds");
|
||||||
|
|
||||||
for (int i = 0; i < invisibleRootItem()->childCount(); i++) {
|
for (int i = 0; i < invisibleRootItem()->childCount(); i++) {
|
||||||
@ -835,7 +800,7 @@ void XTreeWidget::AddDDSFile(std::shared_ptr<DDSFile> aDDSFile) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
XTreeWidgetItem *ddsItem = new XTreeWidgetItem(this);
|
XTreeWidgetItem *ddsItem = new XTreeWidgetItem(this);
|
||||||
ddsItem->setIcon(0, ZoneFile::AssetTypeToIcon(ASSET_IMAGE));
|
ddsItem->setIcon(0, Utils::CreateAssetIcon(ASSET_TYPE_IMAGE));
|
||||||
ddsItem->setText(0, ddsFileName);
|
ddsItem->setText(0, ddsFileName);
|
||||||
mDDSFiles[aDDSFile->fileStem.section(".", 0, 0)] = aDDSFile;
|
mDDSFiles[aDDSFile->fileStem.section(".", 0, 0)] = aDDSFile;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,13 +2,16 @@
|
|||||||
#define XTREEWIDGET_H
|
#define XTREEWIDGET_H
|
||||||
|
|
||||||
#include "d3dbsp_structs.h"
|
#include "d3dbsp_structs.h"
|
||||||
#include "asset_structs.h"
|
|
||||||
#include "ddsfile.h"
|
#include "ddsfile.h"
|
||||||
#include "iwifile.h"
|
#include "iwifile.h"
|
||||||
#include "fastfile.h"
|
#include "fastfile.h"
|
||||||
|
#include "xloadedsound.h"
|
||||||
#include "xtreewidgetitem.h"
|
#include "xtreewidgetitem.h"
|
||||||
#include "zonefile.h"
|
#include "zonefile.h"
|
||||||
#include "utils.h"
|
#include "xrawfile.h"
|
||||||
|
#include "xgfximage.h"
|
||||||
|
#include "xstringtable.h"
|
||||||
|
#include "xmenudef.h"
|
||||||
|
|
||||||
#include <QTreeWidget>
|
#include <QTreeWidget>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
@ -20,31 +23,31 @@ public:
|
|||||||
explicit XTreeWidget(QWidget *parent = nullptr);
|
explicit XTreeWidget(QWidget *parent = nullptr);
|
||||||
~XTreeWidget();
|
~XTreeWidget();
|
||||||
|
|
||||||
void AddFastFile(std::shared_ptr<FastFile> aFastFile);
|
void AddFastFile(FastFile* aFastFile);
|
||||||
void AddZoneFile(std::shared_ptr<ZoneFile> aZoneFile, XTreeWidgetItem *aParentItem = nullptr);
|
void AddZoneFile(const ZoneFile *aZoneFile, XTreeWidgetItem *aParentItem = nullptr);
|
||||||
void AddIWIFile(std::shared_ptr<IWIFile> aIWIFile);
|
void AddIWIFile(IWIFile* aIWIFile);
|
||||||
void AddDDSFile(std::shared_ptr<DDSFile> aDDSFile);
|
void AddDDSFile(DDSFile* aDDSFile);
|
||||||
|
|
||||||
std::shared_ptr<ZoneFile> FindZoneFile(const QString aStem);
|
const ZoneFile *FindZoneFile(const QString aStem);
|
||||||
std::shared_ptr<FastFile> FindFastFile(const QString aStem);
|
const FastFile* FindFastFile(const QString aStem);
|
||||||
|
|
||||||
bool HasZoneFile(const QString aStem);
|
bool HasZoneFile(const QString aStem);
|
||||||
bool HasFastFile(const QString aStem);
|
bool HasFastFile(const QString aStem);
|
||||||
|
|
||||||
void CloseFastFile(const QString aFFName);
|
void CloseFastFile(const QString aFFName);
|
||||||
signals:
|
signals:
|
||||||
void DDSFileSelected(std::shared_ptr<DDSFile> aDDSFile, const QString aParentName);
|
void DDSFileSelected(const DDSFile* aDDSFile, const QString aParentName);
|
||||||
void IWIFileSelected(std::shared_ptr<IWIFile> aIWIFile, const QString aParentName);
|
void IWIFileSelected(const IWIFile* aIWIFile, const QString aParentName);
|
||||||
void FastFileSelected(std::shared_ptr<FastFile> aFastFile, const QString aParentName);
|
void FastFileSelected(const FastFile* aFastFile, const QString aParentName);
|
||||||
void ZoneFileSelected(std::shared_ptr<ZoneFile> aZoneFile, const QString aParentName);
|
void ZoneFileSelected(const ZoneFile* aZoneFile, const QString aParentName);
|
||||||
void LocalStringSelected(std::shared_ptr<ZoneFile> aZoneFile, const QString aParentName);
|
void LocalStringSelected(const ZoneFile* aZoneFile, const QString aParentName);
|
||||||
void RawFileSelected(std::shared_ptr<RawFile> aRawFile, const QString aParentName);
|
void RawFileSelected(const XRawFile* aRawFile, const QString aParentName);
|
||||||
void ImageSelected(std::shared_ptr<Image> aImage, const QString aParentName);
|
void ImageSelected(const XGfxImage* aImage, const QString aParentName);
|
||||||
void TechSetSelected(std::shared_ptr<TechSet> aZoneFile, const QString aParentName);
|
void TechSetSelected(const XMaterialTechniqueSet* aZoneFile, const QString aParentName);
|
||||||
void StrTableSelected(std::shared_ptr<StringTable> aStrTable, const QString aParentName);
|
void StrTableSelected(const XStringTable* aStrTable, const QString aParentName);
|
||||||
void MenuSelected(std::shared_ptr<Menu> aMenu, const QString aParentName);
|
void MenuSelected(const XMenuDef* aMenu, const QString aParentName);
|
||||||
void SoundSelected(std::shared_ptr<Sound> aSound, const QString aParentName);
|
void SoundSelected(const XLoadedSound* aSound, const QString aParentName);
|
||||||
void MaterialSelected(std::shared_ptr<Material> aMaterial, const QString aParentName);
|
void MaterialSelected(const XMaterial* aMaterial, const QString aParentName);
|
||||||
void ItemSelected(const QString itemText);
|
void ItemSelected(const QString itemText);
|
||||||
|
|
||||||
void ItemClosed(const QString itemText);
|
void ItemClosed(const QString itemText);
|
||||||
@ -55,10 +58,10 @@ protected:
|
|||||||
void PrepareContextMenu(const QPoint &pos);
|
void PrepareContextMenu(const QPoint &pos);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QMap<QString, std::shared_ptr<FastFile>> mFastFiles;
|
QMap<QString, const FastFile*> mFastFiles;
|
||||||
QMap<QString, std::shared_ptr<ZoneFile>> mZoneFiles;
|
QMap<QString, const ZoneFile*> mZoneFiles;
|
||||||
QMap<QString, std::shared_ptr<DDSFile>> mDDSFiles;
|
QMap<QString, const DDSFile*> mDDSFiles;
|
||||||
QMap<QString, std::shared_ptr<IWIFile>> mIWIFiles;
|
QMap<QString, const IWIFile*> mIWIFiles;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // XTREEWIDGET_H
|
#endif // XTREEWIDGET_H
|
||||||
|
|||||||
@ -69,7 +69,7 @@ void ZoneFileViewer::SortTags(const QString &aSearchText) {
|
|||||||
ui->listWidget_Tags->addItems(sortedTags);
|
ui->listWidget_Tags->addItems(sortedTags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZoneFileViewer::SetZoneFile(std::shared_ptr<ZoneFile> aZoneFile) {
|
void ZoneFileViewer::SetZoneFile(const ZoneFile* aZoneFile) {
|
||||||
mZoneFile = aZoneFile;
|
mZoneFile = aZoneFile;
|
||||||
|
|
||||||
ui->tableWidget_RecordCounts->clearContents();
|
ui->tableWidget_RecordCounts->clearContents();
|
||||||
@ -88,37 +88,36 @@ void ZoneFileViewer::SetZoneFile(std::shared_ptr<ZoneFile> aZoneFile) {
|
|||||||
ui->groupBox_Tags->show();
|
ui->groupBox_Tags->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
QMap<QString, int> recordCounts = QMap<QString, int>();
|
QMap<XAssetType, int> recordCounts = QMap<XAssetType, int>();
|
||||||
QVector<QPair<QString, int>> assetOccurances = QVector<QPair<QString, int>>();
|
QVector<QPair<XAssetType, int>> assetOccurances = QVector<QPair<XAssetType, int>>();
|
||||||
for (const QString &record : mZoneFile->GetRecords()) {
|
for (XAssetType type : mZoneFile->GetTypes()) {
|
||||||
if (!recordCounts.contains(record)) {
|
if (!recordCounts.contains(type)) {
|
||||||
recordCounts[record] = 0;
|
recordCounts[type] = 0;
|
||||||
}
|
}
|
||||||
recordCounts[record]++;
|
recordCounts[type]++;
|
||||||
|
|
||||||
if (!assetOccurances.isEmpty() && assetOccurances.last().first == record) {
|
if (!assetOccurances.isEmpty() && assetOccurances.last().first == type) {
|
||||||
assetOccurances.last().second++;
|
assetOccurances.last().second++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPair<QString, int> assetOccurance(record, 1);
|
QPair<XAssetType, int> assetOccurance(type, 1);
|
||||||
assetOccurances << assetOccurance;
|
assetOccurances << assetOccurance;
|
||||||
}
|
}
|
||||||
ui->tableWidget_RecordOrder->setRowCount(assetOccurances.size());
|
ui->tableWidget_RecordOrder->setRowCount(assetOccurances.size());
|
||||||
|
|
||||||
int assetIndex = 0;
|
int assetIndex = 0;
|
||||||
foreach (auto assetOccurance, assetOccurances) {
|
foreach (auto assetOccurance, assetOccurances) {
|
||||||
const QString record = assetOccurance.first;
|
XAssetType assetType = assetOccurance.first;
|
||||||
AssetType assetType = mZoneFile->AssetStrToEnum(record);
|
|
||||||
int assetCount = assetOccurance.second;
|
int assetCount = assetOccurance.second;
|
||||||
|
|
||||||
QIcon assetIcon = mZoneFile->AssetTypeToIcon(assetType);
|
QIcon assetIcon = Utils::CreateAssetIcon(assetType);
|
||||||
if (assetIcon.isNull()) {
|
if (assetIcon.isNull()) {
|
||||||
qDebug() << "Icon is null for record: " << record;
|
qDebug() << "Icon is null for record: " << assetType;
|
||||||
}
|
}
|
||||||
|
|
||||||
QTableWidgetItem *recordItem = new QTableWidgetItem(record.toUpper());
|
QTableWidgetItem *recordItem = new QTableWidgetItem(QString::number(assetType, 16));
|
||||||
QTableWidgetItem *recordStrItem = new QTableWidgetItem(mZoneFile->AssetEnumToStr(assetType));
|
QTableWidgetItem *recordStrItem = new QTableWidgetItem(XAsset::XAssetTypeToString(assetType));
|
||||||
QTableWidgetItem *recordCountItem = new QTableWidgetItem(QString::number(assetCount));
|
QTableWidgetItem *recordCountItem = new QTableWidgetItem(QString::number(assetCount));
|
||||||
recordItem->setIcon(assetIcon);
|
recordItem->setIcon(assetIcon);
|
||||||
|
|
||||||
@ -130,19 +129,18 @@ void ZoneFileViewer::SetZoneFile(std::shared_ptr<ZoneFile> aZoneFile) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int recordIndex = 0;
|
int recordIndex = 0;
|
||||||
for (const QString &record : recordCounts.keys()) {
|
for (XAssetType assetType : recordCounts.keys()) {
|
||||||
int recordCount = recordCounts[record];
|
int recordCount = recordCounts[assetType];
|
||||||
|
|
||||||
AssetType assetType = mZoneFile->AssetStrToEnum(record);
|
QIcon assetIcon = Utils::CreateAssetIcon(assetType);
|
||||||
QIcon assetIcon = mZoneFile->AssetTypeToIcon(assetType);
|
|
||||||
if (assetIcon.isNull()) {
|
if (assetIcon.isNull()) {
|
||||||
qDebug() << "Icon is null for record: " << record;
|
qDebug() << "Icon is null for record: " << assetType;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->tableWidget_RecordCounts->setRowCount(recordIndex + 1);
|
ui->tableWidget_RecordCounts->setRowCount(recordIndex + 1);
|
||||||
|
|
||||||
QTableWidgetItem *recordItem = new QTableWidgetItem(record.toUpper());
|
QTableWidgetItem *recordItem = new QTableWidgetItem(QString::number(assetType, 16));
|
||||||
QTableWidgetItem *recordCountStrItem = new QTableWidgetItem(mZoneFile->AssetEnumToStr(assetType));
|
QTableWidgetItem *recordCountStrItem = new QTableWidgetItem(XAsset::XAssetTypeToString(assetType));
|
||||||
QTableWidgetItem *recordCountItem = new QTableWidgetItem(QString::number(recordCount));
|
QTableWidgetItem *recordCountItem = new QTableWidgetItem(QString::number(recordCount));
|
||||||
recordItem->setIcon(assetIcon);
|
recordItem->setIcon(assetIcon);
|
||||||
|
|
||||||
|
|||||||
@ -18,7 +18,7 @@ public:
|
|||||||
explicit ZoneFileViewer(QWidget *parent = nullptr);
|
explicit ZoneFileViewer(QWidget *parent = nullptr);
|
||||||
~ZoneFileViewer();
|
~ZoneFileViewer();
|
||||||
|
|
||||||
void SetZoneFile(std::shared_ptr<ZoneFile> aZoneFile);
|
void SetZoneFile(const ZoneFile *aZoneFile);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void SortTags(const QString &aSearchText);
|
void SortTags(const QString &aSearchText);
|
||||||
@ -27,7 +27,7 @@ public slots:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::ZoneFileViewer *ui;
|
Ui::ZoneFileViewer *ui;
|
||||||
std::shared_ptr<ZoneFile> mZoneFile;
|
const ZoneFile* mZoneFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ZONEFILEVIEWER_H
|
#endif // ZONEFILEVIEWER_H
|
||||||
|
|||||||
@ -20,7 +20,6 @@
|
|||||||
<file>icons/Icon_Editor.png</file>
|
<file>icons/Icon_Editor.png</file>
|
||||||
<file>icons/Icon_Views.png</file>
|
<file>icons/Icon_Views.png</file>
|
||||||
<file>icons/Icon_Tree.png</file>
|
<file>icons/Icon_Tree.png</file>
|
||||||
<file>icons/Icon_Copy.png</file>
|
|
||||||
<file>icons/Icon_Cut.png</file>
|
<file>icons/Icon_Cut.png</file>
|
||||||
<file>icons/Icon_Find.png</file>
|
<file>icons/Icon_Find.png</file>
|
||||||
<file>icons/Icon_NewFile.png</file>
|
<file>icons/Icon_NewFile.png</file>
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 316 B |
@ -1,13 +1,10 @@
|
|||||||
#include "compression.h"
|
#include "compression.h"
|
||||||
#include "minilzo.h"
|
#include "minilzo.h"
|
||||||
|
|
||||||
#define XBOXAPI __declspec(dllimport)
|
|
||||||
#include "xcompress.h"
|
#include "xcompress.h"
|
||||||
|
|
||||||
#include <QLibrary>
|
#include <QLibrary>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QDataStream>
|
|
||||||
|
|
||||||
QByteArray Compression::CompressXMem(const QByteArray &data)
|
QByteArray Compression::CompressXMem(const QByteArray &data)
|
||||||
{
|
{
|
||||||
@ -34,7 +31,8 @@ QByteArray Compression::CompressXMem(const QByteArray &data)
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray Compression::DecompressXMem(const QByteArray &data, int flags, int windowSize, int partSize)
|
QByteArray Compression::DecompressXMem(const QByteArray &data,
|
||||||
|
int flags, int windowSize, int partSize)
|
||||||
{
|
{
|
||||||
if (data.isEmpty())
|
if (data.isEmpty())
|
||||||
return {};
|
return {};
|
||||||
@ -44,27 +42,49 @@ QByteArray Compression::DecompressXMem(const QByteArray &data, int flags, int wi
|
|||||||
lzxParams.WindowSize = windowSize;
|
lzxParams.WindowSize = windowSize;
|
||||||
lzxParams.CompressionPartitionSize = partSize;
|
lzxParams.CompressionPartitionSize = partSize;
|
||||||
|
|
||||||
XMEMDECOMPRESSION_CONTEXT ctx = nullptr;
|
QByteArray internalState(0x94933, Qt::Uninitialized);
|
||||||
if (FAILED(XMemCreateDecompressionContext(XMEMCODEC_LZX, &lzxParams, 0, &ctx)) || !ctx)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
// Allocate large enough buffer for decompression (16 MB is a safe upper bound)
|
XMEMDECOMPRESSION_CONTEXT ctx = XMemInitializeDecompressionContext(
|
||||||
const SIZE_T kMaxOutSize = 16 * 1024 * 1024;
|
XMEMCODEC_LZX, &lzxParams, 1,
|
||||||
QByteArray output(static_cast<int>(kMaxOutSize), Qt::Uninitialized);
|
internalState.data(), internalState.size());
|
||||||
SIZE_T actualSize = kMaxOutSize;
|
|
||||||
|
|
||||||
HRESULT hr = XMemDecompress(ctx,
|
if (!ctx || XMemResetDecompressionContext(ctx)) {
|
||||||
output.data(), &actualSize,
|
qWarning() << "Failed to init LZX context";
|
||||||
data.constData(), data.size() + 16);
|
|
||||||
|
|
||||||
XMemDestroyDecompressionContext(ctx);
|
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
qWarning() << "XMemDecompress failed with HRESULT:" << hr;
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
output.resize(static_cast<int>(actualSize));
|
QByteArray output;
|
||||||
|
output.reserve(16 * 1024 * 1024); // rough guess
|
||||||
|
|
||||||
|
const quint8 *nextIn = reinterpret_cast<const quint8*>(data.constData());
|
||||||
|
SIZE_T availIn = data.size();
|
||||||
|
|
||||||
|
QByteArray scratch(0x10000, Qt::Uninitialized); // 64 KB chunks
|
||||||
|
|
||||||
|
while (availIn > 0) {
|
||||||
|
SIZE_T inSize = availIn; // let XMem tell us how much it will consume
|
||||||
|
SIZE_T outSize = scratch.size(); // max 64 KB per call
|
||||||
|
|
||||||
|
HRESULT hr = XMemDecompressStream(ctx,
|
||||||
|
scratch.data(), &outSize,
|
||||||
|
nextIn, &inSize);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
qWarning() << "XMemDecompressStream failed, hr=" << hr;
|
||||||
|
XMemDestroyDecompressionContext(ctx);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inSize == 0 && outSize == 0)
|
||||||
|
break; // no progress
|
||||||
|
|
||||||
|
output.append(scratch.constData(), static_cast<int>(outSize));
|
||||||
|
|
||||||
|
nextIn += inSize;
|
||||||
|
availIn -= inSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
XMemDestroyDecompressionContext(ctx);
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,19 +100,18 @@ quint32 Compression::CalculateAdler32Checksum(const QByteArray &data) {
|
|||||||
|
|
||||||
qint64 Compression::FindZlibOffset(const QByteArray &bytes)
|
qint64 Compression::FindZlibOffset(const QByteArray &bytes)
|
||||||
{
|
{
|
||||||
static const QByteArray iwffs("IWffs");
|
QDataStream stream(bytes);
|
||||||
auto idx = bytes.indexOf(iwffs);
|
|
||||||
if (idx != -1)
|
|
||||||
return idx + 0x4000;
|
|
||||||
|
|
||||||
const char header = 0x78; // z-lib: 0x78 [FLG]
|
while (!stream.atEnd())
|
||||||
int pos = -1;
|
|
||||||
while ((pos = bytes.indexOf(header, pos + 1)) != -1)
|
|
||||||
{
|
{
|
||||||
QByteArray window = bytes.mid(pos, 0x20);
|
QByteArray testSegment = stream.device()->peek(2).toHex().toUpper();
|
||||||
if (!window.contains(QByteArray::fromHex("000000")) &&
|
if (testSegment == "7801" ||
|
||||||
!window.contains(QByteArray::fromHex("FFFFFF")))
|
testSegment == "785E" ||
|
||||||
return pos;
|
testSegment == "789C" ||
|
||||||
|
testSegment == "78DA") {
|
||||||
|
return stream.device()->pos();
|
||||||
|
}
|
||||||
|
stream.skipRawData(1);
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -295,11 +314,12 @@ QByteArray Compression::CompressDeflateWithSettings(const QByteArray &aData, int
|
|||||||
}
|
}
|
||||||
|
|
||||||
QByteArray Compression::DecompressLZO(const QByteArray &aCompressedData, quint32 aDestSize) {
|
QByteArray Compression::DecompressLZO(const QByteArray &aCompressedData, quint32 aDestSize) {
|
||||||
|
QByteArray dst;
|
||||||
static bool ok = (lzo_init() == LZO_E_OK);
|
static bool ok = (lzo_init() == LZO_E_OK);
|
||||||
if (!ok)
|
if (!ok)
|
||||||
throw std::runtime_error("lzo_init failed");
|
throw std::runtime_error("lzo_init failed");
|
||||||
|
|
||||||
QByteArray dst(aDestSize, Qt::Uninitialized);
|
dst = QByteArray(aDestSize, Qt::Uninitialized);
|
||||||
lzo_uint out = aDestSize;
|
lzo_uint out = aDestSize;
|
||||||
|
|
||||||
int rc = lzo1x_decompress_safe(
|
int rc = lzo1x_decompress_safe(
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include "QtZlib/zlib.h"
|
#include "QtZlib/zlib.h"
|
||||||
|
|
||||||
#include <windows.h>
|
//#include <windows.h>
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
|
|||||||
@ -3,20 +3,14 @@ TEMPLATE = lib
|
|||||||
CONFIG += staticlib c++17
|
CONFIG += staticlib c++17
|
||||||
DEFINES += MINILZO_USE_STATIC
|
DEFINES += MINILZO_USE_STATIC
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += $$files($$PWD/*.cpp, true) \
|
||||||
compression.cpp \
|
$$files($$PWD/*.c, true)
|
||||||
minilzo.c \
|
HEADERS += $$files($$PWD/*.h, true)
|
||||||
lzoconf.h \
|
|
||||||
lzodefs.h
|
|
||||||
|
|
||||||
HEADERS += \
|
|
||||||
compression.h \
|
|
||||||
minilzo.h
|
|
||||||
|
|
||||||
LIBS += \
|
LIBS += \
|
||||||
-L$$PWD/../../third_party/xbox_sdk/lib -lxcompress64 \
|
-L$$PWD/../../third_party/xbox_sdk/lib -lxcompress64 \
|
||||||
-L$$OUT_PWD/../libs/core -lcore \
|
-L$$OUT_PWD/../libs/core -lcore \
|
||||||
-L$$OUT_PWD/../libs/encryption -lencryption
|
-L$$OUT_PWD/../libs/encryption -lencryption
|
||||||
|
|
||||||
INCLUDEPATH += \
|
INCLUDEPATH += \
|
||||||
$$PWD/../../third_party/xbox_sdk/include \
|
$$PWD/../../third_party/xbox_sdk/include \
|
||||||
|
|||||||
@ -57,7 +57,7 @@
|
|||||||
|
|
||||||
/* get OS and architecture defines */
|
/* get OS and architecture defines */
|
||||||
#ifndef __LZODEFS_H_INCLUDED
|
#ifndef __LZODEFS_H_INCLUDED
|
||||||
#include <lzo/lzodefs.h>
|
#include <lzodefs.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@ -105,7 +105,7 @@ extern "C" {
|
|||||||
# define LZO_INT_MAX 9223372036854775807LL
|
# define LZO_INT_MAX 9223372036854775807LL
|
||||||
# define LZO_INT_MIN (-1LL - LZO_INT_MAX)
|
# define LZO_INT_MIN (-1LL - LZO_INT_MAX)
|
||||||
# elif (LZO_ABI_IP32L64) /* MIPS R5900 */
|
# elif (LZO_ABI_IP32L64) /* MIPS R5900 */
|
||||||
typedef unsigned int lzo_uint;
|
typedef quint32 lzo_uint;
|
||||||
typedef int lzo_int;
|
typedef int lzo_int;
|
||||||
# define LZO_SIZEOF_LZO_INT LZO_SIZEOF_INT
|
# define LZO_SIZEOF_LZO_INT LZO_SIZEOF_INT
|
||||||
# define LZO_TYPEOF_LZO_INT LZO_TYPEOF_INT
|
# define LZO_TYPEOF_LZO_INT LZO_TYPEOF_INT
|
||||||
|
|||||||
@ -2847,7 +2847,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
|
|||||||
# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF_LONG
|
# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF_LONG
|
||||||
#elif (LZO_SIZEOF_INT == 2) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT16E_T == LZO_TYPEOF_SHORT)
|
#elif (LZO_SIZEOF_INT == 2) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT16E_T == LZO_TYPEOF_SHORT)
|
||||||
# define lzo_int16e_t int
|
# define lzo_int16e_t int
|
||||||
# define lzo_uint16e_t unsigned int
|
# define lzo_uint16e_t quint32
|
||||||
# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF_INT
|
# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF_INT
|
||||||
#elif (LZO_SIZEOF_SHORT == 2)
|
#elif (LZO_SIZEOF_SHORT == 2)
|
||||||
# define lzo_int16e_t short int
|
# define lzo_int16e_t short int
|
||||||
@ -2856,14 +2856,14 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
|
|||||||
#elif 1 && !(LZO_CFG_TYPE_NO_MODE_HI) && (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x025f00ul) || LZO_CC_LLVM)
|
#elif 1 && !(LZO_CFG_TYPE_NO_MODE_HI) && (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x025f00ul) || LZO_CC_LLVM)
|
||||||
# if !(LZO_LANG_ASSEMBLER)
|
# if !(LZO_LANG_ASSEMBLER)
|
||||||
typedef int lzo_int16e_hi_t__ __attribute__((__mode__(__HI__)));
|
typedef int lzo_int16e_hi_t__ __attribute__((__mode__(__HI__)));
|
||||||
typedef unsigned int lzo_uint16e_hi_t__ __attribute__((__mode__(__HI__)));
|
typedef quint32 lzo_uint16e_hi_t__ __attribute__((__mode__(__HI__)));
|
||||||
# endif
|
# endif
|
||||||
# define lzo_int16e_t lzo_int16e_hi_t__
|
# define lzo_int16e_t lzo_int16e_hi_t__
|
||||||
# define lzo_uint16e_t lzo_uint16e_hi_t__
|
# define lzo_uint16e_t lzo_uint16e_hi_t__
|
||||||
# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF___MODE_HI
|
# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF___MODE_HI
|
||||||
#elif (LZO_SIZEOF___INT16 == 2)
|
#elif (LZO_SIZEOF___INT16 == 2)
|
||||||
# define lzo_int16e_t __int16
|
# define lzo_int16e_t __int16
|
||||||
# define lzo_uint16e_t unsigned __int16
|
# define lzo_uint16e_t quint32
|
||||||
# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF___INT16
|
# define LZO_TYPEOF_LZO_INT16E_T LZO_TYPEOF___INT16
|
||||||
#else
|
#else
|
||||||
#endif
|
#endif
|
||||||
@ -2883,7 +2883,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
|
|||||||
# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF_LONG
|
# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF_LONG
|
||||||
#elif (LZO_SIZEOF_INT == 4)
|
#elif (LZO_SIZEOF_INT == 4)
|
||||||
# define lzo_int32e_t int
|
# define lzo_int32e_t int
|
||||||
# define lzo_uint32e_t unsigned int
|
# define lzo_uint32e_t quint32
|
||||||
# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF_INT
|
# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF_INT
|
||||||
#elif (LZO_SIZEOF_SHORT == 4)
|
#elif (LZO_SIZEOF_SHORT == 4)
|
||||||
# define lzo_int32e_t short int
|
# define lzo_int32e_t short int
|
||||||
@ -2896,7 +2896,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
|
|||||||
#elif 1 && !(LZO_CFG_TYPE_NO_MODE_SI) && (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x025f00ul) || LZO_CC_LLVM) && (__INT_MAX__+0 > 2147483647L)
|
#elif 1 && !(LZO_CFG_TYPE_NO_MODE_SI) && (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x025f00ul) || LZO_CC_LLVM) && (__INT_MAX__+0 > 2147483647L)
|
||||||
# if !(LZO_LANG_ASSEMBLER)
|
# if !(LZO_LANG_ASSEMBLER)
|
||||||
typedef int lzo_int32e_si_t__ __attribute__((__mode__(__SI__)));
|
typedef int lzo_int32e_si_t__ __attribute__((__mode__(__SI__)));
|
||||||
typedef unsigned int lzo_uint32e_si_t__ __attribute__((__mode__(__SI__)));
|
typedef quint32 lzo_uint32e_si_t__ __attribute__((__mode__(__SI__)));
|
||||||
# endif
|
# endif
|
||||||
# define lzo_int32e_t lzo_int32e_si_t__
|
# define lzo_int32e_t lzo_int32e_si_t__
|
||||||
# define lzo_uint32e_t lzo_uint32e_si_t__
|
# define lzo_uint32e_t lzo_uint32e_si_t__
|
||||||
@ -2904,7 +2904,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
|
|||||||
#elif 1 && !(LZO_CFG_TYPE_NO_MODE_SI) && (LZO_CC_GNUC >= 0x025f00ul) && defined(__AVR__) && (__LONG_MAX__+0 == 32767L)
|
#elif 1 && !(LZO_CFG_TYPE_NO_MODE_SI) && (LZO_CC_GNUC >= 0x025f00ul) && defined(__AVR__) && (__LONG_MAX__+0 == 32767L)
|
||||||
# if !(LZO_LANG_ASSEMBLER)
|
# if !(LZO_LANG_ASSEMBLER)
|
||||||
typedef int lzo_int32e_si_t__ __attribute__((__mode__(__SI__)));
|
typedef int lzo_int32e_si_t__ __attribute__((__mode__(__SI__)));
|
||||||
typedef unsigned int lzo_uint32e_si_t__ __attribute__((__mode__(__SI__)));
|
typedef quint32 lzo_uint32e_si_t__ __attribute__((__mode__(__SI__)));
|
||||||
# endif
|
# endif
|
||||||
# define lzo_int32e_t lzo_int32e_si_t__
|
# define lzo_int32e_t lzo_int32e_si_t__
|
||||||
# define lzo_uint32e_t lzo_uint32e_si_t__
|
# define lzo_uint32e_t lzo_uint32e_si_t__
|
||||||
@ -2913,7 +2913,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
|
|||||||
# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF___MODE_SI
|
# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF___MODE_SI
|
||||||
#elif (LZO_SIZEOF___INT32 == 4)
|
#elif (LZO_SIZEOF___INT32 == 4)
|
||||||
# define lzo_int32e_t __int32
|
# define lzo_int32e_t __int32
|
||||||
# define lzo_uint32e_t unsigned __int32
|
# define lzo_uint32e_t quint32
|
||||||
# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF___INT32
|
# define LZO_TYPEOF_LZO_INT32E_T LZO_TYPEOF___INT32
|
||||||
#else
|
#else
|
||||||
#endif
|
#endif
|
||||||
@ -2937,7 +2937,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
|
|||||||
#endif
|
#endif
|
||||||
#if (LZO_SIZEOF_INT == 8) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG)
|
#if (LZO_SIZEOF_INT == 8) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG)
|
||||||
# define lzo_int64e_t int
|
# define lzo_int64e_t int
|
||||||
# define lzo_uint64e_t unsigned int
|
# define lzo_uint64e_t quint32
|
||||||
# define LZO_TYPEOF_LZO_INT64E_T LZO_TYPEOF_INT
|
# define LZO_TYPEOF_LZO_INT64E_T LZO_TYPEOF_INT
|
||||||
#elif (LZO_SIZEOF_LONG == 8) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF_LONG_LONG) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF___INT64)
|
#elif (LZO_SIZEOF_LONG == 8) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF_LONG_LONG) && !(LZO_CFG_PREFER_TYPEOF_ACC_INT64E_T == LZO_TYPEOF___INT64)
|
||||||
# define lzo_int64e_t long int
|
# define lzo_int64e_t long int
|
||||||
@ -2984,7 +2984,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
|
|||||||
# define LZO_TYPEOF_LZO_INT32L_T LZO_TYPEOF_LZO_INT32E_T
|
# define LZO_TYPEOF_LZO_INT32L_T LZO_TYPEOF_LZO_INT32E_T
|
||||||
#elif (LZO_SIZEOF_INT >= 4) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG)
|
#elif (LZO_SIZEOF_INT >= 4) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG)
|
||||||
# define lzo_int32l_t int
|
# define lzo_int32l_t int
|
||||||
# define lzo_uint32l_t unsigned int
|
# define lzo_uint32l_t quint32
|
||||||
# define LZO_SIZEOF_LZO_INT32L_T LZO_SIZEOF_INT
|
# define LZO_SIZEOF_LZO_INT32L_T LZO_SIZEOF_INT
|
||||||
# define LZO_TYPEOF_LZO_INT32L_T LZO_SIZEOF_INT
|
# define LZO_TYPEOF_LZO_INT32L_T LZO_SIZEOF_INT
|
||||||
#elif (LZO_SIZEOF_LONG >= 4)
|
#elif (LZO_SIZEOF_LONG >= 4)
|
||||||
@ -3057,7 +3057,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
|
|||||||
#elif (LZO_CC_MSC && (_MSC_VER >= 1300) && (LZO_SIZEOF_VOID_P == 4) && (LZO_SIZEOF_INT == 4))
|
#elif (LZO_CC_MSC && (_MSC_VER >= 1300) && (LZO_SIZEOF_VOID_P == 4) && (LZO_SIZEOF_INT == 4))
|
||||||
# if !(LZO_LANG_ASSEMBLER)
|
# if !(LZO_LANG_ASSEMBLER)
|
||||||
typedef __w64 int lzo_intptr_t;
|
typedef __w64 int lzo_intptr_t;
|
||||||
typedef __w64 unsigned int lzo_uintptr_t;
|
typedef __w64 quint32 lzo_uintptr_t;
|
||||||
# endif
|
# endif
|
||||||
# define lzo_intptr_t lzo_intptr_t
|
# define lzo_intptr_t lzo_intptr_t
|
||||||
# define lzo_uintptr_t lzo_uintptr_t
|
# define lzo_uintptr_t lzo_uintptr_t
|
||||||
@ -3070,7 +3070,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
|
|||||||
# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_SHORT
|
# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_SHORT
|
||||||
#elif (LZO_SIZEOF_INT >= LZO_SIZEOF_VOID_P) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG)
|
#elif (LZO_SIZEOF_INT >= LZO_SIZEOF_VOID_P) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG)
|
||||||
# define lzo_intptr_t int
|
# define lzo_intptr_t int
|
||||||
# define lzo_uintptr_t unsigned int
|
# define lzo_uintptr_t quint32
|
||||||
# define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_INT
|
# define LZO_SIZEOF_LZO_INTPTR_T LZO_SIZEOF_INT
|
||||||
# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_INT
|
# define LZO_TYPEOF_LZO_INTPTR_T LZO_TYPEOF_INT
|
||||||
#elif (LZO_SIZEOF_LONG >= LZO_SIZEOF_VOID_P)
|
#elif (LZO_SIZEOF_LONG >= LZO_SIZEOF_VOID_P)
|
||||||
@ -3104,7 +3104,7 @@ LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
|
|||||||
# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LONG
|
# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LONG
|
||||||
# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_LONG
|
# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_LONG
|
||||||
#elif (LZO_WORDSIZE == LZO_SIZEOF_INT)
|
#elif (LZO_WORDSIZE == LZO_SIZEOF_INT)
|
||||||
# define lzo_word_t unsigned int
|
# define lzo_word_t quint32
|
||||||
# define lzo_sword_t int
|
# define lzo_sword_t int
|
||||||
# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_INT
|
# define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_INT
|
||||||
# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_INT
|
# define LZO_TYPEOF_LZO_WORD_T LZO_TYPEOF_INT
|
||||||
|
|||||||
@ -25,12 +25,6 @@
|
|||||||
http://www.oberhumer.com/opensource/lzo/
|
http://www.oberhumer.com/opensource/lzo/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
* NOTE:
|
|
||||||
* the full LZO package can be found at
|
|
||||||
* http://www.oberhumer.com/opensource/lzo/
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define __LZO_IN_MINILZO 1
|
#define __LZO_IN_MINILZO 1
|
||||||
|
|
||||||
#if defined(LZO_CFG_FREESTANDING)
|
#if defined(LZO_CFG_FREESTANDING)
|
||||||
|
|||||||
@ -25,13 +25,6 @@
|
|||||||
http://www.oberhumer.com/opensource/lzo/
|
http://www.oberhumer.com/opensource/lzo/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
* NOTE:
|
|
||||||
* the full LZO package can be found at
|
|
||||||
* http://www.oberhumer.com/opensource/lzo/
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef __MINILZO_H_INCLUDED
|
#ifndef __MINILZO_H_INCLUDED
|
||||||
#define __MINILZO_H_INCLUDED 1
|
#define __MINILZO_H_INCLUDED 1
|
||||||
|
|
||||||
|
|||||||
@ -2,23 +2,15 @@ QT += core widgets
|
|||||||
TEMPLATE = lib
|
TEMPLATE = lib
|
||||||
CONFIG += staticlib c++17
|
CONFIG += staticlib c++17
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += $$files($$PWD/*.cpp, true) \
|
||||||
highlighter_cfg.cpp \
|
xdatastream.cpp
|
||||||
highlighter_shock.cpp \
|
HEADERS += $$files($$PWD/*.h, true) \
|
||||||
highlighter_rumble.cpp \
|
xdatastream.h
|
||||||
highlighter_gsc.cpp \
|
|
||||||
logmanager.cpp \
|
|
||||||
statusbarmanager.cpp
|
|
||||||
|
|
||||||
HEADERS += \
|
LIBS += -L$$OUT_PWD/../libs/xassets -lxassets
|
||||||
enums.h \
|
|
||||||
highlighter_cfg.h \
|
INCLUDEPATH += $$PWD/../xassets
|
||||||
highlighter_shock.h \
|
|
||||||
highlighter_rumble.h \
|
DEPENDPATH += $$PWD/../xassets
|
||||||
highlighter_gsc.h \
|
|
||||||
logmanager.h \
|
|
||||||
stringutils.h \
|
|
||||||
utils.h \
|
|
||||||
statusbarmanager.h
|
|
||||||
|
|
||||||
DESTDIR = $$OUT_PWD/../
|
DESTDIR = $$OUT_PWD/../
|
||||||
|
|||||||
@ -3,32 +3,10 @@
|
|||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
enum FF_PLATFORM {
|
|
||||||
FF_PLATFORM_NONE = 0x00, // No platform
|
|
||||||
FF_PLATFORM_XBOX = 0x01, // Xbox 360
|
|
||||||
FF_PLATFORM_PS3 = 0x02, // Playstation 3
|
|
||||||
FF_PLATFORM_PC = 0x03, // PC
|
|
||||||
FF_PLATFORM_WII = 0x04, // WII
|
|
||||||
FF_PLATFORM_WIIU = 0x05 // WII U
|
|
||||||
};
|
|
||||||
|
|
||||||
enum FF_GAME {
|
|
||||||
FF_GAME_NONE = 0x00, // No game
|
|
||||||
FF_GAME_COD1 = 0x01, // Call of Duty
|
|
||||||
FF_GAME_COD2 = 0x02, // Call of Duty 2
|
|
||||||
FF_GAME_COD3 = 0x03, // Call of Duty 3
|
|
||||||
FF_GAME_COD4 = 0x04, // Modern Warware 1
|
|
||||||
FF_GAME_COD5 = 0x05, // World at War
|
|
||||||
FF_GAME_COD6 = 0x06, // Modern Warfare 2
|
|
||||||
FF_GAME_COD7 = 0x07, // Black Ops 1
|
|
||||||
FF_GAME_COD8 = 0x08, // Modern Warfare 3
|
|
||||||
FF_GAME_COD9 = 0x09, // Black Ops 2
|
|
||||||
};
|
|
||||||
|
|
||||||
enum IWI_VERSION {
|
enum IWI_VERSION {
|
||||||
IWI_VERSION_COD2 = 0x05, // 05 CoD2
|
IWI_VERSION_COD2 = 0x05, // 05 CoD2
|
||||||
IWI_VERSION_COD4 = 0x06, // 06 CoD4
|
IWI_VERSION_COD4 = 0x06, // 06 CoD4
|
||||||
IWI_VERSION_COD5 = 0x06, // 06 CoD5
|
IWI_VERSION_COD5 = 0x06, // 06 CoD5
|
||||||
IWI_VERSION_CODMW2 = 0x08, // 08 CoDMW2
|
IWI_VERSION_CODMW2 = 0x08, // 08 CoDMW2
|
||||||
IWI_VERSION_CODMW3 = 0x08, // 08 CoDMW3
|
IWI_VERSION_CODMW3 = 0x08, // 08 CoDMW3
|
||||||
IWI_VERSION_CODBO1 = 0x0D, // 13 CoDBO1
|
IWI_VERSION_CODBO1 = 0x0D, // 13 CoDBO1
|
||||||
@ -38,37 +16,37 @@ enum IWI_VERSION {
|
|||||||
enum IWI_FORMAT {
|
enum IWI_FORMAT {
|
||||||
// IWI Format
|
// IWI Format
|
||||||
IWI_FORMAT_ARGB32 = 0x01, // 01 ARGB32
|
IWI_FORMAT_ARGB32 = 0x01, // 01 ARGB32
|
||||||
IWI_FORMAT_RGB24 = 0x02, // 02 RGB24
|
IWI_FORMAT_RGB24 = 0x02, // 02 RGB24
|
||||||
IWI_FORMAT_GA16 = 0x03, // 03 GA16
|
IWI_FORMAT_GA16 = 0x03, // 03 GA16
|
||||||
IWI_FORMAT_A8 = 0x04, // 04 A8
|
IWI_FORMAT_A8 = 0x04, // 04 A8
|
||||||
IWI_FORMAT_DXT1 = 0x0B, // 11 DXT1
|
IWI_FORMAT_DXT1 = 0x0B, // 11 DXT1
|
||||||
IWI_FORMAT_DXT3 = 0x0C, // 12 DXT3
|
IWI_FORMAT_DXT3 = 0x0C, // 12 DXT3
|
||||||
IWI_FORMAT_DXT5 = 0x0D // 13 DXT5
|
IWI_FORMAT_DXT5 = 0x0D // 13 DXT5
|
||||||
};
|
};
|
||||||
|
|
||||||
enum DDS_FLAGS {
|
enum DDS_FLAGS {
|
||||||
DDSD_CAPS = 0x1,
|
DDSD_CAPS = 0x1,
|
||||||
DDSD_HEIGHT = 0x2,
|
DDSD_HEIGHT = 0x2,
|
||||||
DDSD_WIDTH = 0x4,
|
DDSD_WIDTH = 0x4,
|
||||||
DDSD_PITCH = 0x8,
|
DDSD_PITCH = 0x8,
|
||||||
DDSD_PIXELFORMAT = 0x1000,
|
DDSD_PIXELFORMAT = 0x1000,
|
||||||
DDSD_MIPMAPCOUNT = 0x20000,
|
DDSD_MIPMAPCOUNT = 0x20000,
|
||||||
DDSD_LINEARSIZE = 0x80000,
|
DDSD_LINEARSIZE = 0x80000,
|
||||||
DDSD_DEPTH = 0x800000
|
DDSD_DEPTH = 0x800000
|
||||||
};
|
};
|
||||||
|
|
||||||
enum DDS_PIXELFORMAT_FLAGS {
|
enum DDS_PIXELFORMAT_FLAGS {
|
||||||
DDPF_ALPHAPIXELS = 0x1,
|
DDPF_ALPHAPIXELS = 0x1,
|
||||||
DDPF_ALPHA = 0x2,
|
DDPF_ALPHA = 0x2,
|
||||||
DDPF_FOURCC = 0x4,
|
DDPF_FOURCC = 0x4,
|
||||||
DDPF_RGB = 0x40,
|
DDPF_RGB = 0x40,
|
||||||
DDPF_YUV = 0x200,
|
DDPF_YUV = 0x200,
|
||||||
DDPF_LUMINANCE = 0x20000
|
DDPF_LUMINANCE = 0x20000
|
||||||
};
|
};
|
||||||
|
|
||||||
enum DDS_CAPS_FLAGS {
|
enum DDS_CAPS_FLAGS {
|
||||||
DDSCAPS_COMPLEX = 0x8,
|
DDSCAPS_COMPLEX = 0x8,
|
||||||
DDSCAPS_MIPMAP = 0x400000,
|
DDSCAPS_MIPMAP = 0x400000,
|
||||||
DDSCAPS_TEXTURE = 0x1000
|
DDSCAPS_TEXTURE = 0x1000
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -211,15 +189,15 @@ enum MENU_ITEM_TYPE {
|
|||||||
ITEM_TYPE_RADIOBUTTON = 2, // toggle button, may be grouped
|
ITEM_TYPE_RADIOBUTTON = 2, // toggle button, may be grouped
|
||||||
ITEM_TYPE_CHECKBOX = 3, // check box
|
ITEM_TYPE_CHECKBOX = 3, // check box
|
||||||
ITEM_TYPE_EDITFIELD = 4, // editable text, associated with a dvar
|
ITEM_TYPE_EDITFIELD = 4, // editable text, associated with a dvar
|
||||||
ITEM_TYPE_COMBO = 5, // drop down list
|
ITEM_TYPE_COMBO = 5, // drop down list
|
||||||
ITEM_TYPE_LISTBOX = 6, // scrollable list
|
ITEM_TYPE_LISTBOX = 6, // scrollable list
|
||||||
ITEM_TYPE_MODEL = 7, // model
|
ITEM_TYPE_MODEL = 7, // model
|
||||||
ITEM_TYPE_OWNERDRAW = 8, // owner draw, name specs what it is
|
ITEM_TYPE_OWNERDRAW = 8, // owner draw, name specs what it is
|
||||||
ITEM_TYPE_NUMERICFIELD = 9, // editable text, associated with a dvar
|
ITEM_TYPE_NUMERICFIELD = 9, // editable text, associated with a dvar
|
||||||
ITEM_TYPE_SLIDER = 10, // mouse speed, volume, etc.
|
ITEM_TYPE_SLIDER = 10, // mouse speed, volume, etc.
|
||||||
ITEM_TYPE_YESNO = 11, // yes no dvar setting
|
ITEM_TYPE_YESNO = 11, // yes no dvar setting
|
||||||
ITEM_TYPE_MULTI = 12, // multiple list setting, enumerated
|
ITEM_TYPE_MULTI = 12, // multiple list setting, enumerated
|
||||||
ITEM_TYPE_DVARENUM = 13, // multiple list setting, enumerated from a dvar
|
ITEM_TYPE_DVARENUM = 13, // multiple list setting, enumerated from a dvar
|
||||||
ITEM_TYPE_BIND = 14, // bind
|
ITEM_TYPE_BIND = 14, // bind
|
||||||
ITEM_TYPE_MENUMODEL = 15, // special menu model
|
ITEM_TYPE_MENUMODEL = 15, // special menu model
|
||||||
ITEM_TYPE_VALIDFILEFIELD = 16, // text must be valid for use in a dos filename
|
ITEM_TYPE_VALIDFILEFIELD = 16, // text must be valid for use in a dos filename
|
||||||
@ -432,7 +410,7 @@ enum MENU_FONT_TYPE{
|
|||||||
UI_FONT_DEFAULT = 0, // auto-chose betwen big/reg/small
|
UI_FONT_DEFAULT = 0, // auto-chose betwen big/reg/small
|
||||||
UI_FONT_NORMAL = 1,
|
UI_FONT_NORMAL = 1,
|
||||||
UI_FONT_BIG = 2,
|
UI_FONT_BIG = 2,
|
||||||
UI_FONT_SMALL = 3,
|
UI_GameFontMALL = 3,
|
||||||
UI_FONT_BOLD = 4,
|
UI_FONT_BOLD = 4,
|
||||||
UI_FONT_CONSOLE = 5,
|
UI_FONT_CONSOLE = 5,
|
||||||
UI_FONT_OBJECTIVE = 6,
|
UI_FONT_OBJECTIVE = 6,
|
||||||
|
|||||||
@ -2,15 +2,19 @@
|
|||||||
#define UTILS_H
|
#define UTILS_H
|
||||||
|
|
||||||
#include "enums.h"
|
#include "enums.h"
|
||||||
|
#include "QtZlib/zlib.h"
|
||||||
|
#include "qdir.h"
|
||||||
|
#include "qicon.h"
|
||||||
|
#include "xasset.h"
|
||||||
|
#include "xassettype.h"
|
||||||
|
|
||||||
#include <QString>
|
#include <QMetaEnum>
|
||||||
#include <QtZlib/zlib.h>
|
|
||||||
#include <QFileDialog>
|
|
||||||
#include <QMessageBox>
|
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QCryptographicHash>
|
#include <QCryptographicHash>
|
||||||
|
|
||||||
class Utils {
|
class Utils : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static bool ExportData(const QString aFileName, const QByteArray aData) {
|
static bool ExportData(const QString aFileName, const QByteArray aData) {
|
||||||
QDir workingDir = QDir::currentPath();
|
QDir workingDir = QDir::currentPath();
|
||||||
@ -30,6 +34,29 @@ public:
|
|||||||
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
|
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
static QIcon CreateAssetIcon(XAssetType aAssetType, QColor color = QColor()) {
|
||||||
|
const QString assetTypeStr = XAsset::XAssetTypeToString(aAssetType);
|
||||||
|
|
||||||
|
QString assetAbbr;
|
||||||
|
for (int i = 0; i < assetTypeStr.length(); i++)
|
||||||
|
{
|
||||||
|
if (assetTypeStr[i].isUpper())
|
||||||
|
{
|
||||||
|
assetAbbr += assetTypeStr[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CreateAssetIcon(assetAbbr, color);
|
||||||
|
|
||||||
|
// QString name;
|
||||||
|
// const QStringList parts = assetTypeStr.split('_').mid(1);
|
||||||
|
// foreach (const QString part, parts) {
|
||||||
|
// name += part[0];
|
||||||
|
// }
|
||||||
|
// if (parts.size() == 1) {
|
||||||
|
// name += parts.first()[1];
|
||||||
|
// }
|
||||||
|
// return CreateAssetIcon(name, color);
|
||||||
|
}
|
||||||
static QIcon CreateAssetIcon(const QString& name, QColor color = QColor()) {
|
static QIcon CreateAssetIcon(const QString& name, QColor color = QColor()) {
|
||||||
constexpr int iconSize = 32;
|
constexpr int iconSize = 32;
|
||||||
constexpr int padding = 4;
|
constexpr int padding = 4;
|
||||||
@ -196,7 +223,7 @@ public:
|
|||||||
|
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
static bool ReadUntilString(QDataStream* stream, const QString& targetString) {
|
static bool ReadUntilString(XDataStream* stream, const QString& targetString) {
|
||||||
if (!stream || targetString.isEmpty()) {
|
if (!stream || targetString.isEmpty()) {
|
||||||
return false; // Invalid input
|
return false; // Invalid input
|
||||||
}
|
}
|
||||||
@ -230,7 +257,7 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ReadUntilHex(QDataStream* stream, const QString& hexString) {
|
static bool ReadUntilHex(XDataStream* stream, const QString& hexString) {
|
||||||
if (!stream || hexString.isEmpty() || hexString.size() % 2 != 0) {
|
if (!stream || hexString.isEmpty() || hexString.size() % 2 != 0) {
|
||||||
return false; // Invalid input
|
return false; // Invalid input
|
||||||
}
|
}
|
||||||
@ -380,34 +407,6 @@ public:
|
|||||||
return PadInt4(size) - size;
|
return PadInt4(size) - size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static QString GetOpenFastFileName(QWidget *parent = nullptr) {
|
|
||||||
// Open file dialog to steam apps
|
|
||||||
const QString steamPath = "C:/Program Files (x86)/Steam/steamapps/common/Call of Duty World at War/zone/english/";
|
|
||||||
const QString fastFilePath = QFileDialog::getOpenFileName(parent, "Open Fast File", steamPath, "Fast File (*.ff);;All Files (*.*)");
|
|
||||||
if (fastFilePath.isNull()) {
|
|
||||||
// User pressed cancel
|
|
||||||
return "";
|
|
||||||
} else if (!QFile::exists(fastFilePath)) {
|
|
||||||
QMessageBox::warning(parent, "Warning!", QString("%1 does not exist!.").arg(fastFilePath));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return fastFilePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
static QString GetOpenZoneFileName(QWidget *parent = nullptr) {
|
|
||||||
// Open file dialog to steam apps
|
|
||||||
const QString steamPath = "C:/Program Files (x86)/Steam/steamapps/common/Call of Duty World at War/zone/english/";
|
|
||||||
const QString zoneFilePath = QFileDialog::getOpenFileName(parent, "Open Zone File", steamPath, "Zone File (*.zone);;All Files (*.*)");
|
|
||||||
if (zoneFilePath.isNull()) {
|
|
||||||
// User pressed cancel
|
|
||||||
return "";
|
|
||||||
} else if (!QFile::exists(zoneFilePath)) {
|
|
||||||
QMessageBox::warning(parent, "Warning!", QString("%1 does not exist!.").arg(zoneFilePath));
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return zoneFilePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
static QString CompanyEnumToStr(FF_COMPANY aCompany) {
|
static QString CompanyEnumToStr(FF_COMPANY aCompany) {
|
||||||
switch (aCompany) {
|
switch (aCompany) {
|
||||||
case COMPANY_NONE:
|
case COMPANY_NONE:
|
||||||
|
|||||||
243
libs/core/xdatastream.cpp
Normal file
243
libs/core/xdatastream.cpp
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
#include "xdatastream.h"
|
||||||
|
|
||||||
|
#include <QIODevice>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
XDataStream::XDataStream(QIODevice *aDevice)
|
||||||
|
: QDataStream(aDevice)
|
||||||
|
, mDebug(false)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
XDataStream::XDataStream()
|
||||||
|
: QDataStream()
|
||||||
|
, mDebug(false)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
XDataStream::XDataStream(const QByteArray &aData)
|
||||||
|
: QDataStream(aData)
|
||||||
|
, mDebug(false)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
XDataStream::XDataStream(QByteArray *aData, OpenMode aFlags)
|
||||||
|
: QDataStream(aData, aFlags)
|
||||||
|
, mDebug(false)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
XDataStream::~XDataStream()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void XDataStream::SetDebug(bool aDebug)
|
||||||
|
{
|
||||||
|
mDebug = aDebug;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint8 XDataStream::ParseInt8(const QString& aDebugString)
|
||||||
|
{
|
||||||
|
qint64 start = this->device()->pos();
|
||||||
|
|
||||||
|
qint8 val;
|
||||||
|
*this >> val;
|
||||||
|
|
||||||
|
if (mDebug)
|
||||||
|
{
|
||||||
|
qDebug() << QString("[%1-%2] Parsed %3: %4")
|
||||||
|
.arg(start, 10, 10, QChar('0'))
|
||||||
|
.arg(this->device()->pos(), 10, 10, QChar('0'))
|
||||||
|
.arg(aDebugString)
|
||||||
|
.arg(val);
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
quint8 XDataStream::ParseUInt8(const QString& aDebugString)
|
||||||
|
{
|
||||||
|
qint64 start = this->device()->pos();
|
||||||
|
|
||||||
|
quint8 val;
|
||||||
|
*this >> val;
|
||||||
|
|
||||||
|
if (mDebug)
|
||||||
|
{
|
||||||
|
qDebug() << QString("[%1-%2] Parsed %3: %4")
|
||||||
|
.arg(start, 10, 10, QChar('0'))
|
||||||
|
.arg(this->device()->pos(), 10, 10, QChar('0'))
|
||||||
|
.arg(aDebugString)
|
||||||
|
.arg(val);
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint16 XDataStream::ParseInt16(const QString& aDebugString)
|
||||||
|
{
|
||||||
|
qint64 start = this->device()->pos();
|
||||||
|
|
||||||
|
qint16 val;
|
||||||
|
*this >> val;
|
||||||
|
|
||||||
|
if (mDebug)
|
||||||
|
{
|
||||||
|
qDebug() << QString("[%1-%2] Parsed %3: %4")
|
||||||
|
.arg(start, 10, 10, QChar('0'))
|
||||||
|
.arg(this->device()->pos(), 10, 10, QChar('0'))
|
||||||
|
.arg(aDebugString)
|
||||||
|
.arg(val);
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
quint16 XDataStream::ParseUInt16(const QString& aDebugString)
|
||||||
|
{
|
||||||
|
qint64 start = this->device()->pos();
|
||||||
|
|
||||||
|
quint16 val;
|
||||||
|
*this >> val;
|
||||||
|
|
||||||
|
if (mDebug)
|
||||||
|
{
|
||||||
|
qDebug() << QString("[%1-%2] Parsed %3: %4")
|
||||||
|
.arg(start, 10, 10, QChar('0'))
|
||||||
|
.arg(this->device()->pos(), 10, 10, QChar('0'))
|
||||||
|
.arg(aDebugString)
|
||||||
|
.arg(val);
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint32 XDataStream::ParseInt32(const QString& aDebugString)
|
||||||
|
{
|
||||||
|
qint64 start = this->device()->pos();
|
||||||
|
|
||||||
|
qint32 val;
|
||||||
|
*this >> val;
|
||||||
|
|
||||||
|
if (mDebug)
|
||||||
|
{
|
||||||
|
qDebug() << QString("[%1-%2] Parsed %3: %4")
|
||||||
|
.arg(start, 10, 10, QChar('0'))
|
||||||
|
.arg(this->device()->pos(), 10, 10, QChar('0'))
|
||||||
|
.arg(aDebugString)
|
||||||
|
.arg(val);
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
quint32 XDataStream::ParseUInt32(const QString& aDebugString)
|
||||||
|
{
|
||||||
|
qint64 start = this->device()->pos();
|
||||||
|
|
||||||
|
quint32 val;
|
||||||
|
*this >> val;
|
||||||
|
|
||||||
|
if (mDebug)
|
||||||
|
{
|
||||||
|
qDebug() << QString("[%1-%2] Parsed %3: %4")
|
||||||
|
.arg(start, 10, 10, QChar('0'))
|
||||||
|
.arg(this->device()->pos(), 10, 10, QChar('0'))
|
||||||
|
.arg(aDebugString)
|
||||||
|
.arg(val);
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 XDataStream::ParseInt64(const QString& aDebugString)
|
||||||
|
{
|
||||||
|
qint64 start = this->device()->pos();
|
||||||
|
|
||||||
|
qint64 val;
|
||||||
|
*this >> val;
|
||||||
|
|
||||||
|
if (mDebug)
|
||||||
|
{
|
||||||
|
qDebug() << QString("[%1-%2] Parsed %3: %4")
|
||||||
|
.arg(start, 10, 10, QChar('0'))
|
||||||
|
.arg(this->device()->pos(), 10, 10, QChar('0'))
|
||||||
|
.arg(aDebugString)
|
||||||
|
.arg(val);
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
quint64 XDataStream::ParseUInt64(const QString& aDebugString)
|
||||||
|
{
|
||||||
|
qint64 start = this->device()->pos();
|
||||||
|
|
||||||
|
quint64 val;
|
||||||
|
*this >> val;
|
||||||
|
|
||||||
|
if (mDebug)
|
||||||
|
{
|
||||||
|
qDebug() << QString("[%1-%2] Parsed %3: %4")
|
||||||
|
.arg(start, 10, 10, QChar('0'))
|
||||||
|
.arg(this->device()->pos(), 10, 10, QChar('0'))
|
||||||
|
.arg(aDebugString)
|
||||||
|
.arg(val);
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
float XDataStream::ParseSingle(const QString& aDebugString)
|
||||||
|
{
|
||||||
|
qint64 start = this->device()->pos();
|
||||||
|
|
||||||
|
|
||||||
|
float val;
|
||||||
|
quint32 rawVal;
|
||||||
|
*this >> rawVal;
|
||||||
|
memcpy(&val, &rawVal, sizeof(val));
|
||||||
|
|
||||||
|
if (mDebug)
|
||||||
|
{
|
||||||
|
qDebug() << QString("[%1-%2] Parsed %3: %4")
|
||||||
|
.arg(start, 10, 10, QChar('0'))
|
||||||
|
.arg(this->device()->pos(), 10, 10, QChar('0'))
|
||||||
|
.arg(aDebugString)
|
||||||
|
.arg(val);
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
double XDataStream::ParseDouble(const QString& aDebugString)
|
||||||
|
{
|
||||||
|
qint64 start = this->device()->pos();
|
||||||
|
|
||||||
|
float val;
|
||||||
|
*this >> val;
|
||||||
|
|
||||||
|
if (mDebug)
|
||||||
|
{
|
||||||
|
qDebug() << QString("[%1-%2] Parsed %3: %4")
|
||||||
|
.arg(start, 10, 10, QChar('0'))
|
||||||
|
.arg(this->device()->pos(), 10, 10, QChar('0'))
|
||||||
|
.arg(aDebugString)
|
||||||
|
.arg(val);
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool XDataStream::ParseBool(const QString &aDebugString)
|
||||||
|
{
|
||||||
|
qint64 start = this->device()->pos();
|
||||||
|
|
||||||
|
char val;
|
||||||
|
*this >> val;
|
||||||
|
|
||||||
|
if (mDebug)
|
||||||
|
{
|
||||||
|
qDebug() << QString("[%1-%2] Parsed %3: %4")
|
||||||
|
.arg(start, 10, 10, QChar('0'))
|
||||||
|
.arg(this->device()->pos(), 10, 10, QChar('0'))
|
||||||
|
.arg(aDebugString)
|
||||||
|
.arg(val);
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
34
libs/core/xdatastream.h
Normal file
34
libs/core/xdatastream.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#ifndef XDATASTREAM_H
|
||||||
|
#define XDATASTREAM_H
|
||||||
|
|
||||||
|
#include <QDataStream>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
class XDataStream : public QDataStream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit XDataStream(QIODevice* aDevice);
|
||||||
|
XDataStream();
|
||||||
|
XDataStream(const QByteArray& aData);
|
||||||
|
XDataStream(QByteArray* aData, OpenMode aFlags);
|
||||||
|
~XDataStream();
|
||||||
|
|
||||||
|
void SetDebug(bool aDebug = true);
|
||||||
|
|
||||||
|
qint8 ParseInt8(const QString& aDebugString = "");
|
||||||
|
quint8 ParseUInt8(const QString& aDebugString = "");
|
||||||
|
qint16 ParseInt16(const QString& aDebugString = "");
|
||||||
|
quint16 ParseUInt16(const QString& aDebugString = "");
|
||||||
|
qint32 ParseInt32(const QString& aDebugString = "");
|
||||||
|
quint32 ParseUInt32(const QString& aDebugString = "");
|
||||||
|
qint64 ParseInt64(const QString& aDebugString = "");
|
||||||
|
quint64 ParseUInt64(const QString& aDebugString = "");
|
||||||
|
float ParseSingle(const QString& aDebugString = "");
|
||||||
|
double ParseDouble(const QString& aDebugString = "");
|
||||||
|
bool ParseBool(const QString& aDebugString = "");
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool mDebug;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // XDATASTREAM_H
|
||||||
@ -35,7 +35,7 @@ DDSPixelFormat DDSFile::CalculatePixelFormat(quint8 aIWIFormat) {
|
|||||||
return ddsPixelFormat;
|
return ddsPixelFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DDSFile::SetupExportDirs() {
|
void DDSFile::SetupExportDirs() const {
|
||||||
QDir dir = QDir::currentPath();
|
QDir dir = QDir::currentPath();
|
||||||
if (!dir.exists("exports/")) {
|
if (!dir.exists("exports/")) {
|
||||||
dir.mkdir("exports/");
|
dir.mkdir("exports/");
|
||||||
@ -89,92 +89,92 @@ DDSFile::DDSFile(const QString &aFilePath)
|
|||||||
}
|
}
|
||||||
|
|
||||||
DDSFile::DDSFile(const QByteArray aDDSData, const QString aFileStem) {
|
DDSFile::DDSFile(const QByteArray aDDSData, const QString aFileStem) {
|
||||||
QDataStream ddsIn(aDDSData);
|
// QDataStream ddsIn(aDDSData);
|
||||||
ddsIn.setByteOrder(QDataStream::LittleEndian);
|
// ddsIn.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
DDSHeader ddsHeader;
|
// DDSHeader ddsHeader;
|
||||||
if (ddsIn.readRawData(reinterpret_cast<char*>(&ddsHeader), sizeof(DDSHeader)) != sizeof(DDSHeader)) {
|
// if (ddsIn.readRawData(reinterpret_cast<char*>(&ddsHeader), sizeof(DDSHeader)) != sizeof(DDSHeader)) {
|
||||||
qDebug() << "Error: Failed to read DDSHeader from QByteArray!";
|
// qDebug() << "Error: Failed to read DDSHeader from QByteArray!";
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
fileStem = aFileStem;
|
// fileStem = aFileStem;
|
||||||
header = ddsHeader;
|
// header = ddsHeader;
|
||||||
|
|
||||||
// Ensure DevIL is initialized once globally
|
// // Ensure DevIL is initialized once globally
|
||||||
static bool devilInitialized = false;
|
// static bool devilInitialized = false;
|
||||||
if (!devilInitialized) {
|
// if (!devilInitialized) {
|
||||||
ilInit();
|
// ilInit();
|
||||||
devilInitialized = true;
|
// devilInitialized = true;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Generate and bind an image
|
// // Generate and bind an image
|
||||||
ILuint imageID;
|
// ILuint imageID;
|
||||||
ilGenImages(1, &imageID);
|
// ilGenImages(1, &imageID);
|
||||||
ilBindImage(imageID);
|
// ilBindImage(imageID);
|
||||||
|
|
||||||
ilEnable(IL_ORIGIN_SET);
|
// ilEnable(IL_ORIGIN_SET);
|
||||||
ilOriginFunc(IL_ORIGIN_UPPER_LEFT);
|
// ilOriginFunc(IL_ORIGIN_UPPER_LEFT);
|
||||||
|
|
||||||
// Load DDS file
|
// // Load DDS file
|
||||||
if (!ilLoadL(IL_DDS, aDDSData.constData(), aDDSData.size())) {
|
// if (!ilLoadL(IL_DDS, aDDSData.constData(), aDDSData.size())) {
|
||||||
ILuint devilError = ilGetError();
|
// ILuint devilError = ilGetError();
|
||||||
qDebug() << "DevIL Error while loading DDS: " << devilError;
|
// qDebug() << "DevIL Error while loading DDS: " << devilError;
|
||||||
ilDeleteImages(1, &imageID);
|
// ilDeleteImages(1, &imageID);
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Get mipmap count
|
// // Get mipmap count
|
||||||
ILint numMipmaps = ilGetInteger(IL_NUM_MIPMAPS);
|
// ILint numMipmaps = ilGetInteger(IL_NUM_MIPMAPS);
|
||||||
qDebug() << "Number of mipmaps: " << numMipmaps;
|
// qDebug() << "Number of mipmaps: " << numMipmaps;
|
||||||
|
|
||||||
// Loop over all mipmap levels (0 is the base image)
|
// // Loop over all mipmap levels (0 is the base image)
|
||||||
for (ILint level = 0; level <= numMipmaps; ++level) {
|
// for (ILint level = 0; level <= numMipmaps; ++level) {
|
||||||
ilBindImage(imageID);
|
// ilBindImage(imageID);
|
||||||
if (!ilActiveMipmap(level)) {
|
// if (!ilActiveMipmap(level)) {
|
||||||
qDebug() << "DevIL failed to activate mipmap level" << level;
|
// qDebug() << "DevIL failed to activate mipmap level" << level;
|
||||||
continue;
|
// continue;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Get mipmap properties
|
// // Get mipmap properties
|
||||||
int width = ilGetInteger(IL_IMAGE_WIDTH);
|
// int width = ilGetInteger(IL_IMAGE_WIDTH);
|
||||||
int height = ilGetInteger(IL_IMAGE_HEIGHT);
|
// int height = ilGetInteger(IL_IMAGE_HEIGHT);
|
||||||
int depth = ilGetInteger(IL_IMAGE_DEPTH);
|
// int depth = ilGetInteger(IL_IMAGE_DEPTH);
|
||||||
int format = ilGetInteger(IL_IMAGE_FORMAT);
|
// int format = ilGetInteger(IL_IMAGE_FORMAT);
|
||||||
int bpp = 0;
|
// int bpp = 0;
|
||||||
|
|
||||||
switch (format) {
|
// switch (format) {
|
||||||
case IL_RGB:
|
// case IL_RGB:
|
||||||
bpp = 3;
|
// bpp = 3;
|
||||||
break;
|
// break;
|
||||||
case IL_RGBA:
|
// case IL_RGBA:
|
||||||
bpp = 4;
|
// bpp = 4;
|
||||||
break;
|
// break;
|
||||||
default:
|
// default:
|
||||||
qDebug() << "Unsupported image format.";
|
// qDebug() << "Unsupported image format.";
|
||||||
continue;
|
// continue;
|
||||||
}
|
// }
|
||||||
|
|
||||||
int dataSize = width * height * depth * bpp;
|
// int dataSize = width * height * depth * bpp;
|
||||||
|
|
||||||
ILubyte *data = ilGetData();
|
// ILubyte *data = ilGetData();
|
||||||
if (!data) {
|
// if (!data) {
|
||||||
qDebug() << "Error: DevIL returned null data for mipmap level" << level;
|
// qDebug() << "Error: DevIL returned null data for mipmap level" << level;
|
||||||
continue;
|
// continue;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Create a mipmap structure
|
// // Create a mipmap structure
|
||||||
DDSMipmap mipmap;
|
// DDSMipmap mipmap;
|
||||||
mipmap.width = width;
|
// mipmap.width = width;
|
||||||
mipmap.height = height;
|
// mipmap.height = height;
|
||||||
mipmap.data = QByteArray(reinterpret_cast<const char*>(data), dataSize);
|
// mipmap.data = QByteArray(reinterpret_cast<const char*>(data), dataSize);
|
||||||
mipmap.size = dataSize;
|
// mipmap.size = dataSize;
|
||||||
|
|
||||||
// Store in DDS file
|
// // Store in DDS file
|
||||||
mipmaps.append(mipmap);
|
// mipmaps.append(mipmap);
|
||||||
}
|
// }
|
||||||
|
|
||||||
ilDeleteImages(1, &imageID);
|
// ilDeleteImages(1, &imageID);
|
||||||
}
|
}
|
||||||
|
|
||||||
DDSFile::DDSFile(const DDSFile &ddsFile) :
|
DDSFile::DDSFile(const DDSFile &ddsFile) :
|
||||||
@ -248,7 +248,7 @@ DDSFile &DDSFile::operator=(const DDSFile &other) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write a DDS file from a DDSFile object
|
// Write a DDS file from a DDSFile object
|
||||||
bool DDSFile::SaveDDS() {
|
bool DDSFile::SaveDDS() const {
|
||||||
SetupExportDirs();
|
SetupExportDirs();
|
||||||
|
|
||||||
QFile file("exports/dds/" + fileStem + ".dds");
|
QFile file("exports/dds/" + fileStem + ".dds");
|
||||||
@ -268,7 +268,7 @@ bool DDSFile::SaveDDS() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DDSFile::SaveIWI() {
|
bool DDSFile::SaveIWI() const {
|
||||||
SetupExportDirs();
|
SetupExportDirs();
|
||||||
|
|
||||||
IWIFile iwiFile(*this);
|
IWIFile iwiFile(*this);
|
||||||
@ -279,7 +279,7 @@ bool DDSFile::SaveIWI() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DDSFile::SavePNG() {
|
bool DDSFile::SavePNG() const {
|
||||||
SetupExportDirs();
|
SetupExportDirs();
|
||||||
|
|
||||||
int mipmapIndex = 1;
|
int mipmapIndex = 1;
|
||||||
@ -311,7 +311,7 @@ bool DDSFile::SavePNG() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DDSFile::SaveJPG() {
|
bool DDSFile::SaveJPG() const {
|
||||||
SetupExportDirs();
|
SetupExportDirs();
|
||||||
|
|
||||||
int mipmapIndex = 1;
|
int mipmapIndex = 1;
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
#include <QVector>
|
#include <QVector>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <IL/il.h>
|
//#include <IL/il.h>
|
||||||
|
|
||||||
struct DDSPixelFormat {
|
struct DDSPixelFormat {
|
||||||
quint32 size;
|
quint32 size;
|
||||||
@ -68,12 +68,12 @@ public:
|
|||||||
DDSFile(const DDSFile &ddsFile);
|
DDSFile(const DDSFile &ddsFile);
|
||||||
DDSFile& operator=(const DDSFile& other);
|
DDSFile& operator=(const DDSFile& other);
|
||||||
|
|
||||||
bool SaveDDS();
|
bool SaveDDS() const;
|
||||||
bool SaveIWI();
|
bool SaveIWI() const;
|
||||||
bool SavePNG();
|
bool SavePNG() const;
|
||||||
bool SaveJPG();
|
bool SaveJPG() const;
|
||||||
|
|
||||||
void SetupExportDirs();
|
void SetupExportDirs() const;
|
||||||
static DDSPixelFormat CalculatePixelFormat(quint8 aIWIFormat);
|
static DDSPixelFormat CalculatePixelFormat(quint8 aIWIFormat);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@ -2,26 +2,21 @@ QT += core
|
|||||||
TEMPLATE = lib
|
TEMPLATE = lib
|
||||||
CONFIG += staticlib c++17
|
CONFIG += staticlib c++17
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += $$files($$PWD/*.cpp, true)
|
||||||
ddsfile.cpp
|
HEADERS += $$files($$PWD/*.h, true)
|
||||||
|
|
||||||
HEADERS += \
|
|
||||||
dds_structs.h \
|
|
||||||
ddsfile.h \
|
|
||||||
enums.h
|
|
||||||
|
|
||||||
LIBS += \
|
LIBS += \
|
||||||
-L$$PWD/../../third_party/devil_sdk/lib/ -lDevIL \
|
#-L$$PWD/../../third_party/devil_sdk/lib/ -lDevIL \
|
||||||
-L$$PWD/../../third_party/devil_sdk/lib/ -lILU \
|
#-L$$PWD/../../third_party/devil_sdk/lib/ -lILU \
|
||||||
-L$$PWD/../../third_party/devil_sdk/lib/ -lILUT \
|
#-L$$PWD/../../third_party/devil_sdk/lib/ -lILUT \
|
||||||
-L$$OUT_PWD/../libs/iwifile -liwifile
|
-L$$OUT_PWD/../libs/iwifile -liwifile
|
||||||
|
|
||||||
INCLUDEPATH += \
|
INCLUDEPATH += \
|
||||||
$$PWD/../iwifile/ \
|
$$PWD/../iwifile/ \
|
||||||
$$PWD/../../third_party/devil_sdk/include/
|
#$$PWD/../../third_party/devil_sdk/include/
|
||||||
|
|
||||||
DEPENDPATH += \
|
DEPENDPATH += \
|
||||||
$$PWD/../iwifile/ \
|
$$PWD/../iwifile/ \
|
||||||
$$PWD/../../third_party/devil_sdk/include/
|
#$$PWD/../../third_party/devil_sdk/include/
|
||||||
|
|
||||||
DESTDIR = $$OUT_PWD/../
|
DESTDIR = $$OUT_PWD/../
|
||||||
|
|||||||
@ -24,9 +24,9 @@ enum FF_GAME {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum IWI_VERSION {
|
enum IWI_VERSION {
|
||||||
IWI_VERSION_COD2 = 0x05, // 05 CoD2
|
IWI_VERSION_COD2 = 0x05, // 05 CoD2
|
||||||
IWI_VERSION_COD4 = 0x06, // 06 CoD4
|
IWI_VERSION_COD4 = 0x06, // 06 CoD4
|
||||||
IWI_VERSION_COD5 = 0x06, // 06 CoD5
|
IWI_VERSION_COD5 = 0x06, // 06 CoD5
|
||||||
IWI_VERSION_CODMW2 = 0x08, // 08 CoDMW2
|
IWI_VERSION_CODMW2 = 0x08, // 08 CoDMW2
|
||||||
IWI_VERSION_CODMW3 = 0x08, // 08 CoDMW3
|
IWI_VERSION_CODMW3 = 0x08, // 08 CoDMW3
|
||||||
IWI_VERSION_CODBO1 = 0x0D, // 13 CoDBO1
|
IWI_VERSION_CODBO1 = 0x0D, // 13 CoDBO1
|
||||||
@ -36,37 +36,37 @@ enum IWI_VERSION {
|
|||||||
enum IWI_FORMAT {
|
enum IWI_FORMAT {
|
||||||
// IWI Format
|
// IWI Format
|
||||||
IWI_FORMAT_ARGB32 = 0x01, // 01 ARGB32
|
IWI_FORMAT_ARGB32 = 0x01, // 01 ARGB32
|
||||||
IWI_FORMAT_RGB24 = 0x02, // 02 RGB24
|
IWI_FORMAT_RGB24 = 0x02, // 02 RGB24
|
||||||
IWI_FORMAT_GA16 = 0x03, // 03 GA16
|
IWI_FORMAT_GA16 = 0x03, // 03 GA16
|
||||||
IWI_FORMAT_A8 = 0x04, // 04 A8
|
IWI_FORMAT_A8 = 0x04, // 04 A8
|
||||||
IWI_FORMAT_DXT1 = 0x0B, // 11 DXT1
|
IWI_FORMAT_DXT1 = 0x0B, // 11 DXT1
|
||||||
IWI_FORMAT_DXT3 = 0x0C, // 12 DXT3
|
IWI_FORMAT_DXT3 = 0x0C, // 12 DXT3
|
||||||
IWI_FORMAT_DXT5 = 0x0D // 13 DXT5
|
IWI_FORMAT_DXT5 = 0x0D // 13 DXT5
|
||||||
};
|
};
|
||||||
|
|
||||||
enum DDS_FLAGS {
|
enum DDS_FLAGS {
|
||||||
DDSD_CAPS = 0x1,
|
DDSD_CAPS = 0x1,
|
||||||
DDSD_HEIGHT = 0x2,
|
DDSD_HEIGHT = 0x2,
|
||||||
DDSD_WIDTH = 0x4,
|
DDSD_WIDTH = 0x4,
|
||||||
DDSD_PITCH = 0x8,
|
DDSD_PITCH = 0x8,
|
||||||
DDSD_PIXELFORMAT = 0x1000,
|
DDSD_PIXELFORMAT = 0x1000,
|
||||||
DDSD_MIPMAPCOUNT = 0x20000,
|
DDSD_MIPMAPCOUNT = 0x20000,
|
||||||
DDSD_LINEARSIZE = 0x80000,
|
DDSD_LINEARSIZE = 0x80000,
|
||||||
DDSD_DEPTH = 0x800000
|
DDSD_DEPTH = 0x800000
|
||||||
};
|
};
|
||||||
|
|
||||||
enum DDS_PIXELFORMAT_FLAGS {
|
enum DDS_PIXELFORMAT_FLAGS {
|
||||||
DDPF_ALPHAPIXELS = 0x1,
|
DDPF_ALPHAPIXELS = 0x1,
|
||||||
DDPF_ALPHA = 0x2,
|
DDPF_ALPHA = 0x2,
|
||||||
DDPF_FOURCC = 0x4,
|
DDPF_FOURCC = 0x4,
|
||||||
DDPF_RGB = 0x40,
|
DDPF_RGB = 0x40,
|
||||||
DDPF_YUV = 0x200,
|
DDPF_YUV = 0x200,
|
||||||
DDPF_LUMINANCE = 0x20000
|
DDPF_LUMINANCE = 0x20000
|
||||||
};
|
};
|
||||||
|
|
||||||
enum DDS_CAPS_FLAGS {
|
enum DDS_CAPS_FLAGS {
|
||||||
DDSCAPS_COMPLEX = 0x8,
|
DDSCAPS_COMPLEX = 0x8,
|
||||||
DDSCAPS_MIPMAP = 0x400000,
|
DDSCAPS_MIPMAP = 0x400000,
|
||||||
DDSCAPS_TEXTURE = 0x1000
|
DDSCAPS_TEXTURE = 0x1000
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -209,15 +209,15 @@ enum MENU_ITEM_TYPE {
|
|||||||
ITEM_TYPE_RADIOBUTTON = 2, // toggle button, may be grouped
|
ITEM_TYPE_RADIOBUTTON = 2, // toggle button, may be grouped
|
||||||
ITEM_TYPE_CHECKBOX = 3, // check box
|
ITEM_TYPE_CHECKBOX = 3, // check box
|
||||||
ITEM_TYPE_EDITFIELD = 4, // editable text, associated with a dvar
|
ITEM_TYPE_EDITFIELD = 4, // editable text, associated with a dvar
|
||||||
ITEM_TYPE_COMBO = 5, // drop down list
|
ITEM_TYPE_COMBO = 5, // drop down list
|
||||||
ITEM_TYPE_LISTBOX = 6, // scrollable list
|
ITEM_TYPE_LISTBOX = 6, // scrollable list
|
||||||
ITEM_TYPE_MODEL = 7, // model
|
ITEM_TYPE_MODEL = 7, // model
|
||||||
ITEM_TYPE_OWNERDRAW = 8, // owner draw, name specs what it is
|
ITEM_TYPE_OWNERDRAW = 8, // owner draw, name specs what it is
|
||||||
ITEM_TYPE_NUMERICFIELD = 9, // editable text, associated with a dvar
|
ITEM_TYPE_NUMERICFIELD = 9, // editable text, associated with a dvar
|
||||||
ITEM_TYPE_SLIDER = 10, // mouse speed, volume, etc.
|
ITEM_TYPE_SLIDER = 10, // mouse speed, volume, etc.
|
||||||
ITEM_TYPE_YESNO = 11, // yes no dvar setting
|
ITEM_TYPE_YESNO = 11, // yes no dvar setting
|
||||||
ITEM_TYPE_MULTI = 12, // multiple list setting, enumerated
|
ITEM_TYPE_MULTI = 12, // multiple list setting, enumerated
|
||||||
ITEM_TYPE_DVARENUM = 13, // multiple list setting, enumerated from a dvar
|
ITEM_TYPE_DVARENUM = 13, // multiple list setting, enumerated from a dvar
|
||||||
ITEM_TYPE_BIND = 14, // bind
|
ITEM_TYPE_BIND = 14, // bind
|
||||||
ITEM_TYPE_MENUMODEL = 15, // special menu model
|
ITEM_TYPE_MENUMODEL = 15, // special menu model
|
||||||
ITEM_TYPE_VALIDFILEFIELD = 16, // text must be valid for use in a dos filename
|
ITEM_TYPE_VALIDFILEFIELD = 16, // text must be valid for use in a dos filename
|
||||||
@ -430,7 +430,7 @@ enum MENU_FONT_TYPE{
|
|||||||
UI_FONT_DEFAULT = 0, // auto-chose betwen big/reg/small
|
UI_FONT_DEFAULT = 0, // auto-chose betwen big/reg/small
|
||||||
UI_FONT_NORMAL = 1,
|
UI_FONT_NORMAL = 1,
|
||||||
UI_FONT_BIG = 2,
|
UI_FONT_BIG = 2,
|
||||||
UI_FONT_SMALL = 3,
|
UI_GameFontMALL = 3,
|
||||||
UI_FONT_BOLD = 4,
|
UI_FONT_BOLD = 4,
|
||||||
UI_FONT_CONSOLE = 5,
|
UI_FONT_CONSOLE = 5,
|
||||||
UI_FONT_OBJECTIVE = 6,
|
UI_FONT_OBJECTIVE = 6,
|
||||||
|
|||||||
@ -1,15 +1,5 @@
|
|||||||
/* ecrypt-portable.h */
|
/* ecrypt-portable.h */
|
||||||
|
|
||||||
/*
|
|
||||||
* WARNING: the conversions defined below are implemented as macros,
|
|
||||||
* and should be used carefully. They should NOT be used with
|
|
||||||
* parameters which perform some action. E.g., the following two lines
|
|
||||||
* are not equivalent:
|
|
||||||
*
|
|
||||||
* 1) ++x; y = ROTL32(x, n);
|
|
||||||
* 2) y = ROTL32(++x, n);
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* *** Please do not edit this file. ***
|
* *** Please do not edit this file. ***
|
||||||
*
|
*
|
||||||
@ -27,10 +17,10 @@
|
|||||||
/*
|
/*
|
||||||
* The following types are defined (if available):
|
* The following types are defined (if available):
|
||||||
*
|
*
|
||||||
* u8: unsigned integer type, at least 8 bits
|
* u8: quint32eger type, at least 8 bits
|
||||||
* u16: unsigned integer type, at least 16 bits
|
* u16: quint32eger type, at least 16 bits
|
||||||
* u32: unsigned integer type, at least 32 bits
|
* u32: quint32eger type, at least 32 bits
|
||||||
* u64: unsigned integer type, at least 64 bits
|
* u64: quint32eger type, at least 64 bits
|
||||||
*
|
*
|
||||||
* s8, s16, s32, s64 -> signed counterparts of u8, u16, u32, u64
|
* s8, s16, s32, s64 -> signed counterparts of u8, u16, u32, u64
|
||||||
*
|
*
|
||||||
|
|||||||
@ -1,27 +1,35 @@
|
|||||||
#include "encryption.h"
|
#include <QtCore>
|
||||||
#include "QtZlib/zlib.h"
|
#include "QtZlib/zlib.h"
|
||||||
#include "ecrypt-sync.h"
|
#include "ecrypt-sync.h"
|
||||||
|
#include "sha1.h"
|
||||||
|
#include "encryption.h"
|
||||||
#include "compression.h"
|
#include "compression.h"
|
||||||
|
|
||||||
void Encryption::Convert32BitTo8Bit(quint32 value, quint8 *array) {
|
static QVector<quint32> ivCounter(4, 1); // start all counters at 1
|
||||||
|
|
||||||
|
void Encryption::Convert32BitTo8Bit(quint32 value, quint8 *array)
|
||||||
|
{
|
||||||
array[0] = static_cast<quint8>(value >> 0);
|
array[0] = static_cast<quint8>(value >> 0);
|
||||||
array[1] = static_cast<quint8>(value >> 8);
|
array[1] = static_cast<quint8>(value >> 8);
|
||||||
array[2] = static_cast<quint8>(value >> 16);
|
array[2] = static_cast<quint8>(value >> 16);
|
||||||
array[3] = static_cast<quint8>(value >> 24);
|
array[3] = static_cast<quint8>(value >> 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
quint32 Encryption::ConvertArrayTo32Bit(const QByteArray &array) {
|
quint32 Encryption::ConvertArrayTo32Bit(const QByteArray &array)
|
||||||
|
{
|
||||||
return ((static_cast<quint32>(static_cast<uchar>(array[0])) << 0) |
|
return ((static_cast<quint32>(static_cast<uchar>(array[0])) << 0) |
|
||||||
(static_cast<quint32>(static_cast<uchar>(array[1])) << 8) |
|
(static_cast<quint32>(static_cast<uchar>(array[1])) << 8) |
|
||||||
(static_cast<quint32>(static_cast<uchar>(array[2])) << 16) |
|
(static_cast<quint32>(static_cast<uchar>(array[2])) << 16) |
|
||||||
(static_cast<quint32>(static_cast<uchar>(array[3])) << 24));
|
(static_cast<quint32>(static_cast<uchar>(array[3])) << 24));
|
||||||
}
|
}
|
||||||
|
|
||||||
quint32 Encryption::Rotate(quint32 value, quint32 numBits) {
|
quint32 Encryption::Rotate(quint32 value, quint32 numBits)
|
||||||
|
{
|
||||||
return (value << numBits) | (value >> (32 - numBits));
|
return (value << numBits) | (value >> (32 - numBits));
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray Encryption::InitIVTable(const QByteArray &feed) {
|
QByteArray Encryption::InitIVTable(const QByteArray &feed)
|
||||||
|
{
|
||||||
const int tableSize = 0xFB0;
|
const int tableSize = 0xFB0;
|
||||||
QByteArray table;
|
QByteArray table;
|
||||||
table.resize(tableSize);
|
table.resize(tableSize);
|
||||||
@ -31,7 +39,7 @@ QByteArray Encryption::InitIVTable(const QByteArray &feed) {
|
|||||||
if (static_cast<uchar>(feed.at(ptr)) == 0x00)
|
if (static_cast<uchar>(feed.at(ptr)) == 0x00)
|
||||||
ptr = 0;
|
ptr = 0;
|
||||||
int base = i * 20 + x * 4;
|
int base = i * 20 + x * 4;
|
||||||
table[base] = feed.at(ptr);
|
table[base] = feed.at(ptr);
|
||||||
table[base + 1] = feed.at(ptr);
|
table[base + 1] = feed.at(ptr);
|
||||||
table[base + 2] = feed.at(ptr);
|
table[base + 2] = feed.at(ptr);
|
||||||
table[base + 3] = feed.at(ptr);
|
table[base + 3] = feed.at(ptr);
|
||||||
@ -48,22 +56,23 @@ QByteArray Encryption::InitIVTable(const QByteArray &feed) {
|
|||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Encryption::unk(quint64 arg1, quint8 arg2) {
|
int Encryption::unk(quint64 arg1, quint8 arg2)
|
||||||
|
{
|
||||||
if (arg2 >= 0x40)
|
if (arg2 >= 0x40)
|
||||||
return 0;
|
return 0;
|
||||||
return static_cast<int>(arg1 >> arg2);
|
return static_cast<int>(arg1 >> arg2);
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray Encryption::GetIV(const QByteArray &table, int index) {
|
QByteArray Encryption::GetIV(const QByteArray &table, int index)
|
||||||
int num1 = 0xFA0 + index;
|
{
|
||||||
|
int num1 = (4 * index % 4 + 0xFA0) + index % 4 + (index - (index % 4));
|
||||||
int num2 = unk(0x51EB851FLL * num1, 0x20);
|
int num2 = unk(0x51EB851FLL * num1, 0x20);
|
||||||
int adjust = ((num2 >> 6) + (num2 >> 31));
|
int startIndex = 20 * (num1 - 200 * ((num2 >> 6) + (num2 >> 31)));
|
||||||
int startIndex = 20 * (num1 - 200 * adjust);
|
|
||||||
// Return 8 bytes from that location.
|
|
||||||
return table.mid(startIndex, 8);
|
return table.mid(startIndex, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Encryption::UpdateIVTable(QByteArray &table, int index, const QByteArray §ionHash) {
|
void Encryption::UpdateIVTable(QByteArray &table, int index, const QByteArray §ionHash)
|
||||||
|
{
|
||||||
int blockNumIndex = index % 4;
|
int blockNumIndex = index % 4;
|
||||||
int baseOffset = 0xFA0 + blockNumIndex * 4;
|
int baseOffset = 0xFA0 + blockNumIndex * 4;
|
||||||
quint32 blockNumVal = (static_cast<uchar>(table.at(baseOffset)) ) |
|
quint32 blockNumVal = (static_cast<uchar>(table.at(baseOffset)) ) |
|
||||||
@ -77,7 +86,7 @@ void Encryption::UpdateIVTable(QByteArray &table, int index, const QByteArray &s
|
|||||||
int hashIndex = 0;
|
int hashIndex = 0;
|
||||||
for (int x = 0; x < 4; ++x) {
|
for (int x = 0; x < 4; ++x) {
|
||||||
table[startIndex - 1] = table.at(startIndex - 1) ^ sectionHash.at(hashIndex);
|
table[startIndex - 1] = table.at(startIndex - 1) ^ sectionHash.at(hashIndex);
|
||||||
table[startIndex] = table.at(startIndex) ^ sectionHash.at(hashIndex + 1);
|
table[startIndex] = table.at(startIndex) ^ sectionHash.at(hashIndex + 1);
|
||||||
table[startIndex + 1] = table.at(startIndex + 1) ^ sectionHash.at(hashIndex + 2);
|
table[startIndex + 1] = table.at(startIndex + 1) ^ sectionHash.at(hashIndex + 2);
|
||||||
table[startIndex + 2] = table.at(startIndex + 2) ^ sectionHash.at(hashIndex + 3);
|
table[startIndex + 2] = table.at(startIndex + 2) ^ sectionHash.at(hashIndex + 3);
|
||||||
table[startIndex + 3] = table.at(startIndex + 3) ^ sectionHash.at(hashIndex + 4);
|
table[startIndex + 3] = table.at(startIndex + 3) ^ sectionHash.at(hashIndex + 4);
|
||||||
@ -86,8 +95,9 @@ void Encryption::UpdateIVTable(QByteArray &table, int index, const QByteArray &s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
quint32 Encryption::ToUInt32(const QByteArray &data, int offset) {
|
quint32 Encryption::ToUInt32(const QByteArray &data, int offset)
|
||||||
// Converts 4 bytes (starting at offset) from data into a 32-bit unsigned integer (little-endian)
|
{
|
||||||
|
// Converts 4 bytes (starting at offset) from data into a 32-bit quint32eger (little-endian)
|
||||||
return ((static_cast<quint32>(static_cast<uchar>(data[offset])) ) |
|
return ((static_cast<quint32>(static_cast<uchar>(data[offset])) ) |
|
||||||
(static_cast<quint32>(static_cast<uchar>(data[offset+1])) << 8 ) |
|
(static_cast<quint32>(static_cast<uchar>(data[offset+1])) << 8 ) |
|
||||||
(static_cast<quint32>(static_cast<uchar>(data[offset+2])) << 16) |
|
(static_cast<quint32>(static_cast<uchar>(data[offset+2])) << 16) |
|
||||||
@ -351,96 +361,8 @@ void Encryption::generateNewIV(int index, const QByteArray &hash, QByteArray &iv
|
|||||||
ivCounter[index]++;
|
ivCounter[index]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray Encryption::decryptFastFile_BO2(const QByteArray &fastFileData)
|
QByteArray Encryption::decryptFastFile_BO3(const QByteArray &fastFileData)
|
||||||
{
|
{
|
||||||
const QByteArray bo2_salsa20_key = QByteArray::fromHex("641D8A2FE31D3AA63622BBC9CE8587229D42B0F8ED9B924130BF88B65EDC50BE");
|
|
||||||
|
|
||||||
QByteArray fileData = fastFileData;
|
|
||||||
QByteArray finalFastFile;
|
|
||||||
|
|
||||||
QByteArray ivTable(16000, 0);
|
|
||||||
fillIVTable(fileData, ivTable, 16000 - 1);
|
|
||||||
|
|
||||||
QVector<quint32> ivCounter(4, 1);
|
|
||||||
QDataStream stream(fileData);
|
|
||||||
stream.setByteOrder(QDataStream::LittleEndian);
|
|
||||||
stream.skipRawData(0x138);
|
|
||||||
|
|
||||||
QByteArray sha1Hash(20, 0);
|
|
||||||
QByteArray ivPtr(8, 0);
|
|
||||||
int chunkIndex = 0;
|
|
||||||
|
|
||||||
while (!stream.atEnd()) {
|
|
||||||
quint32 dataLength;
|
|
||||||
stream >> dataLength;
|
|
||||||
|
|
||||||
if (dataLength == 0 || dataLength > fileData.size() - stream.device()->pos()) {
|
|
||||||
qWarning() << "Invalid data length at offset: " << stream.device()->pos();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
fillIV(chunkIndex % 4, ivPtr, ivTable, ivCounter);
|
|
||||||
|
|
||||||
ECRYPT_ctx x;
|
|
||||||
ECRYPT_keysetup(&x, reinterpret_cast<const u8*>(bo2_salsa20_key.constData()), 256, 0);
|
|
||||||
ECRYPT_ivsetup(&x, reinterpret_cast<const u8*>(ivPtr.constData()));
|
|
||||||
|
|
||||||
QByteArray encryptedBlock = fileData.mid(stream.device()->pos(), dataLength);
|
|
||||||
QByteArray decryptedBlock;
|
|
||||||
decryptedBlock.resize(dataLength);
|
|
||||||
|
|
||||||
ECRYPT_decrypt_bytes(&x, reinterpret_cast<const u8*>(encryptedBlock.constData()),
|
|
||||||
reinterpret_cast<u8*>(decryptedBlock.data()), dataLength);
|
|
||||||
|
|
||||||
QCryptographicHash sha1(QCryptographicHash::Sha1);
|
|
||||||
sha1.addData(decryptedBlock);
|
|
||||||
sha1Hash = sha1.result();
|
|
||||||
|
|
||||||
z_stream strm = {};
|
|
||||||
strm.zalloc = Z_NULL;
|
|
||||||
strm.zfree = Z_NULL;
|
|
||||||
strm.opaque = Z_NULL;
|
|
||||||
strm.avail_in = static_cast<uInt>(decryptedBlock.size());
|
|
||||||
strm.next_in = reinterpret_cast<Bytef*>(decryptedBlock.data());
|
|
||||||
|
|
||||||
QByteArray decompressedData;
|
|
||||||
decompressedData.resize(fmax(dataLength * 2, 4096));
|
|
||||||
strm.avail_out = decompressedData.size();
|
|
||||||
strm.next_out = reinterpret_cast<Bytef*>(decompressedData.data());
|
|
||||||
|
|
||||||
int zReturn = inflateInit2(&strm, -15);
|
|
||||||
if (zReturn != Z_OK) {
|
|
||||||
qWarning() << "inflateInit2 failed with error code" << zReturn;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
zReturn = inflate(&strm, Z_FINISH);
|
|
||||||
inflateEnd(&strm);
|
|
||||||
|
|
||||||
if (zReturn != Z_STREAM_END) {
|
|
||||||
qDebug() << "Error decompressing at offset: " << stream.device()->pos() << " : " << zReturn;
|
|
||||||
decompressedData.clear();
|
|
||||||
} else {
|
|
||||||
decompressedData.resize(strm.total_out);
|
|
||||||
}
|
|
||||||
|
|
||||||
finalFastFile.append(decompressedData);
|
|
||||||
|
|
||||||
generateNewIV(chunkIndex % 4, sha1Hash, ivTable, ivCounter);
|
|
||||||
|
|
||||||
if (stream.device()->pos() + static_cast<qint64>(dataLength) > fileData.size()) {
|
|
||||||
qWarning() << "Skipping past file size!";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
stream.skipRawData(dataLength);
|
|
||||||
chunkIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return finalFastFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
QByteArray Encryption::decryptFastFile_BO3(const QByteArray &fastFileData) {
|
|
||||||
const QByteArray salsaKey = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3");
|
const QByteArray salsaKey = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3");
|
||||||
|
|
||||||
QByteArray ivTable(0xFB0, 0);
|
QByteArray ivTable(0xFB0, 0);
|
||||||
@ -504,3 +426,71 @@ QByteArray Encryption::decryptFastFile_BO3(const QByteArray &fastFileData) {
|
|||||||
|
|
||||||
return finalFastFile;
|
return finalFastFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QByteArray Encryption::DecryptFile(const QByteArray &fastFileData, const QString &aFileName, const QByteArray &aKey)
|
||||||
|
{
|
||||||
|
Q_UNUSED(aFileName);
|
||||||
|
|
||||||
|
const QByteArray salsaKey = QByteArray::fromHex(aKey);
|
||||||
|
|
||||||
|
QByteArray ivTable(0xFB0, 0);
|
||||||
|
fillIVTable(fastFileData, ivTable, 0xFB0 - 1);
|
||||||
|
|
||||||
|
QVector<quint32> ivCounter(4, 1);
|
||||||
|
QDataStream stream(fastFileData);
|
||||||
|
stream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
|
QByteArray finalFastFile;
|
||||||
|
QByteArray sha1Hash(20, 0);
|
||||||
|
QByteArray ivPtr(8, 0);
|
||||||
|
int chunkIndex = 0;
|
||||||
|
|
||||||
|
while (!stream.atEnd()) {
|
||||||
|
if (stream.device()->bytesAvailable() < 4) {
|
||||||
|
qWarning() << "No sufficient data for chunk size at offset:" << stream.device()->pos();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
quint32 dataLength;
|
||||||
|
stream >> dataLength;
|
||||||
|
|
||||||
|
if (dataLength == 0 || dataLength > fastFileData.size() - stream.device()->pos()) {
|
||||||
|
qWarning() << "Invalid data length at offset:" << stream.device()->pos();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fillIV(chunkIndex % 4, ivPtr, ivTable, ivCounter);
|
||||||
|
|
||||||
|
ECRYPT_ctx x;
|
||||||
|
ECRYPT_keysetup(&x, reinterpret_cast<const u8*>(salsaKey.constData()), 256, 0);
|
||||||
|
ECRYPT_ivsetup(&x, reinterpret_cast<const u8*>(ivPtr.constData()));
|
||||||
|
|
||||||
|
QByteArray encryptedBlock = fastFileData.mid(stream.device()->pos(), dataLength);
|
||||||
|
QByteArray decryptedBlock(dataLength, Qt::Uninitialized);
|
||||||
|
|
||||||
|
ECRYPT_decrypt_bytes(&x,
|
||||||
|
reinterpret_cast<const u8*>(encryptedBlock.constData()),
|
||||||
|
reinterpret_cast<u8*>(decryptedBlock.data()),
|
||||||
|
dataLength);
|
||||||
|
|
||||||
|
// SHA1 hash update
|
||||||
|
sha1Hash = QCryptographicHash::hash(decryptedBlock, QCryptographicHash::Sha1);
|
||||||
|
|
||||||
|
// Decompress (ZLIB raw DEFLATE)
|
||||||
|
QByteArray decompressedData = Compression::DecompressDeflate(decryptedBlock);
|
||||||
|
if (decompressedData.isEmpty()) {
|
||||||
|
qWarning() << "Failed decompression at chunk index:" << chunkIndex;
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
finalFastFile.append(decompressedData);
|
||||||
|
|
||||||
|
// Update IV table using SHA1
|
||||||
|
generateNewIV(chunkIndex % 4, sha1Hash, ivTable, ivCounter);
|
||||||
|
|
||||||
|
stream.skipRawData(dataLength);
|
||||||
|
chunkIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return finalFastFile;
|
||||||
|
}
|
||||||
|
|||||||
@ -46,8 +46,9 @@ public:
|
|||||||
|
|
||||||
static void generateNewIV(int index, const QByteArray& hash, QByteArray& ivTable, QVector<quint32>& ivCounter);
|
static void generateNewIV(int index, const QByteArray& hash, QByteArray& ivTable, QVector<quint32>& ivCounter);
|
||||||
|
|
||||||
static QByteArray decryptFastFile_BO2(const QByteArray& fastFileData);
|
//static QByteArray decryptFastFile_BO2(const QByteArray& fastFileData);
|
||||||
static QByteArray decryptFastFile_BO3(const QByteArray& fastFileData);
|
static QByteArray decryptFastFile_BO3(const QByteArray& fastFileData);
|
||||||
|
static QByteArray DecryptFile(const QByteArray& fastFileData, const QString& aFileName, const QByteArray& aKey);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ENCRYPTION_H
|
#endif // ENCRYPTION_H
|
||||||
|
|||||||
@ -2,20 +2,8 @@ QT += core
|
|||||||
TEMPLATE = lib
|
TEMPLATE = lib
|
||||||
CONFIG += staticlib c++17
|
CONFIG += staticlib c++17
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += $$files($$PWD/*.cpp, true)
|
||||||
salsa20.cpp \
|
HEADERS += $$files($$PWD/*.h, true)
|
||||||
sha1.cpp \
|
|
||||||
encryption.cpp
|
|
||||||
|
|
||||||
HEADERS += \
|
|
||||||
ecrypt-config.h \
|
|
||||||
ecrypt-machine.h \
|
|
||||||
ecrypt-portable.h \
|
|
||||||
ecrypt-sync.h \
|
|
||||||
encryption.h \
|
|
||||||
os_types.h \
|
|
||||||
config_win32.h \
|
|
||||||
sha1.h
|
|
||||||
|
|
||||||
app.depends += \
|
app.depends += \
|
||||||
compression
|
compression
|
||||||
|
|||||||
@ -59,7 +59,7 @@ void ECRYPT_encrypt_bytes(ECRYPT_ctx *x,const u8 *m,u8 *c,u32 bytes)
|
|||||||
u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
|
u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
|
||||||
u8 *ctarget;
|
u8 *ctarget;
|
||||||
u8 tmp[64];
|
u8 tmp[64];
|
||||||
unsigned int i;
|
u32 i;
|
||||||
|
|
||||||
if (!bytes) return;
|
if (!bytes) return;
|
||||||
|
|
||||||
@ -82,7 +82,10 @@ void ECRYPT_encrypt_bytes(ECRYPT_ctx *x,const u8 *m,u8 *c,u32 bytes)
|
|||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (bytes < 64) {
|
if (bytes < 64) {
|
||||||
for (i = 0;i < bytes;++i) tmp[i] = m[i];
|
for (i = 0; i < bytes; ++i)
|
||||||
|
{
|
||||||
|
tmp[i] = m[i];
|
||||||
|
}
|
||||||
m = tmp;
|
m = tmp;
|
||||||
ctarget = c;
|
ctarget = c;
|
||||||
c = tmp;
|
c = tmp;
|
||||||
|
|||||||
@ -10,7 +10,7 @@ Still 100% Public Domain
|
|||||||
|
|
||||||
Corrected a problem which generated improper hash values on 16 bit machines
|
Corrected a problem which generated improper hash values on 16 bit machines
|
||||||
Routine SHA1Update changed from
|
Routine SHA1Update changed from
|
||||||
void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int
|
void SHA1Update(SHA1_CTX* context, unsigned char* data, quint32
|
||||||
len)
|
len)
|
||||||
to
|
to
|
||||||
void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned
|
void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned
|
||||||
@ -27,7 +27,7 @@ be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million
|
|||||||
"a"s).
|
"a"s).
|
||||||
|
|
||||||
I also changed the declaration of variables i & j in SHA1Update to
|
I also changed the declaration of variables i & j in SHA1Update to
|
||||||
unsigned long from unsigned int for the same reason.
|
unsigned long from quint32 for the same reason.
|
||||||
|
|
||||||
These changes should make no difference to any 32 bit implementations since
|
These changes should make no difference to any 32 bit implementations since
|
||||||
an
|
an
|
||||||
@ -94,7 +94,6 @@ void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]);
|
|||||||
|
|
||||||
/* blk0() and blk() perform the initial expand. */
|
/* blk0() and blk() perform the initial expand. */
|
||||||
/* I got the idea of expanding during the round function from SSLeay */
|
/* I got the idea of expanding during the round function from SSLeay */
|
||||||
/* FIXME: can we do this in an endian-proof way? */
|
|
||||||
#ifdef WORDS_BIGENDIAN
|
#ifdef WORDS_BIGENDIAN
|
||||||
#define blk0(i) block->l[i]
|
#define blk0(i) block->l[i]
|
||||||
#else
|
#else
|
||||||
|
|||||||
@ -36,7 +36,7 @@ FastFile_COD10_360::~FastFile_COD10_360() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray FastFile_COD10_360::GetBinaryData() {
|
QByteArray FastFile_COD10_360::GetBinaryData() const {
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,15 +69,9 @@ bool FastFile_COD10_360::Load(const QString aFilePath) {
|
|||||||
bool FastFile_COD10_360::Load(const QByteArray aData) {
|
bool FastFile_COD10_360::Load(const QByteArray aData) {
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Create a QDataStream on the input data.
|
// Create a XDataStream on the input data.
|
||||||
QDataStream fastFileStream(aData);
|
XDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||||
|
|
||||||
// For COD7/COD9, use BigEndian.
|
|
||||||
fastFileStream.setByteOrder(QDataStream::BigEndian);
|
|
||||||
|
|
||||||
// Select key based on game.
|
|
||||||
QByteArray key = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3");
|
|
||||||
|
|
||||||
// Read the 8-byte magic.
|
// Read the 8-byte magic.
|
||||||
QByteArray fileMagic(8, Qt::Uninitialized);
|
QByteArray fileMagic(8, Qt::Uninitialized);
|
||||||
@ -96,7 +90,7 @@ bool FastFile_COD10_360::Load(const QByteArray aData) {
|
|||||||
QByteArray rsaSignature(256, Qt::Uninitialized);
|
QByteArray rsaSignature(256, Qt::Uninitialized);
|
||||||
fastFileStream.readRawData(rsaSignature.data(), 256);
|
fastFileStream.readRawData(rsaSignature.data(), 256);
|
||||||
|
|
||||||
decompressedData = Encryption::decryptFastFile_BO2(aData);
|
decompressedData = Encryption::DecryptFile(aData, fileName, "0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3");
|
||||||
|
|
||||||
// For COD9, write out the complete decompressed zone for testing.
|
// For COD9, write out the complete decompressed zone for testing.
|
||||||
QFile testFile("exports/" + GetBaseStem() + ".zone");
|
QFile testFile("exports/" + GetBaseStem() + ".zone");
|
||||||
@ -104,12 +98,16 @@ bool FastFile_COD10_360::Load(const QByteArray aData) {
|
|||||||
testFile.write(decompressedData);
|
testFile.write(decompressedData);
|
||||||
testFile.close();
|
testFile.close();
|
||||||
}
|
}
|
||||||
|
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||||
|
|
||||||
// Load the zone file with the decompressed data (using an Xbox platform flag).
|
// Load the zone file with the decompressed data (using an Xbox platform flag).
|
||||||
ZoneFile_COD10_360 zoneFile;
|
ZoneFile_COD10_360* zoneFile = new ZoneFile_COD10_360();
|
||||||
zoneFile.SetStem(GetBaseStem() + ".zone");
|
zoneFile->SetStem(GetBaseStem() + ".zone");
|
||||||
zoneFile.Load(decompressedData);
|
if (!zoneFile->Load(decompressedData)) {
|
||||||
SetZoneFile(std::make_shared<ZoneFile_COD10_360>(zoneFile));
|
qWarning() << "Failed to load ZoneFile!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SetZoneFile(zoneFile);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ public:
|
|||||||
FastFile_COD10_360(const QString aFilePath);
|
FastFile_COD10_360(const QString aFilePath);
|
||||||
~FastFile_COD10_360();
|
~FastFile_COD10_360();
|
||||||
|
|
||||||
QByteArray GetBinaryData() override;
|
QByteArray GetBinaryData() const override;
|
||||||
|
|
||||||
bool Load(const QString aFilePath) override;
|
bool Load(const QString aFilePath) override;
|
||||||
bool Load(const QByteArray aData) override;
|
bool Load(const QByteArray aData) override;
|
||||||
|
|||||||
@ -38,7 +38,7 @@ FastFile_COD11_360::~FastFile_COD11_360() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray FastFile_COD11_360::GetBinaryData() {
|
QByteArray FastFile_COD11_360::GetBinaryData() const {
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,40 +68,84 @@ bool FastFile_COD11_360::Load(const QString aFilePath) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum DB_CompressorType : qint32
|
||||||
|
{
|
||||||
|
DB_COMPRESSOR_INVALID = 0x0,
|
||||||
|
DB_COMPRESSOR_ZLIB = 0x1,
|
||||||
|
DB_COMPRESSOR_LZX = 0x2,
|
||||||
|
DB_COMPRESSOR_PASSTHROUGH = 0x3,
|
||||||
|
};
|
||||||
|
|
||||||
bool FastFile_COD11_360::Load(const QByteArray aData) {
|
bool FastFile_COD11_360::Load(const QByteArray aData) {
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Prepare data stream for parsing
|
// Prepare data stream for parsing
|
||||||
QDataStream fastFileStream(aData);
|
XDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
||||||
|
|
||||||
// Verify magic header
|
// Verify magic header
|
||||||
QByteArray fileMagic(8, Qt::Uninitialized);
|
QByteArray fileMagic(8, Qt::Uninitialized);
|
||||||
fastFileStream.readRawData(fileMagic.data(), 8);
|
fastFileStream.readRawData(fileMagic.data(), 8);
|
||||||
if (fileMagic != "TAff0000") {
|
quint32 version = fastFileStream.ParseUInt32();
|
||||||
qWarning() << "Invalid fast file magic for COD12!";
|
|
||||||
|
fastFileStream.skipRawData(1);
|
||||||
|
|
||||||
|
DB_CompressorType compressorType = (DB_CompressorType)fastFileStream.ParseInt8();
|
||||||
|
|
||||||
|
fastFileStream.skipRawData(10);
|
||||||
|
|
||||||
|
qint32 blockCount = fastFileStream.ParseInt32();
|
||||||
|
|
||||||
|
if (version != 1838)
|
||||||
|
{
|
||||||
|
qWarning() << "Invalid fast file version:" << version << "!";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip: File size (4 bytes), flags/version (4 bytes), unknown (8 bytes), build tag (32 bytes), RSA signature (256 bytes)
|
if (blockCount > 17280)
|
||||||
fastFileStream.skipRawData(4 + 4 + 8 + 32 + 256); // total 304 bytes skipped so far + 8 bytes magic = 312 bytes at correct position.
|
{
|
||||||
|
qWarning() << "Fast file has too many blocks:" << blockCount << "> 17280!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
fastFileStream.skipRawData(12 * blockCount);
|
||||||
|
|
||||||
// Correctly positioned at 0x138
|
qint32 startPos = fastFileStream.ParseInt32();
|
||||||
QByteArray encryptedData = aData.mid(0x138);
|
Q_UNUSED(startPos);
|
||||||
decompressedData = Encryption::decryptFastFile_BO3(encryptedData);
|
|
||||||
|
|
||||||
// Output for verification/testing
|
qint32 endPos = fastFileStream.ParseInt32();
|
||||||
|
Q_UNUSED(endPos);
|
||||||
|
|
||||||
|
if (fileMagic == "S1ffu100")
|
||||||
|
{
|
||||||
|
QByteArray compressedData = aData.mid(fastFileStream.device()->pos());
|
||||||
|
if (compressorType == DB_COMPRESSOR_ZLIB)
|
||||||
|
{
|
||||||
|
decompressedData = Compression::DecompressZLIB(compressedData);
|
||||||
|
}
|
||||||
|
else if (compressorType == DB_COMPRESSOR_LZX)
|
||||||
|
{
|
||||||
|
decompressedData = Compression::DecompressXMem(compressedData, 0, 0x80000, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (fileMagic == "S1ff0100")
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qWarning() << "Invalid fast file magic:" << fileMagic << "!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||||
|
|
||||||
// Load the zone file with decompressed data
|
// Load the zone file with decompressed data
|
||||||
ZoneFile_COD11_360 zoneFile;
|
ZoneFile_COD11_360* zoneFile = new ZoneFile_COD11_360();
|
||||||
zoneFile.SetStem(GetBaseStem() + ".zone");
|
zoneFile->SetStem(GetBaseStem() + ".zone");
|
||||||
if (!zoneFile.Load(decompressedData)) {
|
if (!zoneFile->Load(decompressedData)) {
|
||||||
qWarning() << "Failed to load ZoneFile!";
|
qWarning() << "Failed to load ZoneFile!";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
SetZoneFile(zoneFile);
|
||||||
SetZoneFile(std::make_shared<ZoneFile_COD11_360>(zoneFile));
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ public:
|
|||||||
FastFile_COD11_360(const QString aFilePath);
|
FastFile_COD11_360(const QString aFilePath);
|
||||||
~FastFile_COD11_360();
|
~FastFile_COD11_360();
|
||||||
|
|
||||||
QByteArray GetBinaryData() override;
|
QByteArray GetBinaryData() const override;
|
||||||
|
|
||||||
bool Load(const QString aFilePath) override;
|
bool Load(const QString aFilePath) override;
|
||||||
bool Load(const QByteArray aData) override;
|
bool Load(const QByteArray aData) override;
|
||||||
|
|||||||
@ -38,7 +38,7 @@ FastFile_COD12_360::~FastFile_COD12_360() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray FastFile_COD12_360::GetBinaryData() {
|
QByteArray FastFile_COD12_360::GetBinaryData() const {
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,36 +72,80 @@ bool FastFile_COD12_360::Load(const QByteArray aData) {
|
|||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Prepare data stream for parsing
|
// Prepare data stream for parsing
|
||||||
QDataStream fastFileStream(aData);
|
XDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||||
|
|
||||||
// Verify magic header
|
// Skip header magic
|
||||||
QByteArray fileMagic(8, Qt::Uninitialized);
|
fastFileStream.skipRawData(8);
|
||||||
fastFileStream.readRawData(fileMagic.data(), 8);
|
|
||||||
if (fileMagic != "TAff0000") {
|
quint32 version;
|
||||||
qWarning() << "Invalid fast file magic for COD12!";
|
fastFileStream >> version;
|
||||||
|
|
||||||
|
quint8 unknownFlag, compressionFlag, platformFlag, encryptionFlag;
|
||||||
|
fastFileStream >> unknownFlag >> compressionFlag >> platformFlag >> encryptionFlag;
|
||||||
|
|
||||||
|
if (compressionFlag != 1) {
|
||||||
|
qDebug() << "Invalid fastfile compression: " << compressionFlag;
|
||||||
|
return false;
|
||||||
|
} else if (platformFlag != 4) {
|
||||||
|
qDebug() << "Invalid platform: " << platformFlag;
|
||||||
|
return false;
|
||||||
|
} else if (encryptionFlag != 0) {
|
||||||
|
qDebug() << "Decryption not supported yet!";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip: File size (4 bytes), flags/version (4 bytes), unknown (8 bytes), build tag (32 bytes), RSA signature (256 bytes)
|
fastFileStream.skipRawData(128);
|
||||||
fastFileStream.skipRawData(4 + 4 + 8 + 32 + 256); // total 304 bytes skipped so far + 8 bytes magic = 312 bytes at correct position.
|
|
||||||
|
|
||||||
// Correctly positioned at 0x138
|
quint64 size;
|
||||||
QByteArray encryptedData = aData.mid(0x138);
|
fastFileStream >> size;
|
||||||
decompressedData = Encryption::decryptFastFile_BO3(encryptedData);
|
|
||||||
|
|
||||||
|
fastFileStream.skipRawData(432);
|
||||||
|
|
||||||
|
int consumed = 0;
|
||||||
|
while(consumed < size)
|
||||||
|
{
|
||||||
|
// Read Block Header
|
||||||
|
quint32 compressedSize, decompressedSize, blockSize, blockPosition;
|
||||||
|
fastFileStream >> compressedSize >> decompressedSize >> blockSize >> blockPosition;
|
||||||
|
|
||||||
|
// Validate the block position, it should match
|
||||||
|
if(blockPosition != fastFileStream.device()->pos() - 16)
|
||||||
|
{
|
||||||
|
qDebug() << "Block Position does not match Stream Position.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for padding blocks
|
||||||
|
if(decompressedSize == 0)
|
||||||
|
{
|
||||||
|
fastFileStream.device()->read((((fastFileStream.device()->pos()) + ((0x800000) - 1)) & ~((0x800000) - 1)) - fastFileStream.device()->pos());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
fastFileStream.device()->read(2);
|
||||||
|
|
||||||
|
QByteArray compressedData(compressedSize - 2, Qt::Uninitialized);
|
||||||
|
qDebug() << "Data position: " << fastFileStream.device()->pos() << " - Size: " << compressedSize;
|
||||||
|
fastFileStream.readRawData(compressedData.data(), compressedSize - 2);
|
||||||
|
decompressedData.append(Compression::DecompressDeflate(compressedData));
|
||||||
|
|
||||||
|
consumed += decompressedSize;
|
||||||
|
|
||||||
|
// Sinze Fast Files are aligns, we must skip the full block
|
||||||
|
fastFileStream.device()->seek(blockPosition + 16 + blockSize);
|
||||||
|
}
|
||||||
// Output for verification/testing
|
// Output for verification/testing
|
||||||
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||||
|
|
||||||
// Load the zone file with decompressed data
|
// Load the zone file with decompressed data
|
||||||
ZoneFile_COD12_360 zoneFile;
|
ZoneFile_COD12_360* zoneFile = new ZoneFile_COD12_360();
|
||||||
zoneFile.SetStem(GetBaseStem() + ".zone");
|
zoneFile->SetStem(GetBaseStem() + ".zone");
|
||||||
if (!zoneFile.Load(decompressedData)) {
|
if (!zoneFile->Load(decompressedData)) {
|
||||||
qWarning() << "Failed to load ZoneFile!";
|
qWarning() << "Failed to load ZoneFile!";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
SetZoneFile(zoneFile);
|
||||||
SetZoneFile(std::make_shared<ZoneFile_COD12_360>(zoneFile));
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ public:
|
|||||||
FastFile_COD12_360(const QString aFilePath);
|
FastFile_COD12_360(const QString aFilePath);
|
||||||
~FastFile_COD12_360();
|
~FastFile_COD12_360();
|
||||||
|
|
||||||
QByteArray GetBinaryData() override;
|
QByteArray GetBinaryData() const override;
|
||||||
|
|
||||||
bool Load(const QString aFilePath) override;
|
bool Load(const QString aFilePath) override;
|
||||||
bool Load(const QByteArray aData) override;
|
bool Load(const QByteArray aData) override;
|
||||||
|
|||||||
@ -38,7 +38,7 @@ FastFile_COD2_360::~FastFile_COD2_360() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray FastFile_COD2_360::GetBinaryData() {
|
QByteArray FastFile_COD2_360::GetBinaryData() const {
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,9 +68,9 @@ bool FastFile_COD2_360::Load(const QString aFilePath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool FastFile_COD2_360::Load(const QByteArray aData) {
|
bool FastFile_COD2_360::Load(const QByteArray aData) {
|
||||||
// Create a QDataStream on the input data.
|
// Create a XDataStream on the input data.
|
||||||
QDataStream fastFileStream(aData);
|
XDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||||
|
|
||||||
Utils::ReadUntilHex(&fastFileStream, "78");
|
Utils::ReadUntilHex(&fastFileStream, "78");
|
||||||
QByteArray compressedData = aData.mid(fastFileStream.device()->pos());
|
QByteArray compressedData = aData.mid(fastFileStream.device()->pos());
|
||||||
@ -79,10 +79,13 @@ bool FastFile_COD2_360::Load(const QByteArray aData) {
|
|||||||
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||||
|
|
||||||
// Load the zone file with the decompressed data (using an Xbox platform flag).
|
// Load the zone file with the decompressed data (using an Xbox platform flag).
|
||||||
ZoneFile_COD2_360 zoneFile;
|
ZoneFile_COD2_360* zoneFile = new ZoneFile_COD2_360();
|
||||||
zoneFile.SetStem(GetBaseStem() + ".zone");
|
zoneFile->SetStem(GetBaseStem() + ".zone");
|
||||||
zoneFile.Load(decompressedData);
|
if (!zoneFile->Load(decompressedData)) {
|
||||||
SetZoneFile(std::make_shared<ZoneFile_COD2_360>(zoneFile));
|
qWarning() << "Failed to load ZoneFile!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SetZoneFile(zoneFile);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ public:
|
|||||||
FastFile_COD2_360(const QString aFilePath);
|
FastFile_COD2_360(const QString aFilePath);
|
||||||
~FastFile_COD2_360();
|
~FastFile_COD2_360();
|
||||||
|
|
||||||
QByteArray GetBinaryData() override;
|
QByteArray GetBinaryData() const override;
|
||||||
|
|
||||||
bool Load(const QString aFilePath) override;
|
bool Load(const QString aFilePath) override;
|
||||||
bool Load(const QByteArray aData) override;
|
bool Load(const QByteArray aData) override;
|
||||||
|
|||||||
@ -39,7 +39,7 @@ FastFile_COD4_360::~FastFile_COD4_360() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray FastFile_COD4_360::GetBinaryData() {
|
QByteArray FastFile_COD4_360::GetBinaryData() const {
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,9 +80,9 @@ bool FastFile_COD4_360::Load(const QByteArray aData) {
|
|||||||
// For COD5, simply decompress from offset 12.
|
// For COD5, simply decompress from offset 12.
|
||||||
decompressedData = Compression::DecompressZLIB(aData.mid(12));
|
decompressedData = Compression::DecompressZLIB(aData.mid(12));
|
||||||
} else if (header == "IWff0100") {
|
} else if (header == "IWff0100") {
|
||||||
// Create a QDataStream on the input data.
|
// Create a XDataStream on the input data.
|
||||||
QDataStream fastFileStream(aData.mid(12));
|
XDataStream fastFileStream(aData.mid(12));
|
||||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||||
|
|
||||||
QByteArray magic(8, Qt::Uninitialized);
|
QByteArray magic(8, Qt::Uninitialized);
|
||||||
fastFileStream.readRawData(magic.data(), 8);
|
fastFileStream.readRawData(magic.data(), 8);
|
||||||
@ -126,14 +126,15 @@ bool FastFile_COD4_360::Load(const QByteArray aData) {
|
|||||||
}
|
}
|
||||||
decompressedData = Compression::DecompressZLIB(compressedData);
|
decompressedData = Compression::DecompressZLIB(compressedData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||||
|
|
||||||
ZoneFile_COD4_360 zoneFile;
|
ZoneFile_COD4_360* zoneFile = new ZoneFile_COD4_360();
|
||||||
zoneFile.SetStem(GetBaseStem() + ".zone");
|
zoneFile->SetStem(GetBaseStem() + ".zone");
|
||||||
zoneFile.Load(decompressedData);
|
if (!zoneFile->Load(decompressedData)) {
|
||||||
SetZoneFile(std::make_shared<ZoneFile_COD4_360>(zoneFile));
|
qWarning() << "Failed to load ZoneFile!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SetZoneFile(zoneFile);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ public:
|
|||||||
FastFile_COD4_360(const QString aFilePath);
|
FastFile_COD4_360(const QString aFilePath);
|
||||||
~FastFile_COD4_360();
|
~FastFile_COD4_360();
|
||||||
|
|
||||||
QByteArray GetBinaryData() override;
|
QByteArray GetBinaryData() const override;
|
||||||
|
|
||||||
bool Load(const QString aFilePath) override;
|
bool Load(const QString aFilePath) override;
|
||||||
bool Load(const QByteArray aData) override;
|
bool Load(const QByteArray aData) override;
|
||||||
|
|||||||
@ -39,7 +39,7 @@ FastFile_COD5_360::~FastFile_COD5_360() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray FastFile_COD5_360::GetBinaryData() {
|
QByteArray FastFile_COD5_360::GetBinaryData() const {
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,10 +80,13 @@ bool FastFile_COD5_360::Load(const QByteArray aData) {
|
|||||||
|
|
||||||
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||||
|
|
||||||
ZoneFile_COD5_360 zoneFile;
|
ZoneFile_COD5_360* zoneFile = new ZoneFile_COD5_360();
|
||||||
zoneFile.SetStem(GetBaseStem() + ".zone");
|
zoneFile->SetStem(GetBaseStem() + ".zone");
|
||||||
zoneFile.Load(decompressedData);
|
if (!zoneFile->Load(decompressedData)) {
|
||||||
SetZoneFile(std::make_shared<ZoneFile_COD5_360>(zoneFile));
|
qWarning() << "Failed to load ZoneFile!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SetZoneFile(zoneFile);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ public:
|
|||||||
FastFile_COD5_360(const QString aFilePath);
|
FastFile_COD5_360(const QString aFilePath);
|
||||||
~FastFile_COD5_360();
|
~FastFile_COD5_360();
|
||||||
|
|
||||||
QByteArray GetBinaryData() override;
|
QByteArray GetBinaryData() const override;
|
||||||
|
|
||||||
bool Load(const QString aFilePath) override;
|
bool Load(const QString aFilePath) override;
|
||||||
bool Load(const QByteArray aData) override;
|
bool Load(const QByteArray aData) override;
|
||||||
|
|||||||
@ -39,7 +39,7 @@ FastFile_COD6_360::~FastFile_COD6_360() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray FastFile_COD6_360::GetBinaryData() {
|
QByteArray FastFile_COD6_360::GetBinaryData() const {
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,39 +70,55 @@ bool FastFile_COD6_360::Load(const QString aFilePath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool FastFile_COD6_360::Load(const QByteArray aData) {
|
bool FastFile_COD6_360::Load(const QByteArray aData) {
|
||||||
const qint64 zlibOffset = Compression::FindZlibOffset(aData);
|
XDataStream fastFileStream(aData);
|
||||||
if (zlibOffset == -1)
|
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
||||||
{
|
|
||||||
qWarning() << "Z-Lib stream not found";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
QByteArray compressed = aData.mid(zlibOffset);
|
|
||||||
|
|
||||||
// 2. Try plain decompression first ------------------------------
|
QByteArray magic(8, Qt::Uninitialized);
|
||||||
QByteArray decompressed = Compression::DecompressZLIB(compressed);
|
fastFileStream.readRawData(magic.data(), 8);
|
||||||
|
|
||||||
// 3. If that failed or looks too small, try stripping hash blocks
|
quint32 version = fastFileStream.ParseUInt32();
|
||||||
if (decompressed.isEmpty() || decompressed.size() < 1024)
|
|
||||||
{
|
|
||||||
QByteArray stripped = Compression::StripHashBlocks(compressed);
|
|
||||||
QByteArray retry = Compression::DecompressZLIB(stripped);
|
|
||||||
if (!retry.isEmpty())
|
|
||||||
decompressed.swap(retry);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (decompressed.isEmpty())
|
if (version != 269)
|
||||||
{
|
{
|
||||||
qWarning() << "Unable to decompress fast-file";
|
qDebug() << QString("Invalid version: %1!").arg(version);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optional – keep a copy on disk for quick inspection
|
bool localPatch = fastFileStream.ParseBool();
|
||||||
Utils::ExportData(GetBaseStem() + ".zone", decompressed);
|
Q_UNUSED(localPatch);
|
||||||
|
|
||||||
// 4. Forward to zone-file loader --------------------------------
|
quint8 compressor = fastFileStream.ParseUInt8();
|
||||||
auto zoneFile = std::make_shared<ZoneFile_COD6_360>();
|
Q_UNUSED(compressor);
|
||||||
zoneFile->SetStem(GetStem());
|
|
||||||
zoneFile->Load(decompressed);
|
// Skip fastfile date/time
|
||||||
|
fastFileStream.skipRawData(11);
|
||||||
|
|
||||||
|
quint32 hashCount = fastFileStream.ParseUInt32();
|
||||||
|
fastFileStream.skipRawData(12 * hashCount);
|
||||||
|
|
||||||
|
fastFileStream.skipRawData(8);
|
||||||
|
|
||||||
|
QByteArray decompressedData;
|
||||||
|
if (magic == "IWff0100")
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (magic == "IWffu100")
|
||||||
|
{
|
||||||
|
quint32 zlibSize = aData.size() - fastFileStream.device()->pos();
|
||||||
|
QByteArray zlibData(zlibSize, Qt::Uninitialized);
|
||||||
|
fastFileStream.readRawData(zlibData.data(), zlibSize);
|
||||||
|
|
||||||
|
decompressedData = Compression::DecompressZLIB(zlibData);
|
||||||
|
}
|
||||||
|
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||||
|
|
||||||
|
ZoneFile_COD6_360* zoneFile = new ZoneFile_COD6_360();
|
||||||
|
zoneFile->SetStem(GetBaseStem() + ".zone");
|
||||||
|
if (!zoneFile->Load(decompressedData)) {
|
||||||
|
qWarning() << "Failed to load ZoneFile!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
SetZoneFile(zoneFile);
|
SetZoneFile(zoneFile);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -11,7 +11,7 @@ public:
|
|||||||
FastFile_COD6_360(const QString aFilePath);
|
FastFile_COD6_360(const QString aFilePath);
|
||||||
~FastFile_COD6_360();
|
~FastFile_COD6_360();
|
||||||
|
|
||||||
QByteArray GetBinaryData() override;
|
QByteArray GetBinaryData() const override;
|
||||||
|
|
||||||
bool Load(const QString aFilePath) override;
|
bool Load(const QString aFilePath) override;
|
||||||
bool Load(const QByteArray aData) override;
|
bool Load(const QByteArray aData) override;
|
||||||
|
|||||||
@ -38,7 +38,7 @@ FastFile_COD7_360::~FastFile_COD7_360() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray FastFile_COD7_360::GetBinaryData() {
|
QByteArray FastFile_COD7_360::GetBinaryData() const {
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,19 +71,11 @@ bool FastFile_COD7_360::Load(const QString aFilePath) {
|
|||||||
bool FastFile_COD7_360::Load(const QByteArray aData) {
|
bool FastFile_COD7_360::Load(const QByteArray aData) {
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Create a QDataStream on the input data.
|
// Create a XDataStream on the input data.
|
||||||
QDataStream fastFileStream(aData);
|
XDataStream fastFileStream(aData);
|
||||||
|
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
||||||
|
|
||||||
// Load the zone file with the decompressed data (using an Xbox platform flag).
|
fastFileStream.skipRawData(16);
|
||||||
ZoneFile_COD7_360 zoneFile;
|
|
||||||
zoneFile.SetStem(GetBaseStem() + ".zone");
|
|
||||||
|
|
||||||
// For COD7/COD9, use BigEndian.
|
|
||||||
fastFileStream.setByteOrder(QDataStream::BigEndian);
|
|
||||||
|
|
||||||
// Select key based on game.
|
|
||||||
QByteArray key = QByteArray::fromHex("1ac1d12d527c59b40eca619120ff8217ccff09cd16896f81b829c7f52793405d");
|
|
||||||
fastFileStream.skipRawData(4);
|
|
||||||
|
|
||||||
// Read the 8-byte magic.
|
// Read the 8-byte magic.
|
||||||
QByteArray fileMagic(8, Qt::Uninitialized);
|
QByteArray fileMagic(8, Qt::Uninitialized);
|
||||||
@ -105,6 +97,8 @@ bool FastFile_COD7_360::Load(const QByteArray aData) {
|
|||||||
QByteArray rsaSignature(256, Qt::Uninitialized);
|
QByteArray rsaSignature(256, Qt::Uninitialized);
|
||||||
fastFileStream.readRawData(rsaSignature.data(), 256);
|
fastFileStream.readRawData(rsaSignature.data(), 256);
|
||||||
|
|
||||||
|
QByteArray key = QByteArray::fromHex("1ac1d12d527c59b40eca619120ff8217ccff09cd16896f81b829c7f52793405d");
|
||||||
|
|
||||||
// Now the stream should be positioned at 0x13C, where sections begin.
|
// Now the stream should be positioned at 0x13C, where sections begin.
|
||||||
int sectionIndex = 0;
|
int sectionIndex = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -142,10 +136,15 @@ bool FastFile_COD7_360::Load(const QByteArray aData) {
|
|||||||
|
|
||||||
sectionIndex++;
|
sectionIndex++;
|
||||||
}
|
}
|
||||||
|
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||||
|
|
||||||
zoneFile.Load(decompressedData);
|
ZoneFile_COD7_360* zoneFile = new ZoneFile_COD7_360();
|
||||||
|
zoneFile->SetStem(GetBaseStem() + ".zone");
|
||||||
SetZoneFile(std::make_shared<ZoneFile_COD7_360>(zoneFile));
|
if (!zoneFile->Load(decompressedData)) {
|
||||||
|
qWarning() << "Failed to load ZoneFile!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SetZoneFile(zoneFile);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ public:
|
|||||||
FastFile_COD7_360(const QString aFilePath);
|
FastFile_COD7_360(const QString aFilePath);
|
||||||
~FastFile_COD7_360();
|
~FastFile_COD7_360();
|
||||||
|
|
||||||
QByteArray GetBinaryData() override;
|
QByteArray GetBinaryData() const override;
|
||||||
|
|
||||||
bool Load(const QString aFilePath) override;
|
bool Load(const QString aFilePath) override;
|
||||||
bool Load(const QByteArray aData) override;
|
bool Load(const QByteArray aData) override;
|
||||||
|
|||||||
148
libs/fastfile/360/fastfile_cod7_5_360.cpp
Normal file
148
libs/fastfile/360/fastfile_cod7_5_360.cpp
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
#include "fastfile_cod7_5_360.h"
|
||||||
|
#include "zonefile_cod7_360.h"
|
||||||
|
|
||||||
|
#include "compression.h"
|
||||||
|
#include "encryption.h"
|
||||||
|
|
||||||
|
#include <QFile>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
FastFile_COD7_5_360::FastFile_COD7_5_360()
|
||||||
|
: FastFile() {
|
||||||
|
SetCompany(COMPANY_INFINITY_WARD);
|
||||||
|
SetType(FILETYPE_FAST_FILE);
|
||||||
|
SetSignage(SIGNAGE_UNSIGNED);
|
||||||
|
SetMagic(0);
|
||||||
|
SetVersion(0);
|
||||||
|
SetPlatform("360");
|
||||||
|
SetGame("COD7.5");
|
||||||
|
}
|
||||||
|
|
||||||
|
FastFile_COD7_5_360::FastFile_COD7_5_360(const QByteArray& aData)
|
||||||
|
: FastFile_COD7_5_360() {
|
||||||
|
|
||||||
|
if (!aData.isEmpty()) {
|
||||||
|
Load(aData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FastFile_COD7_5_360::FastFile_COD7_5_360(const QString aFilePath)
|
||||||
|
: FastFile_COD7_5_360() {
|
||||||
|
|
||||||
|
if (!aFilePath.isEmpty()) {
|
||||||
|
Load(aFilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FastFile_COD7_5_360::~FastFile_COD7_5_360() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray FastFile_COD7_5_360::GetBinaryData() const {
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FastFile_COD7_5_360::Load(const QString aFilePath) {
|
||||||
|
if (aFilePath.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check fastfile can be read
|
||||||
|
QFile *file = new QFile(aFilePath);
|
||||||
|
if (!file->open(QIODevice::ReadOnly)) {
|
||||||
|
qDebug() << QString("Error: Failed to open FastFile: %1!").arg(aFilePath);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decompress fastfile and close
|
||||||
|
const QString fastFileStem = aFilePath.section("/", -1, -1);
|
||||||
|
SetStem(fastFileStem);
|
||||||
|
if (!Load(file->readAll())) {
|
||||||
|
qDebug() << "Error: Failed to load fastfile: " << fastFileStem;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
file->close();
|
||||||
|
|
||||||
|
// Open zone file after decompressing ff and writing
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum NX_Language : qint32
|
||||||
|
{
|
||||||
|
LANGUAGE_ENGLISH = 0x0,
|
||||||
|
LANGUAGE_FRENCH = 0x1,
|
||||||
|
LANGUAGE_GERMAN = 0x2,
|
||||||
|
LANGUAGE_ITALIAN = 0x3,
|
||||||
|
LANGUAGE_SPANISH = 0x4,
|
||||||
|
LANGUAGE_BRITISH = 0x5,
|
||||||
|
LANGUAGE_RUSSIAN = 0x6,
|
||||||
|
LANGUAGE_POLISH = 0x7,
|
||||||
|
LANGUAGE_KOREAN = 0x8,
|
||||||
|
LANGUAGE_TAIWANESE = 0x9,
|
||||||
|
LANGUAGE_JAPANESE = 0xA,
|
||||||
|
LANGUAGE_CHINESE = 0xB,
|
||||||
|
LANGUAGE_THAI = 0xC,
|
||||||
|
LANGUAGE_LEET = 0xD,
|
||||||
|
LANGUAGE_CZECH = 0xE,
|
||||||
|
MAX_LANGUAGES = 0xF,
|
||||||
|
};
|
||||||
|
|
||||||
|
bool FastFile_COD7_5_360::Load(const QByteArray aData) {
|
||||||
|
// Create a XDataStream on the input data.
|
||||||
|
XDataStream fastFileStream(aData);
|
||||||
|
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
||||||
|
|
||||||
|
QByteArray magic(8, Qt::Uninitialized);
|
||||||
|
fastFileStream.readRawData(magic.data(), 8);
|
||||||
|
|
||||||
|
quint32 version = fastFileStream.ParseUInt32();
|
||||||
|
|
||||||
|
if (version != 357)
|
||||||
|
{
|
||||||
|
qDebug() << QString("Invalid version: %1!").arg(version);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool localPatch = fastFileStream.ParseBool();
|
||||||
|
Q_UNUSED(localPatch);
|
||||||
|
|
||||||
|
quint8 compressor = fastFileStream.ParseUInt8();
|
||||||
|
Q_UNUSED(compressor);
|
||||||
|
|
||||||
|
// Skip fastfile date/time
|
||||||
|
fastFileStream.skipRawData(8);
|
||||||
|
|
||||||
|
NX_Language language = (NX_Language)fastFileStream.ParseInt32();
|
||||||
|
Q_UNUSED(language);
|
||||||
|
|
||||||
|
quint32 hashCount = fastFileStream.ParseUInt32();
|
||||||
|
fastFileStream.skipRawData(12 * hashCount);
|
||||||
|
|
||||||
|
fastFileStream.skipRawData(8);
|
||||||
|
|
||||||
|
QByteArray decompressedData;
|
||||||
|
if (magic == "NXff0100")
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (magic == "NXffu100")
|
||||||
|
{
|
||||||
|
quint32 zlibSize = aData.size() - fastFileStream.device()->pos();
|
||||||
|
QByteArray zlibData(zlibSize, Qt::Uninitialized);
|
||||||
|
fastFileStream.readRawData(zlibData.data(), zlibSize);
|
||||||
|
|
||||||
|
decompressedData = Compression::DecompressZLIB(zlibData);
|
||||||
|
}
|
||||||
|
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||||
|
|
||||||
|
ZoneFile_COD7_360* zoneFile = new ZoneFile_COD7_360();
|
||||||
|
zoneFile->SetStem(GetBaseStem() + ".zone");
|
||||||
|
if (!zoneFile->Load(decompressedData)) {
|
||||||
|
qWarning() << "Failed to load ZoneFile!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SetZoneFile(zoneFile);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
20
libs/fastfile/360/fastfile_cod7_5_360.h
Normal file
20
libs/fastfile/360/fastfile_cod7_5_360.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#ifndef FASTFILE_COD7_5_360_H
|
||||||
|
#define FASTFILE_COD7_5_360_H
|
||||||
|
|
||||||
|
#include "fastfile.h"
|
||||||
|
|
||||||
|
class FastFile_COD7_5_360 : public FastFile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FastFile_COD7_5_360();
|
||||||
|
FastFile_COD7_5_360(const QByteArray& aData);
|
||||||
|
FastFile_COD7_5_360(const QString aFilePath);
|
||||||
|
~FastFile_COD7_5_360();
|
||||||
|
|
||||||
|
QByteArray GetBinaryData() const override;
|
||||||
|
|
||||||
|
bool Load(const QString aFilePath) override;
|
||||||
|
bool Load(const QByteArray aData) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // FASTFILE_COD7_5_360_H
|
||||||
@ -36,7 +36,7 @@ FastFile_COD8_360::~FastFile_COD8_360() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray FastFile_COD8_360::GetBinaryData() {
|
QByteArray FastFile_COD8_360::GetBinaryData() const {
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,15 +69,12 @@ bool FastFile_COD8_360::Load(const QString aFilePath) {
|
|||||||
bool FastFile_COD8_360::Load(const QByteArray aData) {
|
bool FastFile_COD8_360::Load(const QByteArray aData) {
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Create a QDataStream on the input data.
|
// Create a XDataStream on the input data.
|
||||||
QDataStream fastFileStream(aData);
|
XDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||||
|
|
||||||
// For COD7/COD9, use BigEndian.
|
// For COD7/COD9, use BigEndian.
|
||||||
fastFileStream.setByteOrder(QDataStream::BigEndian);
|
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
||||||
|
|
||||||
// Select key based on game.
|
|
||||||
QByteArray key = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3");
|
|
||||||
|
|
||||||
// Read the 8-byte magic.
|
// Read the 8-byte magic.
|
||||||
QByteArray fileMagic(8, Qt::Uninitialized);
|
QByteArray fileMagic(8, Qt::Uninitialized);
|
||||||
@ -92,11 +89,7 @@ bool FastFile_COD8_360::Load(const QByteArray aData) {
|
|||||||
QByteArray fileName(32, Qt::Uninitialized);
|
QByteArray fileName(32, Qt::Uninitialized);
|
||||||
fastFileStream.readRawData(fileName.data(), 32);
|
fastFileStream.readRawData(fileName.data(), 32);
|
||||||
|
|
||||||
// Skip the RSA signature (256 bytes).
|
decompressedData = Encryption::DecryptFile(aData, fileName, "0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3");
|
||||||
QByteArray rsaSignature(256, Qt::Uninitialized);
|
|
||||||
fastFileStream.readRawData(rsaSignature.data(), 256);
|
|
||||||
|
|
||||||
decompressedData = Encryption::decryptFastFile_BO2(aData);
|
|
||||||
|
|
||||||
// For COD9, write out the complete decompressed zone for testing.
|
// For COD9, write out the complete decompressed zone for testing.
|
||||||
QFile testFile("exports/" + GetBaseStem() + ".zone");
|
QFile testFile("exports/" + GetBaseStem() + ".zone");
|
||||||
@ -106,10 +99,13 @@ bool FastFile_COD8_360::Load(const QByteArray aData) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load the zone file with the decompressed data (using an Xbox platform flag).
|
// Load the zone file with the decompressed data (using an Xbox platform flag).
|
||||||
ZoneFile_COD8_360 zoneFile;
|
ZoneFile_COD8_360* zoneFile = new ZoneFile_COD8_360();
|
||||||
zoneFile.SetStem(GetBaseStem() + ".zone");
|
zoneFile->SetStem(GetBaseStem() + ".zone");
|
||||||
zoneFile.Load(decompressedData);
|
if (!zoneFile->Load(decompressedData)) {
|
||||||
SetZoneFile(std::make_shared<ZoneFile_COD8_360>(zoneFile));
|
qWarning() << "Failed to load ZoneFile!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SetZoneFile(zoneFile);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ public:
|
|||||||
FastFile_COD8_360(const QString aFilePath);
|
FastFile_COD8_360(const QString aFilePath);
|
||||||
~FastFile_COD8_360();
|
~FastFile_COD8_360();
|
||||||
|
|
||||||
QByteArray GetBinaryData() override;
|
QByteArray GetBinaryData() const override;
|
||||||
|
|
||||||
bool Load(const QString aFilePath) override;
|
bool Load(const QString aFilePath) override;
|
||||||
bool Load(const QByteArray aData) override;
|
bool Load(const QByteArray aData) override;
|
||||||
|
|||||||
@ -36,7 +36,7 @@ FastFile_COD9_360::~FastFile_COD9_360() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray FastFile_COD9_360::GetBinaryData() {
|
QByteArray FastFile_COD9_360::GetBinaryData() const {
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,15 +69,12 @@ bool FastFile_COD9_360::Load(const QString aFilePath) {
|
|||||||
bool FastFile_COD9_360::Load(const QByteArray aData) {
|
bool FastFile_COD9_360::Load(const QByteArray aData) {
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Create a QDataStream on the input data.
|
// Create a XDataStream on the input data.
|
||||||
QDataStream fastFileStream(aData);
|
XDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||||
|
|
||||||
// For COD7/COD9, use BigEndian.
|
// For COD7/COD9, use BigEndian.
|
||||||
fastFileStream.setByteOrder(QDataStream::BigEndian);
|
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
||||||
|
|
||||||
// Select key based on game.
|
|
||||||
QByteArray key = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3");
|
|
||||||
|
|
||||||
// Read the 8-byte magic.
|
// Read the 8-byte magic.
|
||||||
QByteArray fileMagic(8, Qt::Uninitialized);
|
QByteArray fileMagic(8, Qt::Uninitialized);
|
||||||
@ -96,7 +93,7 @@ bool FastFile_COD9_360::Load(const QByteArray aData) {
|
|||||||
QByteArray rsaSignature(256, Qt::Uninitialized);
|
QByteArray rsaSignature(256, Qt::Uninitialized);
|
||||||
fastFileStream.readRawData(rsaSignature.data(), 256);
|
fastFileStream.readRawData(rsaSignature.data(), 256);
|
||||||
|
|
||||||
decompressedData = Encryption::decryptFastFile_BO2(aData);
|
decompressedData = Encryption::DecryptFile(aData, fileName, "0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3");
|
||||||
|
|
||||||
// For COD9, write out the complete decompressed zone for testing.
|
// For COD9, write out the complete decompressed zone for testing.
|
||||||
QFile testFile("exports/" + GetBaseStem() + ".zone");
|
QFile testFile("exports/" + GetBaseStem() + ".zone");
|
||||||
@ -106,10 +103,13 @@ bool FastFile_COD9_360::Load(const QByteArray aData) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load the zone file with the decompressed data (using an Xbox platform flag).
|
// Load the zone file with the decompressed data (using an Xbox platform flag).
|
||||||
ZoneFile_COD9_360 zoneFile;
|
ZoneFile_COD9_360* zoneFile = new ZoneFile_COD9_360();
|
||||||
zoneFile.SetStem(GetBaseStem() + ".zone");
|
zoneFile->SetStem(GetBaseStem() + ".zone");
|
||||||
zoneFile.Load(decompressedData);
|
if (!zoneFile->Load(decompressedData)) {
|
||||||
SetZoneFile(std::make_shared<ZoneFile_COD9_360>(zoneFile));
|
qWarning() << "Failed to load ZoneFile!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SetZoneFile(zoneFile);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ public:
|
|||||||
FastFile_COD9_360(const QString aFilePath);
|
FastFile_COD9_360(const QString aFilePath);
|
||||||
~FastFile_COD9_360();
|
~FastFile_COD9_360();
|
||||||
|
|
||||||
QByteArray GetBinaryData() override;
|
QByteArray GetBinaryData() const override;
|
||||||
|
|
||||||
bool Load(const QString aFilePath) override;
|
bool Load(const QString aFilePath) override;
|
||||||
bool Load(const QByteArray aData) override;
|
bool Load(const QByteArray aData) override;
|
||||||
|
|||||||
@ -36,7 +36,7 @@ FastFile_COD10_PC::~FastFile_COD10_PC() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray FastFile_COD10_PC::GetBinaryData() {
|
QByteArray FastFile_COD10_PC::GetBinaryData() const {
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,9 +69,9 @@ bool FastFile_COD10_PC::Load(const QString aFilePath) {
|
|||||||
bool FastFile_COD10_PC::Load(const QByteArray aData) {
|
bool FastFile_COD10_PC::Load(const QByteArray aData) {
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Create a QDataStream on the input data.
|
// Create a XDataStream on the input data.
|
||||||
QDataStream fastFileStream(aData);
|
XDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||||
|
|
||||||
// Parse header values.
|
// Parse header values.
|
||||||
SetCompany(pParseFFCompany(&fastFileStream));
|
SetCompany(pParseFFCompany(&fastFileStream));
|
||||||
@ -84,18 +84,13 @@ bool FastFile_COD10_PC::Load(const QByteArray aData) {
|
|||||||
SetGame("COD9");
|
SetGame("COD9");
|
||||||
|
|
||||||
// For COD7/COD9, use BigEndian.
|
// For COD7/COD9, use BigEndian.
|
||||||
fastFileStream.setByteOrder(QDataStream::BigEndian);
|
fastFileStream.setByteOrder(XDataStream::BigEndian);
|
||||||
if (GetPlatform() == "PC") {
|
if (GetPlatform() == "PC") {
|
||||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select key based on game.
|
// Select key based on game.
|
||||||
QByteArray key;
|
QByteArray key = QByteArray::fromHex("641D8A2FE31D3AA63622BBC9CE8587229D42B0F8ED9B924130BF88B65EDC50BE");
|
||||||
if (GetPlatform() == "360") {
|
|
||||||
key = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3");
|
|
||||||
} else if (GetPlatform() == "PC") {
|
|
||||||
key = QByteArray::fromHex("641D8A2FE31D3AA63622BBC9CE8587229D42B0F8ED9B924130BF88B65EDC50BE");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the 8-byte magic.
|
// Read the 8-byte magic.
|
||||||
QByteArray fileMagic(8, Qt::Uninitialized);
|
QByteArray fileMagic(8, Qt::Uninitialized);
|
||||||
@ -114,11 +109,7 @@ bool FastFile_COD10_PC::Load(const QByteArray aData) {
|
|||||||
QByteArray rsaSignature(256, Qt::Uninitialized);
|
QByteArray rsaSignature(256, Qt::Uninitialized);
|
||||||
fastFileStream.readRawData(rsaSignature.data(), 256);
|
fastFileStream.readRawData(rsaSignature.data(), 256);
|
||||||
|
|
||||||
if (GetPlatform() == "360") {
|
//decompressedData = Encryption::decryptFastFile_BO2(aData);
|
||||||
//decompressedData = Compressor::cod9_decryptFastFile(aData);
|
|
||||||
} else if (GetPlatform() == "PC") {
|
|
||||||
decompressedData = Encryption::decryptFastFile_BO2(aData);
|
|
||||||
}
|
|
||||||
|
|
||||||
// For COD9, write out the complete decompressed zone for testing.
|
// For COD9, write out the complete decompressed zone for testing.
|
||||||
QFile testFile("exports/" + GetBaseStem() + ".zone");
|
QFile testFile("exports/" + GetBaseStem() + ".zone");
|
||||||
@ -126,12 +117,16 @@ bool FastFile_COD10_PC::Load(const QByteArray aData) {
|
|||||||
testFile.write(decompressedData);
|
testFile.write(decompressedData);
|
||||||
testFile.close();
|
testFile.close();
|
||||||
}
|
}
|
||||||
|
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||||
|
|
||||||
// Load the zone file with the decompressed data (using an Xbox platform flag).
|
// Load the zone file with the decompressed data (using an Xbox platform flag).
|
||||||
ZoneFile_COD10_PC zoneFile;
|
ZoneFile_COD10_PC* zoneFile = new ZoneFile_COD10_PC();
|
||||||
zoneFile.SetStem(GetBaseStem() + ".zone");
|
zoneFile->SetStem(GetBaseStem() + ".zone");
|
||||||
zoneFile.Load(decompressedData);
|
if (!zoneFile->Load(decompressedData)) {
|
||||||
SetZoneFile(std::make_shared<ZoneFile_COD10_PC>(zoneFile));
|
qWarning() << "Failed to load ZoneFile!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SetZoneFile(zoneFile);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ public:
|
|||||||
FastFile_COD10_PC(const QString aFilePath);
|
FastFile_COD10_PC(const QString aFilePath);
|
||||||
~FastFile_COD10_PC();
|
~FastFile_COD10_PC();
|
||||||
|
|
||||||
QByteArray GetBinaryData() override;
|
QByteArray GetBinaryData() const override;
|
||||||
|
|
||||||
bool Load(const QString aFilePath) override;
|
bool Load(const QString aFilePath) override;
|
||||||
bool Load(const QByteArray aData) override;
|
bool Load(const QByteArray aData) override;
|
||||||
|
|||||||
@ -36,7 +36,7 @@ FastFile_COD11_PC::~FastFile_COD11_PC() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray FastFile_COD11_PC::GetBinaryData() {
|
QByteArray FastFile_COD11_PC::GetBinaryData() const {
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,9 +69,9 @@ bool FastFile_COD11_PC::Load(const QString aFilePath) {
|
|||||||
bool FastFile_COD11_PC::Load(const QByteArray aData) {
|
bool FastFile_COD11_PC::Load(const QByteArray aData) {
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Create a QDataStream on the input data.
|
// Create a XDataStream on the input data.
|
||||||
QDataStream fastFileStream(aData);
|
XDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||||
|
|
||||||
// Parse header values.
|
// Parse header values.
|
||||||
SetCompany(pParseFFCompany(&fastFileStream));
|
SetCompany(pParseFFCompany(&fastFileStream));
|
||||||
@ -80,22 +80,11 @@ bool FastFile_COD11_PC::Load(const QByteArray aData) {
|
|||||||
SetMagic(pParseFFMagic(&fastFileStream));
|
SetMagic(pParseFFMagic(&fastFileStream));
|
||||||
quint32 version = pParseFFVersion(&fastFileStream);
|
quint32 version = pParseFFVersion(&fastFileStream);
|
||||||
SetVersion(version);
|
SetVersion(version);
|
||||||
SetPlatform(pCalculateFFPlatform(version));
|
|
||||||
SetGame("COD9");
|
|
||||||
|
|
||||||
// For COD7/COD9, use BigEndian.
|
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||||
fastFileStream.setByteOrder(QDataStream::BigEndian);
|
|
||||||
if (GetPlatform() == "PC") {
|
|
||||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Select key based on game.
|
// Select key based on game.
|
||||||
QByteArray key;
|
QByteArray key = QByteArray::fromHex("641D8A2FE31D3AA63622BBC9CE8587229D42B0F8ED9B924130BF88B65EDC50BE");
|
||||||
if (GetPlatform() == "360") {
|
|
||||||
key = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3");
|
|
||||||
} else if (GetPlatform() == "PC") {
|
|
||||||
key = QByteArray::fromHex("641D8A2FE31D3AA63622BBC9CE8587229D42B0F8ED9B924130BF88B65EDC50BE");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the 8-byte magic.
|
// Read the 8-byte magic.
|
||||||
QByteArray fileMagic(8, Qt::Uninitialized);
|
QByteArray fileMagic(8, Qt::Uninitialized);
|
||||||
@ -114,11 +103,7 @@ bool FastFile_COD11_PC::Load(const QByteArray aData) {
|
|||||||
QByteArray rsaSignature(256, Qt::Uninitialized);
|
QByteArray rsaSignature(256, Qt::Uninitialized);
|
||||||
fastFileStream.readRawData(rsaSignature.data(), 256);
|
fastFileStream.readRawData(rsaSignature.data(), 256);
|
||||||
|
|
||||||
if (GetPlatform() == "360") {
|
//decompressedData = Encryption::decryptFastFile_BO2(aData);
|
||||||
//decompressedData = Compressor::cod9_decryptFastFile(aData);
|
|
||||||
} else if (GetPlatform() == "PC") {
|
|
||||||
decompressedData = Encryption::decryptFastFile_BO2(aData);
|
|
||||||
}
|
|
||||||
|
|
||||||
// For COD9, write out the complete decompressed zone for testing.
|
// For COD9, write out the complete decompressed zone for testing.
|
||||||
QFile testFile("exports/" + GetBaseStem() + ".zone");
|
QFile testFile("exports/" + GetBaseStem() + ".zone");
|
||||||
@ -126,12 +111,16 @@ bool FastFile_COD11_PC::Load(const QByteArray aData) {
|
|||||||
testFile.write(decompressedData);
|
testFile.write(decompressedData);
|
||||||
testFile.close();
|
testFile.close();
|
||||||
}
|
}
|
||||||
|
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||||
|
|
||||||
// Load the zone file with the decompressed data (using an Xbox platform flag).
|
// Load the zone file with the decompressed data (using an Xbox platform flag).
|
||||||
ZoneFile_COD11_PC zoneFile;
|
ZoneFile_COD11_PC* zoneFile = new ZoneFile_COD11_PC();
|
||||||
zoneFile.SetStem(GetBaseStem() + ".zone");
|
zoneFile->SetStem(GetBaseStem() + ".zone");
|
||||||
zoneFile.Load(decompressedData);
|
if (!zoneFile->Load(decompressedData)) {
|
||||||
SetZoneFile(std::make_shared<ZoneFile_COD11_PC>(zoneFile));
|
qWarning() << "Failed to load ZoneFile!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SetZoneFile(zoneFile);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ public:
|
|||||||
FastFile_COD11_PC(const QString aFilePath);
|
FastFile_COD11_PC(const QString aFilePath);
|
||||||
~FastFile_COD11_PC();
|
~FastFile_COD11_PC();
|
||||||
|
|
||||||
QByteArray GetBinaryData() override;
|
QByteArray GetBinaryData() const override;
|
||||||
|
|
||||||
bool Load(const QString aFilePath) override;
|
bool Load(const QString aFilePath) override;
|
||||||
bool Load(const QByteArray aData) override;
|
bool Load(const QByteArray aData) override;
|
||||||
|
|||||||
@ -39,7 +39,7 @@ FastFile_COD12_PC::~FastFile_COD12_PC() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray FastFile_COD12_PC::GetBinaryData() {
|
QByteArray FastFile_COD12_PC::GetBinaryData() const {
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,13 +72,9 @@ bool FastFile_COD12_PC::Load(const QString aFilePath) {
|
|||||||
bool FastFile_COD12_PC::Load(const QByteArray aData) {
|
bool FastFile_COD12_PC::Load(const QByteArray aData) {
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Create a QDataStream on the input data.
|
// Create a XDataStream on the input data.
|
||||||
QDataStream fastFileStream(aData);
|
XDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||||
|
|
||||||
// Load the zone file with the decompressed data (using an Xbox platform flag).
|
|
||||||
ZoneFile_COD12_PC zoneFile;
|
|
||||||
zoneFile.SetStem(GetBaseStem() + ".zone");
|
|
||||||
|
|
||||||
// Skip header magic
|
// Skip header magic
|
||||||
fastFileStream.skipRawData(8);
|
fastFileStream.skipRawData(8);
|
||||||
@ -140,12 +136,16 @@ bool FastFile_COD12_PC::Load(const QByteArray aData) {
|
|||||||
// Sinze Fast Files are aligns, we must skip the full block
|
// Sinze Fast Files are aligns, we must skip the full block
|
||||||
fastFileStream.device()->seek(blockPosition + 16 + blockSize);
|
fastFileStream.device()->seek(blockPosition + 16 + blockSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||||
|
|
||||||
zoneFile.Load(decompressedData);
|
// Load the zone file with the decompressed data (using an Xbox platform flag).
|
||||||
|
ZoneFile_COD12_PC* zoneFile = new ZoneFile_COD12_PC();
|
||||||
SetZoneFile(std::make_shared<ZoneFile_COD12_PC>(zoneFile));
|
zoneFile->SetStem(GetBaseStem() + ".zone");
|
||||||
|
if (!zoneFile->Load(decompressedData)) {
|
||||||
|
qWarning() << "Failed to load ZoneFile!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SetZoneFile(zoneFile);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ public:
|
|||||||
FastFile_COD12_PC(const QString aFilePath);
|
FastFile_COD12_PC(const QString aFilePath);
|
||||||
~FastFile_COD12_PC();
|
~FastFile_COD12_PC();
|
||||||
|
|
||||||
QByteArray GetBinaryData() override;
|
QByteArray GetBinaryData() const override;
|
||||||
|
|
||||||
bool Load(const QString aFilePath) override;
|
bool Load(const QString aFilePath) override;
|
||||||
bool Load(const QByteArray aData) override;
|
bool Load(const QByteArray aData) override;
|
||||||
|
|||||||
@ -39,7 +39,7 @@ FastFile_COD4_PC::~FastFile_COD4_PC() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray FastFile_COD4_PC::GetBinaryData() {
|
QByteArray FastFile_COD4_PC::GetBinaryData() const {
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,19 +75,22 @@ bool FastFile_COD4_PC::Load(const QByteArray aData) {
|
|||||||
StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000);
|
StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000);
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Create a QDataStream on the input data.
|
// Create a XDataStream on the input data.
|
||||||
QDataStream fastFileStream(aData);
|
XDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||||
|
|
||||||
// For COD5, simply decompress from offset 12.
|
// For COD5, simply decompress from offset 12.
|
||||||
decompressedData = Compression::DecompressZLIB(aData.mid(12));
|
decompressedData = Compression::DecompressZLIB(aData.mid(12));
|
||||||
|
|
||||||
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||||
|
|
||||||
ZoneFile_COD4_PC zoneFile;
|
ZoneFile_COD4_PC* zoneFile = new ZoneFile_COD4_PC();
|
||||||
zoneFile.SetStem(GetBaseStem() + ".zone");
|
zoneFile->SetStem(GetBaseStem() + ".zone");
|
||||||
zoneFile.Load(decompressedData);
|
if (!zoneFile->Load(decompressedData)) {
|
||||||
SetZoneFile(std::make_shared<ZoneFile_COD4_PC>(zoneFile));
|
qWarning() << "Failed to load ZoneFile!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SetZoneFile(zoneFile);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ public:
|
|||||||
FastFile_COD4_PC(const QString aFilePath);
|
FastFile_COD4_PC(const QString aFilePath);
|
||||||
~FastFile_COD4_PC();
|
~FastFile_COD4_PC();
|
||||||
|
|
||||||
QByteArray GetBinaryData() override;
|
QByteArray GetBinaryData() const override;
|
||||||
|
|
||||||
bool Load(const QString aFilePath) override;
|
bool Load(const QString aFilePath) override;
|
||||||
bool Load(const QByteArray aData) override;
|
bool Load(const QByteArray aData) override;
|
||||||
|
|||||||
@ -39,7 +39,7 @@ FastFile_COD5_PC::~FastFile_COD5_PC() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray FastFile_COD5_PC::GetBinaryData() {
|
QByteArray FastFile_COD5_PC::GetBinaryData() const {
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,19 +75,22 @@ bool FastFile_COD5_PC::Load(const QByteArray aData) {
|
|||||||
StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000);
|
StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000);
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Create a QDataStream on the input data.
|
// Create a XDataStream on the input data.
|
||||||
QDataStream fastFileStream(aData);
|
XDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||||
|
|
||||||
// For COD5, simply decompress from offset 12.
|
// For COD5, simply decompress from offset 12.
|
||||||
decompressedData = Compression::DecompressZLIB(aData.mid(12));
|
decompressedData = Compression::DecompressZLIB(aData.mid(12));
|
||||||
|
|
||||||
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||||
|
|
||||||
ZoneFile_COD5_PC zoneFile;
|
ZoneFile_COD5_PC* zoneFile = new ZoneFile_COD5_PC();
|
||||||
zoneFile.SetStem(GetBaseStem() + ".zone");
|
zoneFile->SetStem(GetBaseStem() + ".zone");
|
||||||
zoneFile.Load(decompressedData);
|
if (!zoneFile->Load(decompressedData)) {
|
||||||
SetZoneFile(std::make_shared<ZoneFile_COD5_PC>(zoneFile));
|
qWarning() << "Failed to load ZoneFile!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SetZoneFile(zoneFile);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ public:
|
|||||||
FastFile_COD5_PC(const QString aFilePath);
|
FastFile_COD5_PC(const QString aFilePath);
|
||||||
~FastFile_COD5_PC();
|
~FastFile_COD5_PC();
|
||||||
|
|
||||||
QByteArray GetBinaryData() override;
|
QByteArray GetBinaryData() const override;
|
||||||
|
|
||||||
bool Load(const QString aFilePath) override;
|
bool Load(const QString aFilePath) override;
|
||||||
bool Load(const QByteArray aData) override;
|
bool Load(const QByteArray aData) override;
|
||||||
|
|||||||
@ -39,7 +39,7 @@ FastFile_COD6_PC::~FastFile_COD6_PC() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray FastFile_COD6_PC::GetBinaryData() {
|
QByteArray FastFile_COD6_PC::GetBinaryData() const {
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,19 +72,40 @@ bool FastFile_COD6_PC::Load(const QString aFilePath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool FastFile_COD6_PC::Load(const QByteArray aData) {
|
bool FastFile_COD6_PC::Load(const QByteArray aData) {
|
||||||
StatusBarManager::instance().updateStatus("Loading COD5 Fast File w/data", 1000);
|
const qint64 zlibOffset = Compression::FindZlibOffset(aData);
|
||||||
QByteArray decompressedData;
|
qDebug() << "ZLib Offset: " << zlibOffset;
|
||||||
|
if (zlibOffset == -1)
|
||||||
|
{
|
||||||
|
qWarning() << "Z-Lib stream not found";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
QByteArray compressed = aData.mid(zlibOffset);
|
||||||
|
|
||||||
// Assume the first 12 bytes are a header; the rest is zlib-compressed zone data.
|
QByteArray decompressedData = Compression::DecompressZLIB(compressed);
|
||||||
const QByteArray compressedData = aData.mid(21);
|
|
||||||
decompressedData = Compression::DecompressZLIB(compressedData);
|
if (decompressedData.isEmpty() || decompressedData.size() < 1024)
|
||||||
|
{
|
||||||
|
QByteArray stripped = Compression::StripHashBlocks(compressed);
|
||||||
|
QByteArray retry = Compression::DecompressZLIB(stripped);
|
||||||
|
if (!retry.isEmpty())
|
||||||
|
decompressedData.swap(retry);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decompressedData.isEmpty())
|
||||||
|
{
|
||||||
|
qWarning() << "Unable to decompress fast-file";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||||
|
|
||||||
ZoneFile_COD6_PC zoneFile;
|
ZoneFile_COD6_PC* zoneFile = new ZoneFile_COD6_PC();
|
||||||
zoneFile.SetStem(GetBaseStem() + ".zone");
|
zoneFile->SetStem(GetBaseStem() + ".zone");
|
||||||
zoneFile.Load(decompressedData);
|
if (!zoneFile->Load(decompressedData)) {
|
||||||
SetZoneFile(std::make_shared<ZoneFile_COD6_PC>(zoneFile));
|
qWarning() << "Failed to load ZoneFile!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SetZoneFile(zoneFile);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ public:
|
|||||||
FastFile_COD6_PC(const QString aFilePath);
|
FastFile_COD6_PC(const QString aFilePath);
|
||||||
~FastFile_COD6_PC();
|
~FastFile_COD6_PC();
|
||||||
|
|
||||||
QByteArray GetBinaryData() override;
|
QByteArray GetBinaryData() const override;
|
||||||
|
|
||||||
bool Load(const QString aFilePath) override;
|
bool Load(const QString aFilePath) override;
|
||||||
bool Load(const QByteArray aData) override;
|
bool Load(const QByteArray aData) override;
|
||||||
|
|||||||
@ -39,7 +39,7 @@ FastFile_COD7_PC::~FastFile_COD7_PC() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray FastFile_COD7_PC::GetBinaryData() {
|
QByteArray FastFile_COD7_PC::GetBinaryData() const {
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,9 +72,9 @@ bool FastFile_COD7_PC::Load(const QString aFilePath) {
|
|||||||
bool FastFile_COD7_PC::Load(const QByteArray aData) {
|
bool FastFile_COD7_PC::Load(const QByteArray aData) {
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Create a QDataStream on the input data.
|
// Create a XDataStream on the input data.
|
||||||
QDataStream fastFileStream(aData);
|
XDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||||
|
|
||||||
// Parse header values.
|
// Parse header values.
|
||||||
SetCompany(pParseFFCompany(&fastFileStream));
|
SetCompany(pParseFFCompany(&fastFileStream));
|
||||||
@ -83,88 +83,22 @@ bool FastFile_COD7_PC::Load(const QByteArray aData) {
|
|||||||
SetMagic(pParseFFMagic(&fastFileStream));
|
SetMagic(pParseFFMagic(&fastFileStream));
|
||||||
quint32 version = pParseFFVersion(&fastFileStream);
|
quint32 version = pParseFFVersion(&fastFileStream);
|
||||||
SetVersion(version);
|
SetVersion(version);
|
||||||
SetPlatform(pCalculateFFPlatform(version));
|
SetPlatform("360");
|
||||||
SetGame("COD7");
|
SetGame("COD7");
|
||||||
|
|
||||||
// Load the zone file with the decompressed data (using an Xbox platform flag).
|
// Assume the first 12 bytes are a header; the rest is zlib-compressed zone data.
|
||||||
ZoneFile_COD7_PC zoneFile;
|
const QByteArray compressedData = aData.mid(12);
|
||||||
zoneFile.SetStem(GetBaseStem() + ".zone");
|
decompressedData = Compression::DecompressZLIB(compressedData);
|
||||||
|
|
||||||
// For COD7/COD9, use BigEndian.
|
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
|
||||||
|
|
||||||
// Select key based on game.
|
ZoneFile_COD7_PC* zoneFile = new ZoneFile_COD7_PC();
|
||||||
QByteArray key;
|
zoneFile->SetStem(GetBaseStem() + ".zone");
|
||||||
fastFileStream.skipRawData(4);
|
if (!zoneFile->Load(decompressedData)) {
|
||||||
if (GetPlatform() == "360") {
|
qWarning() << "Failed to load ZoneFile!";
|
||||||
key = QByteArray::fromHex("1ac1d12d527c59b40eca619120ff8217ccff09cd16896f81b829c7f52793405d");
|
|
||||||
} else if (GetPlatform() == "PS3") {
|
|
||||||
key = QByteArray::fromHex("46D3F997F29C9ACE175B0DAE3AB8C0C1B8E423E2E3BF7E3C311EA35245BF193A");
|
|
||||||
// or
|
|
||||||
// key = QByteArray::fromHex("0C99B3DDB8D6D0845D1147E470F28A8BF2AE69A8A9F534767B54E9180FF55370");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the 8-byte magic.
|
|
||||||
QByteArray fileMagic(8, Qt::Uninitialized);
|
|
||||||
fastFileStream.readRawData(fileMagic.data(), 8);
|
|
||||||
if (fileMagic != "PHEEBs71") {
|
|
||||||
qWarning() << "Invalid fast file magic!";
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
fastFileStream.skipRawData(4);
|
SetZoneFile(zoneFile);
|
||||||
|
|
||||||
// Read IV table name (32 bytes).
|
|
||||||
QByteArray fileName(32, Qt::Uninitialized);
|
|
||||||
fastFileStream.readRawData(fileName.data(), 32);
|
|
||||||
|
|
||||||
// Build the IV table from the fileName.
|
|
||||||
QByteArray ivTable = Encryption::InitIVTable(fileName);
|
|
||||||
|
|
||||||
// Skip the RSA signature (256 bytes).
|
|
||||||
QByteArray rsaSignature(256, Qt::Uninitialized);
|
|
||||||
fastFileStream.readRawData(rsaSignature.data(), 256);
|
|
||||||
|
|
||||||
// Now the stream should be positioned at 0x13C, where sections begin.
|
|
||||||
int sectionIndex = 0;
|
|
||||||
while (true) {
|
|
||||||
qint32 sectionSize = 0;
|
|
||||||
fastFileStream >> sectionSize;
|
|
||||||
qDebug() << "Section index:" << sectionIndex << "Size:" << sectionSize
|
|
||||||
<< "Pos:" << fastFileStream.device()->pos();
|
|
||||||
if (sectionSize == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Read the section data.
|
|
||||||
QByteArray sectionData;
|
|
||||||
sectionData.resize(sectionSize);
|
|
||||||
fastFileStream.readRawData(sectionData.data(), sectionSize);
|
|
||||||
|
|
||||||
// Compute the IV for this section.
|
|
||||||
QByteArray iv = Encryption::GetIV(ivTable, sectionIndex);
|
|
||||||
|
|
||||||
// Decrypt the section using Salsa20.
|
|
||||||
QByteArray decData = Encryption::salsa20DecryptSection(sectionData, key, iv);
|
|
||||||
|
|
||||||
// Compute SHA1 hash of the decrypted data.
|
|
||||||
QByteArray sectionHash = QCryptographicHash::hash(decData, QCryptographicHash::Sha1);
|
|
||||||
|
|
||||||
// Update the IV table based on the section hash.
|
|
||||||
Encryption::UpdateIVTable(ivTable, sectionIndex, sectionHash);
|
|
||||||
|
|
||||||
// Build a compressed data buffer by prepending the two-byte zlib header.
|
|
||||||
QByteArray compressedData;
|
|
||||||
compressedData.append(char(0x78));
|
|
||||||
compressedData.append(char(0x01));
|
|
||||||
compressedData.append(decData);
|
|
||||||
|
|
||||||
decompressedData.append(Compression::DecompressZLIB(compressedData));
|
|
||||||
|
|
||||||
sectionIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
zoneFile.Load(decompressedData);
|
|
||||||
|
|
||||||
SetZoneFile(std::make_shared<ZoneFile_COD7_PC>(zoneFile));
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ public:
|
|||||||
FastFile_COD7_PC(const QString aFilePath);
|
FastFile_COD7_PC(const QString aFilePath);
|
||||||
~FastFile_COD7_PC();
|
~FastFile_COD7_PC();
|
||||||
|
|
||||||
QByteArray GetBinaryData() override;
|
QByteArray GetBinaryData() const override;
|
||||||
|
|
||||||
bool Load(const QString aFilePath) override;
|
bool Load(const QString aFilePath) override;
|
||||||
bool Load(const QByteArray aData) override;
|
bool Load(const QByteArray aData) override;
|
||||||
|
|||||||
@ -39,7 +39,7 @@ FastFile_COD8_PC::~FastFile_COD8_PC() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray FastFile_COD8_PC::GetBinaryData() {
|
QByteArray FastFile_COD8_PC::GetBinaryData() const {
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,99 +72,27 @@ bool FastFile_COD8_PC::Load(const QString aFilePath) {
|
|||||||
bool FastFile_COD8_PC::Load(const QByteArray aData) {
|
bool FastFile_COD8_PC::Load(const QByteArray aData) {
|
||||||
QByteArray decompressedData;
|
QByteArray decompressedData;
|
||||||
|
|
||||||
// Create a QDataStream on the input data.
|
// Create a XDataStream on the input data.
|
||||||
QDataStream fastFileStream(aData);
|
XDataStream fastFileStream(aData);
|
||||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||||
|
|
||||||
// Parse header values.
|
// Parse header values.
|
||||||
SetCompany(pParseFFCompany(&fastFileStream));
|
SetCompany(pParseFFCompany(&fastFileStream));
|
||||||
SetType(pParseFFFileType(&fastFileStream));
|
SetType(pParseFFFileType(&fastFileStream));
|
||||||
SetSignage(pParseFFSignage(&fastFileStream));
|
SetSignage(pParseFFSignage(&fastFileStream));
|
||||||
SetMagic(pParseFFMagic(&fastFileStream));
|
SetMagic(pParseFFMagic(&fastFileStream));
|
||||||
quint32 version = pParseFFVersion(&fastFileStream);
|
SetVersion(pParseFFVersion(&fastFileStream));
|
||||||
SetVersion(version);
|
|
||||||
SetPlatform(pCalculateFFPlatform(version));
|
|
||||||
SetGame("COD7");
|
|
||||||
|
|
||||||
// Load the zone file with the decompressed data (using an Xbox platform flag).
|
decompressedData = Compression::DecompressZLIB(aData.mid(21));
|
||||||
ZoneFile_COD8_PC zoneFile;
|
Utils::ExportData(GetBaseStem() + ".zone", decompressedData);
|
||||||
zoneFile.SetStem(GetBaseStem() + ".zone");
|
|
||||||
|
|
||||||
// For COD7/COD9, use BigEndian.
|
ZoneFile_COD8_PC* zoneFile = new ZoneFile_COD8_PC();
|
||||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
zoneFile->SetStem(GetBaseStem() + ".zone");
|
||||||
|
if (!zoneFile->Load(decompressedData)) {
|
||||||
// Select key based on game.
|
qWarning() << "Failed to load ZoneFile!";
|
||||||
QByteArray key;
|
|
||||||
fastFileStream.skipRawData(4);
|
|
||||||
if (GetPlatform() == "360") {
|
|
||||||
key = QByteArray::fromHex("1ac1d12d527c59b40eca619120ff8217ccff09cd16896f81b829c7f52793405d");
|
|
||||||
} else if (GetPlatform() == "PS3") {
|
|
||||||
key = QByteArray::fromHex("46D3F997F29C9ACE175B0DAE3AB8C0C1B8E423E2E3BF7E3C311EA35245BF193A");
|
|
||||||
// or
|
|
||||||
// key = QByteArray::fromHex("0C99B3DDB8D6D0845D1147E470F28A8BF2AE69A8A9F534767B54E9180FF55370");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the 8-byte magic.
|
|
||||||
QByteArray fileMagic(8, Qt::Uninitialized);
|
|
||||||
fastFileStream.readRawData(fileMagic.data(), 8);
|
|
||||||
if (fileMagic != "PHEEBs71") {
|
|
||||||
qWarning() << "Invalid fast file magic!";
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
fastFileStream.skipRawData(4);
|
SetZoneFile(zoneFile);
|
||||||
|
|
||||||
// Read IV table name (32 bytes).
|
|
||||||
QByteArray fileName(32, Qt::Uninitialized);
|
|
||||||
fastFileStream.readRawData(fileName.data(), 32);
|
|
||||||
|
|
||||||
// Build the IV table from the fileName.
|
|
||||||
QByteArray ivTable = Encryption::InitIVTable(fileName);
|
|
||||||
|
|
||||||
// Skip the RSA signature (256 bytes).
|
|
||||||
QByteArray rsaSignature(256, Qt::Uninitialized);
|
|
||||||
fastFileStream.readRawData(rsaSignature.data(), 256);
|
|
||||||
|
|
||||||
// Now the stream should be positioned at 0x13C, where sections begin.
|
|
||||||
int sectionIndex = 0;
|
|
||||||
while (true) {
|
|
||||||
qint32 sectionSize = 0;
|
|
||||||
fastFileStream >> sectionSize;
|
|
||||||
qDebug() << "Section index:" << sectionIndex << "Size:" << sectionSize
|
|
||||||
<< "Pos:" << fastFileStream.device()->pos();
|
|
||||||
if (sectionSize == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Read the section data.
|
|
||||||
QByteArray sectionData;
|
|
||||||
sectionData.resize(sectionSize);
|
|
||||||
fastFileStream.readRawData(sectionData.data(), sectionSize);
|
|
||||||
|
|
||||||
// Compute the IV for this section.
|
|
||||||
QByteArray iv = Encryption::GetIV(ivTable, sectionIndex);
|
|
||||||
|
|
||||||
// Decrypt the section using Salsa20.
|
|
||||||
QByteArray decData = Encryption::salsa20DecryptSection(sectionData, key, iv);
|
|
||||||
|
|
||||||
// Compute SHA1 hash of the decrypted data.
|
|
||||||
QByteArray sectionHash = QCryptographicHash::hash(decData, QCryptographicHash::Sha1);
|
|
||||||
|
|
||||||
// Update the IV table based on the section hash.
|
|
||||||
Encryption::UpdateIVTable(ivTable, sectionIndex, sectionHash);
|
|
||||||
|
|
||||||
// Build a compressed data buffer by prepending the two-byte zlib header.
|
|
||||||
QByteArray compressedData;
|
|
||||||
compressedData.append(char(0x78));
|
|
||||||
compressedData.append(char(0x01));
|
|
||||||
compressedData.append(decData);
|
|
||||||
|
|
||||||
decompressedData.append(Compression::DecompressZLIB(compressedData));
|
|
||||||
|
|
||||||
sectionIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
zoneFile.Load(decompressedData);
|
|
||||||
|
|
||||||
SetZoneFile(std::make_shared<ZoneFile_COD8_PC>(zoneFile));
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ public:
|
|||||||
FastFile_COD8_PC(const QString aFilePath);
|
FastFile_COD8_PC(const QString aFilePath);
|
||||||
~FastFile_COD8_PC();
|
~FastFile_COD8_PC();
|
||||||
|
|
||||||
QByteArray GetBinaryData() override;
|
QByteArray GetBinaryData() const override;
|
||||||
|
|
||||||
bool Load(const QString aFilePath) override;
|
bool Load(const QString aFilePath) override;
|
||||||
bool Load(const QByteArray aData) override;
|
bool Load(const QByteArray aData) override;
|
||||||
|
|||||||
@ -36,7 +36,7 @@ FastFile_COD9_PC::~FastFile_COD9_PC() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray FastFile_COD9_PC::GetBinaryData() {
|
QByteArray FastFile_COD9_PC::GetBinaryData() const {
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,37 +67,18 @@ bool FastFile_COD9_PC::Load(const QString aFilePath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool FastFile_COD9_PC::Load(const QByteArray aData) {
|
bool FastFile_COD9_PC::Load(const QByteArray aData) {
|
||||||
QByteArray decompressedData;
|
// Create a XDataStream on the input data.
|
||||||
|
XDataStream fastFileStream(aData);
|
||||||
// Create a QDataStream on the input data.
|
fastFileStream.setByteOrder(XDataStream::LittleEndian);
|
||||||
QDataStream fastFileStream(aData);
|
|
||||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
|
||||||
|
|
||||||
// Parse header values.
|
// Parse header values.
|
||||||
SetCompany(pParseFFCompany(&fastFileStream));
|
SetCompany(pParseFFCompany(&fastFileStream));
|
||||||
SetType(pParseFFFileType(&fastFileStream));
|
SetType(pParseFFFileType(&fastFileStream));
|
||||||
SetSignage(pParseFFSignage(&fastFileStream));
|
SetSignage(pParseFFSignage(&fastFileStream));
|
||||||
SetMagic(pParseFFMagic(&fastFileStream));
|
SetMagic(pParseFFMagic(&fastFileStream));
|
||||||
quint32 version = pParseFFVersion(&fastFileStream);
|
SetVersion(pParseFFVersion(&fastFileStream));
|
||||||
SetVersion(version);
|
|
||||||
SetPlatform(pCalculateFFPlatform(version));
|
|
||||||
SetGame("COD9");
|
|
||||||
|
|
||||||
// For COD7/COD9, use BigEndian.
|
// Validate the fastfile magic.
|
||||||
fastFileStream.setByteOrder(QDataStream::BigEndian);
|
|
||||||
if (GetPlatform() == "PC") {
|
|
||||||
fastFileStream.setByteOrder(QDataStream::LittleEndian);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Select key based on game.
|
|
||||||
QByteArray key;
|
|
||||||
if (GetPlatform() == "360") {
|
|
||||||
key = QByteArray::fromHex("0E50F49F412317096038665622DD091332A209BA0A05A00E1377CEDB0A3CB1D3");
|
|
||||||
} else if (GetPlatform() == "PC") {
|
|
||||||
key = QByteArray::fromHex("641D8A2FE31D3AA63622BBC9CE8587229D42B0F8ED9B924130BF88B65EDC50BE");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the 8-byte magic.
|
|
||||||
QByteArray fileMagic(8, Qt::Uninitialized);
|
QByteArray fileMagic(8, Qt::Uninitialized);
|
||||||
fastFileStream.readRawData(fileMagic.data(), 8);
|
fastFileStream.readRawData(fileMagic.data(), 8);
|
||||||
if (fileMagic != "PHEEBs71") {
|
if (fileMagic != "PHEEBs71") {
|
||||||
@ -106,32 +87,100 @@ bool FastFile_COD9_PC::Load(const QByteArray aData) {
|
|||||||
}
|
}
|
||||||
fastFileStream.skipRawData(4);
|
fastFileStream.skipRawData(4);
|
||||||
|
|
||||||
// Read IV table name (32 bytes).
|
// Read IV seed name (32 bytes).
|
||||||
QByteArray fileName(32, Qt::Uninitialized);
|
QByteArray nameKey(32, Qt::Uninitialized);
|
||||||
fastFileStream.readRawData(fileName.data(), 32);
|
fastFileStream.readRawData(nameKey.data(), 32);
|
||||||
|
|
||||||
// Skip the RSA signature (256 bytes).
|
// --- Salsa20 + IV setup ---
|
||||||
QByteArray rsaSignature(256, Qt::Uninitialized);
|
static QVector<quint32> ivCounter(4, 1);
|
||||||
fastFileStream.readRawData(rsaSignature.data(), 256);
|
QByteArray ivTable = Encryption::InitIVTable(nameKey);
|
||||||
|
ivCounter.fill(1); // reset global counters
|
||||||
|
|
||||||
if (GetPlatform() == "360") {
|
// Skip RSA signature (0x100)
|
||||||
//decompressedData = Compressor::cod9_decryptFastFile(aData);
|
fastFileStream.skipRawData(0x100);
|
||||||
} else if (GetPlatform() == "PC") {
|
|
||||||
decompressedData = Encryption::decryptFastFile_BO2(aData);
|
// Decrypt + decompress loop
|
||||||
|
QByteArray finalZone;
|
||||||
|
int chunkIndex = 0;
|
||||||
|
|
||||||
|
while (!fastFileStream.atEnd()) {
|
||||||
|
quint32 dataLength = 0;
|
||||||
|
fastFileStream >> dataLength;
|
||||||
|
if (dataLength == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
QByteArray encryptedBlock(dataLength, Qt::Uninitialized);
|
||||||
|
if (fastFileStream.readRawData(encryptedBlock.data(), dataLength) != dataLength) {
|
||||||
|
qWarning() << "Unexpected EOF while reading block";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Derive IV for this chunk
|
||||||
|
QByteArray iv = Encryption::GetIV(ivTable, chunkIndex % 4);
|
||||||
|
|
||||||
|
// Salsa20 decryption
|
||||||
|
QByteArray decryptedBlock = Encryption::salsa20DecryptSection(
|
||||||
|
encryptedBlock,
|
||||||
|
QByteArray::fromHex("641D8A2FE31D3AA63622BBC9CE8587229D42B0F8ED9B924130BF88B65EDC50BE"),
|
||||||
|
iv,
|
||||||
|
64
|
||||||
|
);
|
||||||
|
|
||||||
|
// SHA1 hash of decrypted block
|
||||||
|
QCryptographicHash sha1(QCryptographicHash::Sha1);
|
||||||
|
sha1.addData(decryptedBlock);
|
||||||
|
QByteArray sha1Hash = sha1.result();
|
||||||
|
|
||||||
|
// Inflate into buffer
|
||||||
|
z_stream strm{};
|
||||||
|
strm.avail_in = static_cast<uInt>(decryptedBlock.size());
|
||||||
|
strm.next_in = reinterpret_cast<Bytef*>(decryptedBlock.data());
|
||||||
|
|
||||||
|
QByteArray decompressedData;
|
||||||
|
QByteArray buffer(0x10000, Qt::Uninitialized);
|
||||||
|
inflateInit2(&strm, -15);
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
do {
|
||||||
|
strm.avail_out = buffer.size();
|
||||||
|
strm.next_out = reinterpret_cast<Bytef*>(buffer.data());
|
||||||
|
|
||||||
|
ret = inflate(&strm, Z_NO_FLUSH);
|
||||||
|
|
||||||
|
if (ret != Z_OK && ret != Z_STREAM_END && ret != Z_BUF_ERROR) {
|
||||||
|
qWarning() << "inflate failed with code" << ret;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int have = buffer.size() - strm.avail_out;
|
||||||
|
if (have > 0)
|
||||||
|
decompressedData.append(buffer.constData(), have);
|
||||||
|
|
||||||
|
} while (ret != Z_STREAM_END);
|
||||||
|
|
||||||
|
inflateEnd(&strm);
|
||||||
|
|
||||||
|
finalZone.append(decompressedData);
|
||||||
|
|
||||||
|
// Update IV table for next block
|
||||||
|
Encryption::UpdateIVTable(ivTable, chunkIndex % 4, sha1Hash);
|
||||||
|
|
||||||
|
chunkIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For COD9, write out the complete decompressed zone for testing.
|
// Export decompressed zone
|
||||||
QFile testFile("exports/" + GetBaseStem() + ".zone");
|
Utils::ExportData(GetBaseStem() + ".zone", finalZone);
|
||||||
if(testFile.open(QIODevice::WriteOnly)) {
|
|
||||||
testFile.write(decompressedData);
|
|
||||||
testFile.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load the zone file with the decompressed data (using an Xbox platform flag).
|
// Load zone file
|
||||||
ZoneFile_COD9_PC zoneFile;
|
ZoneFile_COD9_PC* zoneFile = new ZoneFile_COD9_PC();
|
||||||
zoneFile.SetStem(GetBaseStem() + ".zone");
|
zoneFile->SetStem(GetBaseStem() + ".zone");
|
||||||
zoneFile.Load(decompressedData);
|
if (!zoneFile->Load(finalZone)) {
|
||||||
SetZoneFile(std::make_shared<ZoneFile_COD9_PC>(zoneFile));
|
qWarning() << "Failed to load ZoneFile!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SetZoneFile(zoneFile);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user