import { Packr, Unpackr, decode } from "msgpackr"; import * as fflate from "fflate"; import { AppendableBuffer, isTauri } from "../globalApi.svelte"; const packr = new Packr({ useRecords:false }); const unpackr = new Unpackr({ int64AsType: 'number', useRecords:false }) const magicHeader = new Uint8Array([0, 82, 73, 83, 85, 83, 65, 86, 69, 0, 7]); const magicCompressedHeader = new Uint8Array([0, 82, 73, 83, 85, 83, 65, 86, 69, 0, 8]); const magicStreamCompressedHeader = new Uint8Array([0, 82, 73, 83, 85, 83, 65, 86, 69, 0, 9]); async function checkCompressionStreams(){ if(!CompressionStream){ const {makeCompressionStream} = await import('compression-streams-polyfill/ponyfill'); globalThis.CompressionStream = makeCompressionStream(TransformStream); } if(!DecompressionStream){ const {makeDecompressionStream} = await import('compression-streams-polyfill/ponyfill'); globalThis.DecompressionStream = makeDecompressionStream(TransformStream); } } export function encodeRisuSaveLegacy(data:any, compression:'noCompression'|'compression' = 'noCompression'){ let encoded:Uint8Array = packr.encode(data) if(compression === 'compression'){ encoded = fflate.compressSync(encoded) const result = new Uint8Array(encoded.length + magicCompressedHeader.length); result.set(magicCompressedHeader, 0) result.set(encoded, magicCompressedHeader.length) return result } else{ const result = new Uint8Array(encoded.length + magicHeader.length); result.set(magicHeader, 0) result.set(encoded, magicHeader.length) return result } } export async function encodeRisuSave(data:any) { await checkCompressionStreams() let encoded:Uint8Array = packr.encode(data) const cs = new CompressionStream('gzip'); const writer = cs.writable.getWriter(); writer.write(encoded); writer.close(); const buf = await new Response(cs.readable).arrayBuffer() const result = new Uint8Array(new Uint8Array(buf).length + magicStreamCompressedHeader.length); result.set(magicStreamCompressedHeader, 0) result.set(new Uint8Array(buf), magicStreamCompressedHeader.length) return result } export async function decodeRisuSave(data:Uint8Array){ try { switch(checkHeader(data)){ case "compressed": data = data.slice(magicCompressedHeader.length) return decode(fflate.decompressSync(data)) case "raw": data = data.slice(magicHeader.length) return unpackr.decode(data) case "stream":{ await checkCompressionStreams() data = data.slice(magicStreamCompressedHeader.length) const cs = new DecompressionStream('gzip'); const writer = cs.writable.getWriter(); writer.write(data); writer.close(); const buf = await new Response(cs.readable).arrayBuffer() return unpackr.decode(new Uint8Array(buf)) } } return unpackr.decode(data) } catch (error) { try { console.log('risudecode') const risuSaveHeader = new Uint8Array(Buffer.from("\u0000\u0000RISU",'utf-8')) const realData = data.subarray(risuSaveHeader.length) const dec = unpackr.decode(realData) return dec } catch (error) { const buf = Buffer.from(fflate.decompressSync(Buffer.from(data))) try { return JSON.parse(buf.toString('utf-8')) } catch (error) { return unpackr.decode(buf) } } } } function checkHeader(data: Uint8Array) { let header:'none'|'compressed'|'raw'|'stream' = 'raw' if (data.length < magicHeader.length) { return false; } for (let i = 0; i < magicHeader.length; i++) { if (data[i] !== magicHeader[i]) { header = 'none' break } } if(header === 'none'){ header = 'compressed' for (let i = 0; i < magicCompressedHeader.length; i++) { if (data[i] !== magicCompressedHeader[i]) { header = 'none' break } } } if(header === 'none'){ header = 'stream' for (let i = 0; i < magicStreamCompressedHeader.length; i++) { if (data[i] !== magicStreamCompressedHeader[i]) { header = 'none' break } } } // All bytes matched return header; }