Skip to content

Instantly share code, notes, and snippets.

@odzhan
Last active October 29, 2022 23:53
Show Gist options
  • Select an option

  • Save odzhan/d73f623b21a25ff76e5943abd8a81041 to your computer and use it in GitHub Desktop.

Select an option

Save odzhan/d73f623b21a25ff76e5943abd8a81041 to your computer and use it in GitHub Desktop.
d3d compression
/**
Compile with MSVC : cl /EHsc d3dpack.cpp
C:\d3dpack e C:\windows\system32\cmd.exe cmd.packed
Direct 3D Compression Example.
SHA256("C:\windows\system32\cmd.exe") : b99d61d874728edc0918ca0eb10eab93d381e7367e377406e65963366c874450
Compressing "C:\windows\system32\cmd.exe" -> "cmd.packed"
Compressed ratio : 57%
SHA256("cmd.packed") : 0fe06557a1aadda6d78614de943b8f74b4332f3ca63d4494900b16df99ea16b5
C:\d3dpack d cmd.packed cmd.bin
Direct 3D Compression Example.
SHA256("cmd.packed") : 0fe06557a1aadda6d78614de943b8f74b4332f3ca63d4494900b16df99ea16b5
Decompressing "cmd.packed" -> "cmd.bin"
Decompressed ratio : 57%
SHA256("cmd.bin") : b99d61d874728edc0918ca0eb10eab93d381e7367e377406e65963366c874450
*/
#include <cstdio>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <windows.h>
#include <d3dcompiler.h>
#include <wincrypt.h>
#pragma comment(lib, "advapi32")
#pragma comment(lib, "d3dcompiler")
#define SHA_256_HASH_LENGTH 32
bool
SHA256(PBYTE pbInput, DWORD cbInput, BYTE bHash[SHA_256_HASH_LENGTH]) {
HCRYPTHASH hHash = NULL;
ULONG cbHash;
HCRYPTPROV hProvider = NULL;
BOOL bStatus = FALSE;
do {
bStatus = CryptAcquireContext(&hProvider, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT);
if (!bStatus) break;
bStatus = CryptCreateHash(hProvider, CALG_SHA_256, NULL, 0, &hHash);
if (!bStatus) break;
bStatus = CryptHashData(hHash, pbInput, cbInput, 0);
if (!bStatus) break;
cbHash = SHA_256_HASH_LENGTH;
bStatus = CryptGetHashParam(hHash, HP_HASHVAL, bHash, &cbHash, 0);
if (!bStatus) break;
} while (FALSE);
if (hHash) CryptDestroyHash(hHash);
if (hProvider) CryptReleaseContext(hProvider, 0);
return bStatus;
}
std::vector<BYTE>
ReadFileData(std::string path) {
std::ifstream instream(path, std::ios::in | std::ios::binary);
std::vector<BYTE> data((std::istreambuf_iterator<char>(instream)), std::istreambuf_iterator<char>());
return data;
}
bool
WriteFileData(std::string path, std::vector<BYTE> data) {
std::ofstream outstream(path, std::ios::out | std::ios::binary);
std::copy(data.begin(), data.end(), std::ostreambuf_iterator<char>(outstream));
return outstream.good();
}
size_t
CalcRatio(size_t Before, size_t After) {
if (After <= UINT_MAX / 100) {
After *= 100;
}
else {
Before /= 100;
}
if (Before == 0) {
Before = 1;
}
return (100 - (After / Before));
}
std::string
bin2hex(BYTE bin[], size_t size) {
std::ostringstream s;
for (size_t i=0; i<size; i++)
s << std::hex << std::setfill('0') << std::setw(2) << std::nouppercase << (int)bin[i];
return s.str();
}
void
DumpHash(std::string infile, std::vector<BYTE> inbuf) {
BYTE hash[SHA_256_HASH_LENGTH];
SHA256(inbuf.data(), inbuf.size(), hash);
printf("SHA256(\"%s\") : %s\n", infile.c_str(), bin2hex(hash, 32).c_str());
}
std::vector<BYTE>
d3d_pack(std::vector<BYTE> inbuf) {
D3D_SHADER_DATA dsa;
ID3DBlob *blob;
std::vector<BYTE> outbuf;
dsa.pBytecode = inbuf.data();
dsa.BytecodeLength = inbuf.size();
HRESULT hr = D3DCompressShaders(
1,
&dsa,
D3D_COMPRESS_SHADER_KEEP_ALL_PARTS,
&blob);
if (hr == S_OK) {
PBYTE buf = (PBYTE)blob->GetBufferPointer();
size_t len = blob->GetBufferSize();
outbuf.insert(outbuf.begin(), buf, buf + len);
blob->Release();
}
return outbuf;
}
std::vector<BYTE>
d3d_depack(std::vector<BYTE> inbuf) {
D3D_SHADER_DATA dsa;
ID3DBlob *blob;
std::vector<BYTE> outbuf;
dsa.pBytecode = inbuf.data();
dsa.BytecodeLength = inbuf.size();
HRESULT hr = D3DDecompressShaders(
inbuf.data(),
inbuf.size(),
1,
0,
0,
0,
&blob,
NULL);
if (hr == S_OK) {
PBYTE buf = (PBYTE)blob->GetBufferPointer();
size_t len = blob->GetBufferSize();
outbuf.insert(outbuf.begin(), buf, buf + len);
blob->Release();
}
return outbuf;
}
int
main(int argc, char *argv[]) {
puts("\nDirect 3D Compression Example.");
if (argc != 4) {
printf("usage: d3dpack [e/d] <infile> <outfile>\n");
return 0;
}
if (argv[1][0] != 'e' && argv[1][0] != 'd') {
printf("invalid parameters. first argument should be 'e' for encoding or 'd' for decoding.\n");
return 0;
}
bool depack = (argv[1][0] == 'd');
std::string infile = argv[2];
std::string outfile = argv[3];
std::vector<BYTE> inbuf = ReadFileData(infile);
if (inbuf.empty()) {
printf("%s could not be opened or is empty.\n", infile.c_str());
return 0;
}
DumpHash(infile, inbuf);
printf("%s \"%s\" -> \"%s\"\n",
depack ? "Decompressing" : "Compressing",
infile.c_str(),
outfile.c_str()
);
std::vector<BYTE> outbuf;
size_t ratio = 0;
if (depack) {
outbuf = d3d_depack(inbuf);
ratio = CalcRatio(outbuf.size(), inbuf.size());
} else {
outbuf = d3d_pack(inbuf);
ratio = CalcRatio(inbuf.size(), outbuf.size());
}
printf("%s ratio : %zd%%\n",
depack ? "Decompressed" : "Compressed",
ratio
);
WriteFileData(outfile, outbuf);
DumpHash(outfile, outbuf);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment