11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
# File 'lib/rgltf/glb.rb', line 11
def read(data)
bytes = data.b
raise FormatError, 'truncated GLB header' if bytes.bytesize < 12
magic, version, length = bytes.unpack('L<L<L<')
raise FormatError, 'not a GLB (bad magic)' unless magic == MAGIC
raise UnsupportedError, "GLB version #{version}" unless version == 2
raise FormatError, 'invalid GLB length' if length < 20
raise FormatError, 'GLB length must be 4-byte aligned' unless (length % 4).zero?
raise FormatError, 'GLB length does not match input' unless bytes.bytesize == length
offset = 12
json = nil
bin = nil
first_chunk = true
while offset < length
raise FormatError, 'truncated GLB chunk header' if offset + 8 > length
chunk_length, chunk_type = bytes.byteslice(offset, 8).unpack('L<L<')
raise FormatError, 'GLB chunk length must be 4-byte aligned' unless (chunk_length % 4).zero?
chunk_end = offset + 8 + chunk_length
raise FormatError, 'truncated GLB chunk' if chunk_end > length
raise FormatError, 'GLB JSON must be the first chunk' if first_chunk && chunk_type != CHUNK_JSON
body = bytes.byteslice(offset + 8, chunk_length)
case chunk_type
when CHUNK_JSON
raise FormatError, 'duplicate JSON chunk' if json
json = body
when CHUNK_BIN
raise FormatError, 'duplicate BIN chunk' if bin
bin = body
end
first_chunk = false
offset = chunk_end
end
raise FormatError, 'GLB chunks do not match declared length' unless offset == length
raise FormatError, 'GLB has no JSON chunk' unless json
[json, bin]
end
|