...

Source file src/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/array.go

Documentation: go.mongodb.org/mongo-driver/x/bsonx/bsoncore

     1  // Copyright (C) MongoDB, Inc. 2017-present.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License"); you may
     4  // not use this file except in compliance with the License. You may obtain
     5  // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
     6  
     7  package bsoncore
     8  
     9  import (
    10  	"fmt"
    11  	"io"
    12  	"strconv"
    13  	"strings"
    14  )
    15  
    16  // NewArrayLengthError creates and returns an error for when the length of an array exceeds the
    17  // bytes available.
    18  func NewArrayLengthError(length, rem int) error {
    19  	return lengthError("array", length, rem)
    20  }
    21  
    22  // Array is a raw bytes representation of a BSON array.
    23  type Array []byte
    24  
    25  // NewArrayFromReader reads an array from r. This function will only validate the length is
    26  // correct and that the array ends with a null byte.
    27  func NewArrayFromReader(r io.Reader) (Array, error) {
    28  	return newBufferFromReader(r)
    29  }
    30  
    31  // Index searches for and retrieves the value at the given index. This method will panic if
    32  // the array is invalid or if the index is out of bounds.
    33  func (a Array) Index(index uint) Value {
    34  	value, err := a.IndexErr(index)
    35  	if err != nil {
    36  		panic(err)
    37  	}
    38  	return value
    39  }
    40  
    41  // IndexErr searches for and retrieves the value at the given index.
    42  func (a Array) IndexErr(index uint) (Value, error) {
    43  	elem, err := indexErr(a, index)
    44  	if err != nil {
    45  		return Value{}, err
    46  	}
    47  	return elem.Value(), err
    48  }
    49  
    50  // DebugString outputs a human readable version of Array. It will attempt to stringify the
    51  // valid components of the array even if the entire array is not valid.
    52  func (a Array) DebugString() string {
    53  	if len(a) < 5 {
    54  		return "<malformed>"
    55  	}
    56  	var buf strings.Builder
    57  	buf.WriteString("Array")
    58  	length, rem, _ := ReadLength(a) // We know we have enough bytes to read the length
    59  	buf.WriteByte('(')
    60  	buf.WriteString(strconv.Itoa(int(length)))
    61  	length -= 4
    62  	buf.WriteString(")[")
    63  	var elem Element
    64  	var ok bool
    65  	for length > 1 {
    66  		elem, rem, ok = ReadElement(rem)
    67  		length -= int32(len(elem))
    68  		if !ok {
    69  			buf.WriteString(fmt.Sprintf("<malformed (%d)>", length))
    70  			break
    71  		}
    72  		buf.WriteString(elem.Value().DebugString())
    73  		if length != 1 {
    74  			buf.WriteByte(',')
    75  		}
    76  	}
    77  	buf.WriteByte(']')
    78  
    79  	return buf.String()
    80  }
    81  
    82  // String outputs an ExtendedJSON version of Array. If the Array is not valid, this method
    83  // returns an empty string.
    84  func (a Array) String() string {
    85  	if len(a) < 5 {
    86  		return ""
    87  	}
    88  	var buf strings.Builder
    89  	buf.WriteByte('[')
    90  
    91  	length, rem, _ := ReadLength(a) // We know we have enough bytes to read the length
    92  
    93  	length -= 4
    94  
    95  	var elem Element
    96  	var ok bool
    97  	for length > 1 {
    98  		elem, rem, ok = ReadElement(rem)
    99  		length -= int32(len(elem))
   100  		if !ok {
   101  			return ""
   102  		}
   103  		buf.WriteString(elem.Value().String())
   104  		if length > 1 {
   105  			buf.WriteByte(',')
   106  		}
   107  	}
   108  	if length != 1 { // Missing final null byte or inaccurate length
   109  		return ""
   110  	}
   111  
   112  	buf.WriteByte(']')
   113  	return buf.String()
   114  }
   115  
   116  // Values returns this array as a slice of values. The returned slice will contain valid values.
   117  // If the array is not valid, the values up to the invalid point will be returned along with an
   118  // error.
   119  func (a Array) Values() ([]Value, error) {
   120  	return values(a)
   121  }
   122  
   123  // Validate validates the array and ensures the elements contained within are valid.
   124  func (a Array) Validate() error {
   125  	length, rem, ok := ReadLength(a)
   126  	if !ok {
   127  		return NewInsufficientBytesError(a, rem)
   128  	}
   129  	if int(length) > len(a) {
   130  		return NewArrayLengthError(int(length), len(a))
   131  	}
   132  	if a[length-1] != 0x00 {
   133  		return ErrMissingNull
   134  	}
   135  
   136  	length -= 4
   137  	var elem Element
   138  
   139  	var keyNum int64
   140  	for length > 1 {
   141  		elem, rem, ok = ReadElement(rem)
   142  		length -= int32(len(elem))
   143  		if !ok {
   144  			return NewInsufficientBytesError(a, rem)
   145  		}
   146  
   147  		// validate element
   148  		err := elem.Validate()
   149  		if err != nil {
   150  			return err
   151  		}
   152  
   153  		// validate keys increase numerically
   154  		if fmt.Sprint(keyNum) != elem.Key() {
   155  			return fmt.Errorf("array key %q is out of order or invalid", elem.Key())
   156  		}
   157  		keyNum++
   158  	}
   159  
   160  	if len(rem) < 1 || rem[0] != 0x00 {
   161  		return ErrMissingNull
   162  	}
   163  	return nil
   164  }
   165  

View as plain text