mirror of
https://github.com/xhacker-zzz/QmcWasm.git
synced 2024-11-25 12:32:16 +00:00
75 lines
2.3 KiB
TypeScript
75 lines
2.3 KiB
TypeScript
|
import { QmcCrypto } from '@xhacker/qmcwasm/QmcWasmBundle';
|
|||
|
import QmcCryptoModule from '@xhacker/qmcwasm/QmcWasmBundle';
|
|||
|
import { MergeUint8Array } from '@/utils/MergeUint8Array';
|
|||
|
|
|||
|
// 每次处理 2M 的数据
|
|||
|
const DECRYPTION_BUF_SIZE = 2 *1024 * 1024;
|
|||
|
|
|||
|
export interface QMCDecryptionResult {
|
|||
|
success: boolean;
|
|||
|
data: Uint8Array;
|
|||
|
songId: string | number;
|
|||
|
error: string;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* 解密一个 QMC 加密的文件。
|
|||
|
*
|
|||
|
* 如果检测并解密成功,返回解密后的 Uint8Array 数据。
|
|||
|
* @param {ArrayBuffer} qmcBlob 读入的文件 Blob
|
|||
|
*/
|
|||
|
export async function DecryptQmcWasm(qmcBlob: ArrayBuffer, ext: string): Promise<QMCDecryptionResult> {
|
|||
|
const result: QMCDecryptionResult = { success: false, data: new Uint8Array(), songId: 0, error: '' };
|
|||
|
|
|||
|
// 初始化模组
|
|||
|
let QmcCryptoObj: QmcCrypto;
|
|||
|
|
|||
|
try {
|
|||
|
QmcCryptoObj = await QmcCryptoModule();
|
|||
|
} catch (err: any) {
|
|||
|
result.error = err?.message || 'wasm 加载失败';
|
|||
|
return result;
|
|||
|
}
|
|||
|
if (!QmcCryptoObj) {
|
|||
|
result.error = 'wasm 加载失败';
|
|||
|
return result;
|
|||
|
}
|
|||
|
|
|||
|
// 申请内存块,并文件末端数据到 WASM 的内存堆
|
|||
|
const qmcBuf = new Uint8Array(qmcBlob);
|
|||
|
const pQmcBuf = QmcCryptoObj._malloc(DECRYPTION_BUF_SIZE);
|
|||
|
QmcCryptoObj.writeArrayToMemory(qmcBuf.slice(-DECRYPTION_BUF_SIZE), pQmcBuf);
|
|||
|
|
|||
|
// 进行解密初始化
|
|||
|
ext = '.' + ext;
|
|||
|
const tailSize = QmcCryptoObj.preDec(pQmcBuf, DECRYPTION_BUF_SIZE, ext);
|
|||
|
if (tailSize == -1) {
|
|||
|
result.error = QmcCryptoObj.getErr();
|
|||
|
return result;
|
|||
|
} else {
|
|||
|
result.songId = QmcCryptoObj.getSongId();
|
|||
|
result.songId = result.songId == "0" ? 0 : result.songId;
|
|||
|
}
|
|||
|
|
|||
|
const decryptedParts = [];
|
|||
|
let offset = 0;
|
|||
|
let bytesToDecrypt = qmcBuf.length - tailSize;
|
|||
|
while (bytesToDecrypt > 0) {
|
|||
|
const blockSize = Math.min(bytesToDecrypt, DECRYPTION_BUF_SIZE);
|
|||
|
|
|||
|
// 解密一些片段
|
|||
|
const blockData = new Uint8Array(qmcBuf.slice(offset, offset + blockSize));
|
|||
|
QmcCryptoObj.writeArrayToMemory(blockData, pQmcBuf);
|
|||
|
decryptedParts.push(QmcCryptoObj.HEAPU8.slice(pQmcBuf, pQmcBuf + QmcCryptoObj.decBlob(pQmcBuf, blockSize, offset)));
|
|||
|
|
|||
|
offset += blockSize;
|
|||
|
bytesToDecrypt -= blockSize;
|
|||
|
}
|
|||
|
QmcCryptoObj._free(pQmcBuf);
|
|||
|
|
|||
|
result.data = MergeUint8Array(decryptedParts);
|
|||
|
result.success = true;
|
|||
|
|
|||
|
return result;
|
|||
|
}
|