├── .gitignore ├── Asmodean ├── Asmodean.vcxproj ├── Asmodean.vcxproj.filters ├── asmodean.h ├── blowfish.cpp ├── blowfish.h ├── exkifint.cpp ├── exkifint.h ├── hgx2bmp.cpp └── hgx2bmp.h ├── GrisaiaExtractor.sln ├── GrisaiaExtractor ├── AnimationHelper.cs ├── Asmodean │ ├── Exkifint.MersenneTwister.cs │ ├── Exkifint.PInvoke.cs │ ├── Exkifint.Structs.cs │ ├── Exkifint.cs │ ├── Hgx2png.PInvoke.cs │ ├── Hgx2png.Structs.cs │ └── Hgx2png.cs ├── Attributes.cs ├── Exceptions.cs ├── Extensions │ ├── BinaryExtensions.cs │ ├── StringExtensions.Surround.cs │ └── StringExtensions.cs ├── Extracting.cs ├── GrisaiaExtractor.csproj ├── Identifying │ ├── Backgrounds.cs │ ├── Character.cs │ ├── Effect.cs │ ├── ImageIdentification.cs │ ├── ImageIdentifier.cs │ ├── Item.cs │ ├── Logo.cs │ ├── MiscChibi.cs │ ├── StoryCGChibi.cs │ ├── TmbIcon.cs │ ├── Transition.cs │ ├── Unidentified.cs │ └── UserInterface.cs ├── Locator.cs ├── PathHelper.cs ├── Properties │ └── AssemblyInfo.cs ├── Unused │ ├── Exkifint.Blowfish.Tables.cs │ ├── Exkifint.Blowfish.cs │ └── Hgx2png.BitBuffer.cs └── zlib1.dll ├── GrisaiaExtractorConsole ├── App.ico ├── AsciiImage.cs ├── GrisaiaExtractorConsole.csproj ├── Ini │ ├── IniDocument.cs │ ├── IniEnums.cs │ ├── IniProperty.cs │ ├── IniReflectionSettings.cs │ ├── IniSection.cs │ ├── ReflectionHelper.cs │ └── TypeHelper.cs ├── Program.Classes.cs ├── Program.Input.cs ├── Program.Output.cs ├── Program.cs ├── Properties │ └── AssemblyInfo.cs ├── UserSettings.cs └── grisaia.ascii ├── License.md ├── Readme.md └── zlib ├── bin └── zlib1.dll ├── include ├── zconf.h └── zlib.h ├── lib ├── libz.a ├── libz.dll.a ├── zlib-bcc.lib ├── zlib.def └── zlib.lib └── manifest ├── zlib-1.2.3-lib.mft └── zlib-1.2.3-lib.ver /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | !zlib/bin 25 | [Oo]bj/ 26 | [Ll]og/ 27 | 28 | # Visual Studio 2015/2017 cache/options directory 29 | .vs/ 30 | # Uncomment if you have tasks that create the project's static files in wwwroot 31 | #wwwroot/ 32 | 33 | # Visual Studio 2017 auto generated files 34 | Generated\ Files/ 35 | 36 | # MSTest test Results 37 | [Tt]est[Rr]esult*/ 38 | [Bb]uild[Ll]og.* 39 | 40 | # NUNIT 41 | *.VisualState.xml 42 | TestResult.xml 43 | 44 | # Build Results of an ATL Project 45 | [Dd]ebugPS/ 46 | [Rr]eleasePS/ 47 | dlldata.c 48 | 49 | # Benchmark Results 50 | BenchmarkDotNet.Artifacts/ 51 | 52 | # .NET Core 53 | project.lock.json 54 | project.fragment.lock.json 55 | artifacts/ 56 | **/Properties/launchSettings.json 57 | 58 | # StyleCop 59 | StyleCopReport.xml 60 | 61 | # Files built by Visual Studio 62 | *_i.c 63 | *_p.c 64 | *_i.h 65 | *.ilk 66 | *.meta 67 | *.obj 68 | *.iobj 69 | *.pch 70 | *.pdb 71 | *.ipdb 72 | *.pgc 73 | *.pgd 74 | *.rsp 75 | *.sbr 76 | *.tlb 77 | *.tli 78 | *.tlh 79 | *.tmp 80 | *.tmp_proj 81 | *.log 82 | *.vspscc 83 | *.vssscc 84 | .builds 85 | *.pidb 86 | *.svclog 87 | *.scc 88 | 89 | # Chutzpah Test files 90 | _Chutzpah* 91 | 92 | # Visual C++ cache files 93 | ipch/ 94 | *.aps 95 | *.ncb 96 | *.opendb 97 | *.opensdf 98 | *.sdf 99 | *.cachefile 100 | *.VC.db 101 | *.VC.VC.opendb 102 | 103 | # Visual Studio profiler 104 | *.psess 105 | *.vsp 106 | *.vspx 107 | *.sap 108 | 109 | # Visual Studio Trace Files 110 | *.e2e 111 | 112 | # TFS 2012 Local Workspace 113 | $tf/ 114 | 115 | # Guidance Automation Toolkit 116 | *.gpState 117 | 118 | # ReSharper is a .NET coding add-in 119 | _ReSharper*/ 120 | *.[Rr]e[Ss]harper 121 | *.DotSettings.user 122 | 123 | # JustCode is a .NET coding add-in 124 | .JustCode 125 | 126 | # TeamCity is a build add-in 127 | _TeamCity* 128 | 129 | # DotCover is a Code Coverage Tool 130 | *.dotCover 131 | 132 | # AxoCover is a Code Coverage Tool 133 | .axoCover/* 134 | !.axoCover/settings.json 135 | 136 | # Visual Studio code coverage results 137 | *.coverage 138 | *.coveragexml 139 | 140 | # NCrunch 141 | _NCrunch_* 142 | .*crunch*.local.xml 143 | nCrunchTemp_* 144 | 145 | # MightyMoose 146 | *.mm.* 147 | AutoTest.Net/ 148 | 149 | # Web workbench (sass) 150 | .sass-cache/ 151 | 152 | # Installshield output folder 153 | [Ee]xpress/ 154 | 155 | # DocProject is a documentation generator add-in 156 | DocProject/buildhelp/ 157 | DocProject/Help/*.HxT 158 | DocProject/Help/*.HxC 159 | DocProject/Help/*.hhc 160 | DocProject/Help/*.hhk 161 | DocProject/Help/*.hhp 162 | DocProject/Help/Html2 163 | DocProject/Help/html 164 | 165 | # Click-Once directory 166 | publish/ 167 | 168 | # Publish Web Output 169 | *.[Pp]ublish.xml 170 | *.azurePubxml 171 | # Note: Comment the next line if you want to checkin your web deploy settings, 172 | # but database connection strings (with potential passwords) will be unencrypted 173 | *.pubxml 174 | *.publishproj 175 | 176 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 177 | # checkin your Azure Web App publish settings, but sensitive information contained 178 | # in these scripts will be unencrypted 179 | PublishScripts/ 180 | 181 | # NuGet Packages 182 | *.nupkg 183 | # The packages folder can be ignored because of Package Restore 184 | **/[Pp]ackages/* 185 | # except build/, which is used as an MSBuild target. 186 | !**/[Pp]ackages/build/ 187 | # Uncomment if necessary however generally it will be regenerated when needed 188 | #!**/[Pp]ackages/repositories.config 189 | # NuGet v3's project.json files produces more ignorable files 190 | *.nuget.props 191 | *.nuget.targets 192 | 193 | # Microsoft Azure Build Output 194 | csx/ 195 | *.build.csdef 196 | 197 | # Microsoft Azure Emulator 198 | ecf/ 199 | rcf/ 200 | 201 | # Windows Store app package directories and files 202 | AppPackages/ 203 | BundleArtifacts/ 204 | Package.StoreAssociation.xml 205 | _pkginfo.txt 206 | *.appx 207 | 208 | # Visual Studio cache files 209 | # files ending in .cache can be ignored 210 | *.[Cc]ache 211 | # but keep track of directories ending in .cache 212 | !*.[Cc]ache/ 213 | 214 | # Others 215 | ClientBin/ 216 | ~$* 217 | *~ 218 | *.dbmdl 219 | *.dbproj.schemaview 220 | *.jfm 221 | *.pfx 222 | *.publishsettings 223 | orleans.codegen.cs 224 | 225 | # Including strong name files can present a security risk 226 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 227 | #*.snk 228 | 229 | # Since there are multiple workflows, uncomment next line to ignore bower_components 230 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 231 | #bower_components/ 232 | 233 | # RIA/Silverlight projects 234 | Generated_Code/ 235 | 236 | # Backup & report files from converting an old project file 237 | # to a newer Visual Studio version. Backup files are not needed, 238 | # because we have git ;-) 239 | _UpgradeReport_Files/ 240 | Backup*/ 241 | UpgradeLog*.XML 242 | UpgradeLog*.htm 243 | ServiceFabricBackup/ 244 | *.rptproj.bak 245 | 246 | # SQL Server files 247 | *.mdf 248 | *.ldf 249 | *.ndf 250 | 251 | # Business Intelligence projects 252 | *.rdl.data 253 | *.bim.layout 254 | *.bim_*.settings 255 | *.rptproj.rsuser 256 | 257 | # Microsoft Fakes 258 | FakesAssemblies/ 259 | 260 | # GhostDoc plugin setting file 261 | *.GhostDoc.xml 262 | 263 | # Node.js Tools for Visual Studio 264 | .ntvs_analysis.dat 265 | node_modules/ 266 | 267 | # Visual Studio 6 build log 268 | *.plg 269 | 270 | # Visual Studio 6 workspace options file 271 | *.opt 272 | 273 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 274 | *.vbw 275 | 276 | # Visual Studio LightSwitch build output 277 | **/*.HTMLClient/GeneratedArtifacts 278 | **/*.DesktopClient/GeneratedArtifacts 279 | **/*.DesktopClient/ModelManifest.xml 280 | **/*.Server/GeneratedArtifacts 281 | **/*.Server/ModelManifest.xml 282 | _Pvt_Extensions 283 | 284 | # Paket dependency manager 285 | .paket/paket.exe 286 | paket-files/ 287 | 288 | # FAKE - F# Make 289 | .fake/ 290 | 291 | # JetBrains Rider 292 | .idea/ 293 | *.sln.iml 294 | 295 | # CodeRush 296 | .cr/ 297 | 298 | # Python Tools for Visual Studio (PTVS) 299 | __pycache__/ 300 | *.pyc 301 | 302 | # Cake - Uncomment if you are using it 303 | # tools/** 304 | # !tools/packages.config 305 | 306 | # Tabs Studio 307 | *.tss 308 | 309 | # Telerik's JustMock configuration file 310 | *.jmconfig 311 | 312 | # BizTalk build output 313 | *.btp.cs 314 | *.btm.cs 315 | *.odx.cs 316 | *.xsd.cs 317 | 318 | # OpenCover UI analysis results 319 | OpenCover/ 320 | 321 | # Azure Stream Analytics local run output 322 | ASALocalRun/ 323 | 324 | # MSBuild Binary and Structured Log 325 | *.binlog 326 | 327 | # NVidia Nsight GPU debugger configuration file 328 | *.nvuser 329 | 330 | # MFractors (Xamarin productivity tool) working folder 331 | .mfractor/ 332 | -------------------------------------------------------------------------------- /Asmodean/Asmodean.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 15.0 34 | {5D227B71-C303-400C-8E99-DF63C79E3613} 35 | Asmodean 36 | 10.0.16299.0 37 | asmodean 38 | 39 | 40 | 41 | DynamicLibrary 42 | true 43 | v141 44 | MultiByte 45 | 46 | 47 | DynamicLibrary 48 | false 49 | v141 50 | true 51 | MultiByte 52 | 53 | 54 | Application 55 | true 56 | v141 57 | MultiByte 58 | 59 | 60 | Application 61 | false 62 | v141 63 | true 64 | MultiByte 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | .dll 86 | $(ProjectDir)bin\$(Configuration)\ 87 | obj\$(Configuration)\ 88 | 89 | 90 | .dll 91 | $(ProjectDir)bin\$(Configuration)\ 92 | obj\$(Configuration)\ 93 | 94 | 95 | 96 | Level3 97 | MaxSpeed 98 | true 99 | true 100 | true 101 | true 102 | $(SolutionDir)zlib\include;%(AdditionalIncludeDirectories) 103 | 104 | 105 | true 106 | true 107 | $(SolutionDir)zlib\lib\zlib.lib;%(AdditionalDependencies) 108 | 109 | 110 | xcopy /y /d "$(SolutionDir)zlib\bin\zlib1.dll" "$(OutDir)" 111 | 112 | 113 | Copy zlib1.dll to the output folder 114 | 115 | 116 | 117 | 118 | Level3 119 | Disabled 120 | true 121 | true 122 | $(SolutionDir)zlib\include;%(AdditionalIncludeDirectories) 123 | ProgramDatabase 124 | 125 | 126 | $(SolutionDir)zlib\lib\zlib.lib;%(AdditionalDependencies) 127 | 128 | 129 | xcopy /y /d "$(SolutionDir)zlib\bin\zlib1.dll" "$(OutDir)" 130 | Copy zlib1.dll to the output folder 131 | 132 | 133 | 134 | 135 | Level3 136 | Disabled 137 | true 138 | true 139 | 140 | 141 | 142 | 143 | Level3 144 | MaxSpeed 145 | true 146 | true 147 | true 148 | true 149 | 150 | 151 | true 152 | true 153 | 154 | 155 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /Asmodean/Asmodean.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | 32 | 33 | Source Files 34 | 35 | 36 | Source Files 37 | 38 | 39 | Source Files 40 | 41 | 42 | -------------------------------------------------------------------------------- /Asmodean/asmodean.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef ASMODEAN_DLL_H 4 | #define ASMODEAN_DLL_H 5 | 6 | #define ASMODEAN_API extern "C" __declspec(dllexport) 7 | 8 | #endif /* ASMODEAN_DLL */ -------------------------------------------------------------------------------- /Asmodean/blowfish.cpp: -------------------------------------------------------------------------------- 1 | // blowfish.cpp C++ class implementation of the BLOWFISH encryption algorithm 2 | // _THE BLOWFISH ENCRYPTION ALGORITHM_ 3 | // by Bruce Schneier 4 | // Revised code--3/20/94 5 | // Converted to C++ class 5/96, Jim Conger 6 | 7 | #include "blowfish.h" 8 | 9 | #define S(x,i) (SBoxes[i][x.w.byte##i]) 10 | #define bf_F(x) (((S(x,0) + S(x,1)) ^ S(x,2)) + S(x,3)) 11 | #define ROUND(a,b,n) (a.dword ^= bf_F(b) ^ PArray[n]) 12 | 13 | 14 | Blowfish::Blowfish() { 15 | PArray = new DWORD[18]; 16 | SBoxes = new DWORD[4][256]; 17 | } 18 | 19 | Blowfish::~Blowfish() { 20 | delete PArray; 21 | delete[] SBoxes; 22 | } 23 | 24 | // the low level (private) encryption function 25 | void Blowfish::Blowfish_encipher(DWORD *xl, DWORD *xr) { 26 | union aword Xl, Xr; 27 | 28 | Xl.dword = *xl; 29 | Xr.dword = *xr; 30 | 31 | Xl.dword ^= PArray[0]; 32 | ROUND(Xr, Xl, 1); ROUND(Xl, Xr, 2); 33 | ROUND(Xr, Xl, 3); ROUND(Xl, Xr, 4); 34 | ROUND(Xr, Xl, 5); ROUND(Xl, Xr, 6); 35 | ROUND(Xr, Xl, 7); ROUND(Xl, Xr, 8); 36 | ROUND(Xr, Xl, 9); ROUND(Xl, Xr, 10); 37 | ROUND(Xr, Xl, 11); ROUND(Xl, Xr, 12); 38 | ROUND(Xr, Xl, 13); ROUND(Xl, Xr, 14); 39 | ROUND(Xr, Xl, 15); ROUND(Xl, Xr, 16); 40 | Xr.dword ^= PArray[17]; 41 | 42 | *xr = Xl.dword; 43 | *xl = Xr.dword; 44 | } 45 | 46 | // the low level (private) decryption function 47 | void Blowfish::Blowfish_decipher(DWORD *xl, DWORD *xr) { 48 | union aword Xl; 49 | union aword Xr; 50 | 51 | Xl.dword = *xl; 52 | Xr.dword = *xr; 53 | 54 | Xl.dword ^= PArray[17]; 55 | ROUND(Xr, Xl, 16); ROUND(Xl, Xr, 15); 56 | ROUND(Xr, Xl, 14); ROUND(Xl, Xr, 13); 57 | ROUND(Xr, Xl, 12); ROUND(Xl, Xr, 11); 58 | ROUND(Xr, Xl, 10); ROUND(Xl, Xr, 9); 59 | ROUND(Xr, Xl, 8); ROUND(Xl, Xr, 7); 60 | ROUND(Xr, Xl, 6); ROUND(Xl, Xr, 5); 61 | ROUND(Xr, Xl, 4); ROUND(Xl, Xr, 3); 62 | ROUND(Xr, Xl, 2); ROUND(Xl, Xr, 1); 63 | Xr.dword ^= PArray[0]; 64 | 65 | *xl = Xr.dword; 66 | *xr = Xl.dword; 67 | } 68 | 69 | 70 | // constructs the enctryption sieve 71 | void Blowfish::Initialize(BYTE key[], int keybytes) { 72 | int i, j; 73 | DWORD data, datal, datar; 74 | union aword temp; 75 | 76 | // first fill arrays from data tables 77 | for (i = 0; i < 18; i++) 78 | PArray[i] = bf_P[i]; 79 | 80 | for (i = 0; i < 4; i++) { 81 | for (j = 0; j < 256; j++) 82 | SBoxes[i][j] = bf_S[i][j]; 83 | } 84 | 85 | 86 | j = 0; 87 | for (i = 0; i < NPASS + 2; ++i) { 88 | temp.dword = 0; 89 | temp.w.byte0 = key[j]; 90 | temp.w.byte1 = key[(j + 1) % keybytes]; 91 | temp.w.byte2 = key[(j + 2) % keybytes]; 92 | temp.w.byte3 = key[(j + 3) % keybytes]; 93 | data = temp.dword; 94 | PArray[i] ^= data; 95 | j = (j + 4) % keybytes; 96 | } 97 | 98 | datal = 0; 99 | datar = 0; 100 | 101 | for (i = 0; i < NPASS + 2; i += 2) { 102 | Blowfish_encipher(&datal, &datar); 103 | PArray[i] = datal; 104 | PArray[i + 1] = datar; 105 | } 106 | 107 | for (i = 0; i < 4; ++i) { 108 | for (j = 0; j < 256; j += 2) { 109 | Blowfish_encipher(&datal, &datar); 110 | SBoxes[i][j] = datal; 111 | SBoxes[i][j + 1] = datar; 112 | } 113 | } 114 | } 115 | 116 | // get output length, which must be even MOD 8 117 | DWORD Blowfish::GetOutputLength(DWORD lInputLong) { 118 | DWORD lVal; 119 | 120 | lVal = lInputLong % 8; // find out if uneven number of bytes atthe end 121 | if (lVal != 0) 122 | return lInputLong + 8 - lVal; 123 | else 124 | return lInputLong; 125 | } 126 | 127 | // Encode pIntput into pOutput. Input length in lSize. Returned value 128 | // is length of output which will be even MOD 8 bytes. Inputbuffer and 129 | // output buffer can be the same, but be sure buffer length is even MOD8. 130 | DWORD Blowfish::Encode(BYTE * pInput, BYTE * pOutput, DWORD lSize) { 131 | DWORD lCount, lOutSize, lGoodBytes; 132 | BYTE *pi, *po; 133 | int i, j; 134 | int SameDest = (pInput == pOutput ? 1 : 0); 135 | 136 | lOutSize = GetOutputLength(lSize); 137 | for (lCount = 0; lCount < lOutSize; lCount += 8) { 138 | if (SameDest) // if encoded data is being written into inputbuffer 139 | { 140 | if (lCount < lSize - 7) // if not dealing with unevenbytes at end 141 | { 142 | Blowfish_encipher((DWORD *)pInput, 143 | (DWORD *)(pInput + 4)); 144 | } 145 | else // pad end of data with null bytes tocomplete encryption 146 | { 147 | po = pInput + lSize; // point at bytepast theend of actual data 148 | j = (int)(lOutSize - lSize); // number ofbytes to set to null 149 | for (i = 0; i < j; i++) 150 | *po++ = 0; 151 | Blowfish_encipher((DWORD *)pInput, 152 | (DWORD *)(pInput + 4)); 153 | } 154 | pInput += 8; 155 | } 156 | else // output buffer not equal to inputbuffer, so must copy 157 | { // input to output buffer prior to encrypting 158 | if (lCount < lSize - 7) // if not dealing with unevenbytes at end 159 | { 160 | pi = pInput; 161 | po = pOutput; 162 | for (i = 0; i < 8; i++) 163 | // copy bytes to output 164 | *po++ = *pi++; 165 | Blowfish_encipher((DWORD *)pOutput, // nowencrypt them 166 | (DWORD *)(pOutput + 4)); 167 | } 168 | else // pad end of data with null bytes tocomplete encryption 169 | { 170 | lGoodBytes = lSize - lCount; // number ofremaining data bytes 171 | po = pOutput; 172 | for (i = 0; i < (int)lGoodBytes; i++) 173 | *po++ = *pInput++; 174 | for (j = i; j < 8; j++) 175 | *po++ = 0; 176 | Blowfish_encipher((DWORD *)pOutput, 177 | (DWORD *)(pOutput + 4)); 178 | } 179 | pInput += 8; 180 | pOutput += 8; 181 | } 182 | } 183 | return lOutSize; 184 | } 185 | 186 | // Decode pIntput into pOutput. Input length in lSize. Inputbuffer and 187 | // output buffer can be the same, but be sure buffer length is even MOD8. 188 | void Blowfish::Decode(BYTE * pInput, BYTE * pOutput, DWORD lSize) { 189 | DWORD lCount; 190 | BYTE *pi, *po; 191 | int i; 192 | int SameDest = (pInput == pOutput ? 1 : 0); 193 | 194 | for (lCount = 0; lCount < lSize; lCount += 8) { 195 | if (SameDest) // if encoded data is being written into inputbuffer 196 | { 197 | Blowfish_decipher((DWORD *)pInput, 198 | (DWORD *)(pInput + 4)); 199 | pInput += 8; 200 | } 201 | else // output buffer not equal to inputbuffer 202 | { // so copy input to output before decoding 203 | pi = pInput; 204 | po = pOutput; 205 | for (i = 0; i < 8; i++) 206 | *po++ = *pi++; 207 | Blowfish_decipher((DWORD *)pOutput, 208 | (DWORD *)(pOutput + 4)); 209 | pInput += 8; 210 | pOutput += 8; 211 | } 212 | } 213 | } 214 | 215 | 216 | void Blowfish::Set_Key(BYTE key[], int keybytes) { 217 | Initialize(key, keybytes); 218 | } 219 | 220 | DWORD Blowfish::Encrypt(BYTE * pInput, DWORD lSize) { 221 | if (lSize != GetOutputLength(lSize)) 222 | printf("%s", "Input len != Output len"); 223 | 224 | BYTE *pOutput = new BYTE[lSize]; 225 | DWORD ret = Encode(pInput, pOutput, lSize); 226 | 227 | memcpy(pInput, pOutput, lSize); 228 | delete[] pOutput; 229 | 230 | return ret; 231 | } 232 | 233 | void Blowfish::Decrypt(BYTE * pInput, DWORD lSize) { 234 | if (lSize != GetOutputLength(lSize)) 235 | printf("%s", "Input len != Output len"); 236 | 237 | BYTE *pOutput = new BYTE[lSize]; 238 | Decode(pInput, pOutput, lSize); 239 | 240 | memcpy(pInput, pOutput, lSize); 241 | delete[] pOutput; 242 | } 243 | 244 | 245 |  -------------------------------------------------------------------------------- /Asmodean/exkifint.cpp: -------------------------------------------------------------------------------- 1 | // exkifint.cpp (for P/Invoke), 2018/6/5 2 | // originally code by asmodean 3 | 4 | // contact: 5 | // web: http://asmodean.reverse.net 6 | // email: asmodean [at] hush.com 7 | // irc: asmodean on efnet (irc.efnet.net) 8 | 9 | // This code helps extracts data from Windmill's encrypted KIF (*.int) archives. 10 | #include "exkifint.h" 11 | #include "blowfish.h" 12 | 13 | void DecryptVCode2( 14 | unsigned char* keyBuffer, 15 | unsigned long keyLength, 16 | unsigned char* vcode2Buffer, 17 | unsigned long vcode2Length) 18 | { 19 | Blowfish bf; 20 | bf.Set_Key(keyBuffer, keyLength); 21 | bf.Decrypt(vcode2Buffer, (vcode2Length + 7) & ~7); 22 | } 23 | 24 | void DecryptEntry( 25 | KIFENTRYINFO& entry, 26 | unsigned long fileKey) 27 | { 28 | Blowfish bf; 29 | bf.Set_Key((unsigned char*)&fileKey, 4); 30 | bf.Decrypt((unsigned char*)&entry.offset, 8); 31 | } 32 | 33 | void DecryptData( 34 | unsigned char* buffer, 35 | unsigned long length, 36 | unsigned long fileKey) 37 | { 38 | Blowfish bf; 39 | bf.Set_Key((unsigned char*)&fileKey, 4); 40 | bf.Decrypt(buffer, (length / 8) * 8); 41 | } 42 | -------------------------------------------------------------------------------- /Asmodean/exkifint.h: -------------------------------------------------------------------------------- 1 | // exkifint.h (for P/Invoke), 2018/6/5 2 | // originally code by asmodean 3 | 4 | // contact: 5 | // web: http://asmodean.reverse.net 6 | // email: asmodean [at] hush.com 7 | // irc: asmodean on efnet (irc.efnet.net) 8 | 9 | // This code helps extracts data from Windmill's encrypted KIF (*.int) archives. 10 | #pragma once 11 | 12 | #ifndef EXKIFINT_H 13 | #define EXKIFINT_H 14 | 15 | #include "asmodean.h" 16 | 17 | struct KIFENTRYINFO { 18 | unsigned long offset; 19 | unsigned long length; 20 | }; 21 | 22 | ASMODEAN_API void DecryptVCode2( 23 | unsigned char* keyBuffer, 24 | unsigned long keyLength, 25 | unsigned char* vcode2Buffer, 26 | unsigned long vcode2Length); 27 | 28 | ASMODEAN_API void DecryptEntry( 29 | KIFENTRYINFO& entry, 30 | unsigned long fileKey); 31 | 32 | ASMODEAN_API void DecryptData( 33 | unsigned char* buffer, 34 | unsigned long length, 35 | unsigned long fileKey); 36 | 37 | #endif /* EXKIFINT_H */ -------------------------------------------------------------------------------- /Asmodean/hgx2bmp.cpp: -------------------------------------------------------------------------------- 1 | // hgx2bmp.cpp, (for P/Invoke), 2018/6/5 2 | // originally code by asmodean 3 | 4 | // contact: 5 | // web: http://asmodean.reverse.net 6 | // email: asmodean [at] hush.com 7 | // irc: asmodean on efnet (irc.efnet.net) 8 | 9 | // This code helps decompress Windmill's HG-3 (*.hg3) and HG-2 (*.hg2) images. 10 | #include "hgx2bmp.h" 11 | #include 12 | #include 13 | #include 14 | #include "zlib.h" 15 | 16 | class bitbuff_t { 17 | public: 18 | bitbuff_t(unsigned char* buff, unsigned long len) 19 | : buff(buff), 20 | len(len), 21 | index(0) { 22 | } 23 | 24 | bool get_bit(void) { 25 | if (index > 7) { 26 | buff++; 27 | len--; 28 | index = 0; 29 | } 30 | 31 | return (*buff >> index++) & 1; 32 | } 33 | 34 | // Didn't expect to see this in the wild... 35 | unsigned long get_elias_gamma_value(void) { 36 | unsigned long value = 0; 37 | unsigned long digits = 0; 38 | 39 | while (!get_bit()) digits++; 40 | 41 | value = 1 << digits; 42 | 43 | while (digits--) { 44 | if (get_bit()) { 45 | value |= 1 << digits; 46 | } 47 | } 48 | 49 | return value; 50 | } 51 | 52 | private: 53 | unsigned long index; 54 | unsigned char* buff; 55 | unsigned long len; 56 | }; 57 | 58 | // This encoding tries to optimize for lots of zeros. I think. :) 59 | unsigned char unpack_val(unsigned char c) { 60 | unsigned char z = c & 1 ? 0xFF : 0; 61 | return (c >> 1) ^ z; 62 | } 63 | 64 | void unrle( 65 | unsigned char* buffer, 66 | unsigned long length, 67 | unsigned char* cmdBuffer, 68 | unsigned long cmdLength, 69 | unsigned char*& outBuffer, 70 | unsigned long& outLength) 71 | { 72 | bitbuff_t cmdBits(cmdBuffer, cmdLength); 73 | 74 | bool copyFlag = cmdBits.get_bit(); 75 | 76 | outLength = cmdBits.get_elias_gamma_value(); 77 | outBuffer = new unsigned char[outLength]; 78 | 79 | unsigned long n = 0; 80 | for (unsigned long i = 0; i < outLength; i += n) { 81 | n = cmdBits.get_elias_gamma_value(); 82 | 83 | if (copyFlag) { 84 | memcpy(outBuffer + i, buffer, n); 85 | buffer += n; 86 | } 87 | else { 88 | memset(outBuffer + i, 0, n); 89 | } 90 | 91 | copyFlag = !copyFlag; 92 | } 93 | } 94 | 95 | void undeltafilter( 96 | unsigned char* buffer, 97 | unsigned long length, 98 | unsigned char* outBuffer, 99 | unsigned long width, 100 | unsigned long height, 101 | unsigned long depthBytes) 102 | { 103 | unsigned long table1[256] = { 0 }; 104 | unsigned long table2[256] = { 0 }; 105 | unsigned long table3[256] = { 0 }; 106 | unsigned long table4[256] = { 0 }; 107 | 108 | for (unsigned long i = 0; i < 256; i++) { 109 | unsigned long val = i & 0xC0; 110 | 111 | val <<= 6; 112 | val |= i & 0x30; 113 | 114 | val <<= 6; 115 | val |= i & 0x0C; 116 | 117 | val <<= 6; 118 | val |= i & 0x03; 119 | 120 | table4[i] = val; 121 | table3[i] = val << 2; 122 | table2[i] = val << 4; 123 | table1[i] = val << 6; 124 | } 125 | 126 | unsigned long sect_len = length / 4; 127 | unsigned char* sect1 = buffer; 128 | unsigned char* sect2 = sect1 + sect_len; 129 | unsigned char* sect3 = sect2 + sect_len; 130 | unsigned char* sect4 = sect3 + sect_len; 131 | 132 | unsigned char* outP = outBuffer; 133 | unsigned char* outEnd = outBuffer + length; 134 | 135 | while (outP < outEnd) { 136 | unsigned long val = table1[*sect1++] | table2[*sect2++] | table3[*sect3++] | table4[*sect4++]; 137 | 138 | *outP++ = unpack_val((unsigned char)(val >> 0)); 139 | *outP++ = unpack_val((unsigned char)(val >> 8)); 140 | *outP++ = unpack_val((unsigned char)(val >> 16)); 141 | *outP++ = unpack_val((unsigned char)(val >> 24)); 142 | } 143 | 144 | unsigned long stride = width * depthBytes; 145 | 146 | for (unsigned long x = depthBytes; x < stride; x++) { 147 | outBuffer[x] += outBuffer[x - depthBytes]; 148 | } 149 | 150 | for (unsigned long y = 1; y < height; y++) { 151 | unsigned char* line = outBuffer + y * stride; 152 | unsigned char* prev = outBuffer + (y - 1) * stride; 153 | 154 | for (unsigned long x = 0; x < stride; x++) { 155 | line[x] += prev[x]; 156 | } 157 | } 158 | } 159 | 160 | void ProcessImage( 161 | unsigned char* bufferTmp, 162 | unsigned long length, 163 | unsigned long origLength, 164 | unsigned char* cmdBufferTmp, 165 | unsigned long cmdLength, 166 | unsigned long origCmdLength, 167 | unsigned char*& rgbaBuffer, 168 | unsigned long& rgbaLength, 169 | unsigned long width, 170 | unsigned long height, 171 | unsigned long depthBytes) 172 | { 173 | unsigned char* buffer = new unsigned char[origLength]; 174 | uncompress(buffer, &origLength, bufferTmp, length); 175 | 176 | unsigned char* cmdBuffer = new unsigned char[origCmdLength]; 177 | uncompress(cmdBuffer, &origCmdLength, cmdBufferTmp, cmdLength); 178 | 179 | unsigned long outLength = 0; 180 | unsigned char* outBuffer = nullptr; 181 | unrle(buffer, origLength, cmdBuffer, origCmdLength, outBuffer, outLength); 182 | 183 | rgbaLength = outLength; 184 | rgbaBuffer = (unsigned char*)GlobalAlloc(GMEM_FIXED, rgbaLength); 185 | //rgbaBuffer = new unsigned char[rgbaLength]; 186 | /*if (outLength == width * height * 4) { 187 | undeltafilter(outBuffer, outLength, rgbaBuffer, width, height, depthBytes); 188 | //printf("\n%i ", (outLength - width * height * 4)); 189 | //Beep(500, 2000); 190 | }*/ 191 | undeltafilter(outBuffer, outLength, rgbaBuffer, width, height, depthBytes); 192 | 193 | delete[] outBuffer; 194 | delete[] cmdBuffer; 195 | delete[] buffer; 196 | } 197 | -------------------------------------------------------------------------------- /Asmodean/hgx2bmp.h: -------------------------------------------------------------------------------- 1 | // hgx2bmp.h, (for P/Invoke), 2018/6/5 2 | // originally code by asmodean 3 | 4 | // contact: 5 | // web: http://asmodean.reverse.net 6 | // email: asmodean [at] hush.com 7 | // irc: asmodean on efnet (irc.efnet.net) 8 | 9 | // This code helps decompress Windmill's HG-3 (*.hg3) and HG-2 (*.hg2) images. 10 | #pragma once 11 | 12 | #ifndef HGX2BMP_H 13 | #define HGX2BMP_H 14 | 15 | #include "asmodean.h" 16 | 17 | /* Make sure to free returned rgbaBuffer! */ 18 | ASMODEAN_API void ProcessImage( 19 | unsigned char* bufferTmp, 20 | unsigned long length, 21 | unsigned long origLength, 22 | unsigned char* cmdBufferTmp, 23 | unsigned long cmdLength, 24 | unsigned long origCmdLength, 25 | unsigned char*& rgbaBuffer, 26 | unsigned long& rgbaLength, 27 | unsigned long width, 28 | unsigned long height, 29 | unsigned long depthBytes); 30 | 31 | #endif /* HGX2BMP_H */ -------------------------------------------------------------------------------- /GrisaiaExtractor.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27130.2027 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GrisaiaExtractor", "GrisaiaExtractor\GrisaiaExtractor.csproj", "{B9E8EA56-874B-4CEB-A703-DCA3A307A4D3}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GrisaiaExtractorConsole", "GrisaiaExtractorConsole\GrisaiaExtractorConsole.csproj", "{1B2D824A-DD0D-4019-B234-54E5543B7A42}" 9 | EndProject 10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "asmodean", "Asmodean\Asmodean.vcxproj", "{5D227B71-C303-400C-8E99-DF63C79E3613}" 11 | EndProject 12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Native", "Native", "{D2B3D9D8-003A-4BC4-B53F-D942F09ED122}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Debug|x64 = Debug|x64 18 | Debug|x86 = Debug|x86 19 | Release|Any CPU = Release|Any CPU 20 | Release|x64 = Release|x64 21 | Release|x86 = Release|x86 22 | EndGlobalSection 23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 24 | {B9E8EA56-874B-4CEB-A703-DCA3A307A4D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {B9E8EA56-874B-4CEB-A703-DCA3A307A4D3}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {B9E8EA56-874B-4CEB-A703-DCA3A307A4D3}.Debug|x64.ActiveCfg = Debug|Any CPU 27 | {B9E8EA56-874B-4CEB-A703-DCA3A307A4D3}.Debug|x64.Build.0 = Debug|Any CPU 28 | {B9E8EA56-874B-4CEB-A703-DCA3A307A4D3}.Debug|x86.ActiveCfg = Debug|Any CPU 29 | {B9E8EA56-874B-4CEB-A703-DCA3A307A4D3}.Debug|x86.Build.0 = Debug|Any CPU 30 | {B9E8EA56-874B-4CEB-A703-DCA3A307A4D3}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {B9E8EA56-874B-4CEB-A703-DCA3A307A4D3}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {B9E8EA56-874B-4CEB-A703-DCA3A307A4D3}.Release|x64.ActiveCfg = Release|Any CPU 33 | {B9E8EA56-874B-4CEB-A703-DCA3A307A4D3}.Release|x64.Build.0 = Release|Any CPU 34 | {B9E8EA56-874B-4CEB-A703-DCA3A307A4D3}.Release|x86.ActiveCfg = Release|Any CPU 35 | {B9E8EA56-874B-4CEB-A703-DCA3A307A4D3}.Release|x86.Build.0 = Release|Any CPU 36 | {1B2D824A-DD0D-4019-B234-54E5543B7A42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {1B2D824A-DD0D-4019-B234-54E5543B7A42}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {1B2D824A-DD0D-4019-B234-54E5543B7A42}.Debug|x64.ActiveCfg = Debug|Any CPU 39 | {1B2D824A-DD0D-4019-B234-54E5543B7A42}.Debug|x64.Build.0 = Debug|Any CPU 40 | {1B2D824A-DD0D-4019-B234-54E5543B7A42}.Debug|x86.ActiveCfg = Debug|Any CPU 41 | {1B2D824A-DD0D-4019-B234-54E5543B7A42}.Debug|x86.Build.0 = Debug|Any CPU 42 | {1B2D824A-DD0D-4019-B234-54E5543B7A42}.Release|Any CPU.ActiveCfg = Release|Any CPU 43 | {1B2D824A-DD0D-4019-B234-54E5543B7A42}.Release|Any CPU.Build.0 = Release|Any CPU 44 | {1B2D824A-DD0D-4019-B234-54E5543B7A42}.Release|x64.ActiveCfg = Release|Any CPU 45 | {1B2D824A-DD0D-4019-B234-54E5543B7A42}.Release|x64.Build.0 = Release|Any CPU 46 | {1B2D824A-DD0D-4019-B234-54E5543B7A42}.Release|x86.ActiveCfg = Release|Any CPU 47 | {1B2D824A-DD0D-4019-B234-54E5543B7A42}.Release|x86.Build.0 = Release|Any CPU 48 | {5D227B71-C303-400C-8E99-DF63C79E3613}.Debug|Any CPU.ActiveCfg = Release|Win32 49 | {5D227B71-C303-400C-8E99-DF63C79E3613}.Debug|Any CPU.Build.0 = Release|Win32 50 | {5D227B71-C303-400C-8E99-DF63C79E3613}.Debug|x64.ActiveCfg = Debug|x64 51 | {5D227B71-C303-400C-8E99-DF63C79E3613}.Debug|x64.Build.0 = Debug|x64 52 | {5D227B71-C303-400C-8E99-DF63C79E3613}.Debug|x86.ActiveCfg = Debug|Win32 53 | {5D227B71-C303-400C-8E99-DF63C79E3613}.Debug|x86.Build.0 = Debug|Win32 54 | {5D227B71-C303-400C-8E99-DF63C79E3613}.Release|Any CPU.ActiveCfg = Release|Win32 55 | {5D227B71-C303-400C-8E99-DF63C79E3613}.Release|Any CPU.Build.0 = Release|Win32 56 | {5D227B71-C303-400C-8E99-DF63C79E3613}.Release|x64.ActiveCfg = Release|x64 57 | {5D227B71-C303-400C-8E99-DF63C79E3613}.Release|x64.Build.0 = Release|x64 58 | {5D227B71-C303-400C-8E99-DF63C79E3613}.Release|x86.ActiveCfg = Release|Win32 59 | {5D227B71-C303-400C-8E99-DF63C79E3613}.Release|x86.Build.0 = Release|Win32 60 | EndGlobalSection 61 | GlobalSection(SolutionProperties) = preSolution 62 | HideSolutionNode = FALSE 63 | EndGlobalSection 64 | GlobalSection(NestedProjects) = preSolution 65 | {5D227B71-C303-400C-8E99-DF63C79E3613} = {D2B3D9D8-003A-4BC4-B53F-D942F09ED122} 66 | EndGlobalSection 67 | GlobalSection(ExtensibilityGlobals) = postSolution 68 | SolutionGuid = {C48F6F6E-84B6-4BF8-AE32-6ECAD7113C0C} 69 | EndGlobalSection 70 | EndGlobal 71 | -------------------------------------------------------------------------------- /GrisaiaExtractor/AnimationHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Text.RegularExpressions; 7 | using System.Threading.Tasks; 8 | 9 | namespace GrisaiaExtractor { 10 | /// A static class for help with animation file names. 11 | public static class AnimationHelper { 12 | 13 | /// Matches an animation and its indexes. 14 | public static Regex AnimationRegex = new Regex(@"^(?'name'.*)(?:\+(?'indexA'\d\d\d)\+(?'indexB'\d\d\d))$"); 15 | 16 | /// Gets the filename without extension or animation postfix. 17 | public static string GetBaseFileName(string path) { 18 | return GetBaseFileName(path, out _, out _); 19 | } 20 | 21 | /// Gets the filename without extension or animation postfix. 22 | public static string GetBaseFileName(string path, out bool isAnimation) { 23 | string baseName = GetBaseFileName(path, out int indexA, out int indexB); 24 | isAnimation = indexA != -1 || indexB != -1; 25 | return baseName; 26 | } 27 | 28 | /// Returns true if the file has an animation postfix. 29 | public static bool IsAnimation(string path) { 30 | return AnimationRegex.IsMatch(Path.GetFileNameWithoutExtension(path)); 31 | } 32 | 33 | /// Returns true if the file has an animation postfix and outputs the indexes. 34 | public static bool IsAnimation(string path, out int indexA, out int indexB) { 35 | string fileNameNoExt = Path.GetFileNameWithoutExtension(path); 36 | Match match = AnimationRegex.Match(fileNameNoExt); 37 | if (match.Success) { 38 | indexA = int.Parse(match.Groups["indexA"].Value); 39 | indexB = int.Parse(match.Groups["indexB"].Value); 40 | return true; 41 | } 42 | indexA = indexB = -1; 43 | return false; 44 | } 45 | 46 | /// Gets the filename without extension or animation postfix. 47 | /// Outputs the animation indexes if they exist, otherwise, -1. 48 | public static string GetBaseFileName(string path, out int indexA, out int indexB) { 49 | string fileNameNoExt = Path.GetFileNameWithoutExtension(path); 50 | Match match = AnimationRegex.Match(fileNameNoExt); 51 | if (match.Success) { 52 | indexA = int.Parse(match.Groups["indexA"].Value); 53 | indexB = int.Parse(match.Groups["indexB"].Value); 54 | return match.Groups["name"].Value; 55 | } 56 | indexA = indexB = -1; 57 | return fileNameNoExt; 58 | } 59 | 60 | /// Gets all filenames associated with this file. 61 | public static string[] GetFileNames(string path, string ext = null) { 62 | List files = new List(); 63 | string dir = Path.GetDirectoryName(path); 64 | string name = GetBaseFileName(path); 65 | if (ext == null) 66 | ext = Path.GetExtension(path); 67 | 68 | // Add the base file if one exists 69 | string file = Path.Combine(dir, name + ext); 70 | if (File.Exists(file)) 71 | files.Add(file); 72 | 73 | // Look for files that end with +###+### 74 | // These are mostly used with animations 75 | // Check both +000+000 and +001+000 as first possible name 76 | for (int j = 0; ; j++) { 77 | file = GetFileNameQuick(dir, name, j, 0, ext); 78 | if (!File.Exists(file)) { 79 | if (j == 0) 80 | continue; 81 | else 82 | break; 83 | } 84 | 85 | files.Add(file); 86 | 87 | for (int k = 1; ; k++) { 88 | file = GetFileNameQuick(dir, name, j, k, ext); 89 | if (!File.Exists(file)) 90 | break; 91 | files.Add(file); 92 | } 93 | } 94 | return files.ToArray(); 95 | } 96 | 97 | /// Gets the filepath with the animation postfix and extension. 98 | /// Assumes the filename is just a name with no extension 99 | public static string GetFileNameQuick(string dir, string name, int indexA, int indexB, string ext = "") { 100 | return Path.Combine(dir, 101 | $"{name}" + 102 | $"+{indexA.ToString("000")}" + 103 | $"+{indexB.ToString("000")}" + 104 | $"{ext}"); 105 | } 106 | 107 | /// Gets the filepath with the animation postfix and extension. 108 | public static string GetFileName(string dir, string file, int indexA, int indexB, string ext = "") { 109 | return Path.Combine(dir, 110 | $"{Path.GetFileNameWithoutExtension(file)}" + 111 | $"+{indexA.ToString("000")}" + 112 | $"+{indexB.ToString("000")}" + 113 | $"{ext}"); 114 | } 115 | 116 | /// Gets the filepath with the animation postfix. 117 | public static string GetFileName(string filePath, int indexA, int indexB, string ext = "") { 118 | return 119 | $"{Path.ChangeExtension(filePath, null)}" + 120 | $"+{indexA.ToString("000")}" + 121 | $"+{indexB.ToString("000")}" + 122 | $"{ext}"; 123 | } 124 | 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /GrisaiaExtractor/Asmodean/Exkifint.MersenneTwister.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Runtime.CompilerServices; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace GrisaiaExtractor.Asmodean { 9 | public static partial class Exkifint { 10 | private class MersenneTwister { 11 | #region Constants 12 | 13 | private const int N = 624; 14 | private const int M = 397; 15 | private const uint MATRIX_A = 0x9908b0df; 16 | private const uint UPPER_MASK = 0x80000000; 17 | private const uint LOWER_MASK = 0x7fffffff; 18 | 19 | private const uint TEMPERING_MASK_B = 0x9d2c5680; 20 | private const uint TEMPERING_MASK_C = 0xefc60000; 21 | 22 | #endregion 23 | 24 | #region Fields 25 | 26 | private uint dummy = 0; 27 | private uint mti = N + 1; 28 | private readonly uint[] mt = new uint[N]; 29 | 30 | #endregion 31 | 32 | #region Constructors 33 | 34 | public MersenneTwister() { } 35 | public MersenneTwister(int seed) { 36 | Seed(seed); 37 | } 38 | public MersenneTwister(uint seed) { 39 | Seed(seed); 40 | } 41 | 42 | #endregion 43 | 44 | #region Seed 45 | 46 | public void Seed(int seed) => Seed(unchecked((uint) seed)); 47 | public void Seed(uint seed) { 48 | for (int i = 0; i < N; i++) { 49 | mt[i] = seed & 0xffff0000; 50 | seed = 69069 * seed + 1; 51 | mt[i] |= (seed & 0xffff0000) >> 16; 52 | seed = 69069 * seed + 1; 53 | } 54 | mti = N; 55 | dummy = mti; 56 | } 57 | 58 | #endregion 59 | 60 | #region GenRand 61 | 62 | public uint GenRand() { 63 | uint y; 64 | uint[] mag01 = { 0x0, MATRIX_A }; 65 | /* mag01[x] = x * MATRIX_A for x=0,1 */ 66 | 67 | mti = dummy; 68 | 69 | if (mti >= N) { /* generate N words at one time */ 70 | int kk; 71 | 72 | if (mti == N + 1) /* if sgenrand() has not been called, */ 73 | Seed(4357); /* a default initial seed is used */ 74 | 75 | for (kk = 0; kk < N - M; kk++) { 76 | y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK); 77 | mt[kk] = mt[kk + M] ^ (y >> 1) ^ mag01[y & 0x1]; 78 | } 79 | for (; kk < N - 1; kk++) { 80 | y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK); 81 | mt[kk] = mt[kk + (M - N)] ^ (y >> 1) ^ mag01[y & 0x1]; 82 | } 83 | y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK); 84 | mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ mag01[y & 0x1]; 85 | 86 | mti = 0; 87 | } 88 | 89 | y = mt[mti++]; 90 | y ^= TEMPERING_SHIFT_U(y); 91 | y ^= TEMPERING_SHIFT_S(y) & TEMPERING_MASK_B; 92 | y ^= TEMPERING_SHIFT_T(y) & TEMPERING_MASK_C; 93 | y ^= TEMPERING_SHIFT_L(y); 94 | dummy = mti; 95 | 96 | return y; 97 | } 98 | 99 | #endregion 100 | 101 | #region Static GenRand 102 | 103 | public static uint GenRand(int seed) { 104 | return new MersenneTwister(seed).GenRand(); 105 | } 106 | public static uint GenRand(uint seed) { 107 | return new MersenneTwister(seed).GenRand(); 108 | } 109 | 110 | #endregion 111 | 112 | #region Tempering Shift 113 | 114 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 115 | private static uint TEMPERING_SHIFT_U(uint y) => y >> 11; 116 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 117 | private static uint TEMPERING_SHIFT_S(uint y) => y << 7; 118 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 119 | private static uint TEMPERING_SHIFT_T(uint y) => y << 15; 120 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 121 | private static uint TEMPERING_SHIFT_L(uint y) => y >> 18; 122 | 123 | #endregion 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /GrisaiaExtractor/Asmodean/Exkifint.PInvoke.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Runtime.InteropServices; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace GrisaiaExtractor.Asmodean { 9 | public static partial class Exkifint { 10 | 11 | private const uint LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020; 12 | 13 | [DllImport("kernel32.dll")] 14 | private extern static IntPtr LoadLibraryEx(string lpLibFileName, IntPtr hFile, uint dwFlags); 15 | 16 | [DllImport("kernel32.dll")] 17 | [return: MarshalAs(UnmanagedType.I1)] 18 | private extern static bool FreeLibrary(IntPtr hLibModule); 19 | 20 | [DllImport("kernel32.dll")] 21 | private extern static IntPtr FindResource(IntPtr hModule, string lpName, string lpType); 22 | 23 | [DllImport("kernel32.dll", SetLastError = true)] 24 | private extern static IntPtr LoadResource(IntPtr hModule, IntPtr hResInfo); 25 | 26 | [DllImport("kernel32.dll", SetLastError = true)] 27 | private extern static uint SizeofResource(IntPtr hModule, IntPtr hResInfo); 28 | 29 | [DllImport("kernel32.dll")] 30 | private extern static IntPtr LockResource(IntPtr hGlobal); 31 | 32 | 33 | [DllImport("asmodean.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] 34 | [return: MarshalAs(UnmanagedType.LPStr)] 35 | private extern static void DecryptVCode2( 36 | byte[] keyBuffer, 37 | int keyLength, 38 | byte[] vcode2Buffer, 39 | int vcode2Length); 40 | 41 | [DllImport("asmodean.dll", CallingConvention = CallingConvention.Cdecl)] 42 | private extern static void DecryptEntry( 43 | ref KIFENTRYINFO entry, 44 | uint fileKey); 45 | 46 | [DllImport("asmodean.dll", CallingConvention = CallingConvention.Cdecl)] 47 | private extern static void DecryptData( 48 | byte[] buffer, 49 | int length, 50 | uint fileKey); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /GrisaiaExtractor/Asmodean/Exkifint.Structs.cs: -------------------------------------------------------------------------------- 1 | using GrisaiaExtractor.Extensions; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Runtime.InteropServices; 6 | using System.Runtime.Serialization.Formatters.Binary; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace GrisaiaExtractor.Asmodean { 11 | public static partial class Exkifint { 12 | [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 8, CharSet = CharSet.Ansi)] 13 | private struct KIFHDR { 14 | /// 15 | /// The raw character array signature of the file. 16 | /// 17 | [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 4)] 18 | public char[] SignatureRaw; 19 | /// 20 | /// The number of s in the KIFINT archive. 21 | /// 22 | public int EntryCount; 23 | 24 | /// 25 | /// Gets the signature of the file. 26 | /// 27 | public string Signature => SignatureRaw.ToNullTerminatedString(); 28 | } 29 | 30 | [StructLayout(LayoutKind.Explicit, Pack = 1, Size = 72, CharSet = CharSet.Ansi)] 31 | private struct KIFENTRY { 32 | /// 33 | /// We use this to preserve the developer naming fuckups such as the full-width 'g' in 34 | /// Meikyuu's "bg62t.hg3". 35 | /// 36 | private static readonly Encoding JapaneseEncoding = Encoding.GetEncoding(932); 37 | 38 | /// 39 | /// The raw character array filename of the entry. 40 | /// 41 | [FieldOffset(0)] 42 | [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 64)] 43 | public byte[] FileNameRaw; 44 | /// 45 | /// We don't need to pass the during P/Invoke, so we have this info 46 | /// structure. 47 | /// 48 | [FieldOffset(64)] 49 | public KIFENTRYINFO Info; 50 | /// 51 | /// The file offset to the entry's data. 52 | /// 53 | [FieldOffset(64)] 54 | public uint Offset; 55 | /// 56 | /// The file length to the entry's data. 57 | /// 58 | [FieldOffset(68)] 59 | public int Length; 60 | 61 | /// 62 | /// Gets the filename of the entry. 63 | /// 64 | public string FileName => FileNameRaw.ToNullTerminatedString(JapaneseEncoding); 65 | } 66 | /// 67 | /// We don't need to pass the during P/Invoke, so we have this 68 | /// info structure. 69 | /// 70 | [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 8)] 71 | private struct KIFENTRYINFO { 72 | /// 73 | /// The file offset to the entry's data. 74 | /// 75 | public uint Offset; 76 | /// 77 | /// The file length to the entry's data. 78 | /// 79 | public int Length; 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /GrisaiaExtractor/Asmodean/Exkifint.cs: -------------------------------------------------------------------------------- 1 | using GrisaiaExtractor.Extensions; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Runtime.InteropServices; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | 11 | namespace GrisaiaExtractor.Asmodean { 12 | public static partial class Exkifint { 13 | 14 | private static uint GenTocSeed(string s) { 15 | const uint magic = 0x4C11DB7; 16 | uint seed = uint.MaxValue; 17 | 18 | for (int i = 0; i < s.Length; i++) { 19 | seed ^= ((uint)s[i]) << 24; 20 | 21 | for (int j = 0; j < 8; j++) { 22 | if ((seed & 0x80000000) != 0) { 23 | seed *= 2; 24 | seed ^= magic; 25 | } 26 | else { 27 | seed *= 2; 28 | } 29 | } 30 | 31 | seed = ~seed; 32 | } 33 | 34 | return seed; 35 | } 36 | 37 | private static void UnobfuscateFileName(byte[] s, uint seed) { 38 | const string FWD = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 39 | const string REV = "zyxwvutsrqponmlkjihgfedcbaZYXWVUTSRQPONMLKJIHGFEDCBA"; 40 | 41 | //MersenneTwister.Seed(seed); 42 | //uint key = MersenneTwister.GenRand(); 43 | uint key = MersenneTwister.GenRand(seed); 44 | int shift = (byte) ((key >> 24) + (key >> 16) + (key >> 8) + key); 45 | 46 | for (int i = 0; i < s.Length; i++, shift++) { 47 | byte c = s[i]; 48 | 49 | if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) { 50 | int index = 0; 51 | int index2 = shift; 52 | 53 | while (REV[index2 % 0x34] != c) { 54 | if (REV[(shift + index + 1) % 0x34] == c) { 55 | index += 1; 56 | break; 57 | } 58 | 59 | if (REV[(shift + index + 2) % 0x34] == c) { 60 | index += 2; 61 | break; 62 | } 63 | 64 | if (REV[(shift + index + 3) % 0x34] == c) { 65 | index += 3; 66 | break; 67 | } 68 | 69 | index += 4; 70 | index2 += 4; 71 | 72 | if (index > 0x34) { 73 | break; 74 | } 75 | } 76 | 77 | if (index < 0x34) { 78 | s[i] = (byte) FWD[index]; 79 | } 80 | } 81 | 82 | //shift++; 83 | } 84 | 85 | return; 86 | } 87 | 88 | private static void CopyResource(IntPtr h, 89 | string name, string type, out byte[] buffer, out int length) 90 | { 91 | IntPtr r = FindResource(h, name, type); 92 | if (r == IntPtr.Zero) 93 | throw new ResourceException(name, type, "find"); 94 | 95 | IntPtr g = LoadResource(h, r); 96 | if (g == IntPtr.Zero) 97 | throw new ResourceException(name, type, "load"); 98 | 99 | length = (int) SizeofResource(h, r); 100 | buffer = new byte[(length + 7) & ~7]; 101 | 102 | IntPtr lockPtr = LockResource(g); 103 | if (lockPtr == IntPtr.Zero) 104 | throw new ResourceException(name, type, "lock"); 105 | 106 | Marshal.Copy(lockPtr, buffer, 0, length); 107 | } 108 | 109 | private static string FindVCode2(string exeFile) { 110 | IntPtr h = LoadLibraryEx(exeFile, IntPtr.Zero, 111 | LOAD_LIBRARY_AS_IMAGE_RESOURCE); 112 | if (h == IntPtr.Zero) 113 | throw new LoadLibraryException(exeFile); 114 | 115 | CopyResource(h, "KEY", "KEY_CODE", out byte[] key, out int keyLength); 116 | 117 | for (int i = 0; i < key.Length; i++) 118 | key[i] ^= 0xCD; 119 | 120 | CopyResource(h, "DATA", "V_CODE2", out byte[] vcode2, out int vcode2Length); 121 | 122 | /*Blowfish bf = new Blowfish(); 123 | fixed (byte* key_buff_ptr = keyBuffer) 124 | bf.Set_Key(key_buff_ptr, keyLength); 125 | bf.Decrypt(vcode2Buffer, (vcode2Length + 7) & ~7); 126 | string vcode2 = Encoding.ASCII.GetString(vcode2Buffer, 0, vcode2Length).NullTerminate();*/ 127 | 128 | DecryptVCode2(key, keyLength, vcode2, vcode2Length); 129 | 130 | string result = Encoding.ASCII.GetString(vcode2).NullTerminate(); 131 | 132 | FreeLibrary(h); 133 | 134 | return result; 135 | } 136 | 137 | public static void Run(string intFile, string exeFile, string outputDir, 138 | ExkifintCallback progress = null) 139 | { 140 | using (Stream stream = File.OpenRead(intFile)) 141 | Run(stream, intFile, exeFile, outputDir, progress); 142 | } 143 | 144 | private static void Run(Stream stream, string intFile, string exeFile, 145 | string outputDir, ExkifintCallback progress = null) 146 | { 147 | Stopwatch watch = Stopwatch.StartNew(); 148 | DateTime startTime = DateTime.UtcNow; 149 | string gameId = FindVCode2(exeFile); 150 | 151 | 152 | BinaryReader reader = new BinaryReader(stream); 153 | KIFHDR hdr = reader.ReadStruct(); 154 | 155 | if (hdr.Signature != "KIF") // It's really a KIF INT file 156 | throw new InvalidFileException(Path.GetFileName(intFile), "INT"); 157 | 158 | KIFENTRY[] entries = reader.ReadStructArray(hdr.EntryCount); 159 | 160 | uint tocSeed = GenTocSeed(gameId); 161 | uint fileKey = 0; 162 | bool decrypt = false; 163 | 164 | /*const string fileName = "bom_s.hg3"; 165 | const uint offset = 1112718577; 166 | const int length = 1907629000; 167 | const uint fileKey2 = 1457527205; 168 | KIFENTRY kifEntry = new KIFENTRY { 169 | FileNameRaw = new char[64], 170 | Offset = offset, 171 | Length = length, 172 | }; 173 | Array.Copy(fileName.ToCharArray(), kifEntry.FileNameRaw, fileName.Length); 174 | DecryptEntry(ref kifEntry, fileKey2);*/ 175 | 176 | ExkifintArgs args = new ExkifintArgs(); 177 | for (int i = 0; i < hdr.EntryCount; i++) { 178 | if (entries[i].FileName == "__key__.dat") { 179 | if (!decrypt) { 180 | //MersenneTwister.Seed(entries[i].Length); 181 | //fileKey = MersenneTwister.GenRand(); 182 | fileKey = MersenneTwister.GenRand(entries[i].Length); 183 | decrypt = true; 184 | } 185 | } 186 | else { 187 | args.FileCount++; 188 | } 189 | } 190 | 191 | DateTime lastRefresh = DateTime.MinValue; 192 | Stopwatch writeTime = new Stopwatch(); 193 | TimeSpan refreshTime = TimeSpan.FromMilliseconds(20); 194 | //Stopwatch processTime = new Stopwatch(); 195 | for (uint i = 0; i < hdr.EntryCount; i++) { 196 | if (entries[i].FileName == "__key__.dat") 197 | continue; 198 | 199 | if (decrypt) { 200 | UnobfuscateFileName(entries[i].FileNameRaw, tocSeed + i); 201 | //UnobfuscateFileName(ref entries[i].FileName, tocSeed + i); 202 | 203 | entries[i].Offset += i; 204 | 205 | DecryptEntry(ref entries[i].Info, fileKey); 206 | 207 | /*Blowfish bf = new Blowfish(); 208 | bf.Set_Key((byte*) &file_key, 4); 209 | byte[] entry_buff = entries[i].bytes; 210 | bf.Decrypt(entry_buff, 8); 211 | entries[i].bytes = entry_buff;*/ 212 | } 213 | 214 | args.Ellapsed = DateTime.UtcNow - startTime; 215 | // Round to nearest hundredth 216 | args.Percent = Math.Round((double) args.FileIndex / args.FileCount * 10000) / 100; 217 | args.FileName = entries[i].FileName; 218 | TimeSpan sinceRefresh = DateTime.UtcNow - lastRefresh; 219 | if (sinceRefresh >= refreshTime) { 220 | lastRefresh = DateTime.UtcNow; 221 | writeTime.Start(); 222 | progress?.Invoke(args); 223 | writeTime.Stop(); 224 | } 225 | 226 | //processTime.Restart(); 227 | stream.Position = entries[i].Offset; 228 | byte[] buffer = reader.ReadBytes(entries[i].Length); 229 | 230 | if (decrypt) { 231 | DecryptData(buffer, entries[i].Length, fileKey); 232 | /*Blowfish bf = new Blowfish(); 233 | bf.Set_Key((byte*)&file_key, 4); 234 | bf.Decrypt(buff, (len / 8) * 8);*/ 235 | } 236 | 237 | string path = Path.Combine(outputDir, entries[i].FileName); 238 | File.WriteAllBytes(path, buffer); 239 | args.FileIndex++; 240 | //processTime.Stop(); 241 | //if (processTime.ElapsedMilliseconds >= 500) 242 | // Trace.WriteLine($"Large File: {buffer.Length / 1024:###,###,###,###}KB [{processTime.ElapsedMilliseconds}ms]"); 243 | } 244 | 245 | args.Ellapsed = DateTime.UtcNow - startTime; 246 | args.Percent = 100.0; 247 | progress?.Invoke(args); 248 | Trace.WriteLine($"Console Write Time: {writeTime.Elapsed:mm\\:ss\\.fff}"); 249 | } 250 | } 251 | } 252 | -------------------------------------------------------------------------------- /GrisaiaExtractor/Asmodean/Hgx2png.PInvoke.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Runtime.InteropServices; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace GrisaiaExtractor.Asmodean { 9 | public static partial class Hgx2png { 10 | 11 | //[DllImport("zlib1.dll", EntryPoint = "uncompress", CallingConvention = CallingConvention.Cdecl)] 12 | //private extern static int Uncompress(byte[] dest, ref int destLen, byte[] source, int sourceLen); 13 | 14 | [DllImport("asmodean.dll", CallingConvention = CallingConvention.Cdecl)] 15 | private extern static void ProcessImage( 16 | byte[] bufferTmp, 17 | int length, 18 | int origLength, 19 | byte[] cmdBufferTmp, 20 | int cmdLength, 21 | int origCmdLength, 22 | //byte[] rgbaBuffer, 23 | out IntPtr pRgbaBuffer, 24 | out int rgbaLength, 25 | int width, 26 | int height, 27 | int depthBytes); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /GrisaiaExtractor/Asmodean/Hgx2png.Structs.cs: -------------------------------------------------------------------------------- 1 | using GrisaiaExtractor.Extensions; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Runtime.InteropServices; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace GrisaiaExtractor.Asmodean { 10 | public static partial class Hgx2png { 11 | [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 20, CharSet = CharSet.Ansi)] 12 | private struct HG3HDR { 13 | [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 4)] 14 | public char[] SignatureRaw; // "HG-3" 15 | public int Unknown1; 16 | public int Unknown2; 17 | public int Unknown3; 18 | public int EntryCount; 19 | 20 | public string Signature => SignatureRaw.ToNullTerminatedString(); 21 | } 22 | 23 | [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 16, CharSet = CharSet.Ansi)] 24 | private struct HG3TAG { 25 | [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 8)] 26 | public char[] SignatureRaw; 27 | public int OffsetNext; 28 | public int Length; 29 | 30 | public string Signature => SignatureRaw.ToNullTerminatedString(); 31 | } 32 | 33 | [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 40)] 34 | private struct HG3STDINFO { 35 | public int Width; 36 | public int Height; 37 | public int DepthBits; 38 | public int OffsetX; 39 | public int OffsetY; 40 | public int TotalWidth; 41 | public int TotalHeight; 42 | public int Unknown1; 43 | public int Unknown2; 44 | public int Unknown3; 45 | } 46 | 47 | [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 24)] 48 | private struct HG3IMG { 49 | public int Unknown; 50 | public int Height; 51 | public int DataLength; 52 | public int OriginalDataLength; 53 | public int CmdLength; 54 | public int OriginalCmdLength; 55 | }; 56 | 57 | [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 8)] 58 | private struct HG3IMGAL { 59 | public int Length; 60 | public int OriginalLength; 61 | }; 62 | 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /GrisaiaExtractor/Exceptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace GrisaiaExtractor { 10 | /// An exception thrown when trying to automatically locate the Grisaia 11 | /// executable. 12 | public class GrisaiaExeNotFoundException : Exception { 13 | public GrisaiaExeNotFoundException() 14 | : base("Could not find Grisaia executable file!") { } 15 | } 16 | 17 | /// An exception thrown when an enum is missing it's code attribute. 18 | public class CodeNotFoundException : Exception { 19 | public CodeNotFoundException(FieldInfo field) 20 | : base($"No code attribute found for {field.DeclaringType.Name}.{field.Name}!") { } 21 | } 22 | 23 | /// The result of an .hg3 extract operation. 24 | public enum ExtractHg3Result { 25 | Success, 26 | Hg3ConvertFailed, 27 | BmpConvertFailed, 28 | PngSaveFailed, 29 | BmpDeleteFailed, 30 | Unknown, 31 | } 32 | 33 | /// An exception thrown during an hg3 extraction failure. 34 | public class ExtractHg3Exception : Exception { 35 | 36 | /// The result of the .hg3 extract operation. 37 | public ExtractHg3Result State { get; } 38 | /// The file associated with the error. 39 | public string File { get; } 40 | /// The location in the unrle function where memory would have been leaked. 41 | public int MemoryLeakLocation { get; } 42 | 43 | /// Constructs the exception with a result and associated file. 44 | public ExtractHg3Exception(ExtractHg3Result result, string file) 45 | : base(WriteMessage(result, file)) { 46 | State = result; 47 | File = file; 48 | } 49 | 50 | /// Constructs the exception with a result, associated file, and inner 51 | /// exception. 52 | public ExtractHg3Exception(ExtractHg3Result result, string file, 53 | Exception innerException) 54 | : base(WriteMessage(result, file, innerException), innerException) { 55 | State = result; 56 | File = file; 57 | } 58 | 59 | /// Writes the exception message. 60 | private static string WriteMessage(ExtractHg3Result result, string file, 61 | Exception innerException = null, int memoryLeak = 0) { 62 | string name = Path.GetFileName(file); 63 | string error = innerException?.GetType().Name ?? "Unknown Error"; 64 | switch (result) { 65 | case ExtractHg3Result.Hg3ConvertFailed: 66 | return $"{error} occurred while trying to convert '{name}' to a bmp!"; 67 | case ExtractHg3Result.BmpConvertFailed: 68 | return $"{error} occurred while trying to convert '{name}' to a png!"; 69 | case ExtractHg3Result.PngSaveFailed: 70 | return $"{error} occurred while trying to save '{name}'!"; 71 | case ExtractHg3Result.BmpDeleteFailed: 72 | return $"{error} occurred while trying to delete leftover `{name}`!"; 73 | case ExtractHg3Result.Unknown: 74 | return $"{error} occurred during an unknown point in the operation with '{name}'!"; 75 | default: 76 | return "No error occurred."; 77 | } 78 | } 79 | } 80 | 81 | /// An exception thrown during a failure with a resource. 82 | public class ResourceException : Exception { 83 | /// The name of the resource. May be null. 84 | public string Name { get; } 85 | /// The type of the resource. May be null. 86 | public string Type { get; } 87 | 88 | public ResourceException(string name, string type, string action) 89 | : base($"Failed to {action} resource '{name}:{type}'!") 90 | { 91 | Name = name; 92 | Type = type; 93 | } 94 | } 95 | 96 | /// An exception thrown during a failure to load a library. 97 | public class LoadLibraryException : Exception { 98 | /// The name of the library file. 99 | public string Library { get; } 100 | 101 | public LoadLibraryException(string library) 102 | : base($"Failed to load '{Path.GetFileName(library)}'!") 103 | { 104 | Library = Path.GetFileName(library); 105 | } 106 | } 107 | 108 | /// An exception thrown when the file is not of the valid type. 109 | public class InvalidFileException : Exception { 110 | /// The name of the invalid file. 111 | public string FileName { get; } 112 | 113 | public InvalidFileException(string file, string validType) 114 | : base($"'{Path.GetFileName(file)}' is not a valid {validType} file!") 115 | { 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /GrisaiaExtractor/Extensions/BinaryExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.InteropServices; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace GrisaiaExtractor.Extensions { 10 | public static class BinaryExtensions { 11 | public static TStruct ReadStruct(this BinaryReader reader) 12 | where TStruct : struct { 13 | byte[] buffer = reader.ReadBytes(Marshal.SizeOf()); 14 | 15 | GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned); 16 | 17 | TStruct result = Marshal.PtrToStructure( 18 | handle.AddrOfPinnedObject()); 19 | handle.Free(); 20 | return result; 21 | } 22 | 23 | public static TStruct[] ReadStructArray(this BinaryReader reader, int length) 24 | where TStruct : struct { 25 | TStruct[] result = new TStruct[length]; 26 | int size = Marshal.SizeOf(); 27 | byte[] buffer = reader.ReadBytes(size * length); 28 | 29 | GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned); 30 | IntPtr ptr = handle.AddrOfPinnedObject(); 31 | 32 | for (int i = 0; i < length; i++) { 33 | IntPtr ins = new IntPtr(ptr.ToInt32() + i * size); 34 | result[i] = Marshal.PtrToStructure(ins); 35 | } 36 | 37 | handle.Free(); 38 | return result; 39 | } 40 | 41 | public static void WriteStruct(this BinaryWriter writer, TStruct value) 42 | where TStruct : struct { 43 | byte[] buffer = new byte[Marshal.SizeOf()]; 44 | GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned); 45 | 46 | Marshal.StructureToPtr(value, handle.AddrOfPinnedObject(), true); 47 | writer.Write(buffer); 48 | handle.Free(); 49 | } 50 | 51 | public static string ReadString(this BinaryReader reader, int length) { 52 | return new string(reader.ReadChars(length)); 53 | } 54 | 55 | public static bool IsEndOfStream(this Stream stream) { 56 | return stream.Position >= stream.Length; 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /GrisaiaExtractor/Extensions/StringExtensions.Surround.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace GrisaiaExtractor.Extensions { 8 | public static partial class StringExtensions { 9 | 10 | /// Returns true if the string starts and ends with the 11 | /// parts. 12 | /// The left and right parts of the surrounding. 13 | /// The two parts must not 14 | /// overlap each other. 15 | /// Returns true if the string starts and ends with the 16 | /// parts. 17 | public static bool IsSurrounded(this string str, char openClose, 18 | bool noOverlap = true) 19 | { 20 | return str.IsSurrounded(openClose, openClose, noOverlap); 21 | } 22 | 23 | /// Returns true if the string starts with and 24 | /// ends with . 25 | /// The left part of the surrounding. 26 | /// The right part of the surrounding. 27 | /// The and 28 | /// parts must not overlap each other. 29 | /// Returns true if the string starts with and 30 | /// ends with . 31 | public static bool IsSurrounded(this string str, char open, char close, 32 | bool noOverlap = true) 33 | { 34 | return ((!noOverlap && str.Length >= 1) || str.Length >= 2) && 35 | str[0] == open && str[str.Length - 1] == close; 36 | } 37 | 38 | /// Returns true if the string starts and ends with the 39 | /// parts. 40 | /// The left and right parts of the surrounding. 41 | /// The two parts must not 42 | /// overlap each other. 43 | /// Returns true if the string starts and ends with the 44 | /// parts. 45 | public static bool IsSurrounded(this string str, string openClose, 46 | bool noOverlap = true) 47 | { 48 | return str.IsSurrounded(openClose, openClose, noOverlap); 49 | } 50 | 51 | /// Returns true if the string starts with and 52 | /// ends with . 53 | /// The left part of the surrounding. 54 | /// The right part of the surrounding. 55 | /// The and 56 | /// parts must not overlap each other. 57 | /// Returns true if the string starts with and 58 | /// ends with . 59 | /// or 60 | /// is null. 61 | public static bool IsSurrounded(this string str, string open, string close, 62 | bool noOverlap = true) 63 | { 64 | return (!noOverlap || str.Length >= open.Length + close.Length) && 65 | str.StartsWith(open) && str.EndsWith(close); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /GrisaiaExtractor/Extensions/StringExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace GrisaiaExtractor.Extensions { 8 | public static partial class StringExtensions { 9 | 10 | /// Returns true if the strings are equal, allows for ignore case. 11 | public static bool Equals2(this string a, string b, bool ignoreCase) { 12 | return a.Equals(b, ignoreCase ? 13 | StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); 14 | } 15 | 16 | /*public static string Surround(this string str, string open, string close) { 17 | 18 | }*/ 19 | 20 | /// Removes surrounding quotes from a string. 21 | public static string RemoveQuotes(this string str) { 22 | if (str.StartsWith("\"") && str.EndsWith("\"")) { 23 | if (str.Length >= 2) 24 | return str.Substring(1, str.Length - 2); 25 | return ""; 26 | } 27 | return str; 28 | } 29 | 30 | public static string ReplaceAt(this string str, int index, string value) { 31 | return str.Substring(0, index) + value + str.Substring(index + value.Length); 32 | } 33 | 34 | public static string ReplaceAt(this string str, int index, char c) { 35 | return str.Substring(0, index) + c + str.Substring(index + 1); 36 | } 37 | 38 | public static string NullTerminate(this string str) { 39 | int index = str.IndexOf('\0'); 40 | return (index != -1 ? str.Substring(0, index) : str); 41 | } 42 | 43 | public static int IndexOfNullTerminator(this string str) { 44 | int index = str.IndexOf('\0'); 45 | return (index != -1 ? index : str.Length); 46 | } 47 | 48 | public static int IndexOfNullTerminator(this char[] chars) { 49 | for (int i = 0; i < chars.Length; i++) { 50 | if (chars[i] == '\0') 51 | return i; 52 | } 53 | return chars.Length; 54 | } 55 | 56 | public static int IndexOfNullTerminator(this byte[] chars) { 57 | for (int i = 0; i < chars.Length; i++) { 58 | if (chars[i] == '\0') 59 | return i; 60 | } 61 | return chars.Length; 62 | } 63 | 64 | public static string ToNullTerminatedString(this byte[] chars) { 65 | return Encoding.ASCII.GetString(chars, 0, chars.IndexOfNullTerminator()); 66 | } 67 | public static string ToNullTerminatedString(this byte[] chars, Encoding encoding) { 68 | return encoding.GetString(chars, 0, chars.IndexOfNullTerminator()); 69 | } 70 | 71 | public static string ToNullTerminatedString(this char[] chars) { 72 | return new string(chars, 0, chars.IndexOfNullTerminator()); 73 | } 74 | 75 | public static string GetNullTerminated(this Encoding encoding, byte[] bytes) { 76 | return encoding.GetString(bytes).NullTerminate(); 77 | } 78 | 79 | /// Designed for use with ASCII encoding to easily get a single char 80 | /// from a single byte. 81 | public static char GetChar(this Encoding encoding, byte singleByte) { 82 | return encoding.GetChars(new byte[] { singleByte })[0]; 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /GrisaiaExtractor/GrisaiaExtractor.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {B9E8EA56-874B-4CEB-A703-DCA3A307A4D3} 8 | Library 9 | Properties 10 | GrisaiaExtractor 11 | GrisaiaExtractor 12 | v4.6.1 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | true 24 | x86 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | true 34 | x86 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | zlib1.dll 79 | PreserveNewest 80 | 81 | 82 | 83 | 84 | {8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942} 85 | asmodean 86 | false 87 | Content 88 | PreserveNewest 89 | True 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /GrisaiaExtractor/Identifying/Backgrounds.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Text.RegularExpressions; 8 | using System.Threading.Tasks; 9 | 10 | namespace GrisaiaExtractor.Identifying { 11 | [Flags] 12 | public enum BackgroundFlags { 13 | 14 | [Name("Default"), Code("")] 15 | Default = 0, 16 | 17 | // Special 18 | [Name("Alternate"), Code("t")] 19 | [Description("Some alternates are no different from default")] 20 | Alternate = (1 << 0), 21 | 22 | // Coloration 23 | [Name("Dark"), Code("d")] 24 | Dark = (1 << 1), 25 | [Name("Evening"), Code("e")] 26 | Evening = (1 << 2), 27 | [Name("Night"), Code("n")] 28 | [Description("Dark but with lights on")] 29 | Night = (1 << 3), 30 | [Name("Sepia"), Code("s")] 31 | Sepia = (1 << 4), 32 | 33 | // Weather 34 | [Name("Cloudy"), Code("c")] 35 | Cloudy = (1 << 5), 36 | [Name("Rain"), Code("r")] 37 | Rain = (1 << 6), 38 | [Name("Heavy Rain"), Code("r2")] 39 | HeavyRain = (1 << 7), 40 | 41 | // Meta 42 | [Name("Large"), Code("L")] 43 | Large = (1 << 8), 44 | } 45 | 46 | public enum BackgroundScale { 47 | [Name("Full"), Code("")] 48 | Full = 0, 49 | 50 | [Name("Large"), Code("l")] 51 | Large, 52 | [Name("Medium"), Code("m")] 53 | Medium, 54 | } 55 | 56 | [Flags] 57 | public enum BackgroundOffset { 58 | [Name("No Offset"), Code("")] 59 | NoOffset = 0, 60 | 61 | [Name("Center"), Code("c")] 62 | Center = (1 << 0), 63 | 64 | [Name("Left"), Code("l")] 65 | Left = (1 << 1), 66 | 67 | [Name("Right"), Code("r")] 68 | Right = (1 << 2), 69 | 70 | [Name("Up"), Code("u")] 71 | Up = (1 << 3), 72 | 73 | [Name("Down"), Code("d")] 74 | Down = (1 << 4), 75 | } 76 | 77 | public class BackgroundI : ImageIdentification { 78 | 79 | public static readonly Regex FormatRegex = 80 | new Regex(@"^(bgi_|bgmitei)(?'name'.*)"); 81 | 82 | public string Name { get; private set; } 83 | 84 | public static void Register() { 85 | ImageIdentifier.RegisterIdentifier( 86 | "BackgroundI", FormatRegex, false); 87 | } 88 | 89 | public BackgroundI() { } 90 | 91 | protected override void Setup(Match match) { 92 | Name = match.Groups["name"].Value; 93 | } 94 | 95 | public override string OutputDirectory => "Backgrounds"; 96 | } 97 | 98 | public class MiscBackground : ImageIdentification { 99 | 100 | public static readonly string[] Prefixes = { 101 | "bg_etc", 102 | "bgdave", 103 | "bg", // See: Grisaia no Meikyuu 'bg62t.png' 104 | "b‚‡", // See: Legacy before Japanese encoding 'b‚‡62t.png' 105 | }; 106 | 107 | public static readonly Regex FormatRegex = PrefixesToRegex(Prefixes); 108 | 109 | public static void Register() { 110 | ImageIdentifier.RegisterIdentifier( 111 | "Misc Backgrounds", FormatRegex, false); 112 | } 113 | 114 | public override string OutputDirectory => "Backgrounds"; 115 | 116 | } 117 | 118 | public abstract class BackgroundBase : ImageIdentification { 119 | 120 | /// The index ID of the background. 121 | public int Index { get; private set; } 122 | /// The flags describing the background. 123 | public BackgroundFlags Flags { get; private set; } 124 | /// The unidentified background flags. 125 | public string UnknownFlags { get; private set; } 126 | 127 | public BackgroundBase() { } 128 | 129 | /// Sets up the background base identification information. 130 | protected override void Setup(Match match) { 131 | Index = int.Parse(match.Groups["index"].Value); 132 | 133 | Flags = AttributeHelper.ParseCode( 134 | match.Groups["flags"].Value, out string unknownFlags); 135 | UnknownFlags = unknownFlags; 136 | } 137 | } 138 | 139 | public class Background : BackgroundBase { 140 | public static readonly Regex FormatRegex = 141 | new Regex(@"^bg[ert]?(?'index'\d\d)(?'flags'[a-zA-Z0-9]*)(?:_(?'scale'[a-zA-Z0-9])(?'offset'[a-zA-Z0-9])?)?(?'offsetIndex'\d\d)?(?'leftover'.*)?$"); 142 | 143 | public static void Register() { 144 | ImageIdentifier.RegisterIdentifier( 145 | "Background", FormatRegex, false); 146 | } 147 | 148 | public BackgroundScale Scale { get; private set; } 149 | public string UnknownScale { get; private set; } 150 | public BackgroundOffset Offset { get; private set; } 151 | public string UnknownOffset { get; private set; } 152 | public List SpecialAnimations { get; } 153 | 154 | public Background() { } 155 | 156 | /// Sets up the background identification information. 157 | protected override void Setup(Match match) { 158 | Scale = AttributeHelper.ParseCode( 159 | match.Groups["scale"].Value, out string unknownScale); 160 | UnknownScale = unknownScale; 161 | 162 | Offset = AttributeHelper.ParseCode( 163 | match.Groups["offset"].Value, out string unknownOffset); 164 | UnknownOffset = unknownOffset; 165 | } 166 | 167 | public override string OutputDirectory => "Backgrounds"; 168 | public override IEnumerable Tags { 169 | get { 170 | List tags = new List(); 171 | tags.Add(Index.ToString()); 172 | tags.AddRange(AttributeHelper.GetNames(Flags)); 173 | tags.AddRange(AttributeHelper.GetNames(Scale)); 174 | tags.AddRange(AttributeHelper.GetNames(Offset)); 175 | return tags; 176 | } 177 | } 178 | } 179 | 180 | public class BackgroundSpecialAnimation : BackgroundBase { 181 | public static readonly Regex FormatRegex = 182 | new Regex(@"^(?'parent'bg(e|r)?(?'index'\d\d)(?'flags'[a-zA-Z0-9]*))_(?'name'[a-zA-Z0-9]+)$"); 183 | 184 | public static void Register() { 185 | ImageIdentifier.RegisterIdentifier( 186 | "Background Special Animation", FormatRegex, true, 187 | PostAdd); 188 | } 189 | 190 | public string AnimationName { get; private set; } 191 | public string Parent { get; private set; } 192 | 193 | public BackgroundSpecialAnimation() { } 194 | 195 | /// Sets up the background identification information. 196 | protected override void Setup(Match match) { 197 | AnimationName = match.Groups["name"].Value; 198 | Parent = match.Groups["parent"].Value; 199 | } 200 | 201 | public static void PostAdd(ImageIdentifier identifier, ImageIdentification selfBase) { 202 | BackgroundSpecialAnimation self = (BackgroundSpecialAnimation) selfBase; 203 | if (identifier.TryGetImage(self.AnimationName, out var image)) { 204 | if (image is Background bg) { 205 | bg.SpecialAnimations.Add(self); 206 | } 207 | } 208 | } 209 | public override string OutputDirectory => "Backgrounds"; 210 | public override IEnumerable Tags { 211 | get { 212 | List tags = new List(); 213 | tags.Add(Index.ToString()); 214 | tags.AddRange(AttributeHelper.GetNames(Flags)); 215 | tags.Add(AnimationName); 216 | return tags; 217 | } 218 | } 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /GrisaiaExtractor/Identifying/Character.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Text.RegularExpressions; 7 | using System.Threading.Tasks; 8 | 9 | namespace GrisaiaExtractor.Identifying { 10 | 11 | public enum CharacterType { 12 | [Name("CG"), Code("")] 13 | [Group("CG")] 14 | CG = 0, 15 | 16 | [Name("Chibi"), Code("sd", "_sd", "__sd", IgnoreCase = true)] 17 | [Group("Chibi")] 18 | Chibi, 19 | 20 | [Name("Sprite"), Code("T")] 21 | [Group("Sprites")] 22 | Sprite, 23 | } 24 | 25 | /*public enum CGScale { 26 | [Name("Normal"), Code("")] 27 | Normal = 0, 28 | 29 | [Name("Thumb")] 30 | }*/ 31 | 32 | 33 | 34 | public class Character : ImageIdentification { 35 | 36 | public static readonly Dictionary Characters = 37 | new Dictionary() 38 | { 39 | { "hir", "Amane Classmates/Hiroka Tamaki" }, 40 | { "ibu", "Amane Classmates/Haruna Ibuki" }, 41 | { "kan", "Amane Classmates/Saaya Kaneda" }, 42 | { "koi", "Amane Classmates/Ritsu Koide" }, 43 | { "kom", "Amane Classmates/Megumi Komori" }, 44 | { "och", "Amane Classmates/Yoshihiko Ochi" }, 45 | { "sak", "Amane Classmates/Chiaki Sakashita" }, 46 | { "skm", "Amane Classmates/Minori Sakuma" }, 47 | { "skr", "Amane Classmates/Mifuyu Sakurai" }, 48 | { "tas", "Amane Classmates/Keiji Sakashita" }, 49 | { "sas", "Sachi Komine/Battle" }, 50 | { "mib", "Michiru Matsushima/Black Hair" }, 51 | { "ama", "Amane Suou" }, 52 | { "mak", "Makina Irisu" }, 53 | { "mic", "Michiru Matsushima" }, 54 | { "sac", "Sachi Komine" }, 55 | { "yum", "Yumiko Sakaki" }, 56 | { "kar", "Kazuki Kazami" }, 57 | { "kap", "Kazuki Kazami" }, 58 | { "kaz", "Kazuki Kazami" }, 59 | { "chi", "Chizuru Tachibana" }, 60 | { "jb", "JB" }, 61 | { "jbs", "JB" }, 62 | { "asa", "Asako Kusakabe" }, 63 | { "yuj", "Yuuji Kazami" }, 64 | { "kia", "Chiara Farrell" }, 65 | { "sam", "Sachi's Mother" }, 66 | { "saf", "Sachi's Father" }, 67 | { "yuf", "Michiaki Sakaki (Yumiko's Father)" }, 68 | { "mif", "Michiru's Friend" }, 69 | { "kiy", "Kiyoka Irisu (Makina's Mother)" }, 70 | { "amm", "Amane Suou (Middle School)" }, 71 | { "amp", "Amane Suou (Middle School)" }, 72 | { "nya", "Nyanmel" }, 73 | { "tan", "Thanatochu" }, 74 | { "kam", "Kami-sama" }, 75 | { "yjf", "Ryouji Kazami (Yuuji's Father)" }, 76 | { "yjm", "Satoko Kazami (Yuuji's Mother)" }, 77 | { "dan", "Daniel Bone" }, 78 | { "edi", "Edward Walker" }, 79 | { "gar", "Agnes Garrett" }, 80 | { "jei", "Justin Mikemeyer" }, 81 | { "joh", "John (Yuuji's dog)" }, 82 | { "osr", "Heath Oslo" }, 83 | { "osl", "Heath Oslo" }, 84 | { "mar", "Marin" }, 85 | { "mir", "Milliela Stanfield" }, 86 | { "rob", "Robert Wallson" }, 87 | { "dave", "Professor Dave" }, 88 | { "dav", "Professor Dave" }, 89 | //{ "ev", "Everyone" }, 90 | { "oth", "Other" }, 91 | //{ "op", "Other" }, 92 | 93 | // Zankou 94 | { "iza", "Isabella Fitzgerald" }, 95 | { "mro", "Marion Garland" }, 96 | { "nob", "Ramon Noboa" }, 97 | }; 98 | 99 | public static readonly Dictionary SpriteOnlyCharacters = 100 | new Dictionary() 101 | { 102 | { "meg", "Goddess" }, // TODO: What is her name? 103 | { "cha", "Chaos" }, 104 | { "gho", "Ghost" }, 105 | { "str", "Stranger" }, 106 | { "nan", "Nanano Suou" }, 107 | { "ren", "Renge Yamabuki" }, 108 | { "mag", "Other" }, 109 | }; 110 | 111 | public static readonly Regex FormatRegex = 112 | new Regex( 113 | $"^((?'type'T|_?_?sd)?_?(?'name'{string.Join("|", Characters.Keys.ToArray())})|" + 114 | $"^(?'type'T)_?(?'name'{string.Join("|", SpriteOnlyCharacters.Keys.ToArray())}))", 115 | RegexOptions.IgnoreCase); 116 | 117 | public static void Register() { 118 | ImageIdentifier.RegisterIdentifier( 119 | "Character", FormatRegex, false); 120 | } 121 | 122 | public string Code { get; private set; } 123 | public CharacterType Type { get; private set; } 124 | public string Name { get; private set; } 125 | public string Category { get; private set; } 126 | public string SubCategory { get; private set; } 127 | 128 | static Character() { 129 | // SpriteOnlyCharacters is only needed for regex initialization. 130 | // So let's dump all SpriteOnlyCharacters into Characters. 131 | foreach (var pair in SpriteOnlyCharacters) { 132 | Characters.Add(pair.Key, pair.Value); 133 | } 134 | } 135 | 136 | public Character() { } 137 | 138 | protected override void Setup(Match match) { 139 | Code = match.Groups["name"].Value.ToLower(); 140 | Name = Characters[Code]; 141 | Type = AttributeHelper.ParseCode(match.Groups["type"].Value, out _); 142 | } 143 | 144 | public override string OutputDirectory { 145 | get { 146 | string path = "Characters"; 147 | if (!string.IsNullOrWhiteSpace(Category)) 148 | path = Path.Combine(path, Category); 149 | path = Path.Combine(path, Name); 150 | if (!string.IsNullOrWhiteSpace(SubCategory)) 151 | path = Path.Combine(path, SubCategory); 152 | return Path.Combine(path, AttributeHelper.GetGroup(Type)); 153 | } 154 | } 155 | 156 | public override IEnumerable Tags { 157 | get { 158 | List tags = new List(); 159 | tags.Add(Type.ToString()); 160 | tags.Add(Name); 161 | tags.Add(Category); 162 | tags.Add(SubCategory); 163 | return tags; 164 | } 165 | } 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /GrisaiaExtractor/Identifying/Effect.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Text.RegularExpressions; 6 | using System.Threading.Tasks; 7 | 8 | namespace GrisaiaExtractor.Identifying { 9 | public class Effect : ImageIdentification { 10 | public static readonly string[] Prefixes = { 11 | "anm_", 12 | "bom_", 13 | "glass_anim", 14 | "manpu_", 15 | "mask_", 16 | "parts_", 17 | "slash", 18 | "yuge", 19 | }; 20 | 21 | public static readonly Regex FormatRegex = PrefixesToRegex(Prefixes); 22 | 23 | public static void Register() { 24 | ImageIdentifier.RegisterIdentifier( 25 | "Effect", FormatRegex, false); 26 | } 27 | 28 | public Effect() { } 29 | 30 | public override string OutputDirectory => "Effects"; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /GrisaiaExtractor/Identifying/ImageIdentification.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Text.RegularExpressions; 7 | using System.Threading.Tasks; 8 | 9 | namespace GrisaiaExtractor.Identifying { 10 | /// The base class for an image identification. 11 | public abstract class ImageIdentification { 12 | 13 | // General: 14 | /// The base filename with no extension. 15 | public string FileName { get; private set; } 16 | 17 | // Animation: 18 | /// True if a filename exists without the animation postfix. 19 | public bool HasBase { get; private set; } 20 | /// Gets the first A frame in the animation. -1 if not an animation. 21 | public int FirstFrameA { get; private set; } = -1; 22 | /// Gets the first B frame in the animation. -1 if not an animation. 23 | public int FirstFrameB { get; private set; } = -1; 24 | /// Gets the last A frame in the animation. -1 if not an animation. 25 | public int LastFrameA { get; private set; } = -1; 26 | /// Gets the last B frame in the animation. -1 if not an animation. 27 | public int LastFrameB { get; private set; } = -1; 28 | 29 | 30 | //----------------------------------------------------------------------------- 31 | // Constructors 32 | //----------------------------------------------------------------------------- 33 | 34 | /// Constructs the base image identification. 35 | public ImageIdentification() { } 36 | 37 | /// Initializes the image identification from the filepath. 38 | public void Initialize(string path, Match match, bool findAnimaion) { 39 | FileName = AnimationHelper.GetBaseFileName(path); 40 | 41 | if (findAnimaion) { 42 | string[] fileNames = AnimationHelper.GetFileNames(path); 43 | InitializeFileNames(fileNames); 44 | } 45 | Setup(match); 46 | } 47 | 48 | /// Initializes the image identification from the filepath. 49 | public void Initialize(string[] paths, Match match) { 50 | FileName = AnimationHelper.GetBaseFileName(paths[0]); 51 | 52 | string[] fileNames = paths.Select(p => 53 | Path.GetFileNameWithoutExtension(p)).ToArray(); 54 | InitializeFileNames(fileNames); 55 | Setup(match); 56 | } 57 | 58 | /// Sets up the basic identification information. 59 | private void InitializeFileNames(string[] fileNames) { 60 | // Gather information about the animation: 61 | // Check the first two files for animations 62 | int indexA, indexB; 63 | for (int i = 0; i < 2 && i + 1 < fileNames.Length; i++) { 64 | if (AnimationHelper.IsAnimation(fileNames[i], out indexA, out indexB)) { 65 | FirstFrameA = indexA; 66 | FirstFrameB = indexB; 67 | // Get the last animation frames 68 | AnimationHelper.IsAnimation(fileNames[fileNames.Length - 1], out indexA, out indexB); 69 | LastFrameA = indexA; 70 | LastFrameB = indexB; 71 | break; 72 | } 73 | else { 74 | // This should only ever be reached when i == 0 75 | HasBase = true; 76 | } 77 | } 78 | } 79 | 80 | /// Sets up the extended image identification. 81 | protected virtual void Setup(Match match) { } 82 | 83 | 84 | //----------------------------------------------------------------------------- 85 | // General 86 | //----------------------------------------------------------------------------- 87 | 88 | /// Creates a string representation of the identification as a 89 | /// filename and tags. 90 | public override string ToString() { 91 | string name = FileName; 92 | if (IsAnimated) 93 | return name += $" (+{TotalFrameCount})"; 94 | name += $" {string.Join(",", Tags.ToArray())}"; 95 | return name; 96 | } 97 | 98 | /// A quick method to create regex from a list of prefixes. 99 | protected static Regex PrefixesToRegex(string[] prefixes) 100 | => new Regex($"^({string.Join("|", prefixes)})"); 101 | 102 | 103 | //----------------------------------------------------------------------------- 104 | // File Paths 105 | //----------------------------------------------------------------------------- 106 | 107 | /// Gets the base .png filepath. 108 | public string GetPng(string dir) { 109 | return Path.Combine(dir, OutputDirectory, FileName + ".png"); 110 | } 111 | 112 | /// Gets the animation .png filepath. 113 | public string GetPng(string dir, int indexA, int indexB) { 114 | return AnimationHelper.GetFileNameQuick(Path.Combine(dir, OutputDirectory), FileName, indexA, indexB, ".png"); 115 | } 116 | 117 | /// Gets all .png filepaths for the image. 118 | public IEnumerable GetPngs(string dir) { 119 | if (HasBase) 120 | yield return GetPng(dir); 121 | for (int a = FirstFrameA; a <= LastFrameA; a++) { 122 | for (int b = FirstFrameB; b <= LastFrameB; b++) { 123 | yield return GetPng(dir, a, b); 124 | } 125 | } 126 | } 127 | 128 | /// Gets the .bmp filepath. 129 | public string GetBmp(string dir) { 130 | return Path.Combine(dir, FileName + ".bmp"); 131 | } 132 | 133 | /// Gets the animation .bmp filepath. 134 | public string GetBmp(string dir, int indexA, int indexB) { 135 | return AnimationHelper.GetFileNameQuick(dir, FileName, indexA, indexB, ".bmp"); 136 | } 137 | 138 | /// Gets all .bmp filepaths for the image. 139 | public IEnumerable GetBmps(string dir) { 140 | if (HasBase) 141 | yield return GetBmp(dir); 142 | for (int a = FirstFrameA; a <= LastFrameA; a++) { 143 | for (int b = FirstFrameB; b <= LastFrameB; b++) { 144 | yield return GetBmp(dir, a, b); 145 | } 146 | } 147 | } 148 | 149 | /// Gets the .hg3 filepath. 150 | public string GetHg3(string dir) { 151 | return Path.Combine(dir, FileName + ".hg3"); 152 | } 153 | 154 | 155 | //----------------------------------------------------------------------------- 156 | // Properties 157 | //----------------------------------------------------------------------------- 158 | 159 | /// Returns true if the image has animation frames. 160 | public bool IsAnimated { 161 | get { return FirstFrameA != -1; } 162 | } 163 | 164 | /// Gets the number of A frames in the animation. 165 | public int FrameCountA { 166 | get { return (FirstFrameA == -1 ? 0 : LastFrameA - FirstFrameA + 1); } 167 | } 168 | 169 | /// Gets the number of B frames in the animation. 170 | public int FrameCountB { 171 | get { return (FirstFrameB == -1 ? 0 : LastFrameB - FirstFrameB + 1); } 172 | } 173 | 174 | /// Gets the total number of frames in the animation. 175 | public int TotalFrameCount { 176 | get { return FrameCountA * FrameCountB; } 177 | } 178 | 179 | /// Gets the output directory for the image. 180 | public abstract string OutputDirectory { get; } 181 | 182 | /// Gets the searchable tags for the image. 183 | public virtual IEnumerable Tags { 184 | get { return Enumerable.Empty(); } 185 | } 186 | 187 | /// Gets if the image should be expanded to its full size when 188 | /// extracting. 189 | public virtual bool ExpandImage => true; 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /GrisaiaExtractor/Identifying/ImageIdentifier.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Text.RegularExpressions; 7 | using System.Threading.Tasks; 8 | 9 | namespace GrisaiaExtractor.Identifying { 10 | 11 | /// A handler for matching and creating an identification. 12 | public class ImageIdentifierType { 13 | // Information: 14 | /// The type created from this identifier. 15 | public Type Type { get; } 16 | /// The name of the type created from this identifier. 17 | public string Name { get; } 18 | 19 | // Matching: 20 | /// The regex used to match with this type. 21 | public Regex Regex { get; } 22 | /// True if this type requires an animation. 23 | public bool RequiresAnimation { get; } 24 | 25 | // Functions: 26 | /// Called after the identification has been created. 27 | public Action PostAdd { get; } 28 | 29 | /// Constructs the identifier type. 30 | public ImageIdentifierType(Type type, string name, Regex regex, 31 | bool requiresAnimation, 32 | Action postAdd = null) 33 | { 34 | Type = type; 35 | Name = name; 36 | Regex = regex; 37 | RequiresAnimation = requiresAnimation; 38 | PostAdd = postAdd; 39 | } 40 | 41 | /// Creates an empty image identification from the type. 42 | public ImageIdentification Create() { 43 | return (ImageIdentification) Activator.CreateInstance(Type); 44 | } 45 | } 46 | 47 | /// Identifies . 48 | public class ImageIdentifier { 49 | 50 | private static List identifiers = 51 | new List(); 52 | 53 | static ImageIdentifier() { 54 | Background.Register(); 55 | MiscBackground.Register(); 56 | BackgroundI.Register(); 57 | //BackgroundSpecialAnimation.Register(); 58 | Effect.Register(); 59 | Logo.Register(); 60 | StoryCGChibi.Register(); 61 | Character.Register(); 62 | MiscChibi.Register(); 63 | UserInterface.Register(); 64 | TmbIcon.Register(); 65 | Transition.Register(); 66 | Item.Register(); 67 | } 68 | 69 | public static void RegisterIdentifier( 70 | string name, Regex regex, bool requiresAnimation, 71 | Action postAdd = null) 72 | where IType : ImageIdentification 73 | { 74 | identifiers.Add(new ImageIdentifierType( 75 | typeof(IType), name, regex, requiresAnimation, postAdd)); 76 | } 77 | 78 | 79 | private Dictionary images; 80 | 81 | public ImageIdentifier() { 82 | images = new Dictionary(); 83 | } 84 | 85 | public void AddImage(ImageIdentification image) { 86 | images.Add(image.FileName, image); 87 | } 88 | 89 | public bool TryGetImage(string name, out ImageIdentification result) { 90 | return images.TryGetValue(name, out result); 91 | } 92 | 93 | public ImageIdentifierType GetIdentifier(string path, out Match match) { 94 | string name = AnimationHelper.GetBaseFileName(path, out bool isAnimation); 95 | foreach (ImageIdentifierType identifier in identifiers) { 96 | if (identifier.RequiresAnimation && !isAnimation) 97 | continue; 98 | match = identifier.Regex.Match(name); 99 | if (match.Success) 100 | return identifier; 101 | } 102 | match = null; 103 | return null; 104 | } 105 | 106 | public ImageIdentification PreIdentifyImage(string path) { 107 | ImageIdentifierType identifier = GetIdentifier(path, out Match match); 108 | ImageIdentification image = identifier?.Create() ?? new Unidentified(); 109 | image.Initialize(path, match, false); 110 | //AddImage(image); 111 | //identifier?.PostAdd?.Invoke(this, image); 112 | return image; 113 | } 114 | 115 | public ImageIdentification IdentifyImage(string[] paths) { 116 | ImageIdentifierType identifier = GetIdentifier(paths[0], out Match match); 117 | ImageIdentification image = identifier?.Create() ?? new Unidentified(); 118 | image.Initialize(paths, match); 119 | AddImage(image); 120 | identifier?.PostAdd?.Invoke(this, image); 121 | return image; 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /GrisaiaExtractor/Identifying/Item.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Text.RegularExpressions; 6 | using System.Threading.Tasks; 7 | 8 | namespace GrisaiaExtractor.Identifying { 9 | public class Item : ImageIdentification { 10 | 11 | public static readonly Regex FormatRegex = new Regex(@"^item"); 12 | 13 | public static void Register() { 14 | ImageIdentifier.RegisterIdentifier("Item", FormatRegex, false); 15 | } 16 | 17 | public override string OutputDirectory => "Items"; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /GrisaiaExtractor/Identifying/Logo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Text.RegularExpressions; 6 | using System.Threading.Tasks; 7 | 8 | namespace GrisaiaExtractor.Identifying { 9 | public class Logo : ImageIdentification { 10 | 11 | public static readonly string[] Prefixes = { 12 | "10thlogo", 13 | "fwlogo", 14 | "install", 15 | "logo", 16 | "sddava_logo", 17 | "sekai_logo", 18 | "sys_title", 19 | "title", 20 | }; 21 | 22 | public static readonly Regex FormatRegex = PrefixesToRegex(Prefixes); 23 | 24 | 25 | public static void Register() { 26 | ImageIdentifier.RegisterIdentifier("Logo", FormatRegex, false); 27 | } 28 | 29 | public Logo() { 30 | 31 | } 32 | 33 | public override string OutputDirectory => "Logos"; 34 | public override bool ExpandImage => false; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /GrisaiaExtractor/Identifying/MiscChibi.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Text.RegularExpressions; 7 | using System.Threading.Tasks; 8 | 9 | namespace GrisaiaExtractor.Identifying { 10 | 11 | public class MiscChibi : ImageIdentification { 12 | 13 | public static readonly Regex FormatRegex = 14 | new Regex(@"^_?_?sd\d\d\d", RegexOptions.IgnoreCase); 15 | 16 | 17 | public static void Register() { 18 | ImageIdentifier.RegisterIdentifier( 19 | "Misc Chibi", FormatRegex, false); 20 | } 21 | 22 | public override string OutputDirectory => Path.Combine("Story", "Chibi"); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /GrisaiaExtractor/Identifying/StoryCGChibi.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Text.RegularExpressions; 7 | using System.Threading.Tasks; 8 | 9 | namespace GrisaiaExtractor.Identifying { 10 | public class StoryCGChibi : ImageIdentification { 11 | 12 | public static readonly Dictionary Categories = 13 | new Dictionary() 14 | { 15 | { "op", "Opening" }, 16 | { "pro", "Prologue" }, 17 | { "bla", "Main Story" }, 18 | { "aft", "After Story" }, 19 | { "mag", "Story" }, // Idol Mahou Shoujo 20 | { "ev", "Story" }, // Yuukan 21 | { "evt", "Story" }, // Zankou 22 | }; 23 | 24 | /*public static readonly string[] RegexNames = { 25 | "pro(?!title)", 26 | }; 27 | 28 | public const string NameRegex 29 | 30 | private static string[] GetNames() { 31 | string[] names = new string[Categories.Count]; 32 | int i = 0; 33 | foreach (string name in Categories.Keys) { 34 | names[i] = name + @""; 35 | foreach (string nameRegex in RegexNames) { 36 | if (new Regex(nameRegex).IsMatch(name)) { 37 | names[i] = nameRegex; 38 | break; 39 | } 40 | } 41 | i++; 42 | } 43 | return names; 44 | }*/ 45 | 46 | 47 | public static readonly Regex FormatRegex = new Regex( 48 | $"^(?'chibi'_?_?sd)?(?'category'{string.Join("|", Categories.Keys.ToArray())})(?:[^a-zA-Z]|$)", RegexOptions.IgnoreCase); 49 | 50 | public static void Register() { 51 | ImageIdentifier.RegisterIdentifier( 52 | "CG/Chibi", FormatRegex, false); 53 | } 54 | 55 | 56 | public StoryCGChibi() { 57 | 58 | } 59 | 60 | protected override void Setup(Match match) { 61 | if (string.IsNullOrEmpty(match.Groups["chibi"].Value)) 62 | Type = "CG"; 63 | else 64 | Type = "Chibi"; 65 | Code = match.Groups["category"].Value.ToLower(); 66 | Category = Categories[Code]; 67 | } 68 | 69 | public string Type { get; private set; } 70 | 71 | public string Code { get; private set; } 72 | public string Category { get; private set; } 73 | 74 | 75 | 76 | public override string OutputDirectory => Path.Combine(Category, Type); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /GrisaiaExtractor/Identifying/TmbIcon.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Text.RegularExpressions; 6 | using System.Threading.Tasks; 7 | 8 | namespace GrisaiaExtractor.Identifying { 9 | public class TmbIcon : ImageIdentification { 10 | 11 | public static readonly Regex FormatRegex = new Regex(@"^tmbicon"); 12 | 13 | public static void Register() { 14 | ImageIdentifier.RegisterIdentifier("Icon", FormatRegex, false); 15 | } 16 | 17 | public TmbIcon() { } 18 | 19 | protected override void Setup(Match match) { 20 | 21 | } 22 | 23 | public override string OutputDirectory => "Icons"; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /GrisaiaExtractor/Identifying/Transition.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Text.RegularExpressions; 6 | using System.Threading.Tasks; 7 | 8 | namespace GrisaiaExtractor.Identifying { 9 | public class Transition : ImageIdentification { 10 | 11 | public static readonly Regex FormatRegex = 12 | new Regex(@"^wipe(?'index'\d\d)(?'subtype'[a-z])?"); 13 | 14 | public int Index { get; private set; } 15 | public string Subtype { get; private set; } 16 | 17 | public static void Register() { 18 | ImageIdentifier.RegisterIdentifier("Transition", FormatRegex, false); 19 | } 20 | 21 | public Transition() { } 22 | 23 | protected override void Setup(Match match) { 24 | Index = int.Parse(match.Groups["index"].Value); 25 | Subtype = match.Groups["subtype"].Value; 26 | } 27 | 28 | public override string OutputDirectory => "Transitions"; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /GrisaiaExtractor/Identifying/Unidentified.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace GrisaiaExtractor.Identifying { 8 | public class Unidentified : ImageIdentification { 9 | 10 | public Unidentified() { 11 | 12 | } 13 | 14 | public override string OutputDirectory => "Unidentified"; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /GrisaiaExtractor/Identifying/UserInterface.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Text.RegularExpressions; 6 | using System.Threading.Tasks; 7 | 8 | namespace GrisaiaExtractor.Identifying { 9 | public class UserInterface : ImageIdentification { 10 | private static readonly string[] Prefixes = { 11 | "_conf_txt", 12 | "activate", 13 | "award", 14 | "caution", 15 | "bgm", 16 | "cap_mic_change", 17 | "cg_", 18 | "cgmode", 19 | "click", 20 | "cm001", 21 | "conf", 22 | "cursor", 23 | "dave_select", 24 | "delt_plane", 25 | "delta_plane", 26 | "dl_", 27 | "eyecatch", 28 | "guripe", 29 | "hamon", 30 | "half_plane", 31 | "hist", 32 | "jumpmes", 33 | "moviemode", 34 | "novel_click", 35 | "nowloading", 36 | "progress", 37 | "s_cnf_", 38 | "scenemode", 39 | "scenesel", 40 | "scnhlp", 41 | "scnsel", 42 | "secret", 43 | "seek", 44 | "sel", 45 | "scenarioselect", 46 | "shortcut", 47 | "sl_", 48 | "slide_", 49 | "ss_", 50 | @"str\d_plane", 51 | "sys_(?!title)", // sys_title -> Logo 52 | "userfont", 53 | "wpthm", 54 | }; 55 | 56 | public static readonly Regex FormatRegex = PrefixesToRegex(Prefixes); 57 | 58 | public static void Register() { 59 | ImageIdentifier.RegisterIdentifier( 60 | "User Interface", FormatRegex, false); 61 | } 62 | 63 | public UserInterface() { } 64 | 65 | public override string OutputDirectory => "User Interface"; 66 | public override bool ExpandImage => false; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /GrisaiaExtractor/PathHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace GrisaiaExtractor { 10 | /// A helper with extra methods for paths, files, and directories. 11 | public static class PathHelper { 12 | 13 | //----------------------------------------------------------------------------- 14 | // Constants 15 | //----------------------------------------------------------------------------- 16 | 17 | /// The stored executable path for the entry assembly. 18 | public static readonly string ExePath = 19 | Assembly.GetEntryAssembly().Location; 20 | 21 | /// The directory of the entry executable. 22 | public static readonly string ExeDirectory = 23 | Path.GetDirectoryName(ExePath); 24 | 25 | /// Gets the file name of the entry executable. 26 | public static readonly string ExeFile = 27 | Path.GetFileName(ExePath); 28 | 29 | /// Gets the file name of the entry executable without its extension. 30 | public static readonly string ExeName = 31 | Path.GetFileNameWithoutExtension(ExePath); 32 | 33 | /// Provides a platform-specific character used to separate directory 34 | /// levels in a path string that reflects a hierarchical file system 35 | /// organization. 36 | public static readonly char[] DirectorySeparators = new char[] { 37 | Path.DirectorySeparatorChar, 38 | Path.AltDirectorySeparatorChar, 39 | }; 40 | 41 | //----------------------------------------------------------------------------- 42 | // Methods 43 | //----------------------------------------------------------------------------- 44 | 45 | /// Returns true if the fileName has valid characters for search 46 | /// patterns. 47 | public static bool IsValidNamePattern(string name) { 48 | name = name.Replace("*", "").Replace("?", ""); 49 | return IsValidName(name); 50 | } 51 | 52 | /// Returns true if the filePath has valid characters for search 53 | /// patterns. 54 | public static bool IsValidPathPattern(string path) { 55 | path = path.Replace("*", "").Replace("?", ""); 56 | return IsValidPath(path); 57 | //return path.IndexOfAny(Path.GetInvalidPathChars()) == -1; 58 | } 59 | 60 | /// Returns true if the fileName has valid characters. 61 | public static bool IsValidName(string name) { 62 | return name.IndexOfAny(Path.GetInvalidFileNameChars()) == -1; 63 | } 64 | 65 | /// Returns true if the filePath has valid characters. 66 | public static bool IsValidPath(string path) { 67 | try { 68 | Path.GetFullPath(path); 69 | return true; 70 | } 71 | catch { 72 | return false; 73 | } 74 | //return path.IndexOfAny(Path.GetInvalidPathChars()) == -1; 75 | } 76 | 77 | /// Returns true if the filePath has valid characters and does not 78 | /// lead to a directory. 79 | public static bool IsValidFile(string path) { 80 | return IsValidPath(path) && 81 | !Directory.Exists(path); 82 | } 83 | 84 | /// Returns true if the filePath has valid characters and does not 85 | /// lead to a file. 86 | public static bool IsValidDirectory(string path) { 87 | return IsValidPath(path) && 88 | !File.Exists(path); 89 | } 90 | 91 | /// Returns true if the filePath has valid characters and is not 92 | /// rooted. 93 | public static bool IsValidRelativePath(string path) { 94 | if (Path.IsPathRooted(path)) 95 | return false; 96 | return IsValidPath(path); 97 | } 98 | 99 | /// Returns a path that can be compared with another normalized path. 100 | public static string NormalizePath(string path) { 101 | return Path.GetFullPath(path) 102 | .TrimEnd(DirectorySeparators) 103 | .ToUpperInvariant(); 104 | } 105 | 106 | /// Returns true if the two paths lead to the same location. 107 | public static bool IsPathTheSame(string path1, string path2) { 108 | return string.Compare( 109 | NormalizePath(path1), NormalizePath(path2), true) == 0; 110 | } 111 | 112 | /// Combines the specified paths with the executable directory. 113 | public static string CombineExecutable(string path1) { 114 | return Path.Combine(ExeDirectory, path1); 115 | } 116 | 117 | /// Combines the specified paths with the executable directory. 118 | public static string CombineExecutable(string path1, string path2) { 119 | return Path.Combine(ExeDirectory, path1, path2); 120 | } 121 | 122 | /// Combines the specified paths with the executable directory. 123 | public static string CombineExecutable(string path1, string path2, 124 | string path3) { 125 | return Path.Combine(ExeDirectory, path1, path2, path3); 126 | } 127 | 128 | /// Combines the specified paths with the executable directory. 129 | public static string CombineExecutable(params string[] paths) { 130 | return Path.Combine(ExeDirectory, Path.Combine(paths)); 131 | } 132 | 133 | /// Gets the proper capitalization of a path so it looks nice. 134 | public static string GetProperDirectoryCapitalization(string dir) { 135 | string path = GetProperDirectoryCapitalization(new DirectoryInfo(dir)); 136 | if (path.Length >= 2 && char.IsLetter(path[0]) && 137 | path[1] == ':' && path[2] == '\\') 138 | { 139 | path = char.ToUpper(path[0]) + path.Substring(1); 140 | } 141 | return path; 142 | } 143 | 144 | /// Gets the proper capitalization of a path so it looks nice. 145 | private static string GetProperDirectoryCapitalization(DirectoryInfo dirInfo) { 146 | DirectoryInfo parentDirInfo = dirInfo.Parent; 147 | if (null == parentDirInfo) 148 | return dirInfo.Name; 149 | return Path.Combine(GetProperDirectoryCapitalization(parentDirInfo), 150 | parentDirInfo.GetDirectories(dirInfo.Name)[0].Name); 151 | } 152 | 153 | /// Returns a collection of all files and subfiles in the directory. 154 | public static List GetAllFiles(string directory) { 155 | List files = new List(); 156 | AddAllFiles(files, directory); 157 | return files; 158 | } 159 | 160 | /// Returns a collection of all files and subfiles in the directory. 161 | public static IEnumerable EnumerateAllFiles(string directory, string pattern) { 162 | foreach (string file in Directory.EnumerateFiles(directory, pattern)) { 163 | yield return file; 164 | } 165 | foreach (string dir in Directory.EnumerateDirectories(directory)) { 166 | foreach (string file in EnumerateAllFiles(dir, pattern)) 167 | yield return file; 168 | } 169 | } 170 | 171 | public static bool IsDirectoryEmpty(string directory) { 172 | return !Directory.EnumerateFileSystemEntries(directory).Any(); 173 | } 174 | 175 | /// Returns a collection of all files and subfiles in the directory. 176 | public static void DeleteAllEmptyDirectories(string directory) { 177 | foreach (string dir in Directory.GetDirectories(directory)) { 178 | if (IsDirectoryEmpty(dir)) { 179 | Directory.Delete(dir); 180 | } 181 | else { 182 | DeleteAllEmptyDirectories(dir); 183 | if (IsDirectoryEmpty(dir)) 184 | Directory.Delete(dir); 185 | } 186 | } 187 | } 188 | 189 | 190 | //----------------------------------------------------------------------------- 191 | // Internal Methods 192 | //----------------------------------------------------------------------------- 193 | 194 | /// Adds all of the files and subfiles in the directory to the list. 195 | private static void AddAllFiles(List files, string directory) { 196 | foreach (string file in Directory.GetFiles(directory)) { 197 | files.Add(file); 198 | } 199 | foreach (string dir in Directory.GetDirectories(directory)) { 200 | AddAllFiles(files, dir); 201 | } 202 | } 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /GrisaiaExtractor/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("GrisaiaExtrator")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("GrisaiaExtrator")] 13 | [assembly: AssemblyCopyright("Copyright © Robert Jordan 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("b9e8ea56-874b-4ceb-a703-dca3a307a4d3")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.2.2")] 36 | [assembly: AssemblyFileVersion("1.0.2.2")] 37 | -------------------------------------------------------------------------------- /GrisaiaExtractor/Unused/Exkifint.Blowfish.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Runtime.CompilerServices; 5 | using System.Runtime.InteropServices; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace GrisaiaExtractor.Asmodean { 10 | public static partial class Exkifint { 11 | public unsafe partial class Blowfish { 12 | 13 | private const int MAXKEYBYTES = 56; 14 | private const int NPASS = 16; 15 | 16 | private uint[] PArray; 17 | private uint[,] SBoxes; 18 | 19 | public Blowfish() { 20 | PArray = new uint[18]; 21 | SBoxes = new uint[4,256]; 22 | } 23 | 24 | /*private uint S(aword x, int i) { 25 | return SBoxes[i, x.bytes[i]]; 26 | }*/ 27 | 28 | 29 | //[MethodImpl(MethodImplOptions.AggressiveInlining)] 30 | private uint bf_F(aword x) { 31 | return ((SBoxes[0, x.byte0] + SBoxes[1, x.byte1]) ^ SBoxes[2, x.byte2]) + SBoxes[3, x.byte3]; 32 | } 33 | 34 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 35 | private void ROUND(ref aword a, aword x, int n) { 36 | //a.dword ^= bf_F(x) ^ PArray[n]; 37 | a.dword ^= (((SBoxes[0, x.byte0] + SBoxes[1, x.byte1]) ^ SBoxes[2, x.byte2]) + SBoxes[3, x.byte3]) ^ PArray[n]; 38 | } 39 | 40 | //[MethodImpl(MethodImplOptions.AggressiveInlining)] 41 | private uint ROUND(aword x, int n) { 42 | //a.dword ^= bf_F(x) ^ PArray[n]; 43 | Count++; 44 | return (((SBoxes[0, x.byte0] + SBoxes[1, x.byte1]) ^ SBoxes[2, x.byte2]) + SBoxes[3, x.byte3]) ^ PArray[n]; 45 | } 46 | 47 | public static int Count = 0; 48 | private unsafe void Blowfish_encipher(uint* xl, uint* xr) { 49 | aword Xl = new aword(); 50 | aword Xr = new aword(); 51 | 52 | Xl.dword = *xl; 53 | Xr.dword = *xr; 54 | 55 | Xl.dword ^= PArray[0]; 56 | /*ROUND(ref Xr, Xl, 1); 57 | ROUND(ref Xl, Xr, 2); 58 | ROUND(ref Xr, Xl, 3); 59 | ROUND(ref Xl, Xr, 4); 60 | ROUND(ref Xr, Xl, 5); 61 | ROUND(ref Xl, Xr, 6); 62 | ROUND(ref Xr, Xl, 7); 63 | ROUND(ref Xl, Xr, 8); 64 | ROUND(ref Xr, Xl, 9); 65 | ROUND(ref Xl, Xr, 10); 66 | ROUND(ref Xr, Xl, 11); 67 | ROUND(ref Xl, Xr, 12); 68 | ROUND(ref Xr, Xl, 13); 69 | ROUND(ref Xl, Xr, 14); 70 | ROUND(ref Xr, Xl, 15); 71 | ROUND(ref Xl, Xr, 16);*/ 72 | Xr.dword ^= ROUND(Xl, 1); 73 | Xl.dword ^= ROUND(Xr, 2); 74 | Xr.dword ^= ROUND(Xl, 3); 75 | Xl.dword ^= ROUND(Xr, 4); 76 | Xr.dword ^= ROUND(Xl, 5); 77 | Xl.dword ^= ROUND(Xr, 6); 78 | Xr.dword ^= ROUND(Xl, 7); 79 | Xl.dword ^= ROUND(Xr, 8); 80 | Xr.dword ^= ROUND(Xl, 9); 81 | Xl.dword ^= ROUND(Xr, 10); 82 | Xr.dword ^= ROUND(Xl, 11); 83 | Xl.dword ^= ROUND(Xr, 12); 84 | Xr.dword ^= ROUND(Xl, 13); 85 | Xl.dword ^= ROUND(Xr, 14); 86 | Xr.dword ^= ROUND(Xl, 15); 87 | Xl.dword ^= ROUND(Xr, 16); 88 | Xr.dword ^= PArray[17]; 89 | 90 | *xr = Xl.dword; 91 | *xl = Xr.dword; 92 | } 93 | 94 | private unsafe void Blowfish_decipher(uint* xl, uint* xr) { 95 | aword Xl = new aword(); 96 | aword Xr = new aword(); 97 | 98 | Xl.dword = *xl; 99 | Xr.dword = *xr; 100 | 101 | Xl.dword ^= PArray[17]; 102 | /*ROUND(ref Xr, Xl, 16); 103 | ROUND(ref Xl, Xr, 15); 104 | ROUND(ref Xr, Xl, 14); 105 | ROUND(ref Xl, Xr, 13); 106 | ROUND(ref Xr, Xl, 12); 107 | ROUND(ref Xl, Xr, 11); 108 | ROUND(ref Xr, Xl, 10); 109 | ROUND(ref Xl, Xr, 9); 110 | ROUND(ref Xr, Xl, 8); 111 | ROUND(ref Xl, Xr, 7); 112 | ROUND(ref Xr, Xl, 6); 113 | ROUND(ref Xl, Xr, 5); 114 | ROUND(ref Xr, Xl, 4); 115 | ROUND(ref Xl, Xr, 3); 116 | ROUND(ref Xr, Xl, 2); 117 | ROUND(ref Xl, Xr, 1);*/ 118 | Xr.dword ^= ROUND(Xl, 16); 119 | Xl.dword ^= ROUND(Xr, 15); 120 | Xr.dword ^= ROUND(Xl, 14); 121 | Xl.dword ^= ROUND(Xr, 13); 122 | Xr.dword ^= ROUND(Xl, 12); 123 | Xl.dword ^= ROUND(Xr, 11); 124 | Xr.dword ^= ROUND(Xl, 10); 125 | Xl.dword ^= ROUND(Xr, 9); 126 | Xr.dword ^= ROUND(Xl, 8); 127 | Xl.dword ^= ROUND(Xr, 7); 128 | Xr.dword ^= ROUND(Xl, 6); 129 | Xl.dword ^= ROUND(Xr, 5); 130 | Xr.dword ^= ROUND(Xl, 4); 131 | Xl.dword ^= ROUND(Xr, 3); 132 | Xr.dword ^= ROUND(Xl, 2); 133 | Xl.dword ^= ROUND(Xr, 1); 134 | Xr.dword ^= PArray[0]; 135 | 136 | *xl = Xr.dword; 137 | *xr = Xl.dword; 138 | } 139 | 140 | // constructs the enctryption sieve 141 | public void Initialize(byte* key, int keybytes) { 142 | int i, j; 143 | uint data, datal, datar; 144 | aword temp = new aword(); 145 | 146 | // first fill arrays from data tables 147 | for (i = 0; i < 18; i++) 148 | PArray[i] = bf_P[i]; 149 | 150 | for (i = 0; i < 4; i++) { 151 | for (j = 0; j < 256; j++) 152 | SBoxes[i,j] = bf_S[i,j]; 153 | } 154 | 155 | 156 | j = 0; 157 | for (i = 0; i < NPASS + 2; ++i) { 158 | temp.dword = 0; 159 | temp.byte0 = key[j]; 160 | temp.byte1 = key[(j + 1) % keybytes]; 161 | temp.byte2 = key[(j + 2) % keybytes]; 162 | temp.byte3 = key[(j + 3) % keybytes]; 163 | data = temp.dword; 164 | PArray[i] ^= data; 165 | j = (j + 4) % keybytes; 166 | } 167 | 168 | datal = 0; 169 | datar = 0; 170 | 171 | for (i = 0; i < NPASS + 2; i += 2) { 172 | Blowfish_encipher(&datal, &datar); 173 | PArray[i] = datal; 174 | PArray[i + 1] = datar; 175 | } 176 | 177 | for (i = 0; i < 4; ++i) { 178 | for (j = 0; j < 256; j += 2) { 179 | Blowfish_encipher(&datal, &datar); 180 | SBoxes[i,j] = datal; 181 | SBoxes[i,j + 1] = datar; 182 | } 183 | } 184 | } 185 | 186 | // get output length, which must be even MOD 8 187 | private int GetOutputLength(int lInputLong) { 188 | int lVal; 189 | 190 | lVal = lInputLong % 8; // find out if uneven number of bytes atthe end 191 | if (lVal != 0) 192 | return lInputLong + 8 - lVal; 193 | else 194 | return lInputLong; 195 | } 196 | 197 | // Decode pIntput into pOutput. Input length in lSize. Inputbuffer and 198 | // output buffer can be the same, but be sure buffer length is even MOD8. 199 | public unsafe void Decode(byte[] pInputArray, byte[] pOutputArray, int lSize) { 200 | uint lCount; 201 | byte* pi, po; 202 | int i; 203 | bool SameDest = pInputArray == pOutputArray; 204 | 205 | fixed (byte* pInputFixed = pInputArray) 206 | fixed (byte* pOutputFixed = pOutputArray) { 207 | byte* pInput = pInputFixed; 208 | byte* pOutput = pOutputFixed; 209 | 210 | for (lCount = 0; lCount < lSize; lCount += 8) { 211 | if (SameDest) // if encoded data is being written into inputbuffer 212 | { 213 | Blowfish_decipher((uint*) pInput, 214 | (uint*) (pInput + 4)); 215 | pInput += 8; 216 | } 217 | else // output buffer not equal to inputbuffer 218 | { // so copy input to output before decoding 219 | pi = pInput; 220 | po = pOutput; 221 | for (i = 0; i < 8; i++) 222 | *po++ = *pi++; 223 | Blowfish_decipher((uint*) pOutput, 224 | (uint*) (pOutput + 4)); 225 | pInput += 8; 226 | pOutput += 8; 227 | } 228 | } 229 | } 230 | } 231 | 232 | 233 | public void Set_Key(byte* key, int keybytes) { 234 | Initialize(key, keybytes); 235 | } 236 | 237 | public void Decrypt(byte[] pInput, int lSize) { 238 | if (lSize != GetOutputLength(lSize)) 239 | throw new Exception("Input len != Output len"); 240 | 241 | byte[] pOutput = new byte[lSize]; 242 | Decode(pInput, pOutput, lSize); 243 | 244 | Array.Copy(pOutput, pInput, lSize); 245 | } 246 | 247 | [StructLayout(LayoutKind.Explicit, Pack = 1, Size = 4)] 248 | private struct aword { 249 | [FieldOffset(0)] 250 | public uint dword; 251 | [FieldOffset(0)] 252 | public byte byte3; 253 | [FieldOffset(1)] 254 | public byte byte2; 255 | [FieldOffset(2)] 256 | public byte byte1; 257 | [FieldOffset(3)] 258 | public byte byte0; 259 | 260 | /*public byte byte3 { 261 | get { return (byte) (dword & 0xFF); } 262 | set { dword = (dword & 0xFFFFFF00) ^ value; } 263 | } 264 | public byte byte2 { 265 | get { return (byte) ((dword >> 8) & 0xFF); } 266 | set { dword = (dword & 0xFFFF00FF) ^ (uint) (value << 8); } 267 | } 268 | public byte byte1 { 269 | get { return (byte) ((dword >> 16) & 0xFF); } 270 | set { dword = (dword & 0xFF00FFFF) ^ (uint) (value << 16); } 271 | } 272 | public byte byte0 { 273 | get { return (byte) ((dword >> 24) & 0xFF); } 274 | set { dword = (dword & 0x00FFFFFF) ^ (uint) (value << 24); } 275 | }*/ 276 | } 277 | } 278 | } 279 | } 280 | -------------------------------------------------------------------------------- /GrisaiaExtractor/Unused/Hgx2png.BitBuffer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace GrisaiaExtractor.Asmodean { 8 | public static partial class Hgx2png { 9 | private class BitBuffer { 10 | 11 | private byte[] buffer; 12 | private int index; 13 | 14 | public BitBuffer(byte[] buffer) { 15 | this.buffer = buffer; 16 | this.index = 0; 17 | } 18 | 19 | public bool GetBit() { 20 | return ((buffer[index / 8] >> (index++ % 8)) & 1) == 1; 21 | } 22 | 23 | // Didn't expect to see this in the wild... 24 | public uint GetEliasGammaValue() { 25 | uint value = 0; 26 | int digits = 0; 27 | 28 | while (!GetBit()) 29 | digits++; 30 | 31 | value = 1U << digits; 32 | 33 | while (digits-- != 0) { 34 | if (GetBit()) 35 | value |= 1U << digits; 36 | } 37 | 38 | return value; 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /GrisaiaExtractor/zlib1.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trigger-segfault/GrisaiaExtractor/fdd6e8339fd4e69a0c6fc92acb7aa57000b6b81c/GrisaiaExtractor/zlib1.dll -------------------------------------------------------------------------------- /GrisaiaExtractorConsole/App.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trigger-segfault/GrisaiaExtractor/fdd6e8339fd4e69a0c6fc92acb7aa57000b6b81c/GrisaiaExtractorConsole/App.ico -------------------------------------------------------------------------------- /GrisaiaExtractorConsole/AsciiImage.cs: -------------------------------------------------------------------------------- 1 | using GrisaiaExtractor.Extensions; 2 | using System; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace GrisaiaExtractorConsole { 8 | public class AsciiImage { 9 | public struct Pixel { 10 | public static readonly Encoding ConsoleEncoding = 11 | Encoding.GetEncoding("Windows-1252"); 12 | 13 | public char Character; 14 | public ConsoleColor Foreground; 15 | 16 | public Pixel(char character, ConsoleColor foreground) { 17 | Character = character; 18 | Foreground = foreground; 19 | } 20 | 21 | public Pixel(byte character, byte foreground) { 22 | Character = ConsoleEncoding.GetChar(character); 23 | Foreground = (ConsoleColor) foreground; 24 | } 25 | } 26 | 27 | public Pixel[,] Pixels { get; private set; } 28 | 29 | public int Width => Pixels.GetLength(0); 30 | public int Height => Pixels.GetLength(1); 31 | 32 | public static AsciiImage FromStream(Stream stream) { 33 | AsciiImage image = new AsciiImage(); 34 | BinaryReader reader = new BinaryReader(stream); 35 | 36 | int width = reader.ReadInt32(); 37 | int height = reader.ReadInt32(); 38 | image.Pixels = new Pixel[width, height]; 39 | for (int y = 0; y < height; y++) { 40 | for (int x = 0; x < width; x++) { 41 | image.Pixels[x, y] = new Pixel( 42 | reader.ReadByte(), reader.ReadByte()); 43 | } 44 | } 45 | 46 | return image; 47 | } 48 | 49 | public void Draw() { 50 | ConsoleColor oldForeground = Console.ForegroundColor; 51 | 52 | // Make sure we start on a brand-spanking-new line 53 | if (Console.CursorLeft > 0) 54 | Console.WriteLine(); 55 | 56 | // Optimized by writing to the console as few times as possible 57 | int bufferWidth = Console.BufferWidth; 58 | string currentLine = ""; 59 | for (int y = 0; y < Height; y++) { 60 | for (int x = 0; x < Width && x < bufferWidth; x++) { 61 | if (Pixels[x, y].Foreground != Console.ForegroundColor) { 62 | // We've reached a few color, gotta write the current line 63 | // (Check to make sure this isn't the first pixel 64 | if (currentLine.Length > 0) { 65 | Console.Write(currentLine); 66 | currentLine = ""; 67 | } 68 | // Set the new foreground color for the next line 69 | Console.ForegroundColor = Pixels[x, y].Foreground; 70 | } 71 | currentLine += Pixels[x, y].Character; 72 | } 73 | 74 | // Keep drawing the current string onto the next line 75 | // (If we don't automatically go to the next line due to wrapping) 76 | if ((Console.CursorLeft + currentLine.Length) % bufferWidth != 0) 77 | currentLine += Environment.NewLine; 78 | } 79 | // Write the remaining line 80 | if (currentLine.Length > 0) 81 | Console.Write(currentLine); 82 | 83 | Console.ForegroundColor = oldForeground; 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /GrisaiaExtractorConsole/GrisaiaExtractorConsole.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {1B2D824A-DD0D-4019-B234-54E5543B7A42} 8 | Exe 9 | GrisaiaExtractorConsole 10 | GrisaiaExtract 11 | v4.6.1 12 | 512 13 | true 14 | 15 | 16 | x86 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | TRACE;DEBUG 22 | prompt 23 | 4 24 | 25 | 26 | x86 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | App.ico 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | {b9e8ea56-874b-4ceb-a703-dca3a307a4d3} 66 | GrisaiaExtractor 67 | 68 | 69 | {8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942} 70 | asmodean 71 | false 72 | Content 73 | PreserveNewest 74 | True 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /GrisaiaExtractorConsole/Ini/IniEnums.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace GrisaiaExtractorConsole.Ini { 8 | /// The available property assignment styles for ini documents. 9 | public enum IniAssignmentStyle { 10 | /// Uses "=" for ini property assignment. 11 | Equals, 12 | /// Uses ":" for ini property assignment. 13 | Colon, 14 | /// Uses " = " for ini property assignment. 15 | EqualsSpaced, 16 | /// Uses " : " for ini property assignment. 17 | ColonSpaced, 18 | } 19 | 20 | /// The available comment styles for ini documents. 21 | public enum IniCommentStyle { 22 | /// Uses ";" as the ini comment indicator. 23 | Semicolon, 24 | /// Uses "#" as the ini comment indicator. 25 | Pound, 26 | /// Uses "!" as the ini comment indicator. 27 | Exclamation, 28 | /// Uses "; " as the ini comment indicator. 29 | SemicolonSpaced, 30 | /// Uses "# " as the ini comment indicator. 31 | PoundSpaced, 32 | /// Uses "! " as the ini comment indicator. 33 | ExclamationSpaced, 34 | } 35 | 36 | /// The formats an enum can be stored in. 37 | public enum EnumFormat { 38 | /// The enum is stored in string form. 39 | String, 40 | /// The enum is stored in integer form. 41 | Int, 42 | } 43 | 44 | /// Extensions for the ini enums. 45 | public static class IniEnumExtensions { 46 | /// Gets the string representation of the ini assignment style. 47 | public static string GetString(this IniAssignmentStyle assignmentStyle) { 48 | switch (assignmentStyle) { 49 | case IniAssignmentStyle.Equals: return "="; 50 | case IniAssignmentStyle.Colon: return ":"; 51 | case IniAssignmentStyle.EqualsSpaced: return " = "; 52 | case IniAssignmentStyle.ColonSpaced: return " : "; 53 | } 54 | return ""; 55 | } 56 | 57 | /// Gets the string representation of the ini comment style. 58 | public static string GetString(this IniCommentStyle commentStyle) { 59 | switch (commentStyle) { 60 | case IniCommentStyle.Semicolon: return ";"; 61 | case IniCommentStyle.Pound: return "#"; 62 | case IniCommentStyle.Exclamation: return "!"; 63 | case IniCommentStyle.SemicolonSpaced: return "; "; 64 | case IniCommentStyle.PoundSpaced: return "# "; 65 | case IniCommentStyle.ExclamationSpaced: return "! "; 66 | } 67 | return ""; 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /GrisaiaExtractorConsole/Ini/IniProperty.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace GrisaiaExtractorConsole.Ini { 8 | public class IniProperty { 9 | 10 | //----------------------------------------------------------------------------- 11 | // Members 12 | //----------------------------------------------------------------------------- 13 | 14 | /// The name of the property. 15 | private string name; 16 | /// The comments for the property. 17 | private string comments; 18 | /// The value of the property. 19 | private string value; 20 | 21 | // Save Settings 22 | /// True if the property uses quotes to format its value. 23 | private bool useQuotes; 24 | 25 | 26 | //----------------------------------------------------------------------------- 27 | // Constructor 28 | //----------------------------------------------------------------------------- 29 | 30 | /// Constructs the ini property with the specified name, value, and 31 | /// settings. 32 | public IniProperty(string name, string value = "", string comments = "", 33 | bool useQuotes = false) 34 | { 35 | this.name = name; 36 | this.comments = comments; 37 | this.value = value; 38 | this.useQuotes = useQuotes; 39 | } 40 | 41 | 42 | //----------------------------------------------------------------------------- 43 | // Get Accessors 44 | //----------------------------------------------------------------------------- 45 | 46 | /// Gets the value of the property as an enum. 47 | public TEnum GetEnum(EnumFormat format = EnumFormat.String) 48 | where TEnum : struct, IConvertible 49 | { 50 | if (format == EnumFormat.String) { 51 | TEnum result; 52 | Enum.TryParse(value, out result); 53 | return result; 54 | } 55 | else { 56 | return (TEnum) Enum.ToObject(typeof(TEnum), GetInt()); 57 | } 58 | } 59 | 60 | /// Gets the string value of the property. 61 | public string GetString() { 62 | return value; 63 | } 64 | 65 | /// Gets the integer value of the property. 66 | public int GetInt() { 67 | int result; 68 | int.TryParse(value, out result); 69 | return result; 70 | } 71 | 72 | /// Gets the float value of the property. 73 | public float GetFloat() { 74 | float result; 75 | float.TryParse(value, out result); 76 | return result; 77 | } 78 | 79 | /// Get the boolean value of the property. 80 | public bool GetBool() { 81 | if (string.Compare(value, "true", true) == 0 || 82 | string.Compare(value, "1") == 0) 83 | { 84 | return true; 85 | } 86 | return false; 87 | } 88 | 89 | 90 | //----------------------------------------------------------------------------- 91 | // Try Get Accessors 92 | //----------------------------------------------------------------------------- 93 | 94 | /// Trys to get the value of the property as an enum. 95 | public bool TryGetEnum(out TEnum result, 96 | EnumFormat format = EnumFormat.String) 97 | where TEnum : struct, IConvertible 98 | { 99 | try { 100 | if (format == EnumFormat.String) 101 | result = (TEnum) Enum.Parse(typeof(TEnum), value); 102 | else 103 | result = (TEnum) Enum.ToObject(typeof(TEnum), GetInt()); 104 | return true; 105 | } 106 | catch { 107 | result = Activator.CreateInstance(); 108 | return false; 109 | } 110 | } 111 | 112 | /// Trys to get the integer value of the property. 113 | public bool TryGetInt(out int result) { 114 | return int.TryParse(value, out result); 115 | } 116 | 117 | /// Trys to get the float value of the property. 118 | public bool TryGetFloat(out float result) { 119 | return float.TryParse(value, out result); 120 | } 121 | 122 | /// Trys to get the boolean value of the property. 123 | public bool TryGetBool(out bool result) { 124 | if (string.Compare(value, "true", true) == 0 || 125 | string.Compare(value, "1") == 0) 126 | { 127 | result = true; 128 | return true; 129 | } 130 | if (string.Compare(value, "false", true) == 0 || 131 | string.Compare(value, "0") == 0) 132 | { 133 | result = false; 134 | return true; 135 | } 136 | result = false; 137 | return false; 138 | } 139 | 140 | 141 | //----------------------------------------------------------------------------- 142 | // Mutators 143 | //----------------------------------------------------------------------------- 144 | 145 | /// Set the value of the property as an enum. 146 | public void SetEnum(TEnum value, EnumFormat format = EnumFormat.String) 147 | where TEnum : struct, IConvertible 148 | { 149 | if (format == EnumFormat.String) 150 | this.value = value.ToString(); 151 | else 152 | this.value = ((int)(object) value).ToString(); 153 | } 154 | 155 | /// Sets the string value of the property. 156 | public void SetString(string value) { 157 | this.value = value; 158 | } 159 | 160 | /// Sets the integer value of the property. 161 | public void SetInt(int value) { 162 | this.value = value.ToString(); 163 | } 164 | 165 | /// Sets the float value of the property. 166 | public void SetFloat(float value) { 167 | this.value = value.ToString(); 168 | } 169 | 170 | /// Sets the boolean value of the property. 171 | public void SetBool(bool value) { 172 | this.value = value.ToString(); 173 | } 174 | 175 | /// Sets the object value of the property. 176 | public void SetObject(object value) { 177 | this.value = value.ToString(); 178 | } 179 | 180 | 181 | //----------------------------------------------------------------------------- 182 | // Properties 183 | //----------------------------------------------------------------------------- 184 | 185 | /// Gets the name of the property. 186 | public string Name { 187 | get { return name; } 188 | } 189 | 190 | /// Gets or sets the comments for the property. 191 | public string Comments { 192 | get { return comments; } 193 | set { comments = value; } 194 | } 195 | 196 | /// Gets or sets the value of the property. 197 | public string Value { 198 | get { return value; } 199 | set { this.value = value; } 200 | } 201 | 202 | /// Gets or sets if the property uses quotes to format its value. 203 | public bool UseQuotes { 204 | get { return useQuotes; } 205 | set { useQuotes = value; } 206 | } 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /GrisaiaExtractorConsole/Ini/IniSection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace GrisaiaExtractorConsole.Ini { 9 | public class IniSection : IEnumerable { 10 | 11 | //----------------------------------------------------------------------------- 12 | // Members 13 | //----------------------------------------------------------------------------- 14 | 15 | /// The name of the section. 16 | private string name; 17 | /// The description of the section. 18 | private string comments; 19 | /// The collection of properties in the section. 20 | private Dictionary properties; 21 | 22 | 23 | //----------------------------------------------------------------------------- 24 | // Constructor 25 | //----------------------------------------------------------------------------- 26 | 27 | /// Constructs the ini section with the specified name and optional 28 | /// comments. 29 | public IniSection(string name, string comments = "") { 30 | this.name = name; 31 | this.comments = comments; 32 | this.properties = new Dictionary(); 33 | } 34 | 35 | 36 | //----------------------------------------------------------------------------- 37 | // IEnumerable 38 | //----------------------------------------------------------------------------- 39 | 40 | /// Gets the enumerator for the properties in the section. 41 | public IEnumerator GetEnumerator() { 42 | return properties.Values.GetEnumerator(); 43 | } 44 | 45 | /// Gets the enumerator for the properties in the section. 46 | IEnumerator IEnumerable.GetEnumerator() { 47 | return properties.Values.GetEnumerator(); 48 | } 49 | 50 | 51 | //----------------------------------------------------------------------------- 52 | // Accessors 53 | //----------------------------------------------------------------------------- 54 | 55 | /// Gets the property in the section with the specified name. 56 | public IniProperty Get(string propertyName, bool returnDefault = true) { 57 | IniProperty property; 58 | properties.TryGetValue(propertyName, out property); 59 | if (property == null && returnDefault) 60 | return new IniProperty(propertyName, ""); 61 | return property; 62 | } 63 | 64 | /// Returns true if this section contains the specified property. 65 | public bool Contains(IniProperty property) { 66 | return properties.ContainsKey(property.Name); 67 | } 68 | 69 | /// Returns true if this section contains a property with the 70 | /// specified name. 71 | public bool Contains(string propertyName) { 72 | return properties.ContainsKey(propertyName); 73 | } 74 | 75 | /// Returns true if the section has any properties. 76 | public bool Any() { 77 | return properties.Any(); 78 | } 79 | 80 | 81 | //----------------------------------------------------------------------------- 82 | // Mutators 83 | //----------------------------------------------------------------------------- 84 | 85 | /// Adds the property to the section. 86 | public IniProperty Add(IniProperty property) { 87 | properties[property.Name] = property; 88 | return property; 89 | } 90 | 91 | /// Adds a new property to the section. 92 | public IniProperty Add(string propertyName, string value = "", 93 | string comments = "", bool useQuotes = false) 94 | { 95 | return Add(new IniProperty(propertyName, value, comments, useQuotes)); 96 | } 97 | 98 | /// Removes the property from the section. 99 | public void Remove(IniProperty property) { 100 | properties.Remove(property.Name); 101 | } 102 | 103 | /// Removes the property with the specified name from the section. 104 | public void Remove(string propertyName) { 105 | properties.Remove(propertyName); 106 | } 107 | 108 | /// Removes all of the properties from the section. 109 | public void Clear() { 110 | properties.Clear(); 111 | } 112 | 113 | 114 | //----------------------------------------------------------------------------- 115 | // Get Property Accessors 116 | //----------------------------------------------------------------------------- 117 | 118 | /// Gets the value of the property as an enum. 119 | public TEnum GetEnum(string propertyName, 120 | EnumFormat format = EnumFormat.String) 121 | where TEnum : struct, IConvertible 122 | { 123 | return Get(propertyName).GetEnum(format); 124 | } 125 | 126 | /// Gets the string value of the property. 127 | public string GetString(string propertyName) { 128 | return Get(propertyName).GetString(); 129 | } 130 | 131 | /// Gets the integer value of the property. 132 | public int GetInt(string propertyName) { 133 | return Get(propertyName).GetInt(); 134 | } 135 | 136 | /// Gets the float value of the property. 137 | public float GetFloat(string propertyName) { 138 | return Get(propertyName).GetFloat(); 139 | } 140 | 141 | /// Get the boolean value of the property. 142 | public bool GetBool(string propertyName) { 143 | return Get(propertyName).GetBool(); 144 | } 145 | 146 | 147 | //----------------------------------------------------------------------------- 148 | // Try Get Property Accessors 149 | //----------------------------------------------------------------------------- 150 | 151 | /// Trys to get the value of the property as an enum. 152 | public bool TryGetEnum(string propertyName, out TEnum result, 153 | EnumFormat format = EnumFormat.String) 154 | where TEnum : struct, IConvertible 155 | { 156 | return Get(propertyName).TryGetEnum(out result); 157 | } 158 | 159 | /// Trys to get the integer value of the property. 160 | public bool TryGetInt(string propertyName, out int result) { 161 | return Get(propertyName).TryGetInt(out result); 162 | } 163 | 164 | /// Trys to get the float value of the property. 165 | public bool TryGetFloat(string propertyName, out float result) { 166 | return Get(propertyName).TryGetFloat(out result); 167 | } 168 | 169 | /// Trys to get the boolean value of the property. 170 | public bool TryGetBool(string propertyName, out bool result) { 171 | return Get(propertyName).TryGetBool(out result); 172 | } 173 | 174 | 175 | //----------------------------------------------------------------------------- 176 | // Set Property Mutators 177 | //----------------------------------------------------------------------------- 178 | 179 | /// Set the value of the property as an enum. 180 | public void SetEnum(string propertyName, TEnum value, 181 | EnumFormat format = EnumFormat.String) 182 | where TEnum : struct, IConvertible 183 | { 184 | Get(propertyName).SetEnum(value, format); 185 | } 186 | 187 | /// Sets the string value of the property. 188 | public void SetString(string propertyName, string value) { 189 | Get(propertyName).SetString(value); 190 | } 191 | 192 | /// Sets the integer value of the property. 193 | public void SetInt(string propertyName, int value) { 194 | Get(propertyName).SetInt(value); 195 | } 196 | 197 | /// Sets the float value of the property. 198 | public void SetFloat(string propertyName, float value) { 199 | Get(propertyName).SetFloat(value); 200 | } 201 | 202 | /// Sets the boolean value of the property. 203 | public void SetBool(string propertyName, bool value) { 204 | Get(propertyName).SetBool(value); 205 | } 206 | 207 | /// Sets the object value of the property. 208 | public void SetObject(string propertyName, object value) { 209 | Get(propertyName).SetObject(value); 210 | } 211 | 212 | 213 | //----------------------------------------------------------------------------- 214 | // Properties 215 | //----------------------------------------------------------------------------- 216 | 217 | /// Gets the name of the section. 218 | public string Name { 219 | get { return name; } 220 | } 221 | 222 | /// Gets or sets the description of the section. 223 | public string Comments { 224 | get { return comments; } 225 | set { comments = value; } 226 | } 227 | 228 | /// Gets the number of properties in the section. 229 | public int Count { 230 | get { return properties.Count; } 231 | } 232 | } 233 | } 234 | -------------------------------------------------------------------------------- /GrisaiaExtractorConsole/Ini/TypeHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Reflection; 6 | 7 | namespace GrisaiaExtractorConsole.Ini { 8 | /// An exception thrown when a type could not be found. 9 | public class MissingTypeException : Exception { 10 | /// Constructs the missing type exception for the specified type. 11 | public MissingTypeException(string typeName) 12 | : base("Type '" + typeName + "' could not be found!") { } 13 | } 14 | 15 | /// An exception thrown when a type does not inherit from the 16 | /// required type. 17 | public class NoInheritanceException : Exception { 18 | /// Constructs the does not inherit exception for the specified types. 19 | public NoInheritanceException(Type baseType, Type type) 20 | : base("Type '" + type.Name + "' does not inherit '" + 21 | baseType.Name + "'!") { } 22 | } 23 | 24 | /// A static class for helpers with object types 25 | public static class TypeHelper { 26 | 27 | //----------------------------------------------------------------------------- 28 | // Get Inheritance 29 | //----------------------------------------------------------------------------- 30 | 31 | /// Returns a list of types that Type inherits from. 32 | public static Type[] GetInheritance(Type type, bool baseTypesFirst) { 33 | return GetInheritance(typeof(object), type, baseTypesFirst); 34 | } 35 | 36 | /// Returns a list of types that Type inherits from until BaseType. 37 | public static Type[] GetInheritance(Type type, bool baseTypesFirst) { 38 | return GetInheritance(typeof(BaseType), type, baseTypesFirst); 39 | } 40 | 41 | /// Returns a list of types that Type inherits from until BaseType. 42 | /// Type does not inherit base type. 43 | public static Type[] GetInheritance(Type baseType, Type type, 44 | bool baseTypesFirst) 45 | { 46 | if (baseType == null || type == null) 47 | return new Type[0]; 48 | if (!baseType.IsAssignableFrom(type)) 49 | throw new ArgumentException("Type does not inherit from BaseType!"); 50 | List types = new List(); 51 | while (type != null) { 52 | if (baseTypesFirst) 53 | types.Insert(0, type); 54 | else 55 | types.Add(type); 56 | if (type.Equals(baseType)) 57 | break; 58 | type = type.BaseType; 59 | } 60 | return types.ToArray(); 61 | } 62 | 63 | /// Gets the type's most-extended interface that inherits from the 64 | /// base interface. Returns null if no interface was found. 65 | public static Type GetExtendedInterface(Type type, Type baseInterface) { 66 | Type nextInterface = baseInterface; 67 | bool found = false; 68 | foreach (Type interfaceType in type.GetInterfaces()) { 69 | if (nextInterface.IsAssignableFrom(interfaceType)) { 70 | nextInterface = interfaceType; 71 | found = true; 72 | } 73 | } 74 | return (found ? nextInterface : null); 75 | } 76 | 77 | /// Gets the type's most-extended interface that inherits from the 78 | /// base interface. Returns null if no interface was found. 79 | public static Type GetExtendedInterface(Type type) { 80 | return GetExtendedInterface(type, typeof(BaseInterface)); 81 | } 82 | 83 | 84 | //----------------------------------------------------------------------------- 85 | // Type Has Base 86 | //----------------------------------------------------------------------------- 87 | 88 | /// Returns true if the specified type implements the specified base. 89 | public static bool TypeHasBase(Type type) { 90 | return TypeHasBase(typeof(BaseType), type); 91 | } 92 | 93 | /// Returns true if the specified type implements the specified base. 94 | public static bool TypeHasBase(Type baseType, Type type) { 95 | if (baseType == null || type == null) 96 | return false; 97 | return baseType.IsAssignableFrom(type); 98 | } 99 | 100 | 101 | //----------------------------------------------------------------------------- 102 | // Find Type With Base 103 | //----------------------------------------------------------------------------- 104 | 105 | /// Returns the type with the specified name. 106 | /// The type could not be found. 107 | /// The type does not inherit base type. 108 | public static Type FindTypeWithBase(string typeName, 109 | bool ignoreCase, params Assembly[] assemblies) 110 | { 111 | return FindTypeWithBase(typeof(BaseType), typeName, ignoreCase, 112 | assemblies); 113 | } 114 | 115 | /// Returns the type with the specified name. 116 | /// Returns null if the type was not found or does not inheritf base type. 117 | public static Type FindTypeWithBaseSafe(string typeName, 118 | bool ignoreCase, params Assembly[] assemblies) 119 | { 120 | return FindTypeWithBaseSafe(typeof(BaseType), typeName, ignoreCase, 121 | assemblies); 122 | } 123 | 124 | /// Returns the type with the specified name. 125 | /// The type could not be found. 126 | /// The type does not inherit base type. 127 | public static Type FindTypeWithBase(Type baseType, string typeName, 128 | bool ignoreCase, params Assembly[] assemblies) 129 | { 130 | Type type = FindType(typeName, ignoreCase, assemblies); 131 | if (!baseType.IsAssignableFrom(type)) 132 | throw new NoInheritanceException(baseType, type); 133 | return type; 134 | } 135 | 136 | /// Returns the type with the specified name. 137 | /// Returns null if the type was not found or does not inheritf base type. 138 | public static Type FindTypeWithBaseSafe(Type baseType, string typeName, 139 | bool ignoreCase, params Assembly[] assemblies) 140 | { 141 | Type type = FindTypeSafe(typeName, ignoreCase, assemblies); 142 | if (type != null && !baseType.IsAssignableFrom(type)) 143 | throw new NoInheritanceException(baseType, type); 144 | return type; 145 | } 146 | 147 | 148 | //----------------------------------------------------------------------------- 149 | // Find Type 150 | //----------------------------------------------------------------------------- 151 | 152 | /// Returns the type with the specified name. Throws an exception 153 | /// if the type could not be found. 154 | /// The type could not be found. 155 | public static Type FindType(string typeName, bool ignoreCase, 156 | params Assembly[] assemblies) 157 | { 158 | Type type = FindTypeSafe(typeName, ignoreCase, assemblies); 159 | if (type == null) 160 | throw new MissingTypeException(typeName); 161 | return type; 162 | } 163 | 164 | /// Returns the type with the specified name. Returns null if the 165 | /// type could not be found. 166 | public static Type FindTypeSafe(string typeName, bool ignoreCase, 167 | params Assembly[] assemblies) { 168 | StringComparison comparision = StringComparison.Ordinal; 169 | if (ignoreCase) 170 | comparision = StringComparison.OrdinalIgnoreCase; 171 | 172 | // Check the listed assemblies 173 | Type type = null; 174 | foreach (Assembly assembly in assemblies) { 175 | type = assembly.GetTypes() 176 | .FirstOrDefault(t => t.Name.Equals(typeName, comparision)); 177 | if (type != null) 178 | return type; 179 | } 180 | 181 | return null; 182 | } 183 | 184 | 185 | //----------------------------------------------------------------------------- 186 | // Get Default Value 187 | //----------------------------------------------------------------------------- 188 | 189 | /// Gets the default value of the type. 190 | /// Runtime equivalent of default(type). 191 | public static T GetDefaultValue() { 192 | return (T) GetDefaultValue(typeof(T)); 193 | } 194 | 195 | /// Gets the default value of the type. 196 | /// Runtime equivalent of default(type). 197 | public static object GetDefaultValue(Type type) { 198 | if (type.IsValueType) 199 | return Activator.CreateInstance(type); 200 | return null; 201 | } 202 | 203 | 204 | //----------------------------------------------------------------------------- 205 | // Converting 206 | //----------------------------------------------------------------------------- 207 | 208 | /// Converts the value to the specified type using the type's 209 | /// type converter. 210 | public static object ConvertFrom(Type type, object value) { 211 | var converter = TypeDescriptor.GetConverter(type); 212 | return converter.ConvertFrom(value); 213 | } 214 | 215 | /// Converts the value to the specified type using the value's 216 | /// type converter. 217 | public static object ConvertTo(Type type, object value) { 218 | var converter = TypeDescriptor.GetConverter(value.GetType()); 219 | return converter.ConvertTo(value, type); 220 | } 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /GrisaiaExtractorConsole/Program.Classes.cs: -------------------------------------------------------------------------------- 1 | using GrisaiaExtractor; 2 | using GrisaiaExtractor.Extensions; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace GrisaiaExtractorConsole { 11 | static partial class Program { 12 | public struct IntArgs { 13 | public string InputDir { get; set; } 14 | public string OutputDir { get; set; } 15 | public string OutputDirAfter { get; set; } 16 | public string IntFile { get; set; } 17 | public Game Game { get; set; } 18 | 19 | public bool IsImage { 20 | get { 21 | return Path.GetFileNameWithoutExtension(IntFile).ToLower() 22 | .StartsWith("image"); 23 | } 24 | } 25 | } 26 | 27 | public struct Hg3Args { 28 | public string InputDir { get; set; } 29 | public string InputDirAfter { get; set; } 30 | public string OutputDir { get; set; } 31 | public string OutputDirAfter { get; set; } 32 | public string Pattern { get; set; } 33 | public Hg3Sorting Sorting { get; set; } 34 | public bool StopOnError { get; set; } 35 | public string ContinueFile { get; set; } 36 | public Game Game { get; set; } 37 | } 38 | 39 | public struct PngArgs { 40 | public string ResortDir { get; set; } 41 | public string ResortDirAfter { get; set; } 42 | public Game Game { get; set; } 43 | } 44 | 45 | private class LogInfo : IDisposable { 46 | public DateTime StartTime { get; } = DateTime.UtcNow; 47 | public int GamesComplete { get; set; } 48 | public HashSet GamesWithErrors { get; } = new HashSet(); 49 | public HashSet GamesFailed { get; } = new HashSet(); 50 | 51 | public int OperationsComplete { get; set; } 52 | 53 | 54 | public TimeSpan Ellapsed => DateTime.UtcNow - StartTime; 55 | 56 | public StreamWriter LogWriter { get; } 57 | public int LastOperationLogged { get; set; } 58 | 59 | public void WriteLine(string line) => LogWriter.WriteLine(line); 60 | public void WriteLine() => LogWriter.WriteLine(); 61 | public void Write(string text) => LogWriter.Write(text); 62 | 63 | public LogInfo() { 64 | string path = PathHelper.CombineExecutable($"{PathHelper.ExeName}.log"); 65 | var stream = new FileStream(path, FileMode.Append); 66 | LogWriter = new StreamWriter(stream) { 67 | AutoFlush = true, 68 | }; 69 | } 70 | 71 | public void Dispose() { 72 | LogWriter.Close(); 73 | } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /GrisaiaExtractorConsole/Program.Input.cs: -------------------------------------------------------------------------------- 1 | using GrisaiaExtractor; 2 | using GrisaiaExtractor.Extensions; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace GrisaiaExtractorConsole { 11 | static partial class Program { 12 | private static Game ReadGame(bool allowNone = false) { 13 | do { 14 | List games = Locator.LocateGames(out bool newPaths, true); 15 | if (newPaths) { 16 | settings.Save(); 17 | } 18 | int index = 1; 19 | foreach (Game game in games) { 20 | Console.Write($"{index}) "); 21 | game.WriteLine(settings.General.UseJapaneseNames); 22 | /*Console.Write($"{index}) {game.Game.JPName}"); 23 | if (game.Path == null) 24 | Console.Write(": [NOT FOUND]"); 25 | Console.WriteLine();*/ 26 | index++; 27 | } 28 | Console.WriteLine($"{index}) {Game.All.Name()}"); 29 | if (allowNone) 30 | Console.WriteLine("0) None"); 31 | Console.Write("Choice: "); 32 | if (!int.TryParse(ReadLine(), out index) || index < 0) 33 | WriteError("Input is not a valid index!"); 34 | else if ((!allowNone && index == 0) || index - 1 > games.Count) 35 | WriteError("Input index is out of bounds!"); 36 | else if (index == 0) 37 | return null; 38 | else if (index - 1 == games.Count) { 39 | Console.WriteLine(); 40 | Console.WriteLine("All located games will be ripped and each " + 41 | "game will use a directory with its name."); 42 | Console.WriteLine(); 43 | return Game.All; 44 | } 45 | else 46 | return games[index - 1]; 47 | } while (true); 48 | } 49 | 50 | private static IntArgs RequestExtractIntArgs(Game game) { 51 | IntArgs args = new IntArgs() { 52 | Game = game, 53 | }; 54 | if (game != null) 55 | Console.WriteLine($"Extract {game.Name()} Int Archive:"); 56 | else 57 | Console.WriteLine($"Extract Int Archive:"); 58 | 59 | bool parseSuccess; 60 | 61 | if (game != Game.All) { 62 | do { 63 | Console.Write("Input Directory: "); 64 | if (game.Path != null) 65 | WriteWatermark(""); 66 | args.InputDir = ReadDirectory(game.Path, out parseSuccess); 67 | } while (!parseSuccess); 68 | } 69 | 70 | string defOutputDir = Path.Combine(game.Name(), settings.Directories.IntDirectory); 71 | do { 72 | if (game == Game.All) { 73 | defOutputDir = "."; 74 | Console.Write("Output Directory (Before game name): "); 75 | WriteWatermark(""); 76 | } 77 | else { 78 | Console.Write("Output Directory: "); 79 | WriteWatermark(defOutputDir); 80 | } 81 | args.OutputDir = ReadDirectory(defOutputDir, out parseSuccess); 82 | } while (!parseSuccess); 83 | 84 | if (game == Game.All) { 85 | defOutputDir = settings.Directories.IntDirectory; 86 | do { 87 | Console.Write("Output Directory (After game name): "); 88 | WriteWatermark(defOutputDir); 89 | args.OutputDirAfter = ReadRelativePath(defOutputDir, out parseSuccess); 90 | } while (!parseSuccess); 91 | } 92 | 93 | do { 94 | Console.Write("Int File: "); 95 | WriteWatermark("image*.int"); 96 | args.IntFile = ReadPattern("image*.int", out parseSuccess); 97 | } while (!parseSuccess); 98 | if (!args.IntFile.EndsWith(".int", StringComparison.OrdinalIgnoreCase) && 99 | !args.IntFile.EndsWith(".int*", StringComparison.OrdinalIgnoreCase)) { 100 | args.IntFile += ".int"; 101 | } 102 | 103 | return args; 104 | } 105 | 106 | 107 | private static Hg3Args RequestConvertHg3Args(Game game, IntArgs? intArgs = null) { 108 | Hg3Args args = new Hg3Args() { 109 | Game = game, 110 | }; 111 | if (game != null) 112 | Console.WriteLine($"Convert {game.Name()} Hg3s to Pngs:"); 113 | else 114 | Console.WriteLine($"Convert Hg3s to Pngs:"); 115 | 116 | bool parseSuccess; 117 | 118 | string defInputDir = settings.Directories.IntDirectory; 119 | string defOutputDir = settings.Directories.Hg3Directory; 120 | if (game == Game.All) { 121 | defInputDir = "."; 122 | } 123 | else if (game != null) { 124 | defInputDir = Path.Combine(game.Name(), defInputDir); 125 | defOutputDir = Path.Combine(game.Name(), defOutputDir); 126 | } 127 | if (!intArgs.HasValue) { 128 | do { 129 | if (game == Game.All) { 130 | defInputDir = "."; 131 | Console.Write("Input Directory (Before game name): "); 132 | WriteWatermark(""); 133 | } 134 | else { 135 | Console.Write("Input Directory: "); 136 | WriteWatermark(defInputDir); 137 | } 138 | args.InputDir = ReadDirectory(defInputDir, out parseSuccess); 139 | } while (!parseSuccess); 140 | 141 | if (game == Game.All) { 142 | defInputDir = settings.Directories.IntDirectory; 143 | do { 144 | Console.Write("Input Directory (After game name): "); 145 | WriteWatermark(defInputDir); 146 | args.InputDirAfter = ReadRelativePath(defInputDir, out parseSuccess); 147 | } while (!parseSuccess); 148 | } 149 | } 150 | else { 151 | args.InputDir = intArgs.Value.OutputDir; 152 | args.InputDirAfter = intArgs.Value.OutputDirAfter; 153 | } 154 | 155 | /*do { 156 | Console.Write("Output Directory: "); 157 | WriteWatermark(defOutputDir); 158 | args.OutputDir = ReadDirectory(defOutputDir, out parseSuccess); 159 | } while (!parseSuccess);*/ 160 | 161 | do { 162 | if (game == Game.All) { 163 | defOutputDir = "."; 164 | Console.Write("Output Directory (Before game name): "); 165 | WriteWatermark(""); 166 | } 167 | else { 168 | Console.Write("Output Directory: "); 169 | WriteWatermark(defOutputDir); 170 | } 171 | args.OutputDir = ReadDirectory(defOutputDir, out parseSuccess); 172 | } while (!parseSuccess); 173 | 174 | if (game == Game.All) { 175 | defOutputDir = settings.Directories.Hg3Directory; 176 | do { 177 | Console.Write("Output Directory (After game name): "); 178 | WriteWatermark(defOutputDir); 179 | args.OutputDirAfter = ReadRelativePath(defOutputDir, out parseSuccess); 180 | } while (!parseSuccess); 181 | } 182 | 183 | do { 184 | Console.Write("Search Pattern: "); 185 | WriteWatermark("(none)"); 186 | args.Pattern = ReadPattern("", out parseSuccess); 187 | } while (!parseSuccess); 188 | 189 | do { 190 | Console.Write("Sorting (sorted/unsorted/both): "); 191 | WriteWatermark("sorted"); 192 | args.Sorting = ReadSorting(Hg3Sorting.Sorted, out parseSuccess); 193 | } while (!parseSuccess); 194 | 195 | do { 196 | Console.Write("Stop on Error (y/n): "); 197 | WriteWatermark("no"); 198 | args.StopOnError = ReadYesNo(false, out parseSuccess); 199 | } while (!parseSuccess); 200 | 201 | 202 | return args; 203 | } 204 | 205 | 206 | private static PngArgs RequestResortPngArgs(Game game) { 207 | PngArgs args = new PngArgs() { 208 | Game = game, 209 | }; 210 | if (game != null) 211 | Console.WriteLine($"Resort {game.Name()} Pngs:"); 212 | else 213 | Console.WriteLine($"Resort Pngs:"); 214 | WriteWarning("This will attempt to resort EVERY png found in the specified directory. " + 215 | "Make extra sure that you do not input the wrong directory."); 216 | Console.WriteLine(); 217 | 218 | bool parseSuccess; 219 | 220 | string defOutputDir = settings.Directories.Hg3Directory; 221 | if (game == Game.All) { 222 | } 223 | else if (game != null) { 224 | defOutputDir = Path.Combine(game.Name(), defOutputDir); 225 | } 226 | do { 227 | if (game == Game.All) { 228 | defOutputDir = "."; 229 | Console.Write("Resort Directory (Before game name): "); 230 | WriteWatermark(""); 231 | } 232 | else { 233 | Console.Write("Resort Directory: "); 234 | WriteWatermark(defOutputDir); 235 | } 236 | args.ResortDir = ReadDirectory(defOutputDir, out parseSuccess); 237 | } while (!parseSuccess); 238 | 239 | if (game == Game.All) { 240 | defOutputDir = settings.Directories.Hg3Directory; 241 | do { 242 | Console.Write("Resort Directory (After game name): "); 243 | WriteWatermark(defOutputDir); 244 | args.ResortDirAfter = ReadRelativePath(defOutputDir, out parseSuccess); 245 | } while (!parseSuccess); 246 | } 247 | 248 | return args; 249 | } 250 | 251 | private static string ReadLine() { 252 | Console.ForegroundColor = ConsoleColor.White; 253 | string line = Console.ReadLine(); 254 | ResetForegroundColor(); 255 | return line; 256 | } 257 | 258 | private static Hg3Sorting ReadSorting(Hg3Sorting? defaultValue, out bool parseSuccess) { 259 | string input = ReadLine().Trim(); 260 | parseSuccess = true; 261 | if (string.IsNullOrWhiteSpace(input)) { 262 | if (defaultValue.HasValue) 263 | return defaultValue.Value; 264 | WriteError("Input cannot be empty!"); 265 | } 266 | else { 267 | if (input.Equals2("sorted", true) || 268 | input.Equals2("sort", true) || 269 | input.Equals2("s", true)) 270 | return Hg3Sorting.Sorted; 271 | else if (input.Equals2("unsorted", true) || 272 | input.Equals2("unsort", true) || 273 | input.Equals2("u", true)) 274 | return Hg3Sorting.Unsorted; 275 | else if (input.Equals2("both", true) || 276 | input.Equals2("b", true)) 277 | return Hg3Sorting.Both; 278 | WriteError("Input is not in 'sorted/unsorted/both' format!"); 279 | } 280 | parseSuccess = false; 281 | return Hg3Sorting.None; 282 | } 283 | 284 | private static string ReadPattern(string defaultValue, out bool parseSuccess) { 285 | string input = ReadLine().Trim().RemoveQuotes(); 286 | parseSuccess = true; 287 | if (string.IsNullOrWhiteSpace(input)) { 288 | if (defaultValue != null) 289 | return defaultValue; 290 | WriteError("Input cannot be empty!"); 291 | } 292 | else { 293 | if (PathHelper.IsValidNamePattern(input)) 294 | return input; 295 | WriteError("Input is not a valid path!"); 296 | } 297 | parseSuccess = false; 298 | return ""; 299 | } 300 | 301 | private static string ReadRelativePath(string defaultValue, out bool parseSuccess) { 302 | string input = ReadLine().Trim().RemoveQuotes().Trim(); 303 | parseSuccess = true; 304 | if (string.IsNullOrWhiteSpace(input)) { 305 | if (defaultValue != null) 306 | return defaultValue; 307 | WriteError("Input cannot be empty!"); 308 | } 309 | else { 310 | if (PathHelper.IsValidPathPattern(input)) 311 | return input; 312 | WriteError("Input is not a valid path!"); 313 | } 314 | parseSuccess = false; 315 | return ""; 316 | } 317 | 318 | private static string ReadDirectory(string defaultValue, out bool parseSuccess) { 319 | string input = ReadLine().Trim().RemoveQuotes().Trim(); 320 | parseSuccess = true; 321 | if (string.IsNullOrWhiteSpace(input)) { 322 | if (defaultValue != null) 323 | return defaultValue; 324 | WriteError("Input cannot be empty!"); 325 | } 326 | else { 327 | if (PathHelper.IsValidDirectory(input)) 328 | return input; 329 | WriteError("Input is not a valid path!"); 330 | } 331 | parseSuccess = false; 332 | return ""; 333 | } 334 | 335 | private static bool ReadYesNo(bool? defaultValue, out bool parseSuccess) { 336 | string input = ReadLine().Trim(); 337 | parseSuccess = true; 338 | if (string.IsNullOrWhiteSpace(input)) { 339 | if (defaultValue.HasValue) 340 | return defaultValue.Value; 341 | WriteError("Input cannot be empty!"); 342 | } 343 | else { 344 | if (input.Equals2("yes", true) || input.Equals2("y", true)) 345 | return true; 346 | else if (input.Equals2("no", true) || input.Equals2("n", true)) 347 | return false; 348 | WriteError("Input is not in yes/no format!"); 349 | } 350 | parseSuccess = false; 351 | return false; 352 | } 353 | } 354 | } 355 | -------------------------------------------------------------------------------- /GrisaiaExtractorConsole/Program.Output.cs: -------------------------------------------------------------------------------- 1 | using GrisaiaExtractor; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Reflection; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | 11 | namespace GrisaiaExtractorConsole { 12 | static partial class Program { 13 | 14 | private static void WriteLog(LogInfo log, bool complete) { 15 | if (complete) 16 | Console.WriteLine("Ripping Finished!"); 17 | if (log.GamesComplete > 0) 18 | Console.WriteLine($"Games Completed: {log.GamesComplete}"); 19 | if (log.GamesWithErrors.Any()) { 20 | Console.WriteLine($"Games Failed: {log.GamesFailed.Count}"); 21 | if (complete) 22 | WriteGames(log.GamesFailed); 23 | } 24 | if (log.GamesWithErrors.Any()) { 25 | Console.WriteLine($"Games with Errors: {log.GamesWithErrors.Count}"); 26 | if (complete) 27 | WriteGames(log.GamesWithErrors); 28 | } 29 | if (log.OperationsComplete > 0) { 30 | string operations = "operation"; 31 | if (log.OperationsComplete > 1) 32 | operations += 's'; 33 | if (complete && log.OperationsComplete > 1) 34 | Console.Write($"All {log.OperationsComplete} "); 35 | else if (!complete && log.OperationsComplete == 1) 36 | Console.Write($"Previous "); 37 | else if (!complete && log.OperationsComplete > 1) 38 | Console.Write($"{log.OperationsComplete} previous "); 39 | Console.WriteLine($"{operations} took: {log.Ellapsed.ToString(@"hh\:mm\:ss")}"); 40 | } 41 | } 42 | 43 | private static void LogOperation(IntArgs args, LogInfo log) { 44 | 45 | } 46 | 47 | private static void LogDateTime(LogInfo log) { 48 | log.Write($"[{DateTime.Now}] "); 49 | } 50 | 51 | private static void LogMessage(LogInfo log, string message, Game game = null) { 52 | log.Write($"[{DateTime.Now}] "); 53 | log.WriteLine(message); 54 | if (game != null && game != Game.All) 55 | log.WriteLine($"Game: {game.Name()}"); 56 | } 57 | 58 | private static string Name(this Game game) => 59 | game.Name(settings.General.UseJapaneseNames); 60 | 61 | 62 | private static void WriteWatermark(string watermark) { 63 | int left = Console.CursorLeft; 64 | int top = Console.CursorTop; 65 | Console.ForegroundColor = ConsoleColor.DarkGray; 66 | Console.Write(watermark); 67 | Console.CursorLeft = left; 68 | Console.CursorTop = top; 69 | ResetForegroundColor(); 70 | } 71 | 72 | private static void WriteError(string message) { 73 | if (Console.CursorLeft != 0) 74 | Console.WriteLine(); 75 | Console.ForegroundColor = ConsoleColor.Red; 76 | Console.WriteLine($"Error: {message}"); 77 | ResetForegroundColor(); 78 | } 79 | 80 | private static void WriteWarning(string message) { 81 | if (Console.CursorLeft != 0) 82 | Console.WriteLine(); 83 | Console.ForegroundColor = ConsoleColor.Yellow; 84 | Console.WriteLine($"Warning: {message}"); 85 | ResetForegroundColor(); 86 | } 87 | 88 | private static void WriteError(Exception ex) { 89 | if (Console.CursorLeft != 0) 90 | Console.WriteLine(); 91 | Console.ForegroundColor = ConsoleColor.Red; 92 | string message = ex.Message; 93 | if (Debugger.IsAttached) 94 | message = ex.ToString(); 95 | Console.WriteLine($"Error: {message}"); 96 | ResetForegroundColor(); 97 | } 98 | 99 | private static void DrawLogo() { 100 | Assembly assembly = typeof(AsciiImage).Assembly; 101 | using (Stream stream = assembly.GetManifestResourceStream( 102 | $"GrisaiaExtractorConsole.grisaia.ascii")) 103 | { 104 | AsciiImage logo = AsciiImage.FromStream(stream); 105 | if (Console.CursorLeft != 0) 106 | Console.WriteLine(); 107 | logo.Draw(); 108 | } 109 | } 110 | 111 | private static void WriteIntProgress(int line, TimeSpan ellapsed) { 112 | Console.CursorLeft = 0; 113 | Console.CursorTop = line; 114 | Console.Write($"[{ellapsed.ToString(@"hh\:mm\:ss")}]"); 115 | } 116 | 117 | private static void WriteProgress(int line, ref int lastLineLength, Hgx2pngArgs args) { 118 | Console.CursorLeft = 0; 119 | Console.CursorTop = line; 120 | string newLine = 121 | $"[{args.Percent.ToString("00.00")}%]" + 122 | $"[{Math.Min(args.FileCount, args.FileIndex + 1)}/{args.FileCount}]" + 123 | $"[{args.Ellapsed.ToString(@"hh\:mm\:ss")}]" + 124 | $" {args.FileName}"; 125 | if (newLine.Length > Console.BufferWidth) 126 | newLine = newLine.Substring(0, Console.BufferWidth); 127 | if (lastLineLength > newLine.Length) 128 | newLine += new string(' ', lastLineLength - newLine.Length); 129 | lastLineLength = newLine.Length; 130 | Console.Write(newLine); 131 | 132 | // Display the number of errors if there are any 133 | if (args.TotalErrors > 0) { 134 | Console.CursorLeft = 0; 135 | Console.CursorTop = line + 1; 136 | Console.ForegroundColor = ConsoleColor.Red; 137 | Console.Write($"Errors: {args.TotalErrors}"); 138 | ResetForegroundColor(); 139 | } 140 | } 141 | 142 | private static void WriteProgress(int line, ref int lastLineLength, ExkifintArgs args) { 143 | Console.CursorLeft = 0; 144 | Console.CursorTop = line; 145 | string newLine = 146 | $"[{args.Percent.ToString("00.00")}%]" + 147 | $"[{Math.Min(args.FileCount, args.FileIndex + 1)}/{args.FileCount}]" + 148 | $"[{args.Ellapsed.ToString(@"hh\:mm\:ss")}]" + 149 | $" {args.FileName}"; 150 | if (newLine.Length > Console.BufferWidth) 151 | newLine = newLine.Substring(0, Console.BufferWidth); 152 | if (lastLineLength > newLine.Length) 153 | newLine += new string(' ', lastLineLength - newLine.Length); 154 | lastLineLength = newLine.Length; 155 | Console.Write(newLine); 156 | } 157 | 158 | private static void Beep() { 159 | if (settings.General.BeepAfterOperation) 160 | Console.Beep(); 161 | } 162 | 163 | private static void Beep(int frequency, int duration) { 164 | if (settings.General.BeepAfterOperation) 165 | Console.Beep(frequency, duration); 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /GrisaiaExtractorConsole/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Resources; 2 | using System.Reflection; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyTitle("Grisaia Extract")] 10 | [assembly: AssemblyDescription("A ripping & categorizing tool for Grisaia resources. (Ripping code by asmodean)")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("Trigger's Tools & Games")] 13 | [assembly: AssemblyProduct("GrisaiaExtract")] 14 | [assembly: AssemblyCopyright("Copyright © Robert Jordan 2018")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | 18 | // Setting ComVisible to false makes the types in this assembly not visible 19 | // to COM components. If you need to access a type in this assembly from 20 | // COM, set the ComVisible attribute to true on that type. 21 | [assembly: ComVisible(false)] 22 | 23 | // The following GUID is for the ID of the typelib if this project is exposed to COM 24 | [assembly: Guid("1b2d824a-dd0d-4019-b234-54e5543b7a42")] 25 | 26 | // Version information for an assembly consists of the following four values: 27 | // 28 | // Major Version 29 | // Minor Version 30 | // Build Number 31 | // Revision 32 | // 33 | // You can specify all the values or you can default the Build and Revision Numbers 34 | // by using the '*' as shown below: 35 | // [assembly: AssemblyVersion("1.0.*")] 36 | [assembly: AssemblyVersion("1.0.2.2")] 37 | [assembly: AssemblyFileVersion("1.0.2.2")] 38 | [assembly: NeutralResourcesLanguage("en")] 39 | 40 | -------------------------------------------------------------------------------- /GrisaiaExtractorConsole/UserSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Reflection; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using GrisaiaExtractor; 10 | using GrisaiaExtractorConsole.Ini; 11 | 12 | namespace GrisaiaExtractorConsole { 13 | /// The user settings for Zelda Oracle Engine gameplay. 14 | public class UserSettings : IniReflectionSettings { 15 | 16 | //----------------------------------------------------------------------------- 17 | // Override Methods 18 | //----------------------------------------------------------------------------- 19 | 20 | /// Called after loading finishes only if the load was unsuccessful. 21 | protected override void PostLoadFailed(Exception ex) { 22 | // TODO: Log error here 23 | } 24 | 25 | /// Called after saving finishes only if the save was unsuccessful. 26 | protected override void PostSaveFailed(Exception ex) { 27 | Console.ForegroundColor = ConsoleColor.Red; 28 | Console.WriteLine("Faied to save ini settings!"); 29 | Console.ForegroundColor = ConsoleColor.Gray; 30 | // TODO: Log error here 31 | } 32 | 33 | 34 | //----------------------------------------------------------------------------- 35 | // Override Properties 36 | //----------------------------------------------------------------------------- 37 | 38 | /// The path to the settings file. 39 | protected override string SettingsPath { 40 | get { return PathHelper.CombineExecutable($"{PathHelper.ExeName}.ini"); } 41 | } 42 | 43 | /// The comments to display at the top of the ini file. 44 | protected override string HeaderComments { 45 | get { 46 | return 47 | @" `s- " + '\n' + 48 | @" `y- " + '\n' + 49 | @" ``.--.-:::h/---.``` " + '\n' + 50 | @" .:/+++oo+///+osyssy+/:::::-. " + '\n' + 51 | @" `/o/:///++-do+++o+///+ooooo+++/:-` " + '\n' + 52 | @" -s-`ohyyyy.`hssoooossoossosysso++/:` " + '\n' + 53 | @" `s. :hs+//sh-hyhsoohhoshhyhyyhhyy++/:` " + '\n' + 54 | @" :s` +y+/sssyyyydy+ /// /ddddddhhhyso/- " + '\n' + 55 | @" -s` /y++yso. /sdds .ddhdddddddddhyys+:` " + '\n' + 56 | @" ++`.ys++sh. sdhds /ddddddddddddddhso/` " + '\n' + 57 | @" .os/-/oo+:o.sddo: -+sdddddddddddhhyo/` " + '\n' + 58 | @" `/+osssyyhhyhhdddddddddddddddddhhyyo/` " + '\n' + 59 | @" :/+++ooosyyyhh+:../++/-./dddddhhys+- " + '\n' + 60 | @" ./++ooossyyyyhds .dddhd:-dddddhhys/` " + '\n' + 61 | @" -++oosyyyhyhhds .dd+-dh+dyoooohosss+ " + '\n' + 62 | @" -+oosyyyyhyhds``+:`-dhdddy/`/d+/ys: " + '\n' + 63 | @" .+ssyyhhhhhds`.ddo:md+hdddy.-od- " + '\n' + 64 | @" `:oyyhhhhhds.-ddddms.hmdd+o+-oy:` " + '\n' + 65 | @" ./sydddo/--ooo+/--dh+:/yy/-/oh." + '\n' + 66 | @" `.-/+ooooooooo+//ooo++ooo+:`" + '\n' + 67 | @" " + '\n' + 68 | @" GRISAIA EXTRACT SETTINGS " + '\n' + 69 | @"===================================================================" + '\n' + 70 | @"These are all the settings for Grisaia Extract that cannot be" + '\n' + 71 | @"changed within the program." + '\n' + 72 | @"" + '\n' + 73 | @"ALL RIPPING CODE FOR GRISAIA WAS WRITTEN BY ASMODEAN." + '\n' + 74 | @"Link: http://asmodean.reverse.net/pages/exkifint.html"; 75 | } 76 | } 77 | 78 | 79 | //----------------------------------------------------------------------------- 80 | // Ini Sections 81 | //----------------------------------------------------------------------------- 82 | 83 | /// The general settings. 84 | public class GeneralSection { 85 | /// True if JP game names are used instead of US names. 86 | [DefaultValue(true)] 87 | public bool UseJapaneseNames { get; set; } 88 | 89 | /// Beeps after each int or hg3 operation. 90 | [DefaultValue(true)] 91 | public bool BeepAfterOperation { get; set; } 92 | 93 | /// Beeps after all operations are complete. 94 | [DefaultValue(true)] 95 | public bool BeepOnCompletion { get; set; } 96 | } 97 | 98 | /// The custom default directories. 99 | public class DirectoriesSection { 100 | /// The default current directory. 101 | [DefaultValue("")] 102 | [UseQuotes] 103 | public string CurrentDirectory { get; set; } 104 | 105 | /// The default directory ending for .int file output. 106 | [DefaultValue("Raw")] 107 | [UseQuotes] 108 | public string IntDirectory { get; set; } 109 | 110 | /// The default directory ending for .hg3 file output. 111 | [DefaultValue("Output")] 112 | [UseQuotes] 113 | public string Hg3Directory { get; set; } 114 | } 115 | 116 | // Games ---------------------------------------------------------------------- 117 | 118 | /// The manual game locations. 119 | public class GameLocationsSection { 120 | /// The Fruit of Grisaia. 121 | [DefaultValue("")] 122 | [UseQuotes] 123 | [Comments("The Fruit of Grisaia")] 124 | public string Kajitsu { 125 | get => Locator.GetPath(); 126 | set => Locator.SetPath(value); 127 | } 128 | 129 | /// The Labyrinth of Grisaia. 130 | [DefaultValue("")] 131 | [UseQuotes] 132 | [Comments("The Labyrinth of Grisaia")] 133 | public string Meikyuu { 134 | get => Locator.GetPath(); 135 | set => Locator.SetPath(value); 136 | } 137 | 138 | /// The Eden of Grisaia. 139 | [DefaultValue("")] 140 | [UseQuotes] 141 | [Comments("The Eden of Grisaia")] 142 | public string Rakuen { 143 | get => Locator.GetPath(); 144 | set => Locator.SetPath(value); 145 | } 146 | 147 | /// The Leisure of Grisaia. 148 | [DefaultValue("")] 149 | [UseQuotes] 150 | [Comments("\nThe Leisure of Grisaia")] 151 | public string Yuukan { 152 | get => Locator.GetPath(); 153 | set => Locator.SetPath(value); 154 | } 155 | 156 | /// The Afterglow of Grisaia. 157 | [DefaultValue("")] 158 | [UseQuotes] 159 | [Comments("The Afterglow of Grisaia")] 160 | public string Zankou { 161 | get => Locator.GetPath(); 162 | set => Locator.SetPath(value); 163 | } 164 | 165 | /// The Melody of Grisaia. 166 | [DefaultValue("")] 167 | [UseQuotes] 168 | [Comments("The Melody of Grisaia")] 169 | public string Senritsu { 170 | get => Locator.GetPath(); 171 | set => Locator.SetPath(value); 172 | } 173 | 174 | /// Idol Magical Girl Chiru Chiru Michiru (Full). 175 | [DefaultValue("")] 176 | [UseQuotes] 177 | [Comments("\nIdol Magical Girl Chiru Chiru Michiru (Full)")] 178 | public string IdolMahouFull { 179 | get => Locator.GetPath(); 180 | set => Locator.SetPath(value); 181 | } 182 | 183 | /// Idol Magical Girl Chiru Chiru Michiru (Part 1). 184 | [DefaultValue("")] 185 | [UseQuotes] 186 | [Comments("Idol Magical Girl Chiru Chiru Michiru (Part 1)")] 187 | public string IdolMahouPart1 { 188 | get => Locator.GetPath(); 189 | set => Locator.SetPath(value); 190 | } 191 | 192 | /// Idol Magical Girl Chiru Chiru Michiru (Part 2). 193 | [DefaultValue("")] 194 | [UseQuotes] 195 | [Comments("Idol Magical Girl Chiru Chiru Michiru (Part 2)")] 196 | public string IdolMahouPart2 { 197 | get => Locator.GetPath(); 198 | set => Locator.SetPath(value); 199 | } 200 | 201 | /// Gets all paths listed by the game locations. 202 | [Browsable(false)] 203 | public IEnumerable> Paths { 204 | get { 205 | foreach (PropertyInfo prop in typeof(GameLocationsSection) 206 | .GetProperties()) 207 | { 208 | if (prop.IsBrowsable()) { 209 | yield return new KeyValuePair( 210 | prop.Name, prop.GetValue(this) as string); 211 | } 212 | } 213 | } 214 | } 215 | } 216 | 217 | 218 | //----------------------------------------------------------------------------- 219 | // Ini Properties 220 | //----------------------------------------------------------------------------- 221 | 222 | /// The general settings. 223 | [Section] 224 | public GeneralSection General { get; } = new GeneralSection(); 225 | 226 | /// The custom default directories. 227 | [Section] 228 | public DirectoriesSection Directories { get; } = new DirectoriesSection(); 229 | 230 | /// The manual game locations. 231 | [Section] 232 | [Comments(@"Override or manual locations for games that could not be found")] 233 | public GameLocationsSection GameLocations { get; } = new GameLocationsSection(); 234 | 235 | } 236 | } 237 | -------------------------------------------------------------------------------- /GrisaiaExtractorConsole/grisaia.ascii: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trigger-segfault/GrisaiaExtractor/fdd6e8339fd4e69a0c6fc92acb7aa57000b6b81c/GrisaiaExtractorConsole/grisaia.ascii -------------------------------------------------------------------------------- /License.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Robert Jordan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Grisaia Extract ![AppIcon](https://i.imgur.com/fDnJLIe.png) 2 | 3 | [![Latest Release](https://img.shields.io/github/release/trigger-death/GrisaiaExtractor.svg?style=flat&label=version)](https://github.com/trigger-death/GrisaiaExtractor/releases/latest) 4 | [![Latest Release Date](https://img.shields.io/github/release-date-pre/trigger-death/GrisaiaExtractor.svg?style=flat&label=released)](https://github.com/trigger-death/GrisaiaExtractor/releases/latest) 5 | [![Total Downloads](https://img.shields.io/github/downloads/trigger-death/GrisaiaExtractor/total.svg?style=flat)](https://github.com/trigger-death/GrisaiaExtractor/releases) 6 | [![Creation Date](https://img.shields.io/badge/created-june%202018-A642FF.svg?style=flat)](https://github.com/trigger-death/GrisaiaExtractor/commit/2ae789f18d7387024f2b92b85cc6a21709796ed7) 7 | [![Discord](https://img.shields.io/discord/436949335947870238.svg?style=flat&logo=discord&label=chat&colorB=7389DC&link=https://discord.gg/vB7jUbY)](https://discord.gg/vB7jUbY) 8 | 9 | A ripping tool (Primarily for images) for the Grisaia games. *(Phantom Trigger not supported)* 10 | 11 | This is basically a polished, easy-to-use wrapper for existing programs that extract Grisaia files. (Although much of the original code has been ported to C#) 12 | 13 | **All ripping code written by asmodean:** http://asmodean.reverse.net/pages/exkifint.html 14 | 15 | **Additional thanks to ripping documentation on reddit:** https://www.reddit.com/r/grisaia/wiki/ripping 16 | 17 | I originally planned to turn this into a full-fledged Windows application that would include sprite combining but after realising I wouldn't reach that point, I wrote up a final console version for use instead. 18 | 19 | ![Window Preview](https://i.imgur.com/adjsvrN.png) 20 | 21 | ### [Image Album](https://imgur.com/a/7xouR3f) 22 | 23 | ## About 24 | 25 | * **Created By:** Robert Jordan 26 | * **Ripping By:** asmodean 27 | * **Language:** C#/C++ 28 | 29 | ## Features 30 | 31 | * Designed to be a bit more user friendly than existing tools. Users no longer need to run a program through the command line or write batch files to convert .hg3's. 32 | * Outputs .hg3's directly to .png's with proper transparency. Now an entire int file can be output in one go with disk space to spare. 33 | * Optional ability to sort all images to a categorized directory based on its name. 34 | * Attempts to locate all existing Grisaia games. 35 | * Fixes a bug with `hgx2bmp.exe` where a small selection of .hg3 didn't get all of their images extracted. 36 | * An .ini settings file called `GrisaiaExtract.ini` can be modified after the program is run to modify certain defaults and settings. 37 | 38 | ## Cons 39 | 40 | * Currently no command line support. 41 | * May not play well when not run through a Windows Console. 42 | 43 | **Example of Sorted Images:** *Note, Windows draws folder thumbnails poorly, they do not actually have alpha issues.* 44 | 45 | ![Sorting Preview](https://i.imgur.com/cm07Hzd.png) 46 | -------------------------------------------------------------------------------- /zlib/bin/zlib1.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trigger-segfault/GrisaiaExtractor/fdd6e8339fd4e69a0c6fc92acb7aa57000b6b81c/zlib/bin/zlib1.dll -------------------------------------------------------------------------------- /zlib/include/zconf.h: -------------------------------------------------------------------------------- 1 | /* zconf.h -- configuration of the zlib compression library 2 | * Copyright (C) 1995-2005 Jean-loup Gailly. 3 | * For conditions of distribution and use, see copyright notice in zlib.h 4 | */ 5 | 6 | /* @(#) $Id$ */ 7 | 8 | #ifndef ZCONF_H 9 | #define ZCONF_H 10 | 11 | /* 12 | * If you *really* need a unique prefix for all types and library functions, 13 | * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. 14 | */ 15 | #ifdef Z_PREFIX 16 | # define deflateInit_ z_deflateInit_ 17 | # define deflate z_deflate 18 | # define deflateEnd z_deflateEnd 19 | # define inflateInit_ z_inflateInit_ 20 | # define inflate z_inflate 21 | # define inflateEnd z_inflateEnd 22 | # define deflateInit2_ z_deflateInit2_ 23 | # define deflateSetDictionary z_deflateSetDictionary 24 | # define deflateCopy z_deflateCopy 25 | # define deflateReset z_deflateReset 26 | # define deflateParams z_deflateParams 27 | # define deflateBound z_deflateBound 28 | # define deflatePrime z_deflatePrime 29 | # define inflateInit2_ z_inflateInit2_ 30 | # define inflateSetDictionary z_inflateSetDictionary 31 | # define inflateSync z_inflateSync 32 | # define inflateSyncPoint z_inflateSyncPoint 33 | # define inflateCopy z_inflateCopy 34 | # define inflateReset z_inflateReset 35 | # define inflateBack z_inflateBack 36 | # define inflateBackEnd z_inflateBackEnd 37 | # define compress z_compress 38 | # define compress2 z_compress2 39 | # define compressBound z_compressBound 40 | # define uncompress z_uncompress 41 | # define adler32 z_adler32 42 | # define crc32 z_crc32 43 | # define get_crc_table z_get_crc_table 44 | # define zError z_zError 45 | 46 | # define alloc_func z_alloc_func 47 | # define free_func z_free_func 48 | # define in_func z_in_func 49 | # define out_func z_out_func 50 | # define Byte z_Byte 51 | # define uInt z_uInt 52 | # define uLong z_uLong 53 | # define Bytef z_Bytef 54 | # define charf z_charf 55 | # define intf z_intf 56 | # define uIntf z_uIntf 57 | # define uLongf z_uLongf 58 | # define voidpf z_voidpf 59 | # define voidp z_voidp 60 | #endif 61 | 62 | #if defined(__MSDOS__) && !defined(MSDOS) 63 | # define MSDOS 64 | #endif 65 | #if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) 66 | # define OS2 67 | #endif 68 | #if defined(_WINDOWS) && !defined(WINDOWS) 69 | # define WINDOWS 70 | #endif 71 | #if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) 72 | # ifndef WIN32 73 | # define WIN32 74 | # endif 75 | #endif 76 | #if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) 77 | # if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) 78 | # ifndef SYS16BIT 79 | # define SYS16BIT 80 | # endif 81 | # endif 82 | #endif 83 | 84 | /* 85 | * Compile with -DMAXSEG_64K if the alloc function cannot allocate more 86 | * than 64k bytes at a time (needed on systems with 16-bit int). 87 | */ 88 | #ifdef SYS16BIT 89 | # define MAXSEG_64K 90 | #endif 91 | #ifdef MSDOS 92 | # define UNALIGNED_OK 93 | #endif 94 | 95 | #ifdef __STDC_VERSION__ 96 | # ifndef STDC 97 | # define STDC 98 | # endif 99 | # if __STDC_VERSION__ >= 199901L 100 | # ifndef STDC99 101 | # define STDC99 102 | # endif 103 | # endif 104 | #endif 105 | #if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) 106 | # define STDC 107 | #endif 108 | #if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) 109 | # define STDC 110 | #endif 111 | #if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) 112 | # define STDC 113 | #endif 114 | #if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) 115 | # define STDC 116 | #endif 117 | 118 | #if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ 119 | # define STDC 120 | #endif 121 | 122 | #ifndef STDC 123 | # ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ 124 | # define const /* note: need a more gentle solution here */ 125 | # endif 126 | #endif 127 | 128 | /* Some Mac compilers merge all .h files incorrectly: */ 129 | #if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) 130 | # define NO_DUMMY_DECL 131 | #endif 132 | 133 | /* Maximum value for memLevel in deflateInit2 */ 134 | #ifndef MAX_MEM_LEVEL 135 | # ifdef MAXSEG_64K 136 | # define MAX_MEM_LEVEL 8 137 | # else 138 | # define MAX_MEM_LEVEL 9 139 | # endif 140 | #endif 141 | 142 | /* Maximum value for windowBits in deflateInit2 and inflateInit2. 143 | * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files 144 | * created by gzip. (Files created by minigzip can still be extracted by 145 | * gzip.) 146 | */ 147 | #ifndef MAX_WBITS 148 | # define MAX_WBITS 15 /* 32K LZ77 window */ 149 | #endif 150 | 151 | /* The memory requirements for deflate are (in bytes): 152 | (1 << (windowBits+2)) + (1 << (memLevel+9)) 153 | that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) 154 | plus a few kilobytes for small objects. For example, if you want to reduce 155 | the default memory requirements from 256K to 128K, compile with 156 | make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" 157 | Of course this will generally degrade compression (there's no free lunch). 158 | 159 | The memory requirements for inflate are (in bytes) 1 << windowBits 160 | that is, 32K for windowBits=15 (default value) plus a few kilobytes 161 | for small objects. 162 | */ 163 | 164 | /* Type declarations */ 165 | 166 | #ifndef OF /* function prototypes */ 167 | # ifdef STDC 168 | # define OF(args) args 169 | # else 170 | # define OF(args) () 171 | # endif 172 | #endif 173 | 174 | /* The following definitions for FAR are needed only for MSDOS mixed 175 | * model programming (small or medium model with some far allocations). 176 | * This was tested only with MSC; for other MSDOS compilers you may have 177 | * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, 178 | * just define FAR to be empty. 179 | */ 180 | #ifdef SYS16BIT 181 | # if defined(M_I86SM) || defined(M_I86MM) 182 | /* MSC small or medium model */ 183 | # define SMALL_MEDIUM 184 | # ifdef _MSC_VER 185 | # define FAR _far 186 | # else 187 | # define FAR far 188 | # endif 189 | # endif 190 | # if (defined(__SMALL__) || defined(__MEDIUM__)) 191 | /* Turbo C small or medium model */ 192 | # define SMALL_MEDIUM 193 | # ifdef __BORLANDC__ 194 | # define FAR _far 195 | # else 196 | # define FAR far 197 | # endif 198 | # endif 199 | #endif 200 | 201 | #if defined(WINDOWS) || defined(WIN32) 202 | /* If building or using zlib as a DLL, define ZLIB_DLL. 203 | * This is not mandatory, but it offers a little performance increase. 204 | */ 205 | # ifdef ZLIB_DLL 206 | # if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) 207 | # ifdef ZLIB_INTERNAL 208 | # define ZEXTERN extern __declspec(dllexport) 209 | # else 210 | # define ZEXTERN extern __declspec(dllimport) 211 | # endif 212 | # endif 213 | # endif /* ZLIB_DLL */ 214 | /* If building or using zlib with the WINAPI/WINAPIV calling convention, 215 | * define ZLIB_WINAPI. 216 | * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. 217 | */ 218 | # ifdef ZLIB_WINAPI 219 | # ifdef FAR 220 | # undef FAR 221 | # endif 222 | # include 223 | /* No need for _export, use ZLIB.DEF instead. */ 224 | /* For complete Windows compatibility, use WINAPI, not __stdcall. */ 225 | # define ZEXPORT WINAPI 226 | # ifdef WIN32 227 | # define ZEXPORTVA WINAPIV 228 | # else 229 | # define ZEXPORTVA FAR CDECL 230 | # endif 231 | # endif 232 | #endif 233 | 234 | #if defined (__BEOS__) 235 | # ifdef ZLIB_DLL 236 | # ifdef ZLIB_INTERNAL 237 | # define ZEXPORT __declspec(dllexport) 238 | # define ZEXPORTVA __declspec(dllexport) 239 | # else 240 | # define ZEXPORT __declspec(dllimport) 241 | # define ZEXPORTVA __declspec(dllimport) 242 | # endif 243 | # endif 244 | #endif 245 | 246 | #ifndef ZEXTERN 247 | # define ZEXTERN extern 248 | #endif 249 | #ifndef ZEXPORT 250 | # define ZEXPORT 251 | #endif 252 | #ifndef ZEXPORTVA 253 | # define ZEXPORTVA 254 | #endif 255 | 256 | #ifndef FAR 257 | # define FAR 258 | #endif 259 | 260 | #if !defined(__MACTYPES__) 261 | typedef unsigned char Byte; /* 8 bits */ 262 | #endif 263 | typedef unsigned int uInt; /* 16 bits or more */ 264 | typedef unsigned long uLong; /* 32 bits or more */ 265 | 266 | #ifdef SMALL_MEDIUM 267 | /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ 268 | # define Bytef Byte FAR 269 | #else 270 | typedef Byte FAR Bytef; 271 | #endif 272 | typedef char FAR charf; 273 | typedef int FAR intf; 274 | typedef uInt FAR uIntf; 275 | typedef uLong FAR uLongf; 276 | 277 | #ifdef STDC 278 | typedef void const *voidpc; 279 | typedef void FAR *voidpf; 280 | typedef void *voidp; 281 | #else 282 | typedef Byte const *voidpc; 283 | typedef Byte FAR *voidpf; 284 | typedef Byte *voidp; 285 | #endif 286 | 287 | #if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ 288 | # include /* for off_t */ 289 | # include /* for SEEK_* and off_t */ 290 | # ifdef VMS 291 | # include /* for off_t */ 292 | # endif 293 | # define z_off_t off_t 294 | #endif 295 | #ifndef SEEK_SET 296 | # define SEEK_SET 0 /* Seek from beginning of file. */ 297 | # define SEEK_CUR 1 /* Seek from current position. */ 298 | # define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ 299 | #endif 300 | #ifndef z_off_t 301 | # define z_off_t long 302 | #endif 303 | 304 | #if defined(__OS400__) 305 | # define NO_vsnprintf 306 | #endif 307 | 308 | #if defined(__MVS__) 309 | # define NO_vsnprintf 310 | # ifdef FAR 311 | # undef FAR 312 | # endif 313 | #endif 314 | 315 | /* MVS linker does not support external names larger than 8 bytes */ 316 | #if defined(__MVS__) 317 | # pragma map(deflateInit_,"DEIN") 318 | # pragma map(deflateInit2_,"DEIN2") 319 | # pragma map(deflateEnd,"DEEND") 320 | # pragma map(deflateBound,"DEBND") 321 | # pragma map(inflateInit_,"ININ") 322 | # pragma map(inflateInit2_,"ININ2") 323 | # pragma map(inflateEnd,"INEND") 324 | # pragma map(inflateSync,"INSY") 325 | # pragma map(inflateSetDictionary,"INSEDI") 326 | # pragma map(compressBound,"CMBND") 327 | # pragma map(inflate_table,"INTABL") 328 | # pragma map(inflate_fast,"INFA") 329 | # pragma map(inflate_copyright,"INCOPY") 330 | #endif 331 | 332 | #endif /* ZCONF_H */ 333 | -------------------------------------------------------------------------------- /zlib/lib/libz.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trigger-segfault/GrisaiaExtractor/fdd6e8339fd4e69a0c6fc92acb7aa57000b6b81c/zlib/lib/libz.a -------------------------------------------------------------------------------- /zlib/lib/libz.dll.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trigger-segfault/GrisaiaExtractor/fdd6e8339fd4e69a0c6fc92acb7aa57000b6b81c/zlib/lib/libz.dll.a -------------------------------------------------------------------------------- /zlib/lib/zlib-bcc.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trigger-segfault/GrisaiaExtractor/fdd6e8339fd4e69a0c6fc92acb7aa57000b6b81c/zlib/lib/zlib-bcc.lib -------------------------------------------------------------------------------- /zlib/lib/zlib.def: -------------------------------------------------------------------------------- 1 | ; h:\mingw\3.3.1\bin\dlltool.exe --export-all-symbols --output-def=zlib.def adler32.pic.o compress.pic.o crc32.pic.o gzio.pic.o uncompr.pic.o deflate.pic.o trees.pic.o zutil.pic.o inflate.pic.o infback.pic.o inftrees.pic.o inffast.pic.o zlib-dllversion.o zlib-dll-res.o 2 | EXPORTS 3 | DllGetVersion @ 1 ; 4 | _dist_code @ 2 DATA ; 5 | _length_code @ 3 DATA ; 6 | _tr_align @ 4 ; 7 | _tr_flush_block @ 5 ; 8 | _tr_init @ 6 ; 9 | _tr_stored_block @ 7 ; 10 | _tr_tally @ 8 ; 11 | adler32 @ 9 ; 12 | adler32_combine @ 10 ; 13 | compress @ 11 ; 14 | compress2 @ 12 ; 15 | compressBound @ 13 ; 16 | crc32 @ 14 ; 17 | crc32_combine @ 15 ; 18 | deflate @ 16 ; 19 | deflateBound @ 17 ; 20 | deflateCopy @ 18 ; 21 | deflateEnd @ 19 ; 22 | deflateInit2_ @ 20 ; 23 | deflateInit_ @ 21 ; 24 | deflateParams @ 22 ; 25 | deflatePrime @ 23 ; 26 | deflateReset @ 24 ; 27 | deflateSetDictionary @ 25 ; 28 | deflateSetHeader @ 26 ; 29 | deflateTune @ 27 ; 30 | deflate_copyright @ 28 DATA ; 31 | get_crc_table @ 29 ; 32 | gzclearerr @ 30 ; 33 | gzclose @ 31 ; 34 | gzdirect @ 32 ; 35 | gzdopen @ 33 ; 36 | gzeof @ 34 ; 37 | gzerror @ 35 ; 38 | gzflush @ 36 ; 39 | gzgetc @ 37 ; 40 | gzgets @ 38 ; 41 | gzopen @ 39 ; 42 | gzprintf @ 40 ; 43 | gzputc @ 41 ; 44 | gzputs @ 42 ; 45 | gzread @ 43 ; 46 | gzrewind @ 44 ; 47 | gzseek @ 45 ; 48 | gzsetparams @ 46 ; 49 | gztell @ 47 ; 50 | gzungetc @ 48 ; 51 | gzwrite @ 49 ; 52 | inflate @ 50 ; 53 | inflateBack @ 51 ; 54 | inflateBackEnd @ 52 ; 55 | inflateBackInit_ @ 53 ; 56 | inflateCopy @ 54 ; 57 | inflateEnd @ 55 ; 58 | inflateGetHeader @ 56 ; 59 | inflateInit2_ @ 57 ; 60 | inflateInit_ @ 58 ; 61 | inflatePrime @ 59 ; 62 | inflateReset @ 60 ; 63 | inflateSetDictionary @ 61 ; 64 | inflateSync @ 62 ; 65 | inflateSyncPoint @ 63 ; 66 | inflate_copyright @ 64 DATA ; 67 | inflate_fast @ 65 ; 68 | inflate_table @ 66 ; 69 | uncompress @ 67 ; 70 | zError @ 68 ; 71 | z_errmsg @ 69 DATA ; 72 | zcalloc @ 70 ; 73 | zcfree @ 71 ; 74 | zlibCompileFlags @ 72 ; 75 | zlibVersion @ 73 ; 76 | -------------------------------------------------------------------------------- /zlib/lib/zlib.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trigger-segfault/GrisaiaExtractor/fdd6e8339fd4e69a0c6fc92acb7aa57000b6b81c/zlib/lib/zlib.lib -------------------------------------------------------------------------------- /zlib/manifest/zlib-1.2.3-lib.mft: -------------------------------------------------------------------------------- 1 | include/zconf.h 2 | include/zlib.h 3 | lib/libz.a 4 | lib/libz.dll.a 5 | lib/zlib-bcc.lib 6 | lib/zlib.def 7 | lib/zlib.lib 8 | manifest/zlib-1.2.3-lib.mft 9 | manifest/zlib-1.2.3-lib.ver 10 | -------------------------------------------------------------------------------- /zlib/manifest/zlib-1.2.3-lib.ver: -------------------------------------------------------------------------------- 1 | Zlib-1.2.3: Developer files 2 | Zlib: general purpose data compression / decompression library --------------------------------------------------------------------------------