Repository: qmuntal/gltf
Pull request #52 (2022-03-02 12:16:21)

modeler: ensure Read funcs always return a slice with the right length 
In some situations where modeler.Read* functions were supplied with a buffer longer than accessor.Count, the returned slice had the buffer length instead of the length defined by accessor.Count.


Patch:
diff --git a/modeler/read.go b/modeler/read.go
index 50b571d..59afc1a 100644
--- a/modeler/read.go
+++ b/modeler/read.go
@@ -119,6 +119,8 @@ func ReadIndices(doc *gltf.Document, acr *gltf.Accessor, buffer []uint32) ([]uin
 	}
 	if uint32(len(buffer)) < acr.Count {
 		buffer = append(buffer, make([]uint32, acr.Count-uint32(len(buffer)))...)
+	} else {
+		buffer = buffer[:acr.Count]
 	}
 	switch acr.ComponentType {
 	case gltf.ComponentUbyte:
@@ -189,6 +191,8 @@ func ReadTextureCoord(doc *gltf.Document, acr *gltf.Accessor, buffer [][2]float3
 	}
 	if uint32(len(buffer)) < acr.Count {
 		buffer = append(buffer, make([][2]float32, acr.Count-uint32(len(buffer)))...)
+	} else {
+		buffer = buffer[:acr.Count]
 	}
 	switch acr.ComponentType {
 	case gltf.ComponentUbyte:
@@ -229,6 +233,8 @@ func ReadWeights(doc *gltf.Document, acr *gltf.Accessor, buffer [][4]float32) ([
 	}
 	if uint32(len(buffer)) < acr.Count {
 		buffer = append(buffer, make([][4]float32, acr.Count-uint32(len(buffer)))...)
+	} else {
+		buffer = buffer[:acr.Count]
 	}
 	switch acr.ComponentType {
 	case gltf.ComponentUbyte:
@@ -271,6 +277,8 @@ func ReadJoints(doc *gltf.Document, acr *gltf.Accessor, buffer [][4]uint16) ([][
 	}
 	if uint32(len(buffer)) < acr.Count {
 		buffer = append(buffer, make([][4]uint16, acr.Count-uint32(len(buffer)))...)
+	} else {
+		buffer = buffer[:acr.Count]
 	}
 	switch acr.ComponentType {
 	case gltf.ComponentUbyte:
@@ -325,6 +333,8 @@ func ReadColor(doc *gltf.Document, acr *gltf.Accessor, buffer [][4]uint8) ([][4]
 	}
 	if uint32(len(buffer)) < acr.Count {
 		buffer = append(buffer, make([][4]uint8, acr.Count-uint32(len(buffer)))...)
+	} else {
+		buffer = buffer[:acr.Count]
 	}
 	switch acr.ComponentType {
 	case gltf.ComponentUbyte:
@@ -382,6 +392,8 @@ func ReadColor64(doc *gltf.Document, acr *gltf.Accessor, buffer [][4]uint16) ([]
 	}
 	if uint32(len(buffer)) < acr.Count {
 		buffer = append(buffer, make([][4]uint16, acr.Count-uint32(len(buffer)))...)
+	} else {
+		buffer = buffer[:acr.Count]
 	}
 	switch acr.ComponentType {
 	case gltf.ComponentUbyte:


Test patch:
diff --git a/modeler/read_test.go b/modeler/read_test.go
index 0d2a725..227d514 100644
--- a/modeler/read_test.go
+++ b/modeler/read_test.go
@@ -7,6 +7,40 @@ import (
 	"github.com/qmuntal/gltf"
 )
 
+func TestReadColor64_ReuseBuffer(t *testing.T) {
+	data := []byte{1, 2, 3, 4, 1, 2, 3, 4}
+	acc1 := &gltf.Accessor{
+		BufferView: gltf.Index(0), Count: 1, Type: gltf.AccessorVec4, ComponentType: gltf.ComponentUbyte,
+	}
+	acc2 := &gltf.Accessor{
+		BufferView: gltf.Index(0), Count: 2, Type: gltf.AccessorVec4, ComponentType: gltf.ComponentUbyte,
+	}
+	doc := &gltf.Document{
+		BufferViews: []*gltf.BufferView{
+			{Buffer: 0, ByteLength: uint32(len(data))},
+		},
+		Buffers: []*gltf.Buffer{
+			{Data: data, ByteLength: uint32(len(data))},
+		},
+	}
+	var buf [][4]uint16
+	var err error
+	buf, err = ReadColor64(doc, acc2, buf)
+	if err != nil {
+		t.Error(err)
+	}
+	if len(buf) != int(acc2.Count) {
+		t.Errorf("ReadColor() len = %d, want %d", len(buf), acc2.Count)
+	}
+	buf, err = ReadColor64(doc, acc1, buf)
+	if err != nil {
+		t.Error(err)
+	}
+	if len(buf) != int(acc1.Count) {
+		t.Errorf("ReadColor() len = %d, want %d", len(buf), acc1.Count)
+	}
+}
+
 func TestReadBufferView(t *testing.T) {
 	type args struct {
 		doc *gltf.Document
diff --git a/modeler/write_test.go b/modeler/write_test.go
index e0fff80..ae18d5b 100644
--- a/modeler/write_test.go
+++ b/modeler/write_test.go
@@ -735,9 +735,7 @@ func TestWriteImage(t *testing.T) {
 	}
 }
 
-type errReader struct {
-	r io.Reader
-}
+type errReader struct{}
 
 func (r *errReader) Read(p []byte) (int, error) {
 	return 0, errors.New("")