github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/vendor_skip/go.mongodb.org/mongo-driver/x/mongo/driver/wiremessage/wiremessage.go (about)

     1  // Copyright (C) MongoDB, Inc. 2022-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 wiremessage
     8  
     9  import (
    10  	"bytes"
    11  	"strings"
    12  	"sync/atomic"
    13  
    14  	"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
    15  )
    16  
    17  // WireMessage represents a MongoDB wire message in binary form.
    18  type WireMessage []byte
    19  
    20  var globalRequestID int32
    21  
    22  // CurrentRequestID returns the current request ID.
    23  func CurrentRequestID() int32 { return atomic.LoadInt32(&globalRequestID) }
    24  
    25  // NextRequestID returns the next request ID.
    26  func NextRequestID() int32 { return atomic.AddInt32(&globalRequestID, 1) }
    27  
    28  // OpCode represents a MongoDB wire protocol opcode.
    29  type OpCode int32
    30  
    31  // These constants are the valid opcodes for the version of the wireprotocol
    32  // supported by this library. The skipped OpCodes are historical OpCodes that
    33  // are no longer used.
    34  const (
    35  	OpReply        OpCode = 1
    36  	_              OpCode = 1001
    37  	OpUpdate       OpCode = 2001
    38  	OpInsert       OpCode = 2002
    39  	_              OpCode = 2003
    40  	OpQuery        OpCode = 2004
    41  	OpGetMore      OpCode = 2005
    42  	OpDelete       OpCode = 2006
    43  	OpKillCursors  OpCode = 2007
    44  	OpCommand      OpCode = 2010
    45  	OpCommandReply OpCode = 2011
    46  	OpCompressed   OpCode = 2012
    47  	OpMsg          OpCode = 2013
    48  )
    49  
    50  // String implements the fmt.Stringer interface.
    51  func (oc OpCode) String() string {
    52  	switch oc {
    53  	case OpReply:
    54  		return "OP_REPLY"
    55  	case OpUpdate:
    56  		return "OP_UPDATE"
    57  	case OpInsert:
    58  		return "OP_INSERT"
    59  	case OpQuery:
    60  		return "OP_QUERY"
    61  	case OpGetMore:
    62  		return "OP_GET_MORE"
    63  	case OpDelete:
    64  		return "OP_DELETE"
    65  	case OpKillCursors:
    66  		return "OP_KILL_CURSORS"
    67  	case OpCommand:
    68  		return "OP_COMMAND"
    69  	case OpCommandReply:
    70  		return "OP_COMMANDREPLY"
    71  	case OpCompressed:
    72  		return "OP_COMPRESSED"
    73  	case OpMsg:
    74  		return "OP_MSG"
    75  	default:
    76  		return "<invalid opcode>"
    77  	}
    78  }
    79  
    80  // QueryFlag represents the flags on an OP_QUERY message.
    81  type QueryFlag int32
    82  
    83  // These constants represent the individual flags on an OP_QUERY message.
    84  const (
    85  	_ QueryFlag = 1 << iota
    86  	TailableCursor
    87  	SecondaryOK
    88  	OplogReplay
    89  	NoCursorTimeout
    90  	AwaitData
    91  	Exhaust
    92  	Partial
    93  )
    94  
    95  // String implements the fmt.Stringer interface.
    96  func (qf QueryFlag) String() string {
    97  	strs := make([]string, 0)
    98  	if qf&TailableCursor == TailableCursor {
    99  		strs = append(strs, "TailableCursor")
   100  	}
   101  	if qf&SecondaryOK == SecondaryOK {
   102  		strs = append(strs, "SecondaryOK")
   103  	}
   104  	if qf&OplogReplay == OplogReplay {
   105  		strs = append(strs, "OplogReplay")
   106  	}
   107  	if qf&NoCursorTimeout == NoCursorTimeout {
   108  		strs = append(strs, "NoCursorTimeout")
   109  	}
   110  	if qf&AwaitData == AwaitData {
   111  		strs = append(strs, "AwaitData")
   112  	}
   113  	if qf&Exhaust == Exhaust {
   114  		strs = append(strs, "Exhaust")
   115  	}
   116  	if qf&Partial == Partial {
   117  		strs = append(strs, "Partial")
   118  	}
   119  	str := "["
   120  	str += strings.Join(strs, ", ")
   121  	str += "]"
   122  	return str
   123  }
   124  
   125  // MsgFlag represents the flags on an OP_MSG message.
   126  type MsgFlag uint32
   127  
   128  // These constants represent the individual flags on an OP_MSG message.
   129  const (
   130  	ChecksumPresent MsgFlag = 1 << iota
   131  	MoreToCome
   132  
   133  	ExhaustAllowed MsgFlag = 1 << 16
   134  )
   135  
   136  // ReplyFlag represents the flags of an OP_REPLY message.
   137  type ReplyFlag int32
   138  
   139  // These constants represent the individual flags of an OP_REPLY message.
   140  const (
   141  	CursorNotFound ReplyFlag = 1 << iota
   142  	QueryFailure
   143  	ShardConfigStale
   144  	AwaitCapable
   145  )
   146  
   147  // String implements the fmt.Stringer interface.
   148  func (rf ReplyFlag) String() string {
   149  	strs := make([]string, 0)
   150  	if rf&CursorNotFound == CursorNotFound {
   151  		strs = append(strs, "CursorNotFound")
   152  	}
   153  	if rf&QueryFailure == QueryFailure {
   154  		strs = append(strs, "QueryFailure")
   155  	}
   156  	if rf&ShardConfigStale == ShardConfigStale {
   157  		strs = append(strs, "ShardConfigStale")
   158  	}
   159  	if rf&AwaitCapable == AwaitCapable {
   160  		strs = append(strs, "AwaitCapable")
   161  	}
   162  	str := "["
   163  	str += strings.Join(strs, ", ")
   164  	str += "]"
   165  	return str
   166  }
   167  
   168  // SectionType represents the type for 1 section in an OP_MSG
   169  type SectionType uint8
   170  
   171  // These constants represent the individual section types for a section in an OP_MSG
   172  const (
   173  	SingleDocument SectionType = iota
   174  	DocumentSequence
   175  )
   176  
   177  // OpmsgWireVersion is the minimum wire version needed to use OP_MSG
   178  const OpmsgWireVersion = 6
   179  
   180  // CompressorID is the ID for each type of Compressor.
   181  type CompressorID uint8
   182  
   183  // These constants represent the individual compressor IDs for an OP_COMPRESSED.
   184  const (
   185  	CompressorNoOp CompressorID = iota
   186  	CompressorSnappy
   187  	CompressorZLib
   188  	CompressorZstd
   189  )
   190  
   191  // String implements the fmt.Stringer interface.
   192  func (id CompressorID) String() string {
   193  	switch id {
   194  	case CompressorNoOp:
   195  		return "CompressorNoOp"
   196  	case CompressorSnappy:
   197  		return "CompressorSnappy"
   198  	case CompressorZLib:
   199  		return "CompressorZLib"
   200  	case CompressorZstd:
   201  		return "CompressorZstd"
   202  	default:
   203  		return "CompressorInvalid"
   204  	}
   205  }
   206  
   207  const (
   208  	// DefaultZlibLevel is the default level for zlib compression
   209  	DefaultZlibLevel = 6
   210  	// DefaultZstdLevel is the default level for zstd compression.
   211  	// Matches https://github.com/wiredtiger/wiredtiger/blob/f08bc4b18612ef95a39b12166abcccf207f91596/ext/compressors/zstd/zstd_compress.c#L299
   212  	DefaultZstdLevel = 6
   213  )
   214  
   215  // AppendHeaderStart appends a header to the dst slice and returns an index where the wire message
   216  // starts in dst and the updated slice.
   217  func AppendHeaderStart(dst []byte, reqid, respto int32, opcode OpCode) (index int32, b []byte) {
   218  	index, dst = bsoncore.ReserveLength(dst)
   219  	dst = appendi32(dst, reqid)
   220  	dst = appendi32(dst, respto)
   221  	dst = appendi32(dst, int32(opcode))
   222  	return index, dst
   223  }
   224  
   225  // AppendHeader appends a header to dst.
   226  func AppendHeader(dst []byte, length, reqid, respto int32, opcode OpCode) []byte {
   227  	dst = appendi32(dst, length)
   228  	dst = appendi32(dst, reqid)
   229  	dst = appendi32(dst, respto)
   230  	dst = appendi32(dst, int32(opcode))
   231  	return dst
   232  }
   233  
   234  // ReadHeader reads a wire message header from src.
   235  func ReadHeader(src []byte) (length, requestID, responseTo int32, opcode OpCode, rem []byte, ok bool) {
   236  	if len(src) < 16 {
   237  		return 0, 0, 0, 0, src, false
   238  	}
   239  	length = (int32(src[0]) | int32(src[1])<<8 | int32(src[2])<<16 | int32(src[3])<<24)
   240  	requestID = (int32(src[4]) | int32(src[5])<<8 | int32(src[6])<<16 | int32(src[7])<<24)
   241  	responseTo = (int32(src[8]) | int32(src[9])<<8 | int32(src[10])<<16 | int32(src[11])<<24)
   242  	opcode = OpCode(int32(src[12]) | int32(src[13])<<8 | int32(src[14])<<16 | int32(src[15])<<24)
   243  	return length, requestID, responseTo, opcode, src[16:], true
   244  }
   245  
   246  // AppendQueryFlags appends the flags for an OP_QUERY wire message.
   247  func AppendQueryFlags(dst []byte, flags QueryFlag) []byte {
   248  	return appendi32(dst, int32(flags))
   249  }
   250  
   251  // AppendMsgFlags appends the flags for an OP_MSG wire message.
   252  func AppendMsgFlags(dst []byte, flags MsgFlag) []byte {
   253  	return appendi32(dst, int32(flags))
   254  }
   255  
   256  // AppendReplyFlags appends the flags for an OP_REPLY wire message.
   257  func AppendReplyFlags(dst []byte, flags ReplyFlag) []byte {
   258  	return appendi32(dst, int32(flags))
   259  }
   260  
   261  // AppendMsgSectionType appends the section type to dst.
   262  func AppendMsgSectionType(dst []byte, stype SectionType) []byte {
   263  	return append(dst, byte(stype))
   264  }
   265  
   266  // AppendQueryFullCollectionName appends the full collection name to dst.
   267  func AppendQueryFullCollectionName(dst []byte, ns string) []byte {
   268  	return appendCString(dst, ns)
   269  }
   270  
   271  // AppendQueryNumberToSkip appends the number to skip to dst.
   272  func AppendQueryNumberToSkip(dst []byte, skip int32) []byte {
   273  	return appendi32(dst, skip)
   274  }
   275  
   276  // AppendQueryNumberToReturn appends the number to return to dst.
   277  func AppendQueryNumberToReturn(dst []byte, nor int32) []byte {
   278  	return appendi32(dst, nor)
   279  }
   280  
   281  // AppendReplyCursorID appends the cursor ID to dst.
   282  func AppendReplyCursorID(dst []byte, id int64) []byte {
   283  	return appendi64(dst, id)
   284  }
   285  
   286  // AppendReplyStartingFrom appends the starting from field to dst.
   287  func AppendReplyStartingFrom(dst []byte, sf int32) []byte {
   288  	return appendi32(dst, sf)
   289  }
   290  
   291  // AppendReplyNumberReturned appends the number returned to dst.
   292  func AppendReplyNumberReturned(dst []byte, nr int32) []byte {
   293  	return appendi32(dst, nr)
   294  }
   295  
   296  // AppendCompressedOriginalOpCode appends the original opcode to dst.
   297  func AppendCompressedOriginalOpCode(dst []byte, opcode OpCode) []byte {
   298  	return appendi32(dst, int32(opcode))
   299  }
   300  
   301  // AppendCompressedUncompressedSize appends the uncompressed size of a
   302  // compressed wiremessage to dst.
   303  func AppendCompressedUncompressedSize(dst []byte, size int32) []byte { return appendi32(dst, size) }
   304  
   305  // AppendCompressedCompressorID appends the ID of the compressor to dst.
   306  func AppendCompressedCompressorID(dst []byte, id CompressorID) []byte {
   307  	return append(dst, byte(id))
   308  }
   309  
   310  // AppendCompressedCompressedMessage appends the compressed wiremessage to dst.
   311  func AppendCompressedCompressedMessage(dst []byte, msg []byte) []byte { return append(dst, msg...) }
   312  
   313  // AppendGetMoreZero appends the zero field to dst.
   314  func AppendGetMoreZero(dst []byte) []byte {
   315  	return appendi32(dst, 0)
   316  }
   317  
   318  // AppendGetMoreFullCollectionName appends the fullCollectionName field to dst.
   319  func AppendGetMoreFullCollectionName(dst []byte, ns string) []byte {
   320  	return appendCString(dst, ns)
   321  }
   322  
   323  // AppendGetMoreNumberToReturn appends the numberToReturn field to dst.
   324  func AppendGetMoreNumberToReturn(dst []byte, numToReturn int32) []byte {
   325  	return appendi32(dst, numToReturn)
   326  }
   327  
   328  // AppendGetMoreCursorID appends the cursorID field to dst.
   329  func AppendGetMoreCursorID(dst []byte, cursorID int64) []byte {
   330  	return appendi64(dst, cursorID)
   331  }
   332  
   333  // AppendKillCursorsZero appends the zero field to dst.
   334  func AppendKillCursorsZero(dst []byte) []byte {
   335  	return appendi32(dst, 0)
   336  }
   337  
   338  // AppendKillCursorsNumberIDs appends the numberOfCursorIDs field to dst.
   339  func AppendKillCursorsNumberIDs(dst []byte, numIDs int32) []byte {
   340  	return appendi32(dst, numIDs)
   341  }
   342  
   343  // AppendKillCursorsCursorIDs appends each the cursorIDs field to dst.
   344  func AppendKillCursorsCursorIDs(dst []byte, cursors []int64) []byte {
   345  	for _, cursor := range cursors {
   346  		dst = appendi64(dst, cursor)
   347  	}
   348  	return dst
   349  }
   350  
   351  // ReadMsgFlags reads the OP_MSG flags from src.
   352  func ReadMsgFlags(src []byte) (flags MsgFlag, rem []byte, ok bool) {
   353  	i32, rem, ok := readi32(src)
   354  	return MsgFlag(i32), rem, ok
   355  }
   356  
   357  // IsMsgMoreToCome returns if the provided wire message is an OP_MSG with the more to come flag set.
   358  func IsMsgMoreToCome(wm []byte) bool {
   359  	return len(wm) >= 20 &&
   360  		OpCode(readi32unsafe(wm[12:16])) == OpMsg &&
   361  		MsgFlag(readi32unsafe(wm[16:20]))&MoreToCome == MoreToCome
   362  }
   363  
   364  // ReadMsgSectionType reads the section type from src.
   365  func ReadMsgSectionType(src []byte) (stype SectionType, rem []byte, ok bool) {
   366  	if len(src) < 1 {
   367  		return 0, src, false
   368  	}
   369  	return SectionType(src[0]), src[1:], true
   370  }
   371  
   372  // ReadMsgSectionSingleDocument reads a single document from src.
   373  func ReadMsgSectionSingleDocument(src []byte) (doc bsoncore.Document, rem []byte, ok bool) {
   374  	return bsoncore.ReadDocument(src)
   375  }
   376  
   377  // ReadMsgSectionDocumentSequence reads an identifier and document sequence from src and returns the document sequence
   378  // data parsed into a slice of BSON documents.
   379  func ReadMsgSectionDocumentSequence(src []byte) (identifier string, docs []bsoncore.Document, rem []byte, ok bool) {
   380  	length, rem, ok := readi32(src)
   381  	if !ok || int(length) > len(src) {
   382  		return "", nil, rem, false
   383  	}
   384  
   385  	rem, ret := rem[:length-4], rem[length-4:] // reslice so we can just iterate a loop later
   386  
   387  	identifier, rem, ok = readcstring(rem)
   388  	if !ok {
   389  		return "", nil, rem, false
   390  	}
   391  
   392  	docs = make([]bsoncore.Document, 0)
   393  	var doc bsoncore.Document
   394  	for {
   395  		doc, rem, ok = bsoncore.ReadDocument(rem)
   396  		if !ok {
   397  			break
   398  		}
   399  		docs = append(docs, doc)
   400  	}
   401  	if len(rem) > 0 {
   402  		return "", nil, append(rem, ret...), false
   403  	}
   404  
   405  	return identifier, docs, ret, true
   406  }
   407  
   408  // ReadMsgSectionRawDocumentSequence reads an identifier and document sequence from src and returns the raw document
   409  // sequence data.
   410  func ReadMsgSectionRawDocumentSequence(src []byte) (identifier string, data []byte, rem []byte, ok bool) {
   411  	length, rem, ok := readi32(src)
   412  	if !ok || int(length) > len(src) {
   413  		return "", nil, rem, false
   414  	}
   415  
   416  	// After these assignments, rem will be the data containing the identifier string + the document sequence bytes and
   417  	// rest will be the rest of the wire message after this document sequence.
   418  	rem, rest := rem[:length-4], rem[length-4:]
   419  
   420  	identifier, rem, ok = readcstring(rem)
   421  	if !ok {
   422  		return "", nil, rem, false
   423  	}
   424  
   425  	return identifier, rem, rest, true
   426  }
   427  
   428  // ReadMsgChecksum reads a checksum from src.
   429  func ReadMsgChecksum(src []byte) (checksum uint32, rem []byte, ok bool) {
   430  	i32, rem, ok := readi32(src)
   431  	return uint32(i32), rem, ok
   432  }
   433  
   434  // ReadQueryFlags reads OP_QUERY flags from src.
   435  func ReadQueryFlags(src []byte) (flags QueryFlag, rem []byte, ok bool) {
   436  	i32, rem, ok := readi32(src)
   437  	return QueryFlag(i32), rem, ok
   438  }
   439  
   440  // ReadQueryFullCollectionName reads the full collection name from src.
   441  func ReadQueryFullCollectionName(src []byte) (collname string, rem []byte, ok bool) {
   442  	return readcstring(src)
   443  }
   444  
   445  // ReadQueryNumberToSkip reads the number to skip from src.
   446  func ReadQueryNumberToSkip(src []byte) (nts int32, rem []byte, ok bool) {
   447  	return readi32(src)
   448  }
   449  
   450  // ReadQueryNumberToReturn reads the number to return from src.
   451  func ReadQueryNumberToReturn(src []byte) (ntr int32, rem []byte, ok bool) {
   452  	return readi32(src)
   453  }
   454  
   455  // ReadQueryQuery reads the query from src.
   456  func ReadQueryQuery(src []byte) (query bsoncore.Document, rem []byte, ok bool) {
   457  	return bsoncore.ReadDocument(src)
   458  }
   459  
   460  // ReadQueryReturnFieldsSelector reads a return fields selector document from src.
   461  func ReadQueryReturnFieldsSelector(src []byte) (rfs bsoncore.Document, rem []byte, ok bool) {
   462  	return bsoncore.ReadDocument(src)
   463  }
   464  
   465  // ReadReplyFlags reads OP_REPLY flags from src.
   466  func ReadReplyFlags(src []byte) (flags ReplyFlag, rem []byte, ok bool) {
   467  	i32, rem, ok := readi32(src)
   468  	return ReplyFlag(i32), rem, ok
   469  }
   470  
   471  // ReadReplyCursorID reads a cursor ID from src.
   472  func ReadReplyCursorID(src []byte) (cursorID int64, rem []byte, ok bool) {
   473  	return readi64(src)
   474  }
   475  
   476  // ReadReplyStartingFrom reads the starting from from src.
   477  func ReadReplyStartingFrom(src []byte) (startingFrom int32, rem []byte, ok bool) {
   478  	return readi32(src)
   479  }
   480  
   481  // ReadReplyNumberReturned reads the numbered returned from src.
   482  func ReadReplyNumberReturned(src []byte) (numberReturned int32, rem []byte, ok bool) {
   483  	return readi32(src)
   484  }
   485  
   486  // ReadReplyDocuments reads as many documents as possible from src
   487  func ReadReplyDocuments(src []byte) (docs []bsoncore.Document, rem []byte, ok bool) {
   488  	rem = src
   489  	for {
   490  		var doc bsoncore.Document
   491  		doc, rem, ok = bsoncore.ReadDocument(rem)
   492  		if !ok {
   493  			break
   494  		}
   495  
   496  		docs = append(docs, doc)
   497  	}
   498  
   499  	return docs, rem, true
   500  }
   501  
   502  // ReadReplyDocument reads a reply document from src.
   503  func ReadReplyDocument(src []byte) (doc bsoncore.Document, rem []byte, ok bool) {
   504  	return bsoncore.ReadDocument(src)
   505  }
   506  
   507  // ReadCompressedOriginalOpCode reads the original opcode from src.
   508  func ReadCompressedOriginalOpCode(src []byte) (opcode OpCode, rem []byte, ok bool) {
   509  	i32, rem, ok := readi32(src)
   510  	return OpCode(i32), rem, ok
   511  }
   512  
   513  // ReadCompressedUncompressedSize reads the uncompressed size of a
   514  // compressed wiremessage to dst.
   515  func ReadCompressedUncompressedSize(src []byte) (size int32, rem []byte, ok bool) {
   516  	return readi32(src)
   517  }
   518  
   519  // ReadCompressedCompressorID reads the ID of the compressor to dst.
   520  func ReadCompressedCompressorID(src []byte) (id CompressorID, rem []byte, ok bool) {
   521  	if len(src) < 1 {
   522  		return 0, src, false
   523  	}
   524  	return CompressorID(src[0]), src[1:], true
   525  }
   526  
   527  // ReadCompressedCompressedMessage reads the compressed wiremessage to dst.
   528  func ReadCompressedCompressedMessage(src []byte, length int32) (msg []byte, rem []byte, ok bool) {
   529  	if len(src) < int(length) {
   530  		return nil, src, false
   531  	}
   532  	return src[:length], src[length:], true
   533  }
   534  
   535  // ReadKillCursorsZero reads the zero field from src.
   536  func ReadKillCursorsZero(src []byte) (zero int32, rem []byte, ok bool) {
   537  	return readi32(src)
   538  }
   539  
   540  // ReadKillCursorsNumberIDs reads the numberOfCursorIDs field from src.
   541  func ReadKillCursorsNumberIDs(src []byte) (numIDs int32, rem []byte, ok bool) {
   542  	return readi32(src)
   543  }
   544  
   545  // ReadKillCursorsCursorIDs reads numIDs cursor IDs from src.
   546  func ReadKillCursorsCursorIDs(src []byte, numIDs int32) (cursorIDs []int64, rem []byte, ok bool) {
   547  	var i int32
   548  	var id int64
   549  	for i = 0; i < numIDs; i++ {
   550  		id, src, ok = readi64(src)
   551  		if !ok {
   552  			return cursorIDs, src, false
   553  		}
   554  
   555  		cursorIDs = append(cursorIDs, id)
   556  	}
   557  	return cursorIDs, src, true
   558  }
   559  
   560  func appendi32(dst []byte, i32 int32) []byte {
   561  	return append(dst, byte(i32), byte(i32>>8), byte(i32>>16), byte(i32>>24))
   562  }
   563  
   564  func appendi64(b []byte, i int64) []byte {
   565  	return append(b, byte(i), byte(i>>8), byte(i>>16), byte(i>>24), byte(i>>32), byte(i>>40), byte(i>>48), byte(i>>56))
   566  }
   567  
   568  func appendCString(b []byte, str string) []byte {
   569  	b = append(b, str...)
   570  	return append(b, 0x00)
   571  }
   572  
   573  func readi32(src []byte) (int32, []byte, bool) {
   574  	if len(src) < 4 {
   575  		return 0, src, false
   576  	}
   577  
   578  	return (int32(src[0]) | int32(src[1])<<8 | int32(src[2])<<16 | int32(src[3])<<24), src[4:], true
   579  }
   580  
   581  func readi32unsafe(src []byte) int32 {
   582  	return (int32(src[0]) | int32(src[1])<<8 | int32(src[2])<<16 | int32(src[3])<<24)
   583  }
   584  
   585  func readi64(src []byte) (int64, []byte, bool) {
   586  	if len(src) < 8 {
   587  		return 0, src, false
   588  	}
   589  	i64 := (int64(src[0]) | int64(src[1])<<8 | int64(src[2])<<16 | int64(src[3])<<24 |
   590  		int64(src[4])<<32 | int64(src[5])<<40 | int64(src[6])<<48 | int64(src[7])<<56)
   591  	return i64, src[8:], true
   592  }
   593  
   594  func readcstring(src []byte) (string, []byte, bool) {
   595  	idx := bytes.IndexByte(src, 0x00)
   596  	if idx < 0 {
   597  		return "", src, false
   598  	}
   599  	return string(src[:idx]), src[idx+1:], true
   600  }