// SPDX-License-Identifier: Unlicense OR BSD-3-Clause

package tables

import (
	"encoding/binary"
	"fmt"
)

// Code generated by binarygen from ot_gdef_src.go. DO NOT EDIT

func (item *CaretValue1) mustParse(src []byte) {
	_ = src[3] // early bound checking
	item.caretValueFormat = binary.BigEndian.Uint16(src[0:])
	item.Coordinate = int16(binary.BigEndian.Uint16(src[2:]))
}

func (item *CaretValue2) mustParse(src []byte) {
	_ = src[3] // early bound checking
	item.caretValueFormat = binary.BigEndian.Uint16(src[0:])
	item.CaretValuePointIndex = binary.BigEndian.Uint16(src[2:])
}

func (item *ClassRangeRecord) mustParse(src []byte) {
	_ = src[5] // early bound checking
	item.StartGlyphID = binary.BigEndian.Uint16(src[0:])
	item.EndGlyphID = binary.BigEndian.Uint16(src[2:])
	item.Class = binary.BigEndian.Uint16(src[4:])
}

func ParseAttachList(src []byte) (AttachList, int, error) {
	var item AttachList
	n := 0
	if L := len(src); L < 4 {
		return item, 0, fmt.Errorf("reading AttachList: "+"EOF: expected length: 4, got %d", L)
	}
	_ = src[3] // early bound checking
	offsetCoverage := int(binary.BigEndian.Uint16(src[0:]))
	arrayLengthAttachPoints := int(binary.BigEndian.Uint16(src[2:]))
	n += 4

	{

		if offsetCoverage != 0 { // ignore null offset
			if L := len(src); L < offsetCoverage {
				return item, 0, fmt.Errorf("reading AttachList: "+"EOF: expected length: %d, got %d", offsetCoverage, L)
			}

			var (
				err  error
				read int
			)
			item.Coverage, read, err = ParseCoverage(src[offsetCoverage:])
			if err != nil {
				return item, 0, fmt.Errorf("reading AttachList: %s", err)
			}
			offsetCoverage += read
		}
	}
	{

		if L := len(src); L < 4+arrayLengthAttachPoints*2 {
			return item, 0, fmt.Errorf("reading AttachList: "+"EOF: expected length: %d, got %d", 4+arrayLengthAttachPoints*2, L)
		}

		item.AttachPoints = make([]AttachPoint, arrayLengthAttachPoints) // allocation guarded by the previous check
		for i := range item.AttachPoints {
			offset := int(binary.BigEndian.Uint16(src[4+i*2:]))
			// ignore null offsets
			if offset == 0 {
				continue
			}

			if L := len(src); L < offset {
				return item, 0, fmt.Errorf("reading AttachList: "+"EOF: expected length: %d, got %d", offset, L)
			}

			var err error
			item.AttachPoints[i], _, err = ParseAttachPoint(src[offset:])
			if err != nil {
				return item, 0, fmt.Errorf("reading AttachList: %s", err)
			}
		}
		n += arrayLengthAttachPoints * 2
	}
	return item, n, nil
}

func ParseAttachPoint(src []byte) (AttachPoint, int, error) {
	var item AttachPoint
	n := 0
	if L := len(src); L < 2 {
		return item, 0, fmt.Errorf("reading AttachPoint: "+"EOF: expected length: 2, got %d", L)
	}
	arrayLengthPointIndices := int(binary.BigEndian.Uint16(src[0:]))
	n += 2

	{

		if L := len(src); L < 2+arrayLengthPointIndices*2 {
			return item, 0, fmt.Errorf("reading AttachPoint: "+"EOF: expected length: %d, got %d", 2+arrayLengthPointIndices*2, L)
		}

		item.PointIndices = make([]uint16, arrayLengthPointIndices) // allocation guarded by the previous check
		for i := range item.PointIndices {
			item.PointIndices[i] = binary.BigEndian.Uint16(src[2+i*2:])
		}
		n += arrayLengthPointIndices * 2
	}
	return item, n, nil
}

func ParseCaretValue(src []byte) (CaretValue, int, error) {
	var item CaretValue

	if L := len(src); L < 2 {
		return item, 0, fmt.Errorf("reading CaretValue: "+"EOF: expected length: 2, got %d", L)
	}
	format := uint16(binary.BigEndian.Uint16(src[0:]))
	var (
		read int
		err  error
	)
	switch format {
	case 1:
		item, read, err = ParseCaretValue1(src[0:])
	case 2:
		item, read, err = ParseCaretValue2(src[0:])
	case 3:
		item, read, err = ParseCaretValue3(src[0:])
	default:
		err = fmt.Errorf("unsupported CaretValue format %d", format)
	}
	if err != nil {
		return item, 0, fmt.Errorf("reading CaretValue: %s", err)
	}

	return item, read, nil
}

func ParseCaretValue1(src []byte) (CaretValue1, int, error) {
	var item CaretValue1
	n := 0
	if L := len(src); L < 4 {
		return item, 0, fmt.Errorf("reading CaretValue1: "+"EOF: expected length: 4, got %d", L)
	}
	item.mustParse(src)
	n += 4
	return item, n, nil
}

func ParseCaretValue2(src []byte) (CaretValue2, int, error) {
	var item CaretValue2
	n := 0
	if L := len(src); L < 4 {
		return item, 0, fmt.Errorf("reading CaretValue2: "+"EOF: expected length: 4, got %d", L)
	}
	item.mustParse(src)
	n += 4
	return item, n, nil
}

func ParseCaretValue3(src []byte) (CaretValue3, int, error) {
	var item CaretValue3
	n := 0
	if L := len(src); L < 6 {
		return item, 0, fmt.Errorf("reading CaretValue3: "+"EOF: expected length: 6, got %d", L)
	}
	_ = src[5] // early bound checking
	item.caretValueFormat = binary.BigEndian.Uint16(src[0:])
	item.Coordinate = int16(binary.BigEndian.Uint16(src[2:]))
	item.deviceOffset = Offset16(binary.BigEndian.Uint16(src[4:]))
	n += 6

	{

		err := item.parseDevice(src[:])
		if err != nil {
			return item, 0, fmt.Errorf("reading CaretValue3: %s", err)
		}
	}
	return item, n, nil
}

func ParseClassDef(src []byte) (ClassDef, int, error) {
	var item ClassDef

	if L := len(src); L < 2 {
		return item, 0, fmt.Errorf("reading ClassDef: "+"EOF: expected length: 2, got %d", L)
	}
	format := uint16(binary.BigEndian.Uint16(src[0:]))
	var (
		read int
		err  error
	)
	switch format {
	case 1:
		item, read, err = ParseClassDef1(src[0:])
	case 2:
		item, read, err = ParseClassDef2(src[0:])
	default:
		err = fmt.Errorf("unsupported ClassDef format %d", format)
	}
	if err != nil {
		return item, 0, fmt.Errorf("reading ClassDef: %s", err)
	}

	return item, read, nil
}

func ParseClassDef1(src []byte) (ClassDef1, int, error) {
	var item ClassDef1
	n := 0
	if L := len(src); L < 6 {
		return item, 0, fmt.Errorf("reading ClassDef1: "+"EOF: expected length: 6, got %d", L)
	}
	_ = src[5] // early bound checking
	item.format = binary.BigEndian.Uint16(src[0:])
	item.StartGlyphID = binary.BigEndian.Uint16(src[2:])
	arrayLengthClassValueArray := int(binary.BigEndian.Uint16(src[4:]))
	n += 6

	{

		if L := len(src); L < 6+arrayLengthClassValueArray*2 {
			return item, 0, fmt.Errorf("reading ClassDef1: "+"EOF: expected length: %d, got %d", 6+arrayLengthClassValueArray*2, L)
		}

		item.ClassValueArray = make([]uint16, arrayLengthClassValueArray) // allocation guarded by the previous check
		for i := range item.ClassValueArray {
			item.ClassValueArray[i] = binary.BigEndian.Uint16(src[6+i*2:])
		}
		n += arrayLengthClassValueArray * 2
	}
	return item, n, nil
}

func ParseClassDef2(src []byte) (ClassDef2, int, error) {
	var item ClassDef2
	n := 0
	if L := len(src); L < 4 {
		return item, 0, fmt.Errorf("reading ClassDef2: "+"EOF: expected length: 4, got %d", L)
	}
	_ = src[3] // early bound checking
	item.format = binary.BigEndian.Uint16(src[0:])
	arrayLengthClassRangeRecords := int(binary.BigEndian.Uint16(src[2:]))
	n += 4

	{

		if L := len(src); L < 4+arrayLengthClassRangeRecords*6 {
			return item, 0, fmt.Errorf("reading ClassDef2: "+"EOF: expected length: %d, got %d", 4+arrayLengthClassRangeRecords*6, L)
		}

		item.ClassRangeRecords = make([]ClassRangeRecord, arrayLengthClassRangeRecords) // allocation guarded by the previous check
		for i := range item.ClassRangeRecords {
			item.ClassRangeRecords[i].mustParse(src[4+i*6:])
		}
		n += arrayLengthClassRangeRecords * 6
	}
	return item, n, nil
}

func ParseCoverage(src []byte) (Coverage, int, error) {
	var item Coverage

	if L := len(src); L < 2 {
		return item, 0, fmt.Errorf("reading Coverage: "+"EOF: expected length: 2, got %d", L)
	}
	format := uint16(binary.BigEndian.Uint16(src[0:]))
	var (
		read int
		err  error
	)
	switch format {
	case 1:
		item, read, err = ParseCoverage1(src[0:])
	case 2:
		item, read, err = ParseCoverage2(src[0:])
	default:
		err = fmt.Errorf("unsupported Coverage format %d", format)
	}
	if err != nil {
		return item, 0, fmt.Errorf("reading Coverage: %s", err)
	}

	return item, read, nil
}

func ParseCoverage1(src []byte) (Coverage1, int, error) {
	var item Coverage1
	n := 0
	if L := len(src); L < 4 {
		return item, 0, fmt.Errorf("reading Coverage1: "+"EOF: expected length: 4, got %d", L)
	}
	_ = src[3] // early bound checking
	item.format = binary.BigEndian.Uint16(src[0:])
	arrayLengthGlyphs := int(binary.BigEndian.Uint16(src[2:]))
	n += 4

	{

		if L := len(src); L < 4+arrayLengthGlyphs*2 {
			return item, 0, fmt.Errorf("reading Coverage1: "+"EOF: expected length: %d, got %d", 4+arrayLengthGlyphs*2, L)
		}

		item.Glyphs = make([]uint16, arrayLengthGlyphs) // allocation guarded by the previous check
		for i := range item.Glyphs {
			item.Glyphs[i] = binary.BigEndian.Uint16(src[4+i*2:])
		}
		n += arrayLengthGlyphs * 2
	}
	return item, n, nil
}

func ParseCoverage2(src []byte) (Coverage2, int, error) {
	var item Coverage2
	n := 0
	if L := len(src); L < 4 {
		return item, 0, fmt.Errorf("reading Coverage2: "+"EOF: expected length: 4, got %d", L)
	}
	_ = src[3] // early bound checking
	item.format = binary.BigEndian.Uint16(src[0:])
	arrayLengthRanges := int(binary.BigEndian.Uint16(src[2:]))
	n += 4

	{

		if L := len(src); L < 4+arrayLengthRanges*6 {
			return item, 0, fmt.Errorf("reading Coverage2: "+"EOF: expected length: %d, got %d", 4+arrayLengthRanges*6, L)
		}

		item.Ranges = make([]RangeRecord, arrayLengthRanges) // allocation guarded by the previous check
		for i := range item.Ranges {
			item.Ranges[i].mustParse(src[4+i*6:])
		}
		n += arrayLengthRanges * 6
	}
	return item, n, nil
}

func ParseGDEF(src []byte) (GDEF, int, error) {
	var item GDEF
	n := 0
	if L := len(src); L < 12 {
		return item, 0, fmt.Errorf("reading GDEF: "+"EOF: expected length: 12, got %d", L)
	}
	_ = src[11] // early bound checking
	item.majorVersion = binary.BigEndian.Uint16(src[0:])
	item.minorVersion = binary.BigEndian.Uint16(src[2:])
	offsetGlyphClassDef := int(binary.BigEndian.Uint16(src[4:]))
	offsetAttachList := int(binary.BigEndian.Uint16(src[6:]))
	offsetLigCaretList := int(binary.BigEndian.Uint16(src[8:]))
	offsetMarkAttachClass := int(binary.BigEndian.Uint16(src[10:]))
	n += 12

	{

		if offsetGlyphClassDef != 0 { // ignore null offset
			if L := len(src); L < offsetGlyphClassDef {
				return item, 0, fmt.Errorf("reading GDEF: "+"EOF: expected length: %d, got %d", offsetGlyphClassDef, L)
			}

			var (
				err  error
				read int
			)
			item.GlyphClassDef, read, err = ParseClassDef(src[offsetGlyphClassDef:])
			if err != nil {
				return item, 0, fmt.Errorf("reading GDEF: %s", err)
			}
			offsetGlyphClassDef += read
		}
	}
	{

		if offsetAttachList != 0 { // ignore null offset
			if L := len(src); L < offsetAttachList {
				return item, 0, fmt.Errorf("reading GDEF: "+"EOF: expected length: %d, got %d", offsetAttachList, L)
			}

			var err error
			item.AttachList, _, err = ParseAttachList(src[offsetAttachList:])
			if err != nil {
				return item, 0, fmt.Errorf("reading GDEF: %s", err)
			}

		}
	}
	{

		if offsetLigCaretList != 0 { // ignore null offset
			if L := len(src); L < offsetLigCaretList {
				return item, 0, fmt.Errorf("reading GDEF: "+"EOF: expected length: %d, got %d", offsetLigCaretList, L)
			}

			var err error
			item.LigCaretList, _, err = ParseLigCaretList(src[offsetLigCaretList:])
			if err != nil {
				return item, 0, fmt.Errorf("reading GDEF: %s", err)
			}

		}
	}
	{

		if offsetMarkAttachClass != 0 { // ignore null offset
			if L := len(src); L < offsetMarkAttachClass {
				return item, 0, fmt.Errorf("reading GDEF: "+"EOF: expected length: %d, got %d", offsetMarkAttachClass, L)
			}

			var (
				err  error
				read int
			)
			item.MarkAttachClass, read, err = ParseClassDef(src[offsetMarkAttachClass:])
			if err != nil {
				return item, 0, fmt.Errorf("reading GDEF: %s", err)
			}
			offsetMarkAttachClass += read
		}
	}
	{

		err := item.parseMarkGlyphSetsDef(src[:])
		if err != nil {
			return item, 0, fmt.Errorf("reading GDEF: %s", err)
		}
	}
	{

		read, err := item.parseItemVarStore(src[:])
		if err != nil {
			return item, 0, fmt.Errorf("reading GDEF: %s", err)
		}
		n = read
	}
	return item, n, nil
}

func ParseLigCaretList(src []byte) (LigCaretList, int, error) {
	var item LigCaretList
	n := 0
	if L := len(src); L < 4 {
		return item, 0, fmt.Errorf("reading LigCaretList: "+"EOF: expected length: 4, got %d", L)
	}
	_ = src[3] // early bound checking
	offsetCoverage := int(binary.BigEndian.Uint16(src[0:]))
	arrayLengthLigGlyphs := int(binary.BigEndian.Uint16(src[2:]))
	n += 4

	{

		if offsetCoverage != 0 { // ignore null offset
			if L := len(src); L < offsetCoverage {
				return item, 0, fmt.Errorf("reading LigCaretList: "+"EOF: expected length: %d, got %d", offsetCoverage, L)
			}

			var (
				err  error
				read int
			)
			item.Coverage, read, err = ParseCoverage(src[offsetCoverage:])
			if err != nil {
				return item, 0, fmt.Errorf("reading LigCaretList: %s", err)
			}
			offsetCoverage += read
		}
	}
	{

		if L := len(src); L < 4+arrayLengthLigGlyphs*2 {
			return item, 0, fmt.Errorf("reading LigCaretList: "+"EOF: expected length: %d, got %d", 4+arrayLengthLigGlyphs*2, L)
		}

		item.LigGlyphs = make([]LigGlyph, arrayLengthLigGlyphs) // allocation guarded by the previous check
		for i := range item.LigGlyphs {
			offset := int(binary.BigEndian.Uint16(src[4+i*2:]))
			// ignore null offsets
			if offset == 0 {
				continue
			}

			if L := len(src); L < offset {
				return item, 0, fmt.Errorf("reading LigCaretList: "+"EOF: expected length: %d, got %d", offset, L)
			}

			var err error
			item.LigGlyphs[i], _, err = ParseLigGlyph(src[offset:])
			if err != nil {
				return item, 0, fmt.Errorf("reading LigCaretList: %s", err)
			}
		}
		n += arrayLengthLigGlyphs * 2
	}
	return item, n, nil
}

func ParseLigGlyph(src []byte) (LigGlyph, int, error) {
	var item LigGlyph
	n := 0
	if L := len(src); L < 2 {
		return item, 0, fmt.Errorf("reading LigGlyph: "+"EOF: expected length: 2, got %d", L)
	}
	arrayLengthCaretValues := int(binary.BigEndian.Uint16(src[0:]))
	n += 2

	{

		if L := len(src); L < 2+arrayLengthCaretValues*2 {
			return item, 0, fmt.Errorf("reading LigGlyph: "+"EOF: expected length: %d, got %d", 2+arrayLengthCaretValues*2, L)
		}

		item.CaretValues = make([]CaretValue, arrayLengthCaretValues) // allocation guarded by the previous check
		for i := range item.CaretValues {
			offset := int(binary.BigEndian.Uint16(src[2+i*2:]))
			// ignore null offsets
			if offset == 0 {
				continue
			}

			if L := len(src); L < offset {
				return item, 0, fmt.Errorf("reading LigGlyph: "+"EOF: expected length: %d, got %d", offset, L)
			}

			var err error
			item.CaretValues[i], _, err = ParseCaretValue(src[offset:])
			if err != nil {
				return item, 0, fmt.Errorf("reading LigGlyph: %s", err)
			}
		}
		n += arrayLengthCaretValues * 2
	}
	return item, n, nil
}

func ParseMarkGlyphSets(src []byte) (MarkGlyphSets, int, error) {
	var item MarkGlyphSets
	n := 0
	if L := len(src); L < 4 {
		return item, 0, fmt.Errorf("reading MarkGlyphSets: "+"EOF: expected length: 4, got %d", L)
	}
	_ = src[3] // early bound checking
	item.format = binary.BigEndian.Uint16(src[0:])
	arrayLengthCoverages := int(binary.BigEndian.Uint16(src[2:]))
	n += 4

	{

		if L := len(src); L < 4+arrayLengthCoverages*4 {
			return item, 0, fmt.Errorf("reading MarkGlyphSets: "+"EOF: expected length: %d, got %d", 4+arrayLengthCoverages*4, L)
		}

		item.Coverages = make([]Coverage, arrayLengthCoverages) // allocation guarded by the previous check
		for i := range item.Coverages {
			offset := int(binary.BigEndian.Uint32(src[4+i*4:]))
			// ignore null offsets
			if offset == 0 {
				continue
			}

			if L := len(src); L < offset {
				return item, 0, fmt.Errorf("reading MarkGlyphSets: "+"EOF: expected length: %d, got %d", offset, L)
			}

			var err error
			item.Coverages[i], _, err = ParseCoverage(src[offset:])
			if err != nil {
				return item, 0, fmt.Errorf("reading MarkGlyphSets: %s", err)
			}
		}
		n += arrayLengthCoverages * 4
	}
	return item, n, nil
}

func (item *RangeRecord) mustParse(src []byte) {
	_ = src[5] // early bound checking
	item.StartGlyphID = binary.BigEndian.Uint16(src[0:])
	item.EndGlyphID = binary.BigEndian.Uint16(src[2:])
	item.StartCoverageIndex = binary.BigEndian.Uint16(src[4:])
}
