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

package tables

import (
	"encoding/binary"
	"fmt"
)

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

func (item *ConditionFormat1) mustParse(src []byte) {
	_ = src[7] // early bound checking
	item.format = binary.BigEndian.Uint16(src[0:])
	item.AxisIndex = binary.BigEndian.Uint16(src[2:])
	item.FilterRangeMinValue = Coord(binary.BigEndian.Uint16(src[4:]))
	item.FilterRangeMaxValue = Coord(binary.BigEndian.Uint16(src[6:]))
}

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

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

	{

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

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

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

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

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

	{

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

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

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

	{

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

		item.Records = make([]TagOffsetRecord, arrayLengthRecords) // allocation guarded by the previous check
		for i := range item.Records {
			item.Records[i].mustParse(src[2+i*6:])
		}
		n += arrayLengthRecords * 6
	}
	{

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

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

	{

		offset := 6
		for i := 0; i < arrayLengthSubstitutions; i++ {
			elem, read, err := ParseFeatureTableSubstitutionRecord(src[offset:], src)
			if err != nil {
				return item, 0, fmt.Errorf("reading FeatureTableSubstitution: %s", err)
			}
			item.Substitutions = append(item.Substitutions, elem)
			offset += read
		}
		n = offset
	}
	return item, n, nil
}

func ParseFeatureTableSubstitutionRecord(src []byte, parentSrc []byte) (FeatureTableSubstitutionRecord, int, error) {
	var item FeatureTableSubstitutionRecord
	n := 0
	if L := len(src); L < 6 {
		return item, 0, fmt.Errorf("reading FeatureTableSubstitutionRecord: "+"EOF: expected length: 6, got %d", L)
	}
	_ = src[5] // early bound checking
	item.FeatureIndex = binary.BigEndian.Uint16(src[0:])
	offsetAlternateFeature := int(binary.BigEndian.Uint32(src[2:]))
	n += 6

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

			var err error
			item.AlternateFeature, _, err = ParseFeature(parentSrc[offsetAlternateFeature:])
			if err != nil {
				return item, 0, fmt.Errorf("reading FeatureTableSubstitutionRecord: %s", err)
			}

		}
	}
	return item, n, nil
}

func ParseFeatureVariation(src []byte) (FeatureVariation, int, error) {
	var item FeatureVariation
	n := 0
	if L := len(src); L < 8 {
		return item, 0, fmt.Errorf("reading FeatureVariation: "+"EOF: expected length: 8, got %d", L)
	}
	_ = src[7] // early bound checking
	item.majorVersion = binary.BigEndian.Uint16(src[0:])
	item.minorVersion = binary.BigEndian.Uint16(src[2:])
	arrayLengthFeatureVariationRecords := int(binary.BigEndian.Uint32(src[4:]))
	n += 8

	{

		offset := 8
		for i := 0; i < arrayLengthFeatureVariationRecords; i++ {
			elem, read, err := ParseFeatureVariationRecord(src[offset:], src)
			if err != nil {
				return item, 0, fmt.Errorf("reading FeatureVariation: %s", err)
			}
			item.FeatureVariationRecords = append(item.FeatureVariationRecords, elem)
			offset += read
		}
		n = offset
	}
	return item, n, nil
}

func ParseFeatureVariationRecord(src []byte, parentSrc []byte) (FeatureVariationRecord, int, error) {
	var item FeatureVariationRecord
	n := 0
	if L := len(src); L < 8 {
		return item, 0, fmt.Errorf("reading FeatureVariationRecord: "+"EOF: expected length: 8, got %d", L)
	}
	_ = src[7] // early bound checking
	offsetConditionSet := int(binary.BigEndian.Uint32(src[0:]))
	offsetSubstitutions := int(binary.BigEndian.Uint32(src[4:]))
	n += 8

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

			var err error
			item.ConditionSet, _, err = ParseConditionSet(parentSrc[offsetConditionSet:])
			if err != nil {
				return item, 0, fmt.Errorf("reading FeatureVariationRecord: %s", err)
			}

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

			var err error
			item.Substitutions, _, err = ParseFeatureTableSubstitution(parentSrc[offsetSubstitutions:])
			if err != nil {
				return item, 0, fmt.Errorf("reading FeatureVariationRecord: %s", err)
			}

		}
	}
	return item, n, nil
}

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

	{

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

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

func ParseLayout(src []byte) (Layout, int, error) {
	var item Layout
	n := 0
	if L := len(src); L < 10 {
		return item, 0, fmt.Errorf("reading Layout: "+"EOF: expected length: 10, got %d", L)
	}
	_ = src[9] // early bound checking
	item.majorVersion = binary.BigEndian.Uint16(src[0:])
	item.minorVersion = binary.BigEndian.Uint16(src[2:])
	offsetScriptList := int(binary.BigEndian.Uint16(src[4:]))
	offsetFeatureList := int(binary.BigEndian.Uint16(src[6:]))
	offsetLookupList := int(binary.BigEndian.Uint16(src[8:]))
	n += 10

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

			var err error
			item.ScriptList, _, err = ParseScriptList(src[offsetScriptList:])
			if err != nil {
				return item, 0, fmt.Errorf("reading Layout: %s", err)
			}

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

			var err error
			item.FeatureList, _, err = ParseFeatureList(src[offsetFeatureList:])
			if err != nil {
				return item, 0, fmt.Errorf("reading Layout: %s", err)
			}

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

			var err error
			item.LookupList, _, err = parseLookupList(src[offsetLookupList:])
			if err != nil {
				return item, 0, fmt.Errorf("reading Layout: %s", err)
			}

		}
	}
	{

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

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

	{

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

		item.subtableOffsets = make([]Offset16, arrayLengthSubtableOffsets) // allocation guarded by the previous check
		for i := range item.subtableOffsets {
			item.subtableOffsets[i] = Offset16(binary.BigEndian.Uint16(src[6+i*2:]))
		}
		n += arrayLengthSubtableOffsets * 2
	}
	if L := len(src); L < n+2 {
		return item, 0, fmt.Errorf("reading Lookup: "+"EOF: expected length: n + 2, got %d", L)
	}
	item.MarkFilteringSet = binary.BigEndian.Uint16(src[n:])
	n += 2

	{

		item.rawData = src[0:]
		n = len(src)
	}
	return item, n, nil
}

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

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

			var tmpDefaultLangSys LangSys
			var err error
			tmpDefaultLangSys, _, err = ParseLangSys(src[offsetDefaultLangSys:])
			if err != nil {
				return item, 0, fmt.Errorf("reading Script: %s", err)
			}

			item.DefaultLangSys = &tmpDefaultLangSys
		}
	}
	{

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

		item.LangSysRecords = make([]TagOffsetRecord, arrayLengthLangSysRecords) // allocation guarded by the previous check
		for i := range item.LangSysRecords {
			item.LangSysRecords[i].mustParse(src[4+i*6:])
		}
		n += arrayLengthLangSysRecords * 6
	}
	{

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

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

	{

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

		item.Records = make([]TagOffsetRecord, arrayLengthRecords) // allocation guarded by the previous check
		for i := range item.Records {
			item.Records[i].mustParse(src[2+i*6:])
		}
		n += arrayLengthRecords * 6
	}
	{

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

func (item *TagOffsetRecord) mustParse(src []byte) {
	_ = src[5] // early bound checking
	item.Tag = Tag(binary.BigEndian.Uint32(src[0:]))
	item.Offset = binary.BigEndian.Uint16(src[4:])
}

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

	{

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

		item.Lookups = make([]Lookup, arrayLengthLookups) // allocation guarded by the previous check
		for i := range item.Lookups {
			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 lookupList: "+"EOF: expected length: %d, got %d", offset, L)
			}

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