spine连接器和导出修改
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
import { normalize } from 'node:path'
|
||||
|
||||
const CRC_TABLE = Array.from({ length: 256 }, (_, value) => {
|
||||
let crc = value
|
||||
for (let bit = 0; bit < 8; bit++) crc = (crc & 1) ? 0xedb88320 ^ (crc >>> 1) : crc >>> 1
|
||||
return crc >>> 0
|
||||
})
|
||||
|
||||
function crc32(data) {
|
||||
let crc = 0xffffffff
|
||||
for (const byte of data) crc = CRC_TABLE[(crc ^ byte) & 0xff] ^ (crc >>> 8)
|
||||
return (crc ^ 0xffffffff) >>> 0
|
||||
}
|
||||
|
||||
function archivePath(value) {
|
||||
const path = normalize(String(value || '').replace(/\\/g, '/')).replace(/\\/g, '/').replace(/^\.\//, '')
|
||||
if (!path || path.startsWith('/') || path === '..' || path.startsWith('../')) throw new Error('ZIP 文件路径无效')
|
||||
return path
|
||||
}
|
||||
|
||||
function dosDateTime(date = new Date()) {
|
||||
const year = Math.max(1980, date.getFullYear())
|
||||
return {
|
||||
time: (date.getHours() << 11) | (date.getMinutes() << 5) | Math.floor(date.getSeconds() / 2),
|
||||
date: ((year - 1980) << 9) | ((date.getMonth() + 1) << 5) | date.getDate(),
|
||||
}
|
||||
}
|
||||
|
||||
/** 创建无额外依赖的 ZIP(Store 模式);PNG 和 .spine 本身已压缩,无需重复压缩。 */
|
||||
export function createZipArchive(files) {
|
||||
const localParts = []
|
||||
const centralParts = []
|
||||
let offset = 0
|
||||
const timestamp = dosDateTime()
|
||||
|
||||
for (const file of files) {
|
||||
const name = Buffer.from(archivePath(file.name), 'utf8')
|
||||
const data = Buffer.isBuffer(file.data) ? file.data : Buffer.from(file.data)
|
||||
const crc = crc32(data)
|
||||
const local = Buffer.alloc(30)
|
||||
local.writeUInt32LE(0x04034b50, 0)
|
||||
local.writeUInt16LE(20, 4)
|
||||
local.writeUInt16LE(0x0800, 6)
|
||||
local.writeUInt16LE(0, 8)
|
||||
local.writeUInt16LE(timestamp.time, 10)
|
||||
local.writeUInt16LE(timestamp.date, 12)
|
||||
local.writeUInt32LE(crc, 14)
|
||||
local.writeUInt32LE(data.length, 18)
|
||||
local.writeUInt32LE(data.length, 22)
|
||||
local.writeUInt16LE(name.length, 26)
|
||||
localParts.push(local, name, data)
|
||||
|
||||
const central = Buffer.alloc(46)
|
||||
central.writeUInt32LE(0x02014b50, 0)
|
||||
central.writeUInt16LE(20, 4)
|
||||
central.writeUInt16LE(20, 6)
|
||||
central.writeUInt16LE(0x0800, 8)
|
||||
central.writeUInt16LE(0, 10)
|
||||
central.writeUInt16LE(timestamp.time, 12)
|
||||
central.writeUInt16LE(timestamp.date, 14)
|
||||
central.writeUInt32LE(crc, 16)
|
||||
central.writeUInt32LE(data.length, 20)
|
||||
central.writeUInt32LE(data.length, 24)
|
||||
central.writeUInt16LE(name.length, 28)
|
||||
central.writeUInt32LE(offset, 42)
|
||||
centralParts.push(central, name)
|
||||
offset += local.length + name.length + data.length
|
||||
}
|
||||
|
||||
const centralDirectory = Buffer.concat(centralParts)
|
||||
const end = Buffer.alloc(22)
|
||||
end.writeUInt32LE(0x06054b50, 0)
|
||||
end.writeUInt16LE(files.length, 8)
|
||||
end.writeUInt16LE(files.length, 10)
|
||||
end.writeUInt32LE(centralDirectory.length, 12)
|
||||
end.writeUInt32LE(offset, 16)
|
||||
return Buffer.concat([...localParts, centralDirectory, end])
|
||||
}
|
||||
Reference in New Issue
Block a user