github.com/taubyte/vm-wasm-utils@v1.0.2/binary/section.go (about)

     1  package binary
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  
     8  	wasm "github.com/taubyte/vm-wasm-utils"
     9  	"github.com/taubyte/vm-wasm-utils/leb128"
    10  )
    11  
    12  func decodeTypeSection(enabledFeatures wasm.Features, r *bytes.Reader) ([]*wasm.FunctionType, error) {
    13  	vs, _, err := leb128.DecodeUint32(r)
    14  	if err != nil {
    15  		return nil, fmt.Errorf("get size of vector: %w", err)
    16  	}
    17  
    18  	result := make([]*wasm.FunctionType, vs)
    19  	for i := uint32(0); i < vs; i++ {
    20  		if result[i], err = decodeFunctionType(enabledFeatures, r); err != nil {
    21  			return nil, fmt.Errorf("read %d-th type: %v", i, err)
    22  		}
    23  	}
    24  	return result, nil
    25  }
    26  
    27  func decodeImportSection(
    28  	r *bytes.Reader,
    29  	memorySizer func(minPages uint32, maxPages *uint32) (min, capacity, max uint32),
    30  	enabledFeatures wasm.Features,
    31  ) ([]*wasm.Import, error) {
    32  	vs, _, err := leb128.DecodeUint32(r)
    33  	if err != nil {
    34  		return nil, fmt.Errorf("get size of vector: %w", err)
    35  	}
    36  
    37  	result := make([]*wasm.Import, vs)
    38  	for i := uint32(0); i < vs; i++ {
    39  		if result[i], err = decodeImport(r, i, memorySizer, enabledFeatures); err != nil {
    40  			return nil, err
    41  		}
    42  	}
    43  	return result, nil
    44  }
    45  
    46  func decodeFunctionSection(r *bytes.Reader) ([]uint32, error) {
    47  	vs, _, err := leb128.DecodeUint32(r)
    48  	if err != nil {
    49  		return nil, fmt.Errorf("get size of vector: %w", err)
    50  	}
    51  
    52  	result := make([]uint32, vs)
    53  	for i := uint32(0); i < vs; i++ {
    54  		if result[i], _, err = leb128.DecodeUint32(r); err != nil {
    55  			return nil, fmt.Errorf("get type index: %w", err)
    56  		}
    57  	}
    58  	return result, err
    59  }
    60  
    61  func decodeTableSection(r *bytes.Reader, enabledFeatures wasm.Features) ([]*wasm.Table, error) {
    62  	vs, _, err := leb128.DecodeUint32(r)
    63  	if err != nil {
    64  		return nil, fmt.Errorf("error reading size")
    65  	}
    66  	if vs > 1 {
    67  		if err := enabledFeatures.Require(wasm.FeatureReferenceTypes); err != nil {
    68  			return nil, fmt.Errorf("at most one table allowed in module as %w", err)
    69  		}
    70  	}
    71  
    72  	ret := make([]*wasm.Table, vs)
    73  	for i := range ret {
    74  		table, err := decodeTable(r, enabledFeatures)
    75  		if err != nil {
    76  			return nil, err
    77  		}
    78  		ret[i] = table
    79  	}
    80  	return ret, nil
    81  }
    82  
    83  func decodeMemorySection(
    84  	r *bytes.Reader,
    85  	memorySizer func(minPages uint32, maxPages *uint32) (min, capacity, max uint32),
    86  ) (*wasm.Memory, error) {
    87  	vs, _, err := leb128.DecodeUint32(r)
    88  	if err != nil {
    89  		return nil, fmt.Errorf("error reading size")
    90  	}
    91  	if vs > 1 {
    92  		return nil, fmt.Errorf("at most one memory allowed in module, but read %d", vs)
    93  	}
    94  
    95  	return decodeMemory(r, memorySizer)
    96  }
    97  
    98  func decodeGlobalSection(r *bytes.Reader, enabledFeatures wasm.Features) ([]*wasm.Global, error) {
    99  	vs, _, err := leb128.DecodeUint32(r)
   100  	if err != nil {
   101  		return nil, fmt.Errorf("get size of vector: %w", err)
   102  	}
   103  
   104  	result := make([]*wasm.Global, vs)
   105  	for i := uint32(0); i < vs; i++ {
   106  		if result[i], err = decodeGlobal(r, enabledFeatures); err != nil {
   107  			return nil, fmt.Errorf("global[%d]: %w", i, err)
   108  		}
   109  	}
   110  	return result, nil
   111  }
   112  
   113  func decodeExportSection(r *bytes.Reader) ([]*wasm.Export, error) {
   114  	vs, _, sizeErr := leb128.DecodeUint32(r)
   115  	if sizeErr != nil {
   116  		return nil, fmt.Errorf("get size of vector: %v", sizeErr)
   117  	}
   118  
   119  	usedName := make(map[string]struct{}, vs)
   120  	exportSection := make([]*wasm.Export, 0, vs)
   121  	for i := wasm.Index(0); i < vs; i++ {
   122  		export, err := decodeExport(r)
   123  		if err != nil {
   124  			return nil, fmt.Errorf("read export: %w", err)
   125  		}
   126  		if _, ok := usedName[export.Name]; ok {
   127  			return nil, fmt.Errorf("export[%d] duplicates name %q", i, export.Name)
   128  		} else {
   129  			usedName[export.Name] = struct{}{}
   130  		}
   131  		exportSection = append(exportSection, export)
   132  	}
   133  	return exportSection, nil
   134  }
   135  
   136  func decodeStartSection(r *bytes.Reader) (*wasm.Index, error) {
   137  	vs, _, err := leb128.DecodeUint32(r)
   138  	if err != nil {
   139  		return nil, fmt.Errorf("get function index: %w", err)
   140  	}
   141  	return &vs, nil
   142  }
   143  
   144  func decodeElementSection(r *bytes.Reader, enabledFeatures wasm.Features) ([]*wasm.ElementSegment, error) {
   145  	vs, _, err := leb128.DecodeUint32(r)
   146  	if err != nil {
   147  		return nil, fmt.Errorf("get size of vector: %w", err)
   148  	}
   149  
   150  	result := make([]*wasm.ElementSegment, vs)
   151  	for i := uint32(0); i < vs; i++ {
   152  		if result[i], err = decodeElementSegment(r, enabledFeatures); err != nil {
   153  			return nil, fmt.Errorf("read element: %w", err)
   154  		}
   155  	}
   156  	return result, nil
   157  }
   158  
   159  func decodeCodeSection(r *bytes.Reader) ([]*wasm.Code, error) {
   160  	vs, _, err := leb128.DecodeUint32(r)
   161  	if err != nil {
   162  		return nil, fmt.Errorf("get size of vector: %w", err)
   163  	}
   164  
   165  	result := make([]*wasm.Code, vs)
   166  	for i := uint32(0); i < vs; i++ {
   167  		if result[i], err = decodeCode(r); err != nil {
   168  			return nil, fmt.Errorf("read %d-th code segment: %v", i, err)
   169  		}
   170  	}
   171  	return result, nil
   172  }
   173  
   174  func decodeDataSection(r *bytes.Reader, enabledFeatures wasm.Features) ([]*wasm.DataSegment, error) {
   175  	vs, _, err := leb128.DecodeUint32(r)
   176  	if err != nil {
   177  		return nil, fmt.Errorf("get size of vector: %w", err)
   178  	}
   179  
   180  	result := make([]*wasm.DataSegment, vs)
   181  	for i := uint32(0); i < vs; i++ {
   182  		if result[i], err = decodeDataSegment(r, enabledFeatures); err != nil {
   183  			return nil, fmt.Errorf("read data segment: %w", err)
   184  		}
   185  	}
   186  	return result, nil
   187  }
   188  
   189  func decodeDataCountSection(r *bytes.Reader) (count *uint32, err error) {
   190  	v, _, err := leb128.DecodeUint32(r)
   191  	if err != nil && err != io.EOF {
   192  		// data count is optional, so EOF is fine.
   193  		return nil, err
   194  	}
   195  	return &v, nil
   196  }
   197  
   198  // encodeSection encodes the sectionID, the size of its contents in bytes, followed by the contents.
   199  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#sections%E2%91%A0
   200  func encodeSection(sectionID wasm.SectionID, contents []byte) []byte {
   201  	return append([]byte{sectionID}, encodeSizePrefixed(contents)...)
   202  }
   203  
   204  // encodeTypeSection encodes a wasm.SectionIDType for the given imports in WebAssembly 1.0 (20191205) Binary
   205  // Format.
   206  //
   207  // See encodeFunctionType
   208  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#type-section%E2%91%A0
   209  func encodeTypeSection(types []*wasm.FunctionType) []byte {
   210  	contents := leb128.EncodeUint32(uint32(len(types)))
   211  	for _, t := range types {
   212  		contents = append(contents, encodeFunctionType(t)...)
   213  	}
   214  	return encodeSection(wasm.SectionIDType, contents)
   215  }
   216  
   217  // encodeImportSection encodes a wasm.SectionIDImport for the given imports in WebAssembly 1.0 (20191205) Binary
   218  // Format.
   219  //
   220  // See encodeImport
   221  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#import-section%E2%91%A0
   222  func encodeImportSection(imports []*wasm.Import) []byte {
   223  	contents := leb128.EncodeUint32(uint32(len(imports)))
   224  	for _, i := range imports {
   225  		contents = append(contents, encodeImport(i)...)
   226  	}
   227  	return encodeSection(wasm.SectionIDImport, contents)
   228  }
   229  
   230  // encodeFunctionSection encodes a wasm.SectionIDFunction for the type indices associated with module-defined
   231  // functions in WebAssembly 1.0 (20191205) Binary Format.
   232  //
   233  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#function-section%E2%91%A0
   234  func encodeFunctionSection(typeIndices []wasm.Index) []byte {
   235  	contents := leb128.EncodeUint32(uint32(len(typeIndices)))
   236  	for _, index := range typeIndices {
   237  		contents = append(contents, leb128.EncodeUint32(index)...)
   238  	}
   239  	return encodeSection(wasm.SectionIDFunction, contents)
   240  }
   241  
   242  // encodeCodeSection encodes a wasm.SectionIDCode for the module-defined function in WebAssembly 1.0 (20191205)
   243  // Binary Format.
   244  //
   245  // See encodeCode
   246  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#code-section%E2%91%A0
   247  func encodeCodeSection(code []*wasm.Code) []byte {
   248  	contents := leb128.EncodeUint32(uint32(len(code)))
   249  	for _, i := range code {
   250  		contents = append(contents, encodeCode(i)...)
   251  	}
   252  	return encodeSection(wasm.SectionIDCode, contents)
   253  }
   254  
   255  // encodeTableSection encodes a wasm.SectionIDTable for the module-defined function in WebAssembly 1.0
   256  // (20191205) Binary Format.
   257  //
   258  // See encodeTable
   259  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#table-section%E2%91%A0
   260  func encodeTableSection(tables []*wasm.Table) []byte {
   261  	var contents []byte = leb128.EncodeUint32(uint32(len(tables)))
   262  	for _, table := range tables {
   263  		contents = append(contents, encodeTable(table)...)
   264  	}
   265  	return encodeSection(wasm.SectionIDTable, contents)
   266  }
   267  
   268  // encodeMemorySection encodes a wasm.SectionIDMemory for the module-defined function in WebAssembly 1.0
   269  // (20191205) Binary Format.
   270  //
   271  // See encodeMemory
   272  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#memory-section%E2%91%A0
   273  func encodeMemorySection(memory *wasm.Memory) []byte {
   274  	contents := append([]byte{1}, encodeMemory(memory)...)
   275  	return encodeSection(wasm.SectionIDMemory, contents)
   276  }
   277  
   278  // encodeGlobalSection encodes a wasm.SectionIDGlobal for the given globals in WebAssembly 1.0 (20191205) Binary
   279  // Format.
   280  //
   281  // See encodeGlobal
   282  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#global-section%E2%91%A0
   283  func encodeGlobalSection(globals []*wasm.Global) []byte {
   284  	contents := leb128.EncodeUint32(uint32(len(globals)))
   285  	for _, g := range globals {
   286  		contents = append(contents, encodeGlobal(g)...)
   287  	}
   288  	return encodeSection(wasm.SectionIDGlobal, contents)
   289  }
   290  
   291  // encodeExportSection encodes a wasm.SectionIDExport for the given exports in WebAssembly 1.0 (20191205) Binary
   292  // Format.
   293  //
   294  // See encodeExport
   295  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#export-section%E2%91%A0
   296  func encodeExportSection(exports []*wasm.Export) []byte {
   297  	contents := leb128.EncodeUint32(uint32(len(exports)))
   298  	for _, e := range exports {
   299  		contents = append(contents, encodeExport(e)...)
   300  	}
   301  	return encodeSection(wasm.SectionIDExport, contents)
   302  }
   303  
   304  // encodeStartSection encodes a wasm.SectionIDStart for the given function index in WebAssembly 1.0 (20191205)
   305  // Binary Format.
   306  //
   307  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#start-section%E2%91%A0
   308  func encodeStartSection(funcidx wasm.Index) []byte {
   309  	return encodeSection(wasm.SectionIDStart, leb128.EncodeUint32(funcidx))
   310  }
   311  
   312  // encodeEelementSection encodes a wasm.SectionIDElement for the elements in WebAssembly 1.0 (20191205)
   313  // Binary Format.
   314  //
   315  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#element-section%E2%91%A0
   316  func encodeElementSection(elements []*wasm.ElementSegment) []byte {
   317  	contents := leb128.EncodeUint32(uint32(len(elements)))
   318  	for _, e := range elements {
   319  		contents = append(contents, encodeElement(e)...)
   320  	}
   321  	return encodeSection(wasm.SectionIDElement, contents)
   322  }
   323  
   324  // encodeDataSection encodes a wasm.SectionIDData for the data in WebAssembly 1.0 (20191205)
   325  // Binary Format.
   326  //
   327  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#data-section%E2%91%A0
   328  func encodeDataSection(datum []*wasm.DataSegment) []byte {
   329  	contents := leb128.EncodeUint32(uint32(len(datum)))
   330  	for _, d := range datum {
   331  		contents = append(contents, encodeDataSegment(d)...)
   332  	}
   333  	return encodeSection(wasm.SectionIDData, contents)
   334  }