package binary

import (
	
	
	
	
	

	
	
	
	
)

// DecodeModule implements wasm.DecodeModule for the WebAssembly 1.0 (20191205) Binary Format
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-format%E2%91%A0
func (
	 []byte,
	 api.CoreFeatures,
	 uint32,
	,
	,  bool,
) (*wasm.Module, error) {
	 := bytes.NewReader()

	// Magic number.
	 := make([]byte, 4)
	if ,  := io.ReadFull(, );  != nil || !bytes.Equal(, Magic) {
		return nil, ErrInvalidMagicNumber
	}

	// Version.
	if ,  := io.ReadFull(, );  != nil || !bytes.Equal(, version) {
		return nil, ErrInvalidVersion
	}

	 := newMemorySizer(, )

	 := &wasm.Module{}
	var  wasm.SectionID
	var , , , ,  []byte // For DWARF Data.
	for {
		// TODO: except custom sections, all others are required to be in order, but we aren't checking yet.
		// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#modules%E2%91%A0%E2%93%AA
		,  := .ReadByte()
		if  == io.EOF {
			break
		} else if  != nil {
			return nil, fmt.Errorf("read section id: %w", )
		}

		, ,  := leb128.DecodeUint32()
		if  != nil {
			return nil, fmt.Errorf("get size of section %s: %v", wasm.SectionIDName(), )
		}

		var  bool
		,  = checkSectionOrder(, )
		if ! {
			return nil, errors.New("invalid section order")
		}

		 := .Len()
		switch  {
		case wasm.SectionIDCustom:
			// First, validate the section and determine if the section for this name has already been set
			, ,  := decodeUTF8(, "custom section name")
			if  != nil {
				 = 
				break
			} else if  <  {
				 = fmt.Errorf("malformed custom section %s", )
				break
			} else if  == "name" && .NameSection != nil {
				 = fmt.Errorf("redundant custom section %s", )
				break
			}

			// Now, either decode the NameSection or CustomSection
			 :=  - 

			var  *wasm.CustomSection
			if  != "name" {
				if  ||  {
					,  = decodeCustomSection(, , uint64())
					if  != nil {
						return nil, fmt.Errorf("failed to read custom section name[%s]: %w", , )
					}
					.CustomSections = append(.CustomSections, )
					if  {
						switch  {
						case ".debug_info":
							 = .Data
						case ".debug_line":
							 = .Data
						case ".debug_str":
							 = .Data
						case ".debug_abbrev":
							 = .Data
						case ".debug_ranges":
							 = .Data
						}
					}
				} else {
					if _,  = io.CopyN(io.Discard, , int64());  != nil {
						return nil, fmt.Errorf("failed to skip name[%s]: %w", , )
					}
				}
			} else {
				.NameSection,  = decodeNameSection(, uint64())
			}
		case wasm.SectionIDType:
			.TypeSection,  = decodeTypeSection(, )
		case wasm.SectionIDImport:
			.ImportSection, .ImportPerModule, .ImportFunctionCount, .ImportGlobalCount, .ImportMemoryCount, .ImportTableCount,  = decodeImportSection(, , , )
			if  != nil {
				return nil,  // avoid re-wrapping the error.
			}
		case wasm.SectionIDFunction:
			.FunctionSection,  = decodeFunctionSection()
		case wasm.SectionIDTable:
			.TableSection,  = decodeTableSection(, )
		case wasm.SectionIDMemory:
			.MemorySection,  = decodeMemorySection(, , , )
		case wasm.SectionIDGlobal:
			if .GlobalSection,  = decodeGlobalSection(, );  != nil {
				return nil,  // avoid re-wrapping the error.
			}
		case wasm.SectionIDExport:
			.ExportSection, .Exports,  = decodeExportSection()
		case wasm.SectionIDStart:
			.StartSection,  = decodeStartSection()
		case wasm.SectionIDElement:
			.ElementSection,  = decodeElementSection(, )
		case wasm.SectionIDCode:
			.CodeSection,  = decodeCodeSection()
		case wasm.SectionIDData:
			.DataSection,  = decodeDataSection(, )
		case wasm.SectionIDDataCount:
			if  := .RequireEnabled(api.CoreFeatureBulkMemoryOperations);  != nil {
				return nil, fmt.Errorf("data count section not supported as %v", )
			}
			.DataCountSection,  = decodeDataCountSection()
		default:
			 = ErrInvalidSectionID
		}

		 :=  - .Len()
		if  == nil && int() !=  {
			 = fmt.Errorf("invalid section length: expected to be %d but got %d", , )
		}

		if  != nil {
			return nil, fmt.Errorf("section %s: %v", wasm.SectionIDName(), )
		}
	}

	if  {
		,  := dwarf.New(, nil, nil, , , nil, , )
		.DWARFLines = wasmdebug.NewDWARFLines()
	}

	,  := .SectionElementCount(wasm.SectionIDFunction), .SectionElementCount(wasm.SectionIDCode)
	if  !=  {
		return nil, fmt.Errorf("function and code section have inconsistent lengths: %d != %d", , )
	}
	return , nil
}

func checkSectionOrder(,  wasm.SectionID) (byte, bool) {
	// https://webassembly.github.io/spec/core/binary/modules.html#binary-module

	// Custom sections can show up anywhere.
	if  == wasm.SectionIDCustom {
		return , true
	}

	// DataCount was introduced in Wasm 2.0,
	// and it's the maximum we support so far.
	// It must come after Element and before Code.
	if  > wasm.SectionIDDataCount {
		return , false
	}
	if  == wasm.SectionIDDataCount {
		return ,  <= wasm.SectionIDElement
	}
	if  == wasm.SectionIDDataCount {
		return ,  >= wasm.SectionIDCode
	}

	// Tag will be introduced in Wasm 3.0.
	// It must come after Memory and before Global.

	// Otherwise, strictly increasing order.
	return ,  > 
}

// memorySizer derives min, capacity and max pages from decoded wasm.
type memorySizer func(minPages uint32, maxPages *uint32) (min uint32, capacity uint32, max uint32)

// newMemorySizer sets capacity to minPages unless max is defined and
// memoryCapacityFromMax is true.
func newMemorySizer( uint32,  bool) memorySizer {
	return func( uint32,  *uint32) (, ,  uint32) {
		if  != nil {
			if  {
				return , *, *
			}
			// This is an invalid value: let it propagate, we will fail later.
			if * > wasm.MemoryLimitPages {
				return , , *
			}
			// This is a valid value, but it goes over the run-time limit: return the limit.
			if * >  {
				return , , 
			}
			return , , *
		}
		if  {
			return , , 
		}
		return , , 
	}
}