43 lines
1.4 KiB
TypeScript
43 lines
1.4 KiB
TypeScript
export const DIRECTOR_MAX_GLB_BYTES = 25 * 1024 * 1024;
|
|
/** Only self-contained GLB 2.0 files are accepted; external buffers/textures are not portable. */
|
|
export function validateDirectorGlb(buffer: ArrayBuffer) {
|
|
if (buffer.byteLength < 20 || buffer.byteLength > DIRECTOR_MAX_GLB_BYTES)
|
|
throw new Error("请上传 25 MiB 以内的有效 GLB 模型");
|
|
const view = new DataView(buffer);
|
|
if (
|
|
view.getUint32(0, true) !== 0x46546c67 ||
|
|
view.getUint32(4, true) !== 2 ||
|
|
view.getUint32(8, true) !== buffer.byteLength
|
|
)
|
|
throw new Error("文件不是有效的 GLB 2.0 模型");
|
|
const length = view.getUint32(12, true);
|
|
if (
|
|
view.getUint32(16, true) !== 0x4e4f534a ||
|
|
length % 4 ||
|
|
length > buffer.byteLength - 20
|
|
)
|
|
throw new Error("GLB 场景数据不完整");
|
|
let document: any;
|
|
try {
|
|
document = JSON.parse(
|
|
new TextDecoder().decode(new Uint8Array(buffer, 20, length)),
|
|
);
|
|
} catch {
|
|
throw new Error("GLB 场景数据无效");
|
|
}
|
|
if (
|
|
document?.asset?.version !== "2.0" ||
|
|
!Array.isArray(document.meshes) ||
|
|
!document.meshes.length
|
|
)
|
|
throw new Error("GLB 中没有可显示的网格");
|
|
for (const resource of [
|
|
...(document.buffers || []),
|
|
...(document.images || []),
|
|
]) {
|
|
if (resource.uri && !/^data:/i.test(resource.uri))
|
|
throw new Error("请将纹理和缓冲区嵌入 GLB 后重新上传");
|
|
}
|
|
return document;
|
|
}
|