1// Copyright 2019 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package impl 6 7import ( 8 "encoding/binary" 9 "encoding/json" 10 "hash/crc32" 11 "math" 12 "reflect" 13 14 "google.golang.org/protobuf/internal/errors" 15 "google.golang.org/protobuf/reflect/protoreflect" 16 "google.golang.org/protobuf/runtime/protoiface" 17) 18 19// These functions exist to support exported APIs in generated protobufs. 20// While these are deprecated, they cannot be removed for compatibility reasons. 21 22// LegacyEnumName returns the name of enums used in legacy code. 23func (Export) LegacyEnumName(ed protoreflect.EnumDescriptor) string { 24 return legacyEnumName(ed) 25} 26 27// LegacyMessageTypeOf returns the protoreflect.MessageType for m, 28// with name used as the message name if necessary. 29func (Export) LegacyMessageTypeOf(m protoiface.MessageV1, name protoreflect.FullName) protoreflect.MessageType { 30 if mv := (Export{}).protoMessageV2Of(m); mv != nil { 31 return mv.ProtoReflect().Type() 32 } 33 return legacyLoadMessageType(reflect.TypeOf(m), name) 34} 35 36// UnmarshalJSONEnum unmarshals an enum from a JSON-encoded input. 37// The input can either be a string representing the enum value by name, 38// or a number representing the enum number itself. 39func (Export) UnmarshalJSONEnum(ed protoreflect.EnumDescriptor, b []byte) (protoreflect.EnumNumber, error) { 40 if b[0] == '"' { 41 var name protoreflect.Name 42 if err := json.Unmarshal(b, &name); err != nil { 43 return 0, errors.New("invalid input for enum %v: %s", ed.FullName(), b) 44 } 45 ev := ed.Values().ByName(name) 46 if ev == nil { 47 return 0, errors.New("invalid value for enum %v: %s", ed.FullName(), name) 48 } 49 return ev.Number(), nil 50 } else { 51 var num protoreflect.EnumNumber 52 if err := json.Unmarshal(b, &num); err != nil { 53 return 0, errors.New("invalid input for enum %v: %s", ed.FullName(), b) 54 } 55 return num, nil 56 } 57} 58 59// CompressGZIP compresses the input as a GZIP-encoded file. 60// The current implementation does no compression. 61func (Export) CompressGZIP(in []byte) (out []byte) { 62 // RFC 1952, section 2.3.1. 63 var gzipHeader = [10]byte{0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff} 64 65 // RFC 1951, section 3.2.4. 66 var blockHeader [5]byte 67 const maxBlockSize = math.MaxUint16 68 numBlocks := 1 + len(in)/maxBlockSize 69 70 // RFC 1952, section 2.3.1. 71 var gzipFooter [8]byte 72 binary.LittleEndian.PutUint32(gzipFooter[0:4], crc32.ChecksumIEEE(in)) 73 binary.LittleEndian.PutUint32(gzipFooter[4:8], uint32(len(in))) 74 75 // Encode the input without compression using raw DEFLATE blocks. 76 out = make([]byte, 0, len(gzipHeader)+len(blockHeader)*numBlocks+len(in)+len(gzipFooter)) 77 out = append(out, gzipHeader[:]...) 78 for blockHeader[0] == 0 { 79 blockSize := maxBlockSize 80 if blockSize > len(in) { 81 blockHeader[0] = 0x01 // final bit per RFC 1951, section 3.2.3. 82 blockSize = len(in) 83 } 84 binary.LittleEndian.PutUint16(blockHeader[1:3], uint16(blockSize)) 85 binary.LittleEndian.PutUint16(blockHeader[3:5], ^uint16(blockSize)) 86 out = append(out, blockHeader[:]...) 87 out = append(out, in[:blockSize]...) 88 in = in[blockSize:] 89 } 90 out = append(out, gzipFooter[:]...) 91 return out 92} 93