Module: Rgltf::GLB

Defined in:
lib/rgltf/glb.rb

Constant Summary collapse

MAGIC =
0x46546C67
CHUNK_JSON =
0x4E4F534A
CHUNK_BIN =
0x004E4942

Class Method Summary collapse

Class Method Details

.pad(string, byte) ⇒ Object



67
68
69
# File 'lib/rgltf/glb.rb', line 67

def pad(string, byte)
  string + (byte.chr * ((4 - (string.bytesize % 4)) % 4))
end

.read(data) ⇒ Object

Raises:



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

.write(json_string, bin_string = nil) ⇒ Object



57
58
59
60
61
62
63
64
65
# File 'lib/rgltf/glb.rb', line 57

def write(json_string, bin_string = nil)
  json = pad(json_string.b, 0x20)
  chunks = [[CHUNK_JSON, json]]
  chunks << [CHUNK_BIN, pad(bin_string.b, 0x00)] if bin_string
  total = 12 + chunks.sum { |_, chunk| 8 + chunk.bytesize }
  output = [MAGIC, 2, total].pack('L<L<L<')
  chunks.each { |type, chunk| output << [chunk.bytesize, type].pack('L<L<') << chunk }
  output
end