github.com/taubyte/vm-wasm-utils@v1.0.2/binary/data.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  // dataSegmentPrefix represents three types of data segments.
    13  //
    14  // https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/binary/modules.html#data-section
    15  type dataSegmentPrefix = uint32
    16  
    17  const (
    18  	// dataSegmentPrefixActive is the prefix for the version 1.0 compatible data segment, which is classified as "active" in 2.0.
    19  	dataSegmentPrefixActive dataSegmentPrefix = 0x0
    20  	// dataSegmentPrefixPassive prefixes the "passive" data segment as in version 2.0 specification.
    21  	dataSegmentPrefixPassive dataSegmentPrefix = 0x1
    22  	// dataSegmentPrefixActiveWithMemoryIndex is the active prefix with memory index encoded which is defined for futur use as of 2.0.
    23  	dataSegmentPrefixActiveWithMemoryIndex dataSegmentPrefix = 0x2
    24  )
    25  
    26  func decodeDataSegment(r *bytes.Reader, enabledFeatures wasm.Features) (*wasm.DataSegment, error) {
    27  	dataSegmentPrefx, _, err := leb128.DecodeUint32(r)
    28  	if err != nil {
    29  		return nil, fmt.Errorf("read data segment prefix: %w", err)
    30  	}
    31  
    32  	if dataSegmentPrefx != dataSegmentPrefixActive {
    33  		if err := enabledFeatures.Require(wasm.FeatureBulkMemoryOperations); err != nil {
    34  			return nil, fmt.Errorf("non-zero prefix for data segment is invalid as %w", err)
    35  		}
    36  	}
    37  
    38  	var expr *wasm.ConstantExpression
    39  	switch dataSegmentPrefx {
    40  	case dataSegmentPrefixActive,
    41  		dataSegmentPrefixActiveWithMemoryIndex:
    42  		// Active data segment as in
    43  		// https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/binary/modules.html#data-section
    44  		if dataSegmentPrefx == 0x2 {
    45  			d, _, err := leb128.DecodeUint32(r)
    46  			if err != nil {
    47  				return nil, fmt.Errorf("read memory index: %v", err)
    48  			} else if d != 0 {
    49  				return nil, fmt.Errorf("memory index must be zero but was %d", d)
    50  			}
    51  		}
    52  
    53  		expr, err = decodeConstantExpression(r, enabledFeatures)
    54  		if err != nil {
    55  			return nil, fmt.Errorf("read offset expression: %v", err)
    56  		}
    57  	case dataSegmentPrefixPassive:
    58  		// Passive data segment doesn't need const expr nor memory index encoded.
    59  		// https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/binary/modules.html#data-section
    60  	default:
    61  		return nil, fmt.Errorf("invalid data segment prefix: 0x%x", dataSegmentPrefx)
    62  	}
    63  
    64  	vs, _, err := leb128.DecodeUint32(r)
    65  	if err != nil {
    66  		return nil, fmt.Errorf("get the size of vector: %v", err)
    67  	}
    68  
    69  	b := make([]byte, vs)
    70  	if _, err := io.ReadFull(r, b); err != nil {
    71  		return nil, fmt.Errorf("read bytes for init: %v", err)
    72  	}
    73  
    74  	return &wasm.DataSegment{
    75  		OffsetExpression: expr,
    76  		Init:             b,
    77  	}, nil
    78  }
    79  
    80  func encodeDataSegment(d *wasm.DataSegment) (ret []byte) {
    81  	// Currently multiple memories are not supported.
    82  	ret = append(ret, leb128.EncodeInt32(0)...)
    83  	ret = append(ret, encodeConstantExpression(d.OffsetExpression)...)
    84  	ret = append(ret, leb128.EncodeUint32(uint32(len(d.Init)))...)
    85  	ret = append(ret, d.Init...)
    86  	return
    87  }