xieguigang 5 years ago
parent 4784d4e543
commit 723a3da12f

@ -0,0 +1,75 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2008 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System
Namespace Google.Protobuf
''' <summary>
''' Provides a utility routine to copy small arrays much more quickly than Buffer.BlockCopy
''' </summary>
Friend Module ByteArray
''' <summary>
''' The threshold above which you should use Buffer.BlockCopy rather than ByteArray.Copy
''' </summary>
Private Const CopyThreshold As Integer = 12
''' <summary>
''' Determines which copy routine to use based on the number of bytes to be copied.
''' </summary>
Friend Sub Copy(src As Byte(), srcOffset As Integer, dst As Byte(), dstOffset As Integer, count As Integer)
If count > CopyThreshold Then
Buffer.BlockCopy(src, srcOffset, dst, dstOffset, count)
Else
Dim [stop] = srcOffset + count
For i = srcOffset To [stop] - 1
dst(Math.Min(Threading.Interlocked.Increment(dstOffset), dstOffset - 1)) = src(i)
Next
End If
End Sub
''' <summary>
''' Reverses the order of bytes in the array
''' </summary>
Friend Sub Reverse(bytes As Byte())
Dim first = 0, last = bytes.Length - 1
While first < last
Dim temp = bytes(first)
bytes(first) = bytes(last)
bytes(last) = temp
first += 1
last -= 1
End While
End Sub
End Module
End Namespace

@ -0,0 +1,324 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2008 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System
Imports System.Collections
Imports System.Collections.Generic
Imports System.IO
Imports System.Text
Namespace Google.Protobuf
''' <summary>
''' Immutable array of bytes.
''' </summary>
Public NotInheritable Class ByteString
Implements IEnumerable(Of Byte), IEquatable(Of ByteString)
Private Shared ReadOnly emptyField As ByteString = New ByteString(New Byte(-1) {})
Private ReadOnly bytes As Byte()
''' <summary>
''' Unsafe operations that can cause IO Failure and/or other catestrophic side-effects.
''' </summary>
Friend NotInheritable Class Unsafe
''' <summary>
''' Constructs a new ByteString from the given byte array. The array is
''' *not* copied, and must not be modified after this constructor is called.
''' </summary>
Friend Shared Function FromBytes(bytes As Byte()) As ByteString
Return New ByteString(bytes)
End Function
''' <summary>
''' Provides direct, unrestricted access to the bytes contained in this instance.
''' You must not modify or resize the byte array returned by this method.
''' </summary>
Friend Shared Function GetBuffer(bytes As ByteString) As Byte()
Return bytes.bytes
End Function
End Class
''' <summary>
''' Internal use only. Ensure that the provided array is not mutated and belongs to this instance.
''' </summary>
Friend Shared Function AttachBytes(bytes As Byte()) As ByteString
Return New ByteString(bytes)
End Function
''' <summary>
''' Constructs a new ByteString from the given byte array. The array is
''' *not* copied, and must not be modified after this constructor is called.
''' </summary>
Private Sub New(bytes As Byte())
Me.bytes = bytes
End Sub
''' <summary>
''' Returns an empty ByteString.
''' </summary>
Public Shared ReadOnly Property Empty As ByteString
Get
Return emptyField
End Get
End Property
''' <summary>
''' Returns the length of this ByteString in bytes.
''' </summary>
Public ReadOnly Property Length As Integer
Get
Return bytes.Length
End Get
End Property
''' <summary>
''' Returns <c>true</c> if this byte string is empty, <c>false</c> otherwise.
''' </summary>
Public ReadOnly Property IsEmpty As Boolean
Get
Return Length = 0
End Get
End Property
''' <summary>
''' Converts this <see cref="ByteString"/> into a byte array.
''' </summary>
''' <remarks>The data is copied - changes to the returned array will not be reflected in this <c>ByteString</c>.</remarks>
''' <returns>A byte array with the same data as this <c>ByteString</c>.</returns>
Public Function ToByteArray() As Byte()
Return CType(bytes.Clone(), Byte())
End Function
''' <summary>
''' Converts this <see cref="ByteString"/> into a standard base64 representation.
''' </summary>
''' <returns>A base64 representation of this <c>ByteString</c>.</returns>
Public Function ToBase64() As String
Return Convert.ToBase64String(bytes)
End Function
''' <summary>
''' Constructs a <see cref="ByteString"/> from the Base64 Encoded String.
''' </summary>
Public Shared Function FromBase64(bytes As String) As ByteString
' By handling the empty string explicitly, we not only optimize but we fix a
' problem on CF 2.0. See issue 61 for details.
Return If(Equals(bytes, ""), Empty, New ByteString(Convert.FromBase64String(bytes)))
End Function
''' <summary>
''' Constructs a <see cref="ByteString"/> from the given array. The contents
''' are copied, so further modifications to the array will not
''' be reflected in the returned ByteString.
''' This method can also be invoked in <c>ByteString.CopyFrom(0xaa, 0xbb, ...)</c> form
''' which is primarily useful for testing.
''' </summary>
Public Shared Function CopyFrom(ParamArray bytes As Byte()) As ByteString
Return New ByteString(CType(bytes.Clone(), Byte()))
End Function
''' <summary>
''' Constructs a <see cref="ByteString"/> from a portion of a byte array.
''' </summary>
Public Shared Function CopyFrom(bytes As Byte(), offset As Integer, count As Integer) As ByteString
Dim portion = New Byte(count - 1) {}
Copy(bytes, offset, portion, 0, count)
Return New ByteString(portion)
End Function
''' <summary>
''' Creates a new <see cref="ByteString"/> by encoding the specified text with
''' the given encoding.
''' </summary>
Public Shared Function CopyFrom(text As String, encoding As Encoding) As ByteString
Return New ByteString(encoding.GetBytes(text))
End Function
''' <summary>
''' Creates a new <see cref="ByteString"/> by encoding the specified text in UTF-8.
''' </summary>
Public Shared Function CopyFromUtf8(text As String) As ByteString
Return CopyFrom(text, Encoding.UTF8)
End Function
''' <summary>
''' Retuns the byte at the given index.
''' </summary>
Default Public ReadOnly Property Item(index As Integer) As Byte
Get
Return bytes(index)
End Get
End Property
''' <summary>
''' Converts this <see cref="ByteString"/> into a string by applying the given encoding.
''' </summary>
''' <remarks>
''' This method should only be used to convert binary data which was the result of encoding
''' text with the given encoding.
''' </remarks>
''' <param name="encoding">The encoding to use to decode the binary data into text.</param>
''' <returns>The result of decoding the binary data with the given decoding.</returns>
Public Overloads Function ToString(encoding As Encoding) As String
Return encoding.GetString(bytes, 0, bytes.Length)
End Function
''' <summary>
''' Converts this <see cref="ByteString"/> into a string by applying the UTF-8 encoding.
''' </summary>
''' <remarks>
''' This method should only be used to convert binary data which was the result of encoding
''' text with UTF-8.
''' </remarks>
''' <returns>The result of decoding the binary data with the given decoding.</returns>
Public Function ToStringUtf8() As String
Return ToString(Encoding.UTF8)
End Function
''' <summary>
''' Returns an iterator over the bytes in this <see cref="ByteString"/>.
''' </summary>
''' <returns>An iterator over the bytes in this object.</returns>
Public Function GetEnumerator() As IEnumerator(Of Byte) Implements IEnumerable(Of Byte).GetEnumerator
Return CType(bytes, IEnumerable(Of Byte)).GetEnumerator()
End Function
''' <summary>
''' Returns an iterator over the bytes in this <see cref="ByteString"/>.
''' </summary>
''' <returns>An iterator over the bytes in this object.</returns>
Private Function GetEnumerator1() As IEnumerator Implements IEnumerable.GetEnumerator
Return GetEnumerator()
End Function
''' <summary>
''' Creates a CodedInputStream from this ByteString's data.
''' </summary>
Public Function CreateCodedInput() As CodedInputStream
' We trust CodedInputStream not to reveal the provided byte array or modify it
Return New CodedInputStream(bytes)
End Function
''' <summary>
''' Compares two byte strings for equality.
''' </summary>
''' <param name="lhs">The first byte string to compare.</param>
''' <param name="rhs">The second byte string to compare.</param>
''' <returns><c>true</c> if the byte strings are equal; false otherwise.</returns>
Public Shared Operator =(lhs As ByteString, rhs As ByteString) As Boolean
If ReferenceEquals(lhs, rhs) Then
Return True
End If
If ReferenceEquals(lhs, Nothing) OrElse ReferenceEquals(rhs, Nothing) Then
Return False
End If
If lhs.bytes.Length <> rhs.bytes.Length Then
Return False
End If
For i = 0 To lhs.Length - 1
If rhs.bytes(i) <> lhs.bytes(i) Then
Return False
End If
Next
Return True
End Operator
''' <summary>
''' Compares two byte strings for inequality.
''' </summary>
''' <param name="lhs">The first byte string to compare.</param>
''' <param name="rhs">The second byte string to compare.</param>
''' <returns><c>false</c> if the byte strings are equal; true otherwise.</returns>
Public Shared Operator <>(lhs As ByteString, rhs As ByteString) As Boolean
Return Not lhs Is rhs
End Operator
''' <summary>
''' Compares this byte string with another object.
''' </summary>
''' <param name="obj">The object to compare this with.</param>
''' <returns><c>true</c> if <paramrefname="obj"/> refers to an equal <see cref="ByteString"/>; <c>false</c> otherwise.</returns>
Public Overrides Function Equals(obj As Object) As Boolean
Return Me Is TryCast(obj, ByteString)
End Function
''' <summary>
''' Returns a hash code for this object. Two equal byte strings
''' will return the same hash code.
''' </summary>
''' <returns>A hash code for this object.</returns>
Public Overrides Function GetHashCode() As Integer
Dim ret = 23
For Each b In bytes
ret = ret << 8 Or b
Next
Return ret
End Function
''' <summary>
''' Compares this byte string with another.
''' </summary>
''' <param name="other">The <see cref="ByteString"/> to compare this with.</param>
''' <returns><c>true</c> if <paramrefname="other"/> refers to an equal byte string; <c>false</c> otherwise.</returns>
Public Overloads Function Equals(other As ByteString) As Boolean Implements IEquatable(Of ByteString).Equals
Return Me Is other
End Function
''' <summary>
''' Used internally by CodedOutputStream to avoid creating a copy for the write
''' </summary>
Friend Sub WriteRawBytesTo(outputStream As CodedOutputStream)
outputStream.WriteRawBytes(bytes, 0, bytes.Length)
End Sub
''' <summary>
''' Copies the entire byte array to the destination array provided at the offset specified.
''' </summary>
Public Sub CopyTo(array As Byte(), position As Integer)
Copy(bytes, 0, array, position, bytes.Length)
End Sub
''' <summary>
''' Writes the entire byte array to the provided stream
''' </summary>
Public Sub WriteTo(outputStream As Stream)
outputStream.Write(bytes, 0, bytes.Length)
End Sub
End Class
End Namespace

File diff suppressed because it is too large Load Diff

@ -0,0 +1,276 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2008 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Namespace Google.Protobuf
' This part of CodedOutputStream provides all the static entry points that are used
' by generated code and internally to compute the size of messages prior to being
' written to an instance of CodedOutputStream.
Public NotInheritable Partial Class CodedOutputStream
Private Const LittleEndian64Size As Integer = 8
Private Const LittleEndian32Size As Integer = 4
''' <summary>
''' Computes the number of bytes that would be needed to encode a
''' double field, including the tag.
''' </summary>
Public Shared Function ComputeDoubleSize(value As Double) As Integer
Return LittleEndian64Size
End Function
''' <summary>
''' Computes the number of bytes that would be needed to encode a
''' float field, including the tag.
''' </summary>
Public Shared Function ComputeFloatSize(value As Single) As Integer
Return LittleEndian32Size
End Function
''' <summary>
''' Computes the number of bytes that would be needed to encode a
''' uint64 field, including the tag.
''' </summary>
Public Shared Function ComputeUInt64Size(value As ULong) As Integer
Return ComputeRawVarint64Size(value)
End Function
''' <summary>
''' Computes the number of bytes that would be needed to encode an
''' int64 field, including the tag.
''' </summary>
Public Shared Function ComputeInt64Size(value As Long) As Integer
Return ComputeRawVarint64Size(value)
End Function
''' <summary>
''' Computes the number of bytes that would be needed to encode an
''' int32 field, including the tag.
''' </summary>
Public Shared Function ComputeInt32Size(value As Integer) As Integer
If value >= 0 Then
Return ComputeRawVarint32Size(value)
Else
' Must sign-extend.
Return 10
End If
End Function
''' <summary>
''' Computes the number of bytes that would be needed to encode a
''' fixed64 field, including the tag.
''' </summary>
Public Shared Function ComputeFixed64Size(value As ULong) As Integer
Return LittleEndian64Size
End Function
''' <summary>
''' Computes the number of bytes that would be needed to encode a
''' fixed32 field, including the tag.
''' </summary>
Public Shared Function ComputeFixed32Size(value As UInteger) As Integer
Return LittleEndian32Size
End Function
''' <summary>
''' Computes the number of bytes that would be needed to encode a
''' bool field, including the tag.
''' </summary>
Public Shared Function ComputeBoolSize(value As Boolean) As Integer
Return 1
End Function
''' <summary>
''' Computes the number of bytes that would be needed to encode a
''' string field, including the tag.
''' </summary>
Public Shared Function ComputeStringSize(value As String) As Integer
Dim byteArraySize = Utf8Encoding.GetByteCount(value)
Return ComputeLengthSize(byteArraySize) + byteArraySize
End Function
''' <summary>
''' Computes the number of bytes that would be needed to encode a
''' group field, including the tag.
''' </summary>
Public Shared Function ComputeGroupSize(value As IMessage) As Integer
Return value.CalculateSize()
End Function
''' <summary>
''' Computes the number of bytes that would be needed to encode an
''' embedded message field, including the tag.
''' </summary>
Public Shared Function ComputeMessageSize(value As IMessage) As Integer
Dim size As Integer = value.CalculateSize()
Return ComputeLengthSize(size) + size
End Function
''' <summary>
''' Computes the number of bytes that would be needed to encode a
''' bytes field, including the tag.
''' </summary>
Public Shared Function ComputeBytesSize(value As ByteString) As Integer
Return ComputeLengthSize(value.Length) + value.Length
End Function
''' <summary>
''' Computes the number of bytes that would be needed to encode a
''' uint32 field, including the tag.
''' </summary>
Public Shared Function ComputeUInt32Size(value As UInteger) As Integer
Return ComputeRawVarint32Size(value)
End Function
''' <summary>
''' Computes the number of bytes that would be needed to encode a
''' enum field, including the tag. The caller is responsible for
''' converting the enum value to its numeric value.
''' </summary>
Public Shared Function ComputeEnumSize(value As Integer) As Integer
' Currently just a pass-through, but it's nice to separate it logically.
Return ComputeInt32Size(value)
End Function
''' <summary>
''' Computes the number of bytes that would be needed to encode an
''' sfixed32 field, including the tag.
''' </summary>
Public Shared Function ComputeSFixed32Size(value As Integer) As Integer
Return LittleEndian32Size
End Function
''' <summary>
''' Computes the number of bytes that would be needed to encode an
''' sfixed64 field, including the tag.
''' </summary>
Public Shared Function ComputeSFixed64Size(value As Long) As Integer
Return LittleEndian64Size
End Function
''' <summary>
''' Computes the number of bytes that would be needed to encode an
''' sint32 field, including the tag.
''' </summary>
Public Shared Function ComputeSInt32Size(value As Integer) As Integer
Return ComputeRawVarint32Size(EncodeZigZag32(value))
End Function
''' <summary>
''' Computes the number of bytes that would be needed to encode an
''' sint64 field, including the tag.
''' </summary>
Public Shared Function ComputeSInt64Size(value As Long) As Integer
Return ComputeRawVarint64Size(EncodeZigZag64(value))
End Function
''' <summary>
''' Computes the number of bytes that would be needed to encode a length,
''' as written by <see cref="WriteLength"/>.
''' </summary>
Public Shared Function ComputeLengthSize(length As Integer) As Integer
Return ComputeRawVarint32Size(length)
End Function
''' <summary>
''' Computes the number of bytes that would be needed to encode a varint.
''' </summary>
Public Shared Function ComputeRawVarint32Size(value As UInteger) As Integer
If (value And &HfffffffF << 7) = 0 Then
Return 1
End If
If (value And &HfffffffF << 14) = 0 Then
Return 2
End If
If (value And &HfffffffF << 21) = 0 Then
Return 3
End If
If (value And &HfffffffF << 28) = 0 Then
Return 4
End If
Return 5
End Function
''' <summary>
''' Computes the number of bytes that would be needed to encode a varint.
''' </summary>
Public Shared Function ComputeRawVarint64Size(value As ULong) As Integer
If (value And &HffffffffffffffffL << 7) = 0 Then
Return 1
End If
If (value And &HffffffffffffffffL << 14) = 0 Then
Return 2
End If
If (value And &HffffffffffffffffL << 21) = 0 Then
Return 3
End If
If (value And &HffffffffffffffffL << 28) = 0 Then
Return 4
End If
If (value And &HffffffffffffffffL << 35) = 0 Then
Return 5
End If
If (value And &HffffffffffffffffL << 42) = 0 Then
Return 6
End If
If (value And &HffffffffffffffffL << 49) = 0 Then
Return 7
End If
If (value And &HffffffffffffffffL << 56) = 0 Then
Return 8
End If
If (value And &HffffffffffffffffL << 63) = 0 Then
Return 9
End If
Return 10
End Function
''' <summary>
''' Computes the number of bytes that would be needed to encode a tag.
''' </summary>
Public Shared Function ComputeTagSize(fieldNumber As Integer) As Integer
Return ComputeRawVarint32Size(MakeTag(fieldNumber, 0))
End Function
End Class
End Namespace

@ -0,0 +1,676 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2008 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System
Imports System.IO
Imports System.Text
Namespace Google.Protobuf
''' <summary>
''' Encodes and writes protocol message fields.
''' </summary>
''' <remarks>
''' <para>
''' This class is generally used by generated code to write appropriate
''' primitives to the stream. It effectively encapsulates the lowest
''' levels of protocol buffer format. Unlike some other implementations,
''' this does not include combined "write tag and value" methods. Generated
''' code knows the exact byte representations of the tags they're going to write,
''' so there's no need to re-encode them each time. Manually-written code calling
''' this class should just call one of the <c>WriteTag</c> overloads before each value.
''' </para>
''' <para>
''' Repeated fields and map fields are not handled by this class; use <c>RepeatedField&lt;T&gt;</c>
''' and <c>MapField&lt;TKey, TValue&gt;</c> to serialize such fields.
''' </para>
''' </remarks>
Public NotInheritable Partial Class CodedOutputStream
Implements IDisposable
' "Local" copy of Encoding.UTF8, for efficiency. (Yes, it makes a difference.)
Friend Shared ReadOnly Utf8Encoding As Encoding = Encoding.UTF8
''' <summary>
''' The buffer size used by CreateInstance(Stream).
''' </summary>
Public Shared ReadOnly DefaultBufferSize As Integer = 4096
Private ReadOnly leaveOpen As Boolean
Private ReadOnly buffer As Byte()
Private ReadOnly limit As Integer
Private positionField As Integer
Private ReadOnly output As Stream
#Region "Construction"
''' <summary>
''' Creates a new CodedOutputStream that writes directly to the given
''' byte array. If more bytes are written than fit in the array,
''' OutOfSpaceException will be thrown.
''' </summary>
Public Sub New(flatArray As Byte())
Me.New(flatArray, 0, flatArray.Length)
End Sub
''' <summary>
''' Creates a new CodedOutputStream that writes directly to the given
''' byte array slice. If more bytes are written than fit in the array,
''' OutOfSpaceException will be thrown.
''' </summary>
Private Sub New(buffer As Byte(), offset As Integer, length As Integer)
output = Nothing
Me.buffer = buffer
positionField = offset
limit = offset + length
leaveOpen = True ' Simple way of avoiding trying to dispose of a null reference
End Sub
Private Sub New(output As Stream, buffer As Byte(), leaveOpen As Boolean)
Me.output = CheckNotNull(output, NameOf(output))
Me.buffer = buffer
positionField = 0
limit = buffer.Length
Me.leaveOpen = leaveOpen
End Sub
''' <summary>
''' Creates a new <see cref="CodedOutputStream"/> which write to the given stream, and disposes of that
''' stream when the returned <c>CodedOutputStream</c> is disposed.
''' </summary>
''' <param name="output">The stream to write to. It will be disposed when the returned <c>CodedOutputStream is disposed.</c></param>
Public Sub New(output As Stream)
Me.New(output, DefaultBufferSize, False)
End Sub
''' <summary>
''' Creates a new CodedOutputStream which write to the given stream and uses
''' the specified buffer size.
''' </summary>
''' <param name="output">The stream to write to. It will be disposed when the returned <c>CodedOutputStream is disposed.</c></param>
''' <param name="bufferSize">The size of buffer to use internally.</param>
Public Sub New(output As Stream, bufferSize As Integer)
Me.New(output, New Byte(bufferSize - 1) {}, False)
End Sub
''' <summary>
''' Creates a new CodedOutputStream which write to the given stream.
''' </summary>
''' <param name="output">The stream to write to.</param>
''' <param name="leaveOpen">If <c>true</c>, <paramrefname="output"/> is left open when the returned <c>CodedOutputStream</c> is disposed;
''' if <c>false</c>, the provided stream is disposed as well.</param>
Public Sub New(output As Stream, leaveOpen As Boolean)
Me.New(output, DefaultBufferSize, leaveOpen)
End Sub
''' <summary>
''' Creates a new CodedOutputStream which write to the given stream and uses
''' the specified buffer size.
''' </summary>
''' <param name="output">The stream to write to.</param>
''' <param name="bufferSize">The size of buffer to use internally.</param>
''' <param name="leaveOpen">If <c>true</c>, <paramrefname="output"/> is left open when the returned <c>CodedOutputStream</c> is disposed;
''' if <c>false</c>, the provided stream is disposed as well.</param>
Public Sub New(output As Stream, bufferSize As Integer, leaveOpen As Boolean)
Me.New(output, New Byte(bufferSize - 1) {}, leaveOpen)
End Sub
#End Region
''' <summary>
''' Returns the current position in the stream, or the position in the output buffer
''' </summary>
Public ReadOnly Property Position As Long
Get
If output IsNot Nothing Then
Return output.Position + positionField
End If
Return positionField
End Get
End Property
#Region "Writing of values (not including tags)"
''' <summary>
''' Writes a double field value, without a tag, to the stream.
''' </summary>
''' <param name="value">The value to write</param>
Public Sub WriteDouble(value As Double)
WriteRawLittleEndian64(BitConverter.DoubleToInt64Bits(value))
End Sub
''' <summary>
''' Writes a float field value, without a tag, to the stream.
''' </summary>
''' <param name="value">The value to write</param>
Public Sub WriteFloat(value As Single)
Dim rawBytes = BitConverter.GetBytes(value)
If Not BitConverter.IsLittleEndian Then
Reverse(rawBytes)
End If
If limit - positionField >= 4 Then
buffer(Math.Min(Threading.Interlocked.Increment(positionField), positionField - 1)) = rawBytes(0)
buffer(Math.Min(Threading.Interlocked.Increment(positionField), positionField - 1)) = rawBytes(1)
buffer(Math.Min(Threading.Interlocked.Increment(positionField), positionField - 1)) = rawBytes(2)
buffer(Math.Min(Threading.Interlocked.Increment(positionField), positionField - 1)) = rawBytes(3)
Else
WriteRawBytes(rawBytes, 0, 4)
End If
End Sub
''' <summary>
''' Writes a uint64 field value, without a tag, to the stream.
''' </summary>
''' <param name="value">The value to write</param>
Public Sub WriteUInt64(value As ULong)
WriteRawVarint64(value)
End Sub
''' <summary>
''' Writes an int64 field value, without a tag, to the stream.
''' </summary>
''' <param name="value">The value to write</param>
Public Sub WriteInt64(value As Long)
WriteRawVarint64(value)
End Sub
''' <summary>
''' Writes an int32 field value, without a tag, to the stream.
''' </summary>
''' <param name="value">The value to write</param>
Public Sub WriteInt32(value As Integer)
If value >= 0 Then
WriteRawVarint32(value)
Else
' Must sign-extend.
WriteRawVarint64(value)
End If
End Sub
''' <summary>
''' Writes a fixed64 field value, without a tag, to the stream.
''' </summary>
''' <param name="value">The value to write</param>
Public Sub WriteFixed64(value As ULong)
WriteRawLittleEndian64(value)
End Sub
''' <summary>
''' Writes a fixed32 field value, without a tag, to the stream.
''' </summary>
''' <param name="value">The value to write</param>
Public Sub WriteFixed32(value As UInteger)
WriteRawLittleEndian32(value)
End Sub
''' <summary>
''' Writes a bool field value, without a tag, to the stream.
''' </summary>
''' <param name="value">The value to write</param>
Public Sub WriteBool(value As Boolean)
WriteRawByte(If(value, CByte(1), CByte(0)))
End Sub
''' <summary>
''' Writes a string field value, without a tag, to the stream.
''' The data is length-prefixed.
''' </summary>
''' <param name="value">The value to write</param>
Public Sub WriteString(value As String)
' Optimise the case where we have enough space to write
' the string directly to the buffer, which should be common.
Dim length = Utf8Encoding.GetByteCount(value)
WriteLength(length)
If limit - positionField >= length Then
If length = value.Length Then ' Must be all ASCII...
For i = 0 To length - 1
buffer(positionField + i) = Microsoft.VisualBasic.AscW(value(i))
Next
Else
Utf8Encoding.GetBytes(value, 0, value.Length, buffer, positionField)
End If
positionField += length
Else
Dim bytes = Utf8Encoding.GetBytes(value)
WriteRawBytes(bytes)
End If
End Sub
''' <summary>
''' Writes a message, without a tag, to the stream.
''' The data is length-prefixed.
''' </summary>
''' <param name="value">The value to write</param>
Public Sub WriteMessage(value As IMessage)
WriteLength(value.CalculateSize())
value.WriteTo(Me)
End Sub
''' <summary>
''' Write a byte string, without a tag, to the stream.
''' The data is length-prefixed.
''' </summary>
''' <param name="value">The value to write</param>
Public Sub WriteBytes(value As ByteString)
WriteLength(value.Length)
value.WriteRawBytesTo(Me)
End Sub
''' <summary>
''' Writes a uint32 value, without a tag, to the stream.
''' </summary>
''' <param name="value">The value to write</param>
Public Sub WriteUInt32(value As UInteger)
WriteRawVarint32(value)
End Sub
''' <summary>
''' Writes an enum value, without a tag, to the stream.
''' </summary>
''' <param name="value">The value to write</param>
Public Sub WriteEnum(value As Integer)
WriteInt32(value)
End Sub
''' <summary>
''' Writes an sfixed32 value, without a tag, to the stream.
''' </summary>
''' <param name="value">The value to write.</param>
Public Sub WriteSFixed32(value As Integer)
WriteRawLittleEndian32(value)
End Sub
''' <summary>
''' Writes an sfixed64 value, without a tag, to the stream.
''' </summary>
''' <param name="value">The value to write</param>
Public Sub WriteSFixed64(value As Long)
WriteRawLittleEndian64(value)
End Sub
''' <summary>
''' Writes an sint32 value, without a tag, to the stream.
''' </summary>
''' <param name="value">The value to write</param>
Public Sub WriteSInt32(value As Integer)
WriteRawVarint32(EncodeZigZag32(value))
End Sub
''' <summary>
''' Writes an sint64 value, without a tag, to the stream.
''' </summary>
''' <param name="value">The value to write</param>
Public Sub WriteSInt64(value As Long)
WriteRawVarint64(EncodeZigZag64(value))
End Sub
''' <summary>
''' Writes a length (in bytes) for length-delimited data.
''' </summary>
''' <remarks>
''' This method simply writes a rawint, but exists for clarity in calling code.
''' </remarks>
''' <param name="length">Length value, in bytes.</param>
Public Sub WriteLength(length As Integer)
WriteRawVarint32(length)
End Sub
#End Region
#Region "Raw tag writing"
''' <summary>
''' Encodes and writes a tag.
''' </summary>
''' <param name="fieldNumber">The number of the field to write the tag for</param>
''' <param name="type">The wire format type of the tag to write</param>
Public Sub WriteTag(fieldNumber As Integer, type As WireType)
WriteRawVarint32(MakeTag(fieldNumber, type))
End Sub
''' <summary>
''' Writes an already-encoded tag.
''' </summary>
''' <param name="tag">The encoded tag</param>
Public Sub WriteTag(tag As UInteger)
WriteRawVarint32(tag)
End Sub
''' <summary>
''' Writes the given single-byte tag directly to the stream.
''' </summary>
''' <param name="b1">The encoded tag</param>
Public Sub WriteRawTag(b1 As Byte)
WriteRawByte(b1)
End Sub
''' <summary>
''' Writes the given two-byte tag directly to the stream.
''' </summary>
''' <param name="b1">The first byte of the encoded tag</param>
''' <param name="b2">The second byte of the encoded tag</param>
Public Sub WriteRawTag(b1 As Byte, b2 As Byte)
WriteRawByte(b1)
WriteRawByte(b2)
End Sub
''' <summary>
''' Writes the given three-byte tag directly to the stream.
''' </summary>
''' <param name="b1">The first byte of the encoded tag</param>
''' <param name="b2">The second byte of the encoded tag</param>
''' <param name="b3">The third byte of the encoded tag</param>
Public Sub WriteRawTag(b1 As Byte, b2 As Byte, b3 As Byte)
WriteRawByte(b1)
WriteRawByte(b2)
WriteRawByte(b3)
End Sub
''' <summary>
''' Writes the given four-byte tag directly to the stream.
''' </summary>
''' <param name="b1">The first byte of the encoded tag</param>
''' <param name="b2">The second byte of the encoded tag</param>
''' <param name="b3">The third byte of the encoded tag</param>
''' <param name="b4">The fourth byte of the encoded tag</param>
Public Sub WriteRawTag(b1 As Byte, b2 As Byte, b3 As Byte, b4 As Byte)
WriteRawByte(b1)
WriteRawByte(b2)
WriteRawByte(b3)
WriteRawByte(b4)
End Sub
''' <summary>
''' Writes the given five-byte tag directly to the stream.
''' </summary>
''' <param name="b1">The first byte of the encoded tag</param>
''' <param name="b2">The second byte of the encoded tag</param>
''' <param name="b3">The third byte of the encoded tag</param>
''' <param name="b4">The fourth byte of the encoded tag</param>
''' <param name="b5">The fifth byte of the encoded tag</param>
Public Sub WriteRawTag(b1 As Byte, b2 As Byte, b3 As Byte, b4 As Byte, b5 As Byte)
WriteRawByte(b1)
WriteRawByte(b2)
WriteRawByte(b3)
WriteRawByte(b4)
WriteRawByte(b5)
End Sub
#End Region
#Region "Underlying writing primitives"
''' <summary>
''' Writes a 32 bit value as a varint. The fast route is taken when
''' there's enough buffer space left to whizz through without checking
''' for each byte; otherwise, we resort to calling WriteRawByte each time.
''' </summary>
Friend Sub WriteRawVarint32(value As UInteger)
' Optimize for the common case of a single byte value
If value < 128 AndAlso positionField < limit Then
buffer(Math.Min(Threading.Interlocked.Increment(positionField), positionField - 1)) = CByte(value)
Return
End If
While value > 127 AndAlso positionField < limit
buffer(Math.Min(Threading.Interlocked.Increment(positionField), positionField - 1)) = CByte(value And &H7F Or &H80)
value >>= 7
End While
While value > 127
WriteRawByte(CByte(value And &H7F Or &H80))
value >>= 7
End While
If positionField < limit Then
buffer(Math.Min(Threading.Interlocked.Increment(positionField), positionField - 1)) = CByte(value)
Else
WriteRawByte(CByte(value))
End If
End Sub
Friend Sub WriteRawVarint64(value As ULong)
While value > 127 AndAlso positionField < limit
buffer(Math.Min(Threading.Interlocked.Increment(positionField), positionField - 1)) = CByte(value And &H7F Or &H80)
value >>= 7
End While
While value > 127
WriteRawByte(CByte(value And &H7F Or &H80))
value >>= 7
End While
If positionField < limit Then
buffer(Math.Min(Threading.Interlocked.Increment(positionField), positionField - 1)) = CByte(value)
Else
WriteRawByte(CByte(value))
End If
End Sub
Friend Sub WriteRawLittleEndian32(value As UInteger)
If positionField + 4 > limit Then
WriteRawByte(CByte(value))
WriteRawByte(CByte(value >> 8))
WriteRawByte(CByte(value >> 16))
WriteRawByte(CByte(value >> 24))
Else
buffer(Math.Min(Threading.Interlocked.Increment(positionField), positionField - 1)) = CByte(value)
buffer(Math.Min(Threading.Interlocked.Increment(positionField), positionField - 1)) = CByte(value >> 8)
buffer(Math.Min(Threading.Interlocked.Increment(positionField), positionField - 1)) = CByte(value >> 16)
buffer(Math.Min(Threading.Interlocked.Increment(positionField), positionField - 1)) = CByte(value >> 24)
End If
End Sub
Friend Sub WriteRawLittleEndian64(value As ULong)
If positionField + 8 > limit Then
WriteRawByte(CByte(value))
WriteRawByte(CByte(value >> 8))
WriteRawByte(CByte(value >> 16))
WriteRawByte(CByte(value >> 24))
WriteRawByte(CByte(value >> 32))
WriteRawByte(CByte(value >> 40))
WriteRawByte(CByte(value >> 48))
WriteRawByte(CByte(value >> 56))
Else
buffer(Math.Min(Threading.Interlocked.Increment(positionField), positionField - 1)) = CByte(value)
buffer(Math.Min(Threading.Interlocked.Increment(positionField), positionField - 1)) = CByte(value >> 8)
buffer(Math.Min(Threading.Interlocked.Increment(positionField), positionField - 1)) = CByte(value >> 16)
buffer(Math.Min(Threading.Interlocked.Increment(positionField), positionField - 1)) = CByte(value >> 24)
buffer(Math.Min(Threading.Interlocked.Increment(positionField), positionField - 1)) = CByte(value >> 32)
buffer(Math.Min(Threading.Interlocked.Increment(positionField), positionField - 1)) = CByte(value >> 40)
buffer(Math.Min(Threading.Interlocked.Increment(positionField), positionField - 1)) = CByte(value >> 48)
buffer(Math.Min(Threading.Interlocked.Increment(positionField), positionField - 1)) = CByte(value >> 56)
End If
End Sub
Friend Sub WriteRawByte(value As Byte)
If positionField = limit Then
RefreshBuffer()
End If
buffer(Math.Min(Threading.Interlocked.Increment(positionField), positionField - 1)) = value
End Sub
Friend Sub WriteRawByte(value As UInteger)
WriteRawByte(CByte(value))
End Sub
''' <summary>
''' Writes out an array of bytes.
''' </summary>
Friend Sub WriteRawBytes(value As Byte())
WriteRawBytes(value, 0, value.Length)
End Sub
''' <summary>
''' Writes out part of an array of bytes.
''' </summary>
Friend Sub WriteRawBytes(value As Byte(), offset As Integer, length As Integer)
If limit - positionField >= length Then
Copy(value, offset, buffer, positionField, length)
' We have room in the current buffer.
positionField += length
Else
' Write extends past current buffer. Fill the rest of this buffer and
' flush.
Dim bytesWritten = limit - positionField
Copy(value, offset, buffer, positionField, bytesWritten)
offset += bytesWritten
length -= bytesWritten
positionField = limit
RefreshBuffer()
' Now deal with the rest.
' Since we have an output stream, this is our buffer
' and buffer offset == 0
If length <= limit Then
' Fits in new buffer.
Copy(value, offset, buffer, 0, length)
positionField = length
Else
' Write is very big. Let's do it all at once.
output.Write(value, offset, length)
End If
End If
End Sub
#End Region
''' <summary>
''' Encode a 32-bit value with ZigZag encoding.
''' </summary>
''' <remarks>
''' ZigZag encodes signed integers into values that can be efficiently
''' encoded with varint. (Otherwise, negative values must be
''' sign-extended to 64 bits to be varint encoded, thus always taking
''' 10 bytes on the wire.)
''' </remarks>
Friend Shared Function EncodeZigZag32(n As Integer) As UInteger
' Note: the right-shift must be arithmetic
Return n << 1 Xor n >> 31
End Function
''' <summary>
''' Encode a 64-bit value with ZigZag encoding.
''' </summary>
''' <remarks>
''' ZigZag encodes signed integers into values that can be efficiently
''' encoded with varint. (Otherwise, negative values must be
''' sign-extended to 64 bits to be varint encoded, thus always taking
''' 10 bytes on the wire.)
''' </remarks>
Friend Shared Function EncodeZigZag64(n As Long) As ULong
Return n << 1 Xor n >> 63
End Function
Private Sub RefreshBuffer()
If output Is Nothing Then
' We're writing to a single buffer.
Throw New OutOfSpaceException()
End If
' Since we have an output stream, this is our buffer
' and buffer offset == 0
output.Write(buffer, 0, positionField)
positionField = 0
End Sub
''' <summary>
''' Indicates that a CodedOutputStream wrapping a flat byte array
''' ran out of space.
''' </summary>
Public NotInheritable Class OutOfSpaceException
Inherits IOException
Friend Sub New()
MyBase.New("CodedOutputStream was writing to a flat byte array and ran out of space.")
End Sub
End Class
''' <summary>
''' Flushes any buffered data and optionally closes the underlying stream, if any.
''' </summary>
''' <remarks>
''' <para>
''' By default, any underlying stream is closed by this method. To configure this behaviour,
''' use a constructor overload with a <c>leaveOpen</c> parameter. If this instance does not
''' have an underlying stream, this method does nothing.
''' </para>
''' <para>
''' For the sake of efficiency, calling this method does not prevent future write calls - but
''' if a later write ends up writing to a stream which has been disposed, that is likely to
''' fail. It is recommend that you not call any other methods after this.
''' </para>
''' </remarks>
Public Sub Dispose() Implements IDisposable.Dispose
Flush()
If Not leaveOpen Then
output.Dispose()
End If
End Sub
''' <summary>
''' Flushes any buffered data to the underlying stream (if there is one).
''' </summary>
Public Sub Flush()
If output IsNot Nothing Then
RefreshBuffer()
End If
End Sub
''' <summary>
''' Verifies that SpaceLeft returns zero. It's common to create a byte array
''' that is exactly big enough to hold a message, then write to it with
''' a CodedOutputStream. Calling CheckNoSpaceLeft after writing verifies that
''' the message was actually as big as expected, which can help bugs.
''' </summary>
Public Sub CheckNoSpaceLeft()
If SpaceLeft <> 0 Then
Throw New InvalidOperationException("Did not write as much data as expected.")
End If
End Sub
''' <summary>
''' If writing to a flat array, returns the space left in the array. Otherwise,
''' throws an InvalidOperationException.
''' </summary>
Public ReadOnly Property SpaceLeft As Integer
Get
If output Is Nothing Then
Return limit - positionField
Else
Throw New InvalidOperationException("SpaceLeft can only be called on CodedOutputStreams that are " & "writing to a flat array.")
End If
End Get
End Property
End Class
End Namespace

@ -0,0 +1,778 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2015 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports Google.Protobuf.Reflection
Imports System
Imports System.Collections
Imports System.Collections.Generic
Imports System.IO
Imports System.Linq
Imports System.Runtime.InteropServices
Namespace Google.Protobuf.Collections
''' <summary>
''' Representation of a map field in a Protocol Buffer message.
''' </summary>
''' <typeparamname="TKey">Key type in the map. Must be a type supported by Protocol Buffer map keys.</typeparam>
''' <typeparamname="TValue">Value type in the map. Must be a type supported by Protocol Buffers.</typeparam>
''' <remarks>
''' <para>
''' For string keys, the equality comparison is provided by <see cref="StringComparer.Ordinal"/>.
''' </para>
''' <para>
''' Null values are not permitted in the map, either for wrapper types or regular messages.
''' If a map is deserialized from a data stream and the value is missing from an entry, a default value
''' is created instead. For primitive types, that is the regular default value (0, the empty string and so
''' on); for message types, an empty instance of the message is created, as if the map entry contained a 0-length
''' encoded value for the field.
''' </para>
''' <para>
''' This implementation does not generally prohibit the use of key/value types which are not
''' supported by Protocol Buffers (e.g. using a key type of <code>byte</code>) but nor does it guarantee
''' that all operations will work in such cases.
''' </para>
''' <para>
''' The order in which entries are returned when iterating over this object is undefined, and may change
''' in future versions.
''' </para>
''' </remarks>
Public NotInheritable Class MapField(Of TKey, TValue)
Implements IDeepCloneable(Of MapField(Of TKey, TValue)), IDictionary(Of TKey, TValue), IEquatable(Of MapField(Of TKey, TValue)), IDictionary
' TODO: Don't create the map/list until we have an entry. (Assume many maps will be empty.)
Private ReadOnly map As Dictionary(Of TKey, LinkedListNode(Of KeyValuePair(Of TKey, TValue))) = New Dictionary(Of TKey, LinkedListNode(Of KeyValuePair(Of TKey, TValue)))()
Private ReadOnly list As LinkedList(Of KeyValuePair(Of TKey, TValue)) = New LinkedList(Of KeyValuePair(Of TKey, TValue))()
''' <summary>
''' Creates a deep clone of this object.
''' </summary>
''' <returns>
''' A deep clone of this object.
''' </returns>
Public Function Clone() As MapField(Of TKey, TValue) Implements IDeepCloneable(Of MapField(Of TKey, TValue)).Clone
Dim lClone = New MapField(Of TKey, TValue)()
' Keys are never cloneable. Values might be.
If GetType(IDeepCloneable(Of TValue)).IsAssignableFrom(GetType(TValue)) Then
For Each pair In list
lClone.Add(pair.Key, CType(pair.Value, IDeepCloneable(Of TValue)).Clone())
Next
Else
' Nothing is cloneable, so we don't need to worry.
lClone.Add(Me)
End If
Return lClone
End Function
''' <summary>
''' Adds the specified key/value pair to the map.
''' </summary>
''' <remarks>
''' This operation fails if the key already exists in the map. To replace an existing entry, use the indexer.
''' </remarks>
''' <param name="key">The key to add</param>
''' <param name="value">The value to add.</param>
''' <exception cref="System.ArgumentException">The given key already exists in map.</exception>
Public Sub Add(key As TKey, value As TValue) Implements IDictionary(Of TKey, TValue).Add
' Validation of arguments happens in ContainsKey and the indexer
If ContainsKey(key) Then
Throw New ArgumentException("Key already exists in map", NameOf(key))
End If
Me(key) = value
End Sub
''' <summary>
''' Determines whether the specified key is present in the map.
''' </summary>
''' <param name="key">The key to check.</param>
''' <returns><c>true</c> if the map contains the given key; <c>false</c> otherwise.</returns>
Public Function ContainsKey(key As TKey) As Boolean Implements IDictionary(Of TKey, TValue).ContainsKey
CheckNotNullUnconstrained(key, NameOf(key))
Return map.ContainsKey(key)
End Function
Private Function ContainsValue(value As TValue) As Boolean
Dim comparer = EqualityComparer(Of TValue).Default
Return list.Any(Function(pair) comparer.Equals(pair.Value, value))
End Function
''' <summary>
''' Removes the entry identified by the given key from the map.
''' </summary>
''' <param name="key">The key indicating the entry to remove from the map.</param>
''' <returns><c>true</c> if the map contained the given key before the entry was removed; <c>false</c> otherwise.</returns>
Public Function Remove(key As TKey) As Boolean Implements IDictionary(Of TKey, TValue).Remove
CheckNotNullUnconstrained(key, NameOf(key))
Dim node As LinkedListNode(Of KeyValuePair(Of TKey, TValue))
If map.TryGetValue(key, node) Then
map.Remove(key)
node.List.Remove(node)
Return True
Else
Return False
End If
End Function
''' <summary>
''' Gets the value associated with the specified key.
''' </summary>
''' <param name="key">The key whose value to get.</param>
''' <param name="value">When this method returns, the value associated with the specified key, if the key is found;
''' otherwise, the default value for the type of the <paramrefname="value"/> parameter.
''' This parameter is passed uninitialized.</param>
''' <returns><c>true</c> if the map contains an element with the specified key; otherwise, <c>false</c>.</returns>
Public Function TryGetValue(key As TKey, <Out> ByRef value As TValue) As Boolean Implements IDictionary(Of TKey, TValue).TryGetValue
Dim node As LinkedListNode(Of KeyValuePair(Of TKey, TValue))
If map.TryGetValue(key, node) Then
value = node.Value.Value
Return True
Else
value = Nothing
Return False
End If
End Function
''' <summary>
''' Gets or sets the value associated with the specified key.
''' </summary>
''' <param name="key">The key of the value to get or set.</param>
''' <exception cref="KeyNotFoundException">The property is retrieved and key does not exist in the collection.</exception>
''' <returns>The value associated with the specified key. If the specified key is not found,
''' a get operation throws a <see cref="KeyNotFoundException"/>, and a set operation creates a new element with the specified key.</returns>
Default Public Property Item(key As TKey) As TValue Implements IDictionary(Of TKey, TValue).Item
Get
CheckNotNullUnconstrained(key, NameOf(key))
Dim value As TValue
If TryGetValue(key, value) Then
Return value
End If
Throw New KeyNotFoundException()
End Get
Set(value As TValue)
CheckNotNullUnconstrained(key, NameOf(key))
' value == null check here is redundant, but avoids boxing.
If value Is Nothing Then
CheckNotNullUnconstrained(value, NameOf(value))
End If
Dim node As LinkedListNode(Of KeyValuePair(Of TKey, TValue))
Dim pair = New KeyValuePair(Of TKey, TValue)(key, value)
If map.TryGetValue(key, node) Then
node.Value = pair
Else
node = list.AddLast(pair)
map(key) = node
End If
End Set
End Property
''' <summary>
''' Gets a collection containing the keys in the map.
''' </summary>
Public ReadOnly Property KeysProp As ICollection(Of TKey) Implements IDictionary(Of TKey, TValue).Keys
Get
Return New MapView(Of TKey)(Me, Function(pair) pair.Key, AddressOf ContainsKey)
End Get
End Property
''' <summary>
''' Gets a collection containing the values in the map.
''' </summary>
Public ReadOnly Property ValuesProp As ICollection(Of TValue) Implements IDictionary(Of TKey, TValue).Values
Get
Return New MapView(Of TValue)(Me, Function(pair) pair.Value, AddressOf ContainsValue)
End Get
End Property
''' <summary>
''' Adds the specified entries to the map. The keys and values are not automatically cloned.
''' </summary>
''' <param name="entries">The entries to add to the map.</param>
Public Sub Add(entries As IDictionary(Of TKey, TValue))
CheckNotNull(entries, NameOf(entries))
For Each pair In entries
Add(pair.Key, pair.Value)
Next
End Sub
''' <summary>
''' Returns an enumerator that iterates through the collection.
''' </summary>
''' <returns>
''' An enumerator that can be used to iterate through the collection.
''' </returns>
Public Function GetEnumerator() As IEnumerator(Of KeyValuePair(Of TKey, TValue)) Implements IEnumerable(Of KeyValuePair(Of TKey, TValue)).GetEnumerator
Return list.GetEnumerator()
End Function
''' <summary>
''' Returns an enumerator that iterates through a collection.
''' </summary>
''' <returns>
''' An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
''' </returns>
Private Function GetEnumerator1() As IEnumerator Implements IEnumerable.GetEnumerator
Return GetEnumerator()
End Function
''' <summary>
''' Adds the specified item to the map.
''' </summary>
''' <param name="item">The item to add to the map.</param>
Private Sub Add1(item As KeyValuePair(Of TKey, TValue)) Implements ICollection(Of KeyValuePair(Of TKey, TValue)).Add
Add(item.Key, item.Value)
End Sub
''' <summary>
''' Removes all items from the map.
''' </summary>
Public Sub Clear() Implements ICollection(Of KeyValuePair(Of TKey, TValue)).Clear, IDictionary.Clear
list.Clear()
map.Clear()
End Sub
''' <summary>
''' Determines whether map contains an entry equivalent to the given key/value pair.
''' </summary>
''' <param name="item">The key/value pair to find.</param>
''' <returns></returns>
Private Function Contains1(item As KeyValuePair(Of TKey, TValue)) As Boolean Implements ICollection(Of KeyValuePair(Of TKey, TValue)).Contains
Dim value As TValue
Return TryGetValue(item.Key, value) AndAlso EqualityComparer(Of TValue).Default.Equals(item.Value, value)
End Function
''' <summary>
''' Copies the key/value pairs in this map to an array.
''' </summary>
''' <param name="array">The array to copy the entries into.</param>
''' <param name="arrayIndex">The index of the array at which to start copying values.</param>
Private Sub CopyTo1(array As KeyValuePair(Of TKey, TValue)(), arrayIndex As Integer) Implements ICollection(Of KeyValuePair(Of TKey, TValue)).CopyTo
list.CopyTo(array, arrayIndex)
End Sub
''' <summary>
''' Removes the specified key/value pair from the map.
''' </summary>
''' <remarks>Both the key and the value must be found for the entry to be removed.</remarks>
''' <param name="item">The key/value pair to remove.</param>
''' <returns><c>true</c> if the key/value pair was found and removed; <c>false</c> otherwise.</returns>
Private Function Remove1(item As KeyValuePair(Of TKey, TValue)) As Boolean Implements ICollection(Of KeyValuePair(Of TKey, TValue)).Remove
If item.Key Is Nothing Then
Throw New ArgumentException("Key is null", NameOf(item))
End If
Dim node As LinkedListNode(Of KeyValuePair(Of TKey, TValue))
If map.TryGetValue(item.Key, node) AndAlso EqualityComparer(Of TValue).Default.Equals(item.Value, node.Value.Value) Then
map.Remove(item.Key)
node.List.Remove(node)
Return True
Else
Return False
End If
End Function
''' <summary>
''' Gets the number of elements contained in the map.
''' </summary>
Public ReadOnly Property Count As Integer Implements ICollection(Of KeyValuePair(Of TKey, TValue)).Count, ICollection.Count
Get
Return list.Count
End Get
End Property
''' <summary>
''' Gets a value indicating whether the map is read-only.
''' </summary>
Public ReadOnly Property IsReadOnly As Boolean Implements ICollection(Of KeyValuePair(Of TKey, TValue)).IsReadOnly, IDictionary.IsReadOnly
Get
Return False
End Get
End Property
''' <summary>
''' Determines whether the specified <see cref="System.Object"/>, is equal to this instance.
''' </summary>
''' <param name="other">The <see cref="System.Object"/> to compare with this instance.</param>
''' <returns>
''' <c>true</c> if the specified <see cref="System.Object"/> is equal to this instance; otherwise, <c>false</c>.
''' </returns>
Public Overrides Function Equals(other As Object) As Boolean
Return Equals(TryCast(other, MapField(Of TKey, TValue)))
End Function
''' <summary>
''' Returns a hash code for this instance.
''' </summary>
''' <returns>
''' A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
''' </returns>
Public Overrides Function GetHashCode() As Integer
Dim valueComparer = EqualityComparer(Of TValue).Default
Dim hash = 0
For Each pair In list
hash = hash Xor pair.Key.GetHashCode() * 31 + valueComparer.GetHashCode(pair.Value)
Next
Return hash
End Function
''' <summary>
''' Compares this map with another for equality.
''' </summary>
''' <remarks>
''' The order of the key/value pairs in the maps is not deemed significant in this comparison.
''' </remarks>
''' <param name="other">The map to compare this with.</param>
''' <returns><c>true</c> if <paramrefname="other"/> refers to an equal map; <c>false</c> otherwise.</returns>
Public Overloads Function Equals(other As MapField(Of TKey, TValue)) As Boolean Implements IEquatable(Of MapField(Of TKey, TValue)).Equals
If other Is Nothing Then
Return False
End If
If other Is Me Then
Return True
End If
If other.Count <> Count Then
Return False
End If
Dim valueComparer = EqualityComparer(Of TValue).Default
For Each pair In Me
Dim value As TValue
If Not other.TryGetValue(pair.Key, value) Then
Return False
End If
If Not valueComparer.Equals(value, pair.Value) Then
Return False
End If
Next
Return True
End Function
''' <summary>
''' Adds entries to the map from the given stream.
''' </summary>
''' <remarks>
''' It is assumed that the stream is initially positioned after the tag specified by the codec.
''' This method will continue reading entries from the stream until the end is reached, or
''' a different tag is encountered.
''' </remarks>
''' <param name="input">Stream to read from</param>
''' <param name="codec">Codec describing how the key/value pairs are encoded</param>
Public Sub AddEntriesFrom(input As CodedInputStream, codec As Codec)
Dim adapter = New Codec.MessageAdapter(codec)
Do
adapter.Reset()
input.ReadMessage(adapter)
Me(adapter.Key) = adapter.Value
Loop While input.MaybeConsumeTag(codec.MapTag)
End Sub
''' <summary>
''' Writes the contents of this map to the given coded output stream, using the specified codec
''' to encode each entry.
''' </summary>
''' <param name="output">The output stream to write to.</param>
''' <param name="codec">The codec to use for each entry.</param>
Public Sub WriteTo(output As CodedOutputStream, codec As Codec)
Dim message = New Codec.MessageAdapter(codec)
For Each entry In list
message.Key = entry.Key
message.Value = entry.Value
output.WriteTag(codec.MapTag)
output.WriteMessage(message)
Next
End Sub
''' <summary>
''' Calculates the size of this map based on the given entry codec.
''' </summary>
''' <param name="codec">The codec to use to encode each entry.</param>
''' <returns></returns>
Public Function CalculateSize(codec As Codec) As Integer
If Count = 0 Then
Return 0
End If
Dim message = New Codec.MessageAdapter(codec)
Dim size = 0
For Each entry In list
message.Key = entry.Key
message.Value = entry.Value
size += CodedOutputStream.ComputeRawVarint32Size(codec.MapTag)
size += CodedOutputStream.ComputeMessageSize(message)
Next
Return size
End Function
''' <summary>
''' Returns a string representation of this repeated field, in the same
''' way as it would be represented by the default JSON formatter.
''' </summary>
Public Overrides Function ToString() As String
Dim writer = New StringWriter()
JsonFormatter.Default.WriteDictionary(writer, Me)
Return writer.ToString()
End Function
#Region "IDictionary explicit interface implementation"
Private Sub Add2(key As Object, value As Object) Implements IDictionary.Add
Add(key, value)
End Sub
Private Function Contains2(key As Object) As Boolean Implements IDictionary.Contains
If Not (TypeOf key Is TKey) Then
Return False
End If
Return ContainsKey(key)
End Function
Private Function GetEnumerator2() As IDictionaryEnumerator Implements IDictionary.GetEnumerator
Return New DictionaryEnumerator(GetEnumerator())
End Function
Private Sub Remove2(key As Object) Implements IDictionary.Remove
CheckNotNull(key, NameOf(key))
If Not (TypeOf key Is TKey) Then
Return
End If
Remove(key)
End Sub
Private Sub CopyTo2(array As Array, index As Integer) Implements ICollection.CopyTo
' This is ugly and slow as heck, but with any luck it will never be used anyway.
Dim temp As ICollection = [Select](Function(pair) New DictionaryEntry(pair.Key, pair.Value)).ToList()
temp.CopyTo(array, index)
End Sub
Private ReadOnly Property IsFixedSize As Boolean Implements IDictionary.IsFixedSize
Get
Return False
End Get
End Property
Private ReadOnly Property Keys As ICollection Implements IDictionary.Keys
Get
Return CType(KeysProp, ICollection)
End Get
End Property
Private ReadOnly Property Values As ICollection Implements IDictionary.Values
Get
Return CType(ValuesProp, ICollection)
End Get
End Property
Private ReadOnly Property IsSynchronized As Boolean Implements ICollection.IsSynchronized
Get
Return False
End Get
End Property
Private ReadOnly Property SyncRoot As Object Implements ICollection.SyncRoot
Get
Return Me
End Get
End Property
Private Property Item1(key As Object) As Object Implements IDictionary.Item
Get
CheckNotNull(key, NameOf(key))
If Not (TypeOf key Is TKey) Then
Return Nothing
End If
Dim value As TValue
TryGetValue(key, value)
Return value
End Get
Set(value As Object)
Me(key) = CType(value, TValue)
End Set
End Property
#End Region
Private Class DictionaryEnumerator
Implements IDictionaryEnumerator
Private ReadOnly enumerator As IEnumerator(Of KeyValuePair(Of TKey, TValue))
Friend Sub New(enumerator As IEnumerator(Of KeyValuePair(Of TKey, TValue)))
Me.enumerator = enumerator
End Sub
Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext
Return enumerator.MoveNext()
End Function
Public Sub Reset() Implements IEnumerator.Reset
enumerator.Reset()
End Sub
Public ReadOnly Property Current As Object Implements IEnumerator.Current
Get
Return Entry
End Get
End Property
Public ReadOnly Property Entry As DictionaryEntry Implements IDictionaryEnumerator.Entry
Get
Return New DictionaryEntry(Key, Value)
End Get
End Property
Public ReadOnly Property Key As Object Implements IDictionaryEnumerator.Key
Get
Return enumerator.Current.Key
End Get
End Property
Public ReadOnly Property Value As Object Implements IDictionaryEnumerator.Value
Get
Return enumerator.Current.Value
End Get
End Property
End Class
''' <summary>
''' A codec for a specific map field. This contains all the information required to encode and
''' decode the nested messages.
''' </summary>
Public NotInheritable Class Codec
Private ReadOnly keyCodec As FieldCodecType(Of TKey)
Private ReadOnly valueCodec As FieldCodecType(Of TValue)
Private ReadOnly mapTagField As UInteger
''' <summary>
''' Creates a new entry codec based on a separate key codec and value codec,
''' and the tag to use for each map entry.
''' </summary>
''' <param name="keyCodec">The key codec.</param>
''' <param name="valueCodec">The value codec.</param>
''' <param name="mapTag">The map tag to use to introduce each map entry.</param>
Public Sub New(keyCodec As FieldCodecType(Of TKey), valueCodec As FieldCodecType(Of TValue), mapTag As UInteger)
Me.keyCodec = keyCodec
Me.valueCodec = valueCodec
mapTagField = mapTag
End Sub
''' <summary>
''' The tag used in the enclosing message to indicate map entries.
''' </summary>
Friend ReadOnly Property MapTag As UInteger
Get
Return mapTagField
End Get
End Property
''' <summary>
''' A mutable message class, used for parsing and serializing. This
''' delegates the work to a codec, but implements the <see cref="IMessage"/> interface
''' for interop with <see cref="CodedInputStream"/> and <see cref="CodedOutputStream"/>.
''' This is nested inside Codec as it's tightly coupled to the associated codec,
''' and it's simpler if it has direct access to all its fields.
''' </summary>
Friend Class MessageAdapter
Implements IMessage
Private Shared ReadOnly ZeroLengthMessageStreamData As Byte() = New Byte() {0}
Private ReadOnly codec As Codec
Friend Property Key As TKey
Friend Property Value As TValue
Friend Sub New(codec As Codec)
Me.codec = codec
End Sub
Friend Sub Reset()
Key = codec.keyCodec.DefaultValue
Value = codec.valueCodec.DefaultValue
End Sub
Public Sub MergeFrom(input As CodedInputStream) Implements IMessage.MergeFrom
Dim tag As UInteger
While (CSharpImpl.__Assign(tag, input.ReadTag())) <> 0
If tag = codec.keyCodec.Tag Then
Key = codec.keyCodec.Read(input)
ElseIf tag = codec.valueCodec.Tag Then
Value = codec.valueCodec.Read(input)
Else
input.SkipLastField()
End If
End While
' Corner case: a map entry with a key but no value, where the value type is a message.
' Read it as if we'd seen an input stream with no data (i.e. create a "default" message).
If Value Is Nothing Then
Value = codec.valueCodec.Read(New CodedInputStream(ZeroLengthMessageStreamData))
End If
End Sub
Public Sub WriteTo(output As CodedOutputStream) Implements IMessage.WriteTo
codec.keyCodec.WriteTagAndValue(output, Key)
codec.valueCodec.WriteTagAndValue(output, Value)
End Sub
Public Function CalculateSize() As Integer Implements IMessage.CalculateSize
Return codec.keyCodec.CalculateSizeWithTag(Key) + codec.valueCodec.CalculateSizeWithTag(Value)
End Function
Private ReadOnly Property Descriptor As MessageDescriptor Implements IMessage.Descriptor
Get
Return Nothing
End Get
End Property
Private Class CSharpImpl
<Obsolete("Please refactor calling code to use normal Visual Basic assignment")>
Shared Function __Assign(Of T)(ByRef target As T, value As T) As T
target = value
Return value
End Function
End Class
End Class
End Class
Private Class MapView(Of T)
Implements ICollection(Of T), ICollection
Private ReadOnly parent As MapField(Of TKey, TValue)
Private ReadOnly projection As Func(Of KeyValuePair(Of TKey, TValue), T)
Private ReadOnly containsCheck As Func(Of T, Boolean)
Friend Sub New(parent As MapField(Of TKey, TValue), projection As Func(Of KeyValuePair(Of TKey, TValue), T), containsCheck As Func(Of T, Boolean))
Me.parent = parent
Me.projection = projection
Me.containsCheck = containsCheck
End Sub
Public ReadOnly Property Count As Integer Implements ICollection(Of T).Count, ICollection.Count
Get
Return parent.Count
End Get
End Property
Public ReadOnly Property IsReadOnly As Boolean Implements ICollection(Of T).IsReadOnly
Get
Return True
End Get
End Property
Public ReadOnly Property IsSynchronized As Boolean Implements ICollection.IsSynchronized
Get
Return False
End Get
End Property
Public ReadOnly Property SyncRoot As Object Implements ICollection.SyncRoot
Get
Return parent
End Get
End Property
Public Sub Add(item As T) Implements ICollection(Of T).Add
Throw New NotSupportedException()
End Sub
Public Sub Clear() Implements ICollection(Of T).Clear
Throw New NotSupportedException()
End Sub
Public Function Contains(item As T) As Boolean Implements ICollection(Of T).Contains
Return containsCheck(item)
End Function
Public Sub CopyTo(array As T(), arrayIndex As Integer) Implements ICollection(Of T).CopyTo
If arrayIndex < 0 Then
Throw New ArgumentOutOfRangeException(NameOf(arrayIndex))
End If
If arrayIndex + Count >= array.Length Then
Throw New ArgumentException("Not enough space in the array", NameOf(array))
End If
For Each item As T In Me
array(Math.Min(Threading.Interlocked.Increment(arrayIndex), arrayIndex - 1)) = item
Next
End Sub
Public Function GetEnumerator() As IEnumerator(Of T) Implements IEnumerable(Of T).GetEnumerator
Return Enumerable.Select(parent.list, projection).GetEnumerator()
End Function
Public Function Remove(item As T) As Boolean Implements ICollection(Of T).Remove
Throw New NotSupportedException()
End Function
Private Function GetEnumerator3() As IEnumerator Implements IEnumerable.GetEnumerator
Return GetEnumerator()
End Function
Public Sub CopyTo(array As Array, index As Integer) Implements ICollection.CopyTo
If index < 0 Then
Throw New ArgumentOutOfRangeException(NameOf(index))
End If
If index + Count >= array.Length Then
Throw New ArgumentException("Not enough space in the array", NameOf(array))
End If
For Each item As T In Me
array.SetValue(item, Math.Min(Threading.Interlocked.Increment(index), index - 1))
Next
End Sub
End Class
End Class
End Namespace

@ -0,0 +1,140 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2008 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System
Imports System.Collections
Imports System.Collections.Generic
Imports System.Runtime.InteropServices
Namespace Google.Protobuf.Collections
''' <summary>
''' Read-only wrapper around another dictionary.
''' </summary>
Friend NotInheritable Class ReadOnlyDictionary(Of TKey, TValue)
Implements IDictionary(Of TKey, TValue)
Private ReadOnly wrapped As IDictionary(Of TKey, TValue)
Public Sub New(wrapped As IDictionary(Of TKey, TValue))
Me.wrapped = wrapped
End Sub
Public Sub Add(key As TKey, value As TValue) Implements IDictionary(Of TKey, TValue).Add
Throw New InvalidOperationException()
End Sub
Public Function ContainsKey(key As TKey) As Boolean Implements IDictionary(Of TKey, TValue).ContainsKey
Return wrapped.ContainsKey(key)
End Function
Public ReadOnly Property KeysProp As ICollection(Of TKey) Implements IDictionary(Of TKey, TValue).Keys
Get
Return wrapped.Keys
End Get
End Property
Public Function Remove(key As TKey) As Boolean Implements IDictionary(Of TKey, TValue).Remove
Throw New InvalidOperationException()
End Function
Public Function TryGetValue(key As TKey, <Out> ByRef value As TValue) As Boolean Implements IDictionary(Of TKey, TValue).TryGetValue
Return wrapped.TryGetValue(key, value)
End Function
Public ReadOnly Property ValuesProp As ICollection(Of TValue) Implements IDictionary(Of TKey, TValue).Values
Get
Return wrapped.Values
End Get
End Property
Default Public Property Item(key As TKey) As TValue Implements IDictionary(Of TKey, TValue).Item
Get
Return wrapped(key)
End Get
Set(value As TValue)
Throw New InvalidOperationException()
End Set
End Property
Public Sub Add(item As KeyValuePair(Of TKey, TValue)) Implements ICollection(Of KeyValuePair(Of TKey, TValue)).Add
Throw New InvalidOperationException()
End Sub
Public Sub Clear() Implements ICollection(Of KeyValuePair(Of TKey, TValue)).Clear
Throw New InvalidOperationException()
End Sub
Public Function Contains(item As KeyValuePair(Of TKey, TValue)) As Boolean Implements ICollection(Of KeyValuePair(Of TKey, TValue)).Contains
Return wrapped.Contains(item)
End Function
Public Sub CopyTo(array As KeyValuePair(Of TKey, TValue)(), arrayIndex As Integer) Implements ICollection(Of KeyValuePair(Of TKey, TValue)).CopyTo
wrapped.CopyTo(array, arrayIndex)
End Sub
Public ReadOnly Property Count As Integer Implements ICollection(Of KeyValuePair(Of TKey, TValue)).Count
Get
Return wrapped.Count
End Get
End Property
Public ReadOnly Property IsReadOnly As Boolean Implements ICollection(Of KeyValuePair(Of TKey, TValue)).IsReadOnly
Get
Return True
End Get
End Property
Public Function Remove(item As KeyValuePair(Of TKey, TValue)) As Boolean Implements ICollection(Of KeyValuePair(Of TKey, TValue)).Remove
Throw New InvalidOperationException()
End Function
Public Function GetEnumerator() As IEnumerator(Of KeyValuePair(Of TKey, TValue)) Implements IEnumerable(Of KeyValuePair(Of TKey, TValue)).GetEnumerator
Return wrapped.GetEnumerator()
End Function
Private Function GetEnumerator1() As IEnumerator Implements IEnumerable.GetEnumerator
Return CType(wrapped, IEnumerable).GetEnumerator()
End Function
Public Overrides Function Equals(obj As Object) As Boolean
Return wrapped.Equals(obj)
End Function
Public Overrides Function GetHashCode() As Integer
Return wrapped.GetHashCode()
End Function
Public Overrides Function ToString() As String
Return wrapped.ToString()
End Function
End Class
End Namespace

@ -0,0 +1,585 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2015 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System
Imports System.Collections
Imports System.Collections.Generic
Imports System.IO
Namespace Google.Protobuf.Collections
''' <summary>
''' The contents of a repeated field: essentially, a collection with some extra
''' restrictions (no null values) and capabilities (deep cloning).
''' </summary>
''' <remarks>
''' This implementation does not generally prohibit the use of types which are not
''' supported by Protocol Buffers but nor does it guarantee that all operations will work in such cases.
''' </remarks>
''' <typeparamname="T">The element type of the repeated field.</typeparam>
Public NotInheritable Class RepeatedField(Of T)
Implements IList(Of T), IList, IDeepCloneable(Of RepeatedField(Of T)), IEquatable(Of RepeatedField(Of T))
Private Shared ReadOnly EmptyArray As T() = New T(-1) {}
Private Const MinArraySize As Integer = 8
Private array As T() = EmptyArray
Private countField As Integer = 0
Public Sub New()
End Sub
Sub New(data As IEnumerable(Of T))
For Each item As T In data
Call Add(item)
Next
End Sub
''' <summary>
''' Creates a deep clone of this repeated field.
''' </summary>
''' <remarks>
''' If the field type is
''' a message type, each element is also cloned; otherwise, it is
''' assumed that the field type is primitive (including string and
''' bytes, both of which are immutable) and so a simple copy is
''' equivalent to a deep clone.
''' </remarks>
''' <returns>A deep clone of this repeated field.</returns>
Public Function Clone() As RepeatedField(Of T) Implements IDeepCloneable(Of RepeatedField(Of T)).Clone
Dim lClone As RepeatedField(Of T) = New RepeatedField(Of T)()
If array IsNot EmptyArray Then
lClone.array = CType(array.Clone(), T())
Dim cloneableArray As IDeepCloneable(Of T)() = TryCast(lClone.array, IDeepCloneable(Of T)())
If cloneableArray IsNot Nothing Then
For i = 0 To countField - 1
lClone.array(i) = cloneableArray(i).Clone()
Next
End If
End If
lClone.countField = countField
Return lClone
End Function
''' <summary>
''' Adds the entries from the given input stream, decoding them with the specified codec.
''' </summary>
''' <param name="input">The input stream to read from.</param>
''' <param name="codec">The codec to use in order to read each entry.</param>
Public Sub AddEntriesFrom(input As CodedInputStream, codec As FieldCodecType(Of T))
' TODO: Inline some of the Add code, so we can avoid checking the size on every
' iteration.
Dim tag = input.LastTag
Dim reader = codec.ValueReader
' Non-nullable value types can be packed or not.
If FieldCodecType(Of T).IsPackedRepeatedField(tag) Then
Dim length As Integer = input.ReadLength()
If length > 0 Then
Dim oldLimit = input.PushLimit(length)
While Not input.ReachedLimit
Add(reader(input))
End While
input.PopLimit(oldLimit)
' Empty packed field. Odd, but valid - just ignore.
End If
Else
' Not packed... (possibly not packable)
Do
Add(reader(input))
Loop While input.MaybeConsumeTag(tag)
End If
End Sub
''' <summary>
''' Calculates the size of this collection based on the given codec.
''' </summary>
''' <param name="codec">The codec to use when encoding each field.</param>
''' <returns>The number of bytes that would be written to a <see cref="CodedOutputStream"/> by <see cref="WriteTo"/>,
''' using the same codec.</returns>
Public Function CalculateSize(codec As FieldCodecType(Of T)) As Integer
If countField = 0 Then
Return 0
End If
Dim tag = codec.Tag
If codec.PackedRepeatedField Then
Dim dataSize = CalculatePackedDataSize(codec)
Return CodedOutputStream.ComputeRawVarint32Size(tag) + CodedOutputStream.ComputeLengthSize(dataSize) + dataSize
Else
Dim sizeCalculator = codec.ValueSizeCalculator
Dim size = countField * CodedOutputStream.ComputeRawVarint32Size(tag)
For i = 0 To countField - 1
size += sizeCalculator(array(i))
Next
Return size
End If
End Function
Private Function CalculatePackedDataSize(codec As FieldCodecType(Of T)) As Integer
Dim fixedSize = codec.FixedSize
If fixedSize = 0 Then
Dim calculator = codec.ValueSizeCalculator
Dim tmp = 0
For i = 0 To countField - 1
tmp += calculator(array(i))
Next
Return tmp
Else
Return fixedSize * Count
End If
End Function
''' <summary>
''' Writes the contents of this collection to the given <see cref="CodedOutputStream"/>,
''' encoding each value using the specified codec.
''' </summary>
''' <param name="output">The output stream to write to.</param>
''' <param name="codec">The codec to use when encoding each value.</param>
Public Sub WriteTo(output As CodedOutputStream, codec As FieldCodecType(Of T))
If countField = 0 Then
Return
End If
Dim writer = codec.ValueWriter
Dim tag = codec.Tag
If codec.PackedRepeatedField Then
' Packed primitive type
Dim size As UInteger = CalculatePackedDataSize(codec)
output.WriteTag(tag)
output.WriteRawVarint32(size)
For i = 0 To countField - 1
writer(output, array(i))
Next
Else
' Not packed: a simple tag/value pair for each value.
' Can't use codec.WriteTagAndValue, as that omits default values.
For i = 0 To countField - 1
output.WriteTag(tag)
writer(output, array(i))
Next
End If
End Sub
Private Sub EnsureSize(size As Integer)
If array.Length < size Then
size = Math.Max(size, MinArraySize)
Dim newSize = Math.Max(array.Length * 2, size)
Dim tmp = New T(newSize - 1) {}
System.Array.Copy(array, 0, tmp, 0, array.Length)
array = tmp
End If
End Sub
''' <summary>
''' Adds the specified item to the collection.
''' </summary>
''' <param name="item">The item to add.</param>
Public Sub Add(item As T) Implements ICollection(Of T).Add
CheckNotNullUnconstrained(item, NameOf(item))
EnsureSize(countField + 1)
array(Math.Min(Threading.Interlocked.Increment(countField), countField - 1)) = item
End Sub
''' <summary>
''' Removes all items from the collection.
''' </summary>
Public Sub Clear() Implements ICollection(Of T).Clear, IList.Clear
array = EmptyArray
countField = 0
End Sub
''' <summary>
''' Determines whether this collection contains the given item.
''' </summary>
''' <param name="item">The item to find.</param>
''' <returns><c>true</c> if this collection contains the given item; <c>false</c> otherwise.</returns>
Public Function Contains(item As T) As Boolean Implements ICollection(Of T).Contains
Return IndexOf(item) <> -1
End Function
''' <summary>
''' Copies this collection to the given array.
''' </summary>
''' <param name="array">The array to copy to.</param>
''' <param name="arrayIndex">The first index of the array to copy to.</param>
Public Sub CopyTo(array As T(), arrayIndex As Integer) Implements ICollection(Of T).CopyTo
System.Array.Copy(Me.array, 0, array, arrayIndex, countField)
End Sub
''' <summary>
''' Removes the specified item from the collection
''' </summary>
''' <param name="item">The item to remove.</param>
''' <returns><c>true</c> if the item was found and removed; <c>false</c> otherwise.</returns>
Public Function Remove(item As T) As Boolean Implements ICollection(Of T).Remove
Dim index = IndexOf(item)
If index = -1 Then
Return False
End If
System.Array.Copy(array, index + 1, array, index, countField - index - 1)
countField -= 1
array(countField) = Nothing
Return True
End Function
''' <summary>
''' Gets the number of elements contained in the collection.
''' </summary>
Public ReadOnly Property Count As Integer Implements ICollection(Of T).Count, ICollection.Count
Get
Return countField
End Get
End Property
''' <summary>
''' Gets a value indicating whether the collection is read-only.
''' </summary>
Public ReadOnly Property IsReadOnly As Boolean Implements ICollection(Of T).IsReadOnly, IList.IsReadOnly
Get
Return False
End Get
End Property
''' <summary>
''' Adds all of the specified values into this collection.
''' </summary>
''' <param name="values">The values to add to this collection.</param>
Public Sub AddRange(values As IEnumerable(Of T))
CheckNotNull(values, NameOf(values))
' Optimization 1: If the collection we're adding is already a RepeatedField<T>,
' we know the values are valid.
Dim otherRepeatedField = TryCast(values, RepeatedField(Of T))
If otherRepeatedField IsNot Nothing Then
EnsureSize(countField + otherRepeatedField.countField)
System.Array.Copy(otherRepeatedField.array, 0, array, countField, otherRepeatedField.countField)
countField += otherRepeatedField.countField
Return
End If
' Optimization 2: The collection is an ICollection, so we can expand
' just once and ask the collection to copy itself into the array.
Dim collection = TryCast(values, ICollection)
If collection IsNot Nothing Then
Dim extraCount = collection.Count
' For reference types and nullable value types, we need to check that there are no nulls
' present. (This isn't a thread-safe approach, but we don't advertise this is thread-safe.)
' We expect the JITter to optimize this test to true/false, so it's effectively conditional
' specialization.
If Nothing Is Nothing Then
' TODO: Measure whether iterating once to check and then letting the collection copy
' itself is faster or slower than iterating and adding as we go. For large
' collections this will not be great in terms of cache usage... but the optimized
' copy may be significantly faster than doing it one at a time.
For Each item As T In collection
If item Is Nothing Then
Throw New ArgumentException("Sequence contained null element", NameOf(values))
End If
Next
End If
EnsureSize(countField + extraCount)
collection.CopyTo(array, countField)
countField += extraCount
Return
End If
' We *could* check for ICollection<T> as well, but very very few collections implement
' ICollection<T> but not ICollection. (HashSet<T> does, for one...)
' Fall back to a slower path of adding items one at a time.
For Each item As T In values
Add(item)
Next
End Sub
''' <summary>
''' Adds all of the specified values into this collection. This method is present to
''' allow repeated fields to be constructed from queries within collection initializers.
''' Within non-collection-initializer code, consider using the equivalent <see cref="AddRange"/>
''' method instead for clarity.
''' </summary>
''' <param name="values">The values to add to this collection.</param>
Public Sub Add(values As IEnumerable(Of T))
AddRange(values)
End Sub
''' <summary>
''' Returns an enumerator that iterates through the collection.
''' </summary>
''' <returns>
''' An enumerator that can be used to iterate through the collection.
''' </returns>
Public Iterator Function GetEnumerator() As IEnumerator(Of T) Implements IEnumerable(Of T).GetEnumerator
For i = 0 To countField - 1
Yield array(i)
Next
End Function
''' <summary>
''' Determines whether the specified <see cref="System.Object"/>, is equal to this instance.
''' </summary>
''' <param name="obj">The <see cref="System.Object"/> to compare with this instance.</param>
''' <returns>
''' <c>true</c> if the specified <see cref="System.Object"/> is equal to this instance; otherwise, <c>false</c>.
''' </returns>
Public Overrides Function Equals(obj As Object) As Boolean
Return Equals(TryCast(obj, RepeatedField(Of T)))
End Function
''' <summary>
''' Returns an enumerator that iterates through a collection.
''' </summary>
''' <returns>
''' An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
''' </returns>
Private Function GetEnumerator1() As IEnumerator Implements IEnumerable.GetEnumerator
Return GetEnumerator()
End Function
''' <summary>
''' Returns a hash code for this instance.
''' </summary>
''' <returns>
''' A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
''' </returns>
Public Overrides Function GetHashCode() As Integer
Dim hash = 0
For i = 0 To countField - 1
hash = hash * 31 + array(i).GetHashCode()
Next
Return hash
End Function
''' <summary>
''' Compares this repeated field with another for equality.
''' </summary>
''' <param name="other">The repeated field to compare this with.</param>
''' <returns><c>true</c> if <paramrefname="other"/> refers to an equal repeated field; <c>false</c> otherwise.</returns>
Public Overloads Function Equals(other As RepeatedField(Of T)) As Boolean Implements IEquatable(Of RepeatedField(Of T)).Equals
If ReferenceEquals(other, Nothing) Then
Return False
End If
If ReferenceEquals(other, Me) Then
Return True
End If
If other.Count <> Count Then
Return False
End If
Dim comparer = EqualityComparer(Of T).Default
For i = 0 To countField - 1
If Not comparer.Equals(array(i), other.array(i)) Then
Return False
End If
Next
Return True
End Function
''' <summary>
''' Returns the index of the given item within the collection, or -1 if the item is not
''' present.
''' </summary>
''' <param name="item">The item to find in the collection.</param>
''' <returns>The zero-based index of the item, or -1 if it is not found.</returns>
Public Function IndexOf(item As T) As Integer Implements IList(Of T).IndexOf
CheckNotNullUnconstrained(item, NameOf(item))
Dim comparer = EqualityComparer(Of T).Default
For i = 0 To countField - 1
If comparer.Equals(array(i), item) Then
Return i
End If
Next
Return -1
End Function
''' <summary>
''' Inserts the given item at the specified index.
''' </summary>
''' <param name="index">The index at which to insert the item.</param>
''' <param name="item">The item to insert.</param>
Public Sub Insert(index As Integer, item As T) Implements IList(Of T).Insert
CheckNotNullUnconstrained(item, NameOf(item))
If index < 0 OrElse index > countField Then
Throw New ArgumentOutOfRangeException(NameOf(index))
End If
EnsureSize(countField + 1)
System.Array.Copy(array, index, array, index + 1, countField - index)
array(index) = item
countField += 1
End Sub
''' <summary>
''' Removes the item at the given index.
''' </summary>
''' <param name="index">The zero-based index of the item to remove.</param>
Public Sub RemoveAt(index As Integer) Implements IList(Of T).RemoveAt, IList.RemoveAt
If index < 0 OrElse index >= countField Then
Throw New ArgumentOutOfRangeException(NameOf(index))
End If
System.Array.Copy(array, index + 1, array, index, countField - index - 1)
countField -= 1
array(countField) = Nothing
End Sub
''' <summary>
''' Returns a string representation of this repeated field, in the same
''' way as it would be represented by the default JSON formatter.
''' </summary>
Public Overrides Function ToString() As String
Dim writer = New StringWriter()
JsonFormatter.Default.WriteList(writer, Me)
Return writer.ToString()
End Function
''' <summary>
''' Gets or sets the item at the specified index.
''' </summary>
''' <value>
''' The element at the specified index.
''' </value>
''' <param name="index">The zero-based index of the element to get or set.</param>
''' <returns>The item at the specified index.</returns>
Default Public Overloads Property Item(index As Integer) As T Implements IList(Of T).Item
Get
If index < 0 OrElse index >= countField Then
Throw New ArgumentOutOfRangeException(NameOf(index))
End If
Return array(index)
End Get
Set(value As T)
If index < 0 OrElse index >= countField Then
Throw New ArgumentOutOfRangeException(NameOf(index))
End If
CheckNotNullUnconstrained(value, NameOf(value))
array(index) = value
End Set
End Property
#Region "Explicit interface implementation for IList and ICollection."
Private ReadOnly Property IsFixedSize As Boolean Implements IList.IsFixedSize
Get
Return False
End Get
End Property
Private Sub CopyTo1(array As Array, index As Integer) Implements ICollection.CopyTo
Array.Copy(Me.array, 0, array, index, countField)
End Sub
Private ReadOnly Property IsSynchronized As Boolean Implements ICollection.IsSynchronized
Get
Return False
End Get
End Property
Private ReadOnly Property SyncRoot As Object Implements ICollection.SyncRoot
Get
Return Me
End Get
End Property
Private Property Item1(index As Integer) As Object Implements IList.Item
Get
Return Me(index)
End Get
Set(value As Object)
Me(index) = CType(value, T)
End Set
End Property
Private Function Add1(value As Object) As Integer Implements IList.Add
Add(CType(value, T))
Return countField - 1
End Function
Private Function Contains1(value As Object) As Boolean Implements IList.Contains
Return TypeOf value Is T AndAlso Contains(value)
End Function
Private Function IndexOf1(value As Object) As Integer Implements IList.IndexOf
If Not (TypeOf value Is T) Then
Return -1
End If
Return IndexOf(value)
End Function
Private Sub Insert1(index As Integer, value As Object) Implements IList.Insert
Insert(index, value)
End Sub
Private Sub Remove1(value As Object) Implements IList.Remove
If Not (TypeOf value Is T) Then
Return
End If
Remove(value)
End Sub
#End Region
End Class
End Namespace

@ -0,0 +1,71 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2015 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System.Reflection
Imports System.Runtime.CompilerServices
Namespace Google.Protobuf.Compatibility
''' <summary>
''' Extension methods for <see cref="PropertyInfo"/>, effectively providing
''' the familiar members from previous desktop framework versions while
''' targeting the newer releases, .NET Core etc.
''' </summary>
Friend Module PropertyInfoExtensions
''' <summary>
''' Returns the public getter of a property, or null if there is no such getter
''' (either because it's read-only, or the getter isn't public).
''' </summary>
<Extension()>
Friend Function GetGetMethod(target As PropertyInfo) As MethodInfo
#If DOTNET35
var method = target.GetGetMethod();
#Else
Dim method = target.GetMethod
#End If
Return If(method IsNot Nothing AndAlso method.IsPublic, method, Nothing)
End Function
''' <summary>
''' Returns the public setter of a property, or null if there is no such setter
''' (either because it's write-only, or the setter isn't public).
''' </summary>
<Extension()>
Friend Function GetSetMethod(target As PropertyInfo) As MethodInfo
#If DOTNET35
var method = target.GetSetMethod();
#Else
Dim method = target.SetMethod
#End If
Return If(method IsNot Nothing AndAlso method.IsPublic, method, Nothing)
End Function
End Module
End Namespace

@ -0,0 +1,107 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2015 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System
Imports System.Reflection
Imports System.Runtime.CompilerServices
#If Not DOTNET35
Namespace Google.Protobuf.Compatibility
''' <summary>
''' Provides extension methods on Type that just proxy to TypeInfo.
''' These are used to support the new type system from .NET 4.5, without
''' having calls to GetTypeInfo all over the place. While the methods here are meant to be
''' broadly compatible with the desktop framework, there are some subtle differences in behaviour - but
''' they're not expected to affect our use cases. While the class is internal, that should be fine: we can
''' evaluate each new use appropriately.
''' </summary>
Friend Module TypeExtensions
''' <summary>
''' See https://msdn.microsoft.com/en-us/library/system.type.isassignablefrom
''' </summary>
<Extension()>
Friend Function IsAssignableFrom(target As Type, c As Type) As Boolean
Return target.GetTypeInfo().IsAssignableFrom(c.GetTypeInfo())
End Function
''' <summary>
''' Returns a representation of the public property associated with the given name in the given type,
''' including inherited properties or null if there is no such public property.
''' Here, "public property" means a property where either the getter, or the setter, or both, is public.
''' </summary>
<Extension()>
Friend Function GetProperty(target As Type, name As String) As PropertyInfo
' GetDeclaredProperty only returns properties declared in the given type, so we need to recurse.
While target IsNot Nothing
Dim typeInfo = target.GetTypeInfo()
Dim ret = typeInfo.GetDeclaredProperty(name)
If ret IsNot Nothing AndAlso (ret.CanRead AndAlso ret.GetMethod.IsPublic OrElse ret.CanWrite AndAlso ret.SetMethod.IsPublic) Then
Return ret
End If
target = typeInfo.BaseType
End While
Return Nothing
End Function
''' <summary>
''' Returns a representation of the public method associated with the given name in the given type,
''' including inherited methods.
''' </summary>
''' <remarks>
''' This has a few differences compared with Type.GetMethod in the desktop framework. It will throw
''' if there is an ambiguous match even between a private method and a public one, but it *won't* throw
''' if there are two overloads at different levels in the type hierarchy (e.g. class Base declares public void Foo(int) and
''' class Child : Base declares public void Foo(long)).
''' </remarks>
''' <exception cref="AmbiguousMatchException">One type in the hierarchy declared more than one method with the same name</exception>
<Extension()>
Friend Function GetMethod(target As Type, name As String) As MethodInfo
' GetDeclaredMethod only returns methods declared in the given type, so we need to recurse.
While target IsNot Nothing
Dim typeInfo = target.GetTypeInfo()
Dim ret = typeInfo.GetDeclaredMethod(name)
If ret IsNot Nothing AndAlso ret.IsPublic Then
Return ret
End If
target = typeInfo.BaseType
End While
Return Nothing
End Function
End Module
End Namespace
#End If

@ -0,0 +1,426 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2015 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports Google.Protobuf.WellKnownTypes
Imports System
Imports System.Collections.Generic
Namespace Google.Protobuf
''' <summary>
''' Factory methods for <see cref="FieldCodecType(OfT)"/>.
''' </summary>
Public Module FieldCodec
' TODO: Avoid the "dual hit" of lambda expressions: create open delegates instead. (At least test...)
''' <summary>
''' Retrieves a codec suitable for a string field with the given tag.
''' </summary>
''' <param name="tag">The tag.</param>
''' <returns>A codec for the given tag.</returns>
Public Function ForString(tag As UInteger) As FieldCodecType(Of String)
Return New FieldCodecType(Of String)(Function(input) input.ReadString(), Sub(output, value) output.WriteString(value), AddressOf CodedOutputStream.ComputeStringSize, tag)
End Function
''' <summary>
''' Retrieves a codec suitable for a bytes field with the given tag.
''' </summary>
''' <param name="tag">The tag.</param>
''' <returns>A codec for the given tag.</returns>
Public Function ForBytes(tag As UInteger) As FieldCodecType(Of ByteString)
Return New FieldCodecType(Of ByteString)(Function(input) input.ReadBytes(), Sub(output, value) output.WriteBytes(value), AddressOf CodedOutputStream.ComputeBytesSize, tag)
End Function
''' <summary>
''' Retrieves a codec suitable for a bool field with the given tag.
''' </summary>
''' <param name="tag">The tag.</param>
''' <returns>A codec for the given tag.</returns>
Public Function ForBool(tag As UInteger) As FieldCodecType(Of Boolean)
Return New FieldCodecType(Of Boolean)(Function(input) input.ReadBool(), Sub(output, value) output.WriteBool(value), AddressOf CodedOutputStream.ComputeBoolSize, tag)
End Function
''' <summary>
''' Retrieves a codec suitable for an int32 field with the given tag.
''' </summary>
''' <param name="tag">The tag.</param>
''' <returns>A codec for the given tag.</returns>
Public Function ForInt32(tag As UInteger) As FieldCodecType(Of Integer)
Return New FieldCodecType(Of Integer)(Function(input) input.ReadInt32(), Sub(output, value) output.WriteInt32(value), AddressOf CodedOutputStream.ComputeInt32Size, tag)
End Function
''' <summary>
''' Retrieves a codec suitable for an sint32 field with the given tag.
''' </summary>
''' <param name="tag">The tag.</param>
''' <returns>A codec for the given tag.</returns>
Public Function ForSInt32(tag As UInteger) As FieldCodecType(Of Integer)
Return New FieldCodecType(Of Integer)(Function(input) input.ReadSInt32(), Sub(output, value) output.WriteSInt32(value), AddressOf CodedOutputStream.ComputeSInt32Size, tag)
End Function
''' <summary>
''' Retrieves a codec suitable for a fixed32 field with the given tag.
''' </summary>
''' <param name="tag">The tag.</param>
''' <returns>A codec for the given tag.</returns>
Public Function ForFixed32(tag As UInteger) As FieldCodecType(Of UInteger)
Return New FieldCodecType(Of UInteger)(Function(input) input.ReadFixed32(), Sub(output, value) output.WriteFixed32(value), 4, tag)
End Function
''' <summary>
''' Retrieves a codec suitable for an sfixed32 field with the given tag.
''' </summary>
''' <param name="tag">The tag.</param>
''' <returns>A codec for the given tag.</returns>
Public Function ForSFixed32(tag As UInteger) As FieldCodecType(Of Integer)
Return New FieldCodecType(Of Integer)(Function(input) input.ReadSFixed32(), Sub(output, value) output.WriteSFixed32(value), 4, tag)
End Function
''' <summary>
''' Retrieves a codec suitable for a uint32 field with the given tag.
''' </summary>
''' <param name="tag">The tag.</param>
''' <returns>A codec for the given tag.</returns>
Public Function ForUInt32(tag As UInteger) As FieldCodecType(Of UInteger)
Return New FieldCodecType(Of UInteger)(Function(input) input.ReadUInt32(), Sub(output, value) output.WriteUInt32(value), AddressOf CodedOutputStream.ComputeUInt32Size, tag)
End Function
''' <summary>
''' Retrieves a codec suitable for an int64 field with the given tag.
''' </summary>
''' <param name="tag">The tag.</param>
''' <returns>A codec for the given tag.</returns>
Public Function ForInt64(tag As UInteger) As FieldCodecType(Of Long)
Return New FieldCodecType(Of Long)(Function(input) input.ReadInt64(), Sub(output, value) output.WriteInt64(value), AddressOf CodedOutputStream.ComputeInt64Size, tag)
End Function
''' <summary>
''' Retrieves a codec suitable for an sint64 field with the given tag.
''' </summary>
''' <param name="tag">The tag.</param>
''' <returns>A codec for the given tag.</returns>
Public Function ForSInt64(tag As UInteger) As FieldCodecType(Of Long)
Return New FieldCodecType(Of Long)(Function(input) input.ReadSInt64(), Sub(output, value) output.WriteSInt64(value), AddressOf CodedOutputStream.ComputeSInt64Size, tag)
End Function
''' <summary>
''' Retrieves a codec suitable for a fixed64 field with the given tag.
''' </summary>
''' <param name="tag">The tag.</param>
''' <returns>A codec for the given tag.</returns>
Public Function ForFixed64(tag As UInteger) As FieldCodecType(Of ULong)
Return New FieldCodecType(Of ULong)(Function(input) input.ReadFixed64(), Sub(output, value) output.WriteFixed64(value), 8, tag)
End Function
''' <summary>
''' Retrieves a codec suitable for an sfixed64 field with the given tag.
''' </summary>
''' <param name="tag">The tag.</param>
''' <returns>A codec for the given tag.</returns>
Public Function ForSFixed64(tag As UInteger) As FieldCodecType(Of Long)
Return New FieldCodecType(Of Long)(Function(input) input.ReadSFixed64(), Sub(output, value) output.WriteSFixed64(value), 8, tag)
End Function
''' <summary>
''' Retrieves a codec suitable for a uint64 field with the given tag.
''' </summary>
''' <param name="tag">The tag.</param>
''' <returns>A codec for the given tag.</returns>
Public Function ForUInt64(tag As UInteger) As FieldCodecType(Of ULong)
Return New FieldCodecType(Of ULong)(Function(input) input.ReadUInt64(), Sub(output, value) output.WriteUInt64(value), AddressOf CodedOutputStream.ComputeUInt64Size, tag)
End Function
''' <summary>
''' Retrieves a codec suitable for a float field with the given tag.
''' </summary>
''' <param name="tag">The tag.</param>
''' <returns>A codec for the given tag.</returns>
Public Function ForFloat(tag As UInteger) As FieldCodecType(Of Single)
Return New FieldCodecType(Of Single)(Function(input) input.ReadFloat(), Sub(output, value) output.WriteFloat(value), AddressOf CodedOutputStream.ComputeFloatSize, tag)
End Function
''' <summary>
''' Retrieves a codec suitable for a double field with the given tag.
''' </summary>
''' <param name="tag">The tag.</param>
''' <returns>A codec for the given tag.</returns>
Public Function ForDouble(tag As UInteger) As FieldCodecType(Of Double)
Return New FieldCodecType(Of Double)(Function(input) input.ReadDouble(), Sub(output, value) output.WriteDouble(value), AddressOf CodedOutputStream.ComputeDoubleSize, tag)
End Function
' Enums are tricky. We can probably use expression trees to build these delegates automatically,
' but it's easy to generate the code for it.
''' <summary>
''' Retrieves a codec suitable for an enum field with the given tag.
''' </summary>
''' <param name="tag">The tag.</param>
''' <param name="toInt32">A conversion function from <see cref="Int32"/> to the enum type.</param>
''' <param name="fromInt32">A conversion function from the enum type to <see cref="Int32"/>.</param>
''' <returns>A codec for the given tag.</returns>
Public Function ForEnum(Of T)(tag As UInteger, toInt32 As Func(Of T, Integer), fromInt32 As Func(Of Integer, T)) As FieldCodecType(Of T)
Return New FieldCodecType(Of T)(Function(input) fromInt32(input.ReadEnum()), Sub(output, value) output.WriteEnum(toInt32(value)), Function(value) CodedOutputStream.ComputeEnumSize(toInt32(value)), tag)
End Function
''' <summary>
''' Retrieves a codec suitable for a message field with the given tag.
''' </summary>
''' <param name="tag">The tag.</param>
''' <param name="parser">A parser to use for the message type.</param>
''' <returns>A codec for the given tag.</returns>
Public Function ForMessage(Of T As IMessageType(Of T))(tag As UInteger, parser As MessageParserType(Of T)) As FieldCodecType(Of T)
Return New FieldCodecType(Of T)(Function(input)
Dim message As T = parser.CreateTemplate()
input.ReadMessage(message)
Return message
End Function, Sub(output, value) output.WriteMessage(value), Function(message) CodedOutputStream.ComputeMessageSize(message), tag)
End Function
''' <summary>
''' Creates a codec for a wrapper type of a class - which must be string or ByteString.
''' </summary>
Public Function ForClassWrapper(Of T As Class)(tag As UInteger) As FieldCodecType(Of T)
Dim nestedCodec = WrapperCodecs.GetCodec(Of T)()
Return New FieldCodecType(Of T)(Function(input) WrapperCodecs.Read(input, nestedCodec), Sub(output, value) WrapperCodecs.Write(output, value, nestedCodec), Function(value) WrapperCodecs.CalculateSize(value, nestedCodec), tag, Nothing) ' Default value for the wrapper
End Function
''' <summary>
''' Creates a codec for a wrapper type of a struct - which must be Int32, Int64, UInt32, UInt64,
''' Bool, Single or Double.
''' </summary>
Public Function ForStructWrapper(Of T As Structure)(tag As UInteger) As FieldCodecType(Of T?)
Dim nestedCodec = WrapperCodecs.GetCodec(Of T)()
Return New FieldCodecType(Of T?)(Function(input) WrapperCodecs.Read(input, nestedCodec), Sub(output, value) WrapperCodecs.Write(output, value.Value, nestedCodec), Function(value) If(value Is Nothing, 0, WrapperCodecs.CalculateSize(value.Value, nestedCodec)), tag, Nothing) ' Default value for the wrapper
End Function
''' <summary>
''' Helper code to create codecs for wrapper types.
''' </summary>
''' <remarks>
''' Somewhat ugly with all the static methods, but the conversions involved to/from nullable types make it
''' slightly tricky to improve. So long as we keep the public API (ForClassWrapper, ForStructWrapper) in place,
''' we can refactor later if we come up with something cleaner.
''' </remarks>
Private NotInheritable Class WrapperCodecs
Private Shared ReadOnly Codecs As Dictionary(Of System.Type, Object) = New Dictionary(Of System.Type, Object) From {
{GetType(Boolean), ForBool(MakeTag(WrapperValueFieldNumber, WireType.Varint))},
{GetType(Integer), ForInt32(MakeTag(WrapperValueFieldNumber, WireType.Varint))},
{GetType(Long), ForInt64(MakeTag(WrapperValueFieldNumber, WireType.Varint))},
{GetType(UInteger), ForUInt32(MakeTag(WrapperValueFieldNumber, WireType.Varint))},
{GetType(ULong), ForUInt64(MakeTag(WrapperValueFieldNumber, WireType.Varint))},
{GetType(Single), ForFloat(MakeTag(WrapperValueFieldNumber, WireType.Fixed32))},
{GetType(Double), ForDouble(MakeTag(WrapperValueFieldNumber, WireType.Fixed64))},
{GetType(String), ForString(MakeTag(WrapperValueFieldNumber, WireType.LengthDelimited))},
{GetType(ByteString), ForBytes(MakeTag(WrapperValueFieldNumber, WireType.LengthDelimited))}
}
''' <summary>
''' Returns a field codec which effectively wraps a value of type T in a message.
'''
''' </summary>
Friend Shared Function GetCodec(Of T)() As FieldCodecType(Of T)
Dim value As Object
If Not Codecs.TryGetValue(GetType(T), value) Then
Throw New InvalidOperationException("Invalid type argument requested for wrapper codec: " & GetType(T).ToString)
End If
Return CType(value, FieldCodecType(Of T))
End Function
Friend Shared Function Read(Of T)(input As CodedInputStream, codec As FieldCodecType(Of T)) As T
Dim length As Integer = input.ReadLength()
Dim oldLimit = input.PushLimit(length)
Dim tag As UInteger
Dim value = codec.DefaultValue
While (CSharpImpl.__Assign(tag, input.ReadTag())) <> 0
If tag = codec.Tag Then
value = codec.Read(input)
Else
input.SkipLastField()
End If
End While
input.CheckReadEndOfStreamTag()
input.PopLimit(oldLimit)
Return value
End Function
Friend Shared Sub Write(Of T)(output As CodedOutputStream, value As T, codec As FieldCodecType(Of T))
output.WriteLength(codec.CalculateSizeWithTag(value))
codec.WriteTagAndValue(output, value)
End Sub
Friend Shared Function CalculateSize(Of T)(value As T, codec As FieldCodecType(Of T)) As Integer
Dim fieldLength = codec.CalculateSizeWithTag(value)
Return CodedOutputStream.ComputeLengthSize(fieldLength) + fieldLength
End Function
Private Class CSharpImpl
<Obsolete("Please refactor calling code to use normal Visual Basic assignment")>
Shared Function __Assign(Of T)(ByRef target As T, value As T) As T
target = value
Return value
End Function
End Class
End Class
End Module
''' <summary>
''' <para>
''' An encode/decode pair for a single field. This effectively encapsulates
''' all the information needed to read or write the field value from/to a coded
''' stream.
''' </para>
''' <para>
''' This class is public and has to be as it is used by generated code, but its public
''' API is very limited - just what the generated code needs to call directly.
''' </para>
''' </summary>
''' <remarks>
''' This never writes default values to the stream, and does not address "packedness"
''' in repeated fields itself, other than to know whether or not the field *should* be packed.
''' </remarks>
Public NotInheritable Class FieldCodecType(Of T)
Private Shared ReadOnly DefaultDefault As T
' Only non-nullable value types support packing. This is the simplest way of detecting that.
Private Shared ReadOnly TypeSupportsPacking As Boolean = Nothing IsNot Nothing
Shared Sub New()
If GetType(T) Is GetType(String) Then
DefaultDefault = CType(CObj(""), T)
ElseIf GetType(T) Is GetType(ByteString) Then
DefaultDefault = CType(CObj(ByteString.Empty), T)
End If
' Otherwise it's the default value of the CLR type
End Sub
Friend Shared Function IsPackedRepeatedField(tag As UInteger) As Boolean
Return TypeSupportsPacking AndAlso GetTagWireType(tag) = WireType.LengthDelimited
End Function
Friend ReadOnly Property PackedRepeatedField As Boolean
''' <summary>
''' Returns a delegate to write a value (unconditionally) to a coded output stream.
''' </summary>
Friend ReadOnly Property ValueWriter As Action(Of CodedOutputStream, T)
''' <summary>
''' Returns the size calculator for just a value.
''' </summary>
Friend ReadOnly Property ValueSizeCalculator As Func(Of T, Integer)
''' <summary>
''' Returns a delegate to read a value from a coded input stream. It is assumed that
''' the stream is already positioned on the appropriate tag.
''' </summary>
Friend ReadOnly Property ValueReader As Func(Of CodedInputStream, T)
''' <summary>
''' Returns the fixed size for an entry, or 0 if sizes vary.
''' </summary>
Friend ReadOnly Property FixedSize As Integer
''' <summary>
''' Gets the tag of the codec.
''' </summary>
''' <value>
''' The tag of the codec.
''' </value>
Friend ReadOnly Property Tag As UInteger
''' <summary>
''' Default value for this codec. Usually the same for every instance of the same type, but
''' for string/ByteString wrapper fields the codec's default value is null, whereas for
''' other string/ByteString fields it's "" or ByteString.Empty.
''' </summary>
''' <value>
''' The default value of the codec's type.
''' </value>
Friend ReadOnly Property DefaultValue As T
Private ReadOnly tagSize As Integer
Friend Sub New(reader As Func(Of CodedInputStream, T), writer As Action(Of CodedOutputStream, T), fixedSize As Integer, tag As UInteger)
Me.New(reader, writer, Function(__) fixedSize, tag)
Me.FixedSize = fixedSize
End Sub
Friend Sub New(reader As Func(Of CodedInputStream, T), writer As Action(Of CodedOutputStream, T), sizeCalculator As Func(Of T, Integer), tag As UInteger)
Me.New(reader, writer, sizeCalculator, tag, DefaultDefault)
End Sub
Friend Sub New(reader As Func(Of CodedInputStream, T), writer As Action(Of CodedOutputStream, T), sizeCalculator As Func(Of T, Integer), tag As UInteger, defaultValue As T)
ValueReader = reader
ValueWriter = writer
ValueSizeCalculator = sizeCalculator
FixedSize = 0
Me.Tag = tag
Me.DefaultValue = defaultValue
tagSize = CodedOutputStream.ComputeRawVarint32Size(tag)
' Detect packed-ness once, so we can check for it within RepeatedField<T>.
PackedRepeatedField = IsPackedRepeatedField(tag)
End Sub
''' <summary>
''' Write a tag and the given value, *if* the value is not the default.
''' </summary>
Public Sub WriteTagAndValue(output As CodedOutputStream, value As T)
If Not IsDefault(value) Then
output.WriteTag(Tag)
Me.ValueWriter()(output, value)
End If
End Sub
''' <summary>
''' Reads a value of the codec type from the given <see cref="CodedInputStream"/>.
''' </summary>
''' <param name="input">The input stream to read from.</param>
''' <returns>The value read from the stream.</returns>
Public Function Read(input As CodedInputStream) As T
Return ValueReader(input)
End Function
''' <summary>
''' Calculates the size required to write the given value, with a tag,
''' if the value is not the default.
''' </summary>
Public Function CalculateSizeWithTag(value As T) As Integer
Return If(IsDefault(value), 0, ValueSizeCalculator(value) + tagSize)
End Function
Private Function IsDefault(value As T) As Boolean
Return EqualityComparer(Of T).Default.Equals(value, DefaultValue)
End Function
End Class
End Namespace

@ -0,0 +1,46 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2008 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System
Imports System.Text.RegularExpressions
Namespace Google.Protobuf
''' <summary>
''' Class containing helpful workarounds for various platform compatibility
''' </summary>
Friend Module FrameworkPortability
' The value of RegexOptions.Compiled is 8. We can test for the presence at
' execution time using Enum.IsDefined, so a single build will do the right thing
' on each platform. (RegexOptions.Compiled isn't supported by PCLs.)
Friend ReadOnly CompiledRegexWhereAvailable As RegexOptions = If([Enum].IsDefined(GetType(RegexOptions), 8), CType(8, RegexOptions), RegexOptions.None)
End Module
End Namespace

@ -0,0 +1,67 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OptionInfer>On</OptionInfer>
<ProductVersion>8.0.30703</ProductVersion>
<RootNamespace></RootNamespace>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<AssemblyTitle>CodeGenerator</AssemblyTitle>
<Description>Generates C# code from a .proto file</Description>
<Copyright>Peter Hultqvist 2015</Copyright>
<AssemblyVersion>2015.10.13</AssemblyVersion>
<FileVersion>2015.10.13</FileVersion>
<TargetFramework>net48</TargetFramework>
<OutputType>Exe</OutputType>
<DefaultItemExcludes>$(DefaultItemExcludes);$(ProjectDir)**\*.cs</DefaultItemExcludes>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG</DefineConstants>
<ConsolePause>False</ConsolePause>
<Commandlineparameters>--fix-nameclash ../../../TestProgram/ProtoSpec/LocalFeatures.proto --no-generate-imported --output ../../../TestProgram/Generated/GeneratedLocal.cs --ctor --utc --skip-default</Commandlineparameters>
<RemoveIntegerChecks>true</RemoveIntegerChecks>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<Optimize>False</Optimize>
<OutputPath>bin\Release</OutputPath>
<ConsolePause>False</ConsolePause>
<Commandlineparameters>--fix-nameclash ../../../TestProgram/ProtoSpec/ImportAll.proto --ctor --utc --output ../../../TestProgram/Generated/Generated.vb</Commandlineparameters>
<DebugSymbols>True</DebugSymbols>
</PropertyGroup>
<PropertyGroup>
<StartupObject />
<OutputType>Library</OutputType>
<AssemblyName>Google.Protobuf</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'BuildTests|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<DefineConstants>DEBUG;BUILD_TESTS</DefineConstants>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Compile Remove="ProtocolParser\**" />
<EmbeddedResource Remove="ProtocolParser\**" />
<None Remove="ProtocolParser\**" />
</ItemGroup>
<ItemGroup>
<Folder Include="My Project\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\GCModeller\src\runtime\sciBASIC#\Microsoft.VisualBasic.Core\src\47-dotnet_Microsoft.VisualBasic.vbproj" />
</ItemGroup>
</Project>

@ -0,0 +1,68 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2016 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Namespace Google.Protobuf
''' <summary>
''' A message type that has a custom string format for diagnostic purposes.
''' </summary>
''' <remarks>
''' <para>
''' Calling <see cref="Object.ToString"/> on a generated message type normally
''' returns the JSON representation. If a message type implements this interface,
''' then the <see cref="ToDiagnosticString"/> method will be called instead of the regular
''' JSON formatting code, but only when <c>ToString()</c> is called either on the message itself
''' or on another message which contains it. This does not affect the normal JSON formatting of
''' the message.
''' </para>
''' <para>
''' For example, if you create a proto message representing a GUID, the internal
''' representation may be a <c>bytes</c> field or four <c>fixed32</c> fields. However, when debugging
''' it may be more convenient to see a result in the same format as <see cref="System.Guid"/> provides.
''' </para>
''' <para>This interface extends <see cref="IMessage"/> to avoid it accidentally being implemented
''' on types other than messages, where it would not be used by anything in the framework.</para>
''' </remarks>
Public Interface ICustomDiagnosticMessage
Inherits IMessage
''' <summary>
''' Returns a string representation of this object, for diagnostic purposes.
''' </summary>
''' <remarks>
''' This method is called when a message is formatted as part of a <see cref="Object.ToString"/>
''' call. It does not affect the JSON representation used by <see cref="JsonFormatter"/> other than
''' in calls to <see cref="JsonFormatter.ToDiagnosticString(IMessage)"/>. While it is recommended
''' that the result is valid JSON, this is never assumed by the Protobuf library.
''' </remarks>
''' <returns>A string representation of this object, for diagnostic purposes.</returns>
Function ToDiagnosticString() As String
End Interface
End Namespace

@ -0,0 +1,52 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2015 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Namespace Google.Protobuf
''' <summary>
''' Generic interface for a deeply cloneable type.
''' </summary>
''' <remarks>
''' <para>
''' All generated messages implement this interface, but so do some non-message types.
''' Additionally, due to the type constraint on <c>T</c> in <see cref="IMessageType(OfT)"/>,
''' it is simpler to keep this as a separate interface.
''' </para>
''' </remarks>
''' <typeparamname="T">The type itself, returned by the <see cref="Clone"/> method.</typeparam>
Public Interface IDeepCloneable(Of T)
''' <summary>
''' Creates a deep clone of this object.
''' </summary>
''' <returns>A deep clone of this object.</returns>
Function Clone() As T
End Interface
End Namespace

@ -0,0 +1,85 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2008 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System
Imports Google.Protobuf.Reflection
Namespace Google.Protobuf
''' <summary>
''' Interface for a Protocol Buffers message, supporting
''' basic operations required for serialization.
''' </summary>
Public Interface IMessage
''' <summary>
''' Merges the data from the specified coded input stream with the current message.
''' </summary>
''' <remarks>See the user guide for precise merge semantics.</remarks>
''' <param name="input"></param>
Sub MergeFrom(input As CodedInputStream)
''' <summary>
''' Writes the data to the given coded output stream.
''' </summary>
''' <param name="output">Coded output stream to write the data to. Must not be null.</param>
Sub WriteTo(output As CodedOutputStream)
''' <summary>
''' Calculates the size of this message in Protocol Buffer wire format, in bytes.
''' </summary>
''' <returns>The number of bytes required to write this message
''' to a coded output stream.</returns>
Function CalculateSize() As Integer
''' <summary>
''' Descriptor for this message. All instances are expected to return the same descriptor,
''' and for generated types this will be an explicitly-implemented member, returning the
''' same value as the static property declared on the type.
''' </summary>
ReadOnly Property Descriptor As MessageDescriptor
End Interface
''' <summary>
''' Generic interface for a Protocol Buffers message,
''' where the type parameter is expected to be the same type as
''' the implementation class.
''' </summary>
''' <typeparamname="T">The message type.</typeparam>
Public Interface IMessageType(Of T As IMessageType(Of T))
Inherits IMessage, IEquatable(Of T), IDeepCloneable(Of T)
''' <summary>
''' Merges the given message into this one.
''' </summary>
''' <remarks>See the user guide for precise merge semantics.</remarks>
''' <param name="message">The message to merge with this one. Must not be null.</param>
Overloads Sub MergeFrom(message As T)
End Interface
End Namespace

@ -0,0 +1,52 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2015 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System.IO
Namespace Google.Protobuf
''' <summary>
''' Thrown when an attempt is made to parse invalid JSON, e.g. using
''' a non-string property key, or including a redundant comma. Parsing a protocol buffer
''' message represented in JSON using <see cref="JsonParser"/> can throw both this
''' exception and <see cref="InvalidProtocolBufferException"/> depending on the situation. This
''' exception is only thrown for "pure JSON" errors, whereas <c>InvalidProtocolBufferException</c>
''' is thrown when the JSON may be valid in and of itself, but cannot be parsed as a protocol buffer
''' message.
''' </summary>
Public NotInheritable Class InvalidJsonException
Inherits IOException
Friend Sub New(message As String)
MyBase.New(message)
End Sub
End Class
End Namespace

@ -0,0 +1,99 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2008 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System
Imports System.IO
Namespace Google.Protobuf
''' <summary>
''' Thrown when a protocol message being parsed is invalid in some way,
''' e.g. it contains a malformed varint or a negative byte length.
''' </summary>
Public NotInheritable Class InvalidProtocolBufferException
Inherits IOException
Friend Sub New(message As String)
MyBase.New(message)
End Sub
Friend Sub New(message As String, innerException As Exception)
MyBase.New(message, innerException)
End Sub
Friend Shared Function MoreDataAvailable() As InvalidProtocolBufferException
Return New InvalidProtocolBufferException("Completed reading a message while more data was available in the stream.")
End Function
Friend Shared Function TruncatedMessage() As InvalidProtocolBufferException
Return New InvalidProtocolBufferException("While parsing a protocol message, the input ended unexpectedly " & "in the middle of a field. This could mean either than the " & "input has been truncated or that an embedded message " & "misreported its own length.")
End Function
Friend Shared Function NegativeSize() As InvalidProtocolBufferException
Return New InvalidProtocolBufferException("CodedInputStream encountered an embedded string or message " & "which claimed to have negative size.")
End Function
Friend Shared Function MalformedVarint() As InvalidProtocolBufferException
Return New InvalidProtocolBufferException("CodedInputStream encountered a malformed varint.")
End Function
''' <summary>
''' Creates an exception for an error condition of an invalid tag being encountered.
''' </summary>
Friend Shared Function InvalidTag() As InvalidProtocolBufferException
Return New InvalidProtocolBufferException("Protocol message contained an invalid tag (zero).")
End Function
Friend Shared Function InvalidBase64(innerException As Exception) As InvalidProtocolBufferException
Return New InvalidProtocolBufferException("Invalid base64 data", innerException)
End Function
Friend Shared Function InvalidEndTag() As InvalidProtocolBufferException
Return New InvalidProtocolBufferException("Protocol message end-group tag did not match expected tag.")
End Function
Friend Shared Function RecursionLimitExceeded() As InvalidProtocolBufferException
Return New InvalidProtocolBufferException("Protocol message had too many levels of nesting. May be malicious. " & "Use CodedInputStream.SetRecursionLimit() to increase the depth limit.")
End Function
Friend Shared Function JsonRecursionLimitExceeded() As InvalidProtocolBufferException
Return New InvalidProtocolBufferException("Protocol message had too many levels of nesting. May be malicious. " & "Use JsonParser.Settings to increase the depth limit.")
End Function
Friend Shared Function SizeLimitExceeded() As InvalidProtocolBufferException
Return New InvalidProtocolBufferException("Protocol message was too large. May be malicious. " & "Use CodedInputStream.SetSizeLimit() to increase the size limit.")
End Function
Friend Shared Function InvalidMessageStreamTag() As InvalidProtocolBufferException
Return New InvalidProtocolBufferException("Stream of protocol messages had invalid tag. Expected tag is length-delimited field 1.")
End Function
End Class
End Namespace

@ -0,0 +1,800 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2015 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System
Imports System.Collections
Imports System.Globalization
Imports System.Text
Imports Google.Protobuf.Reflection
Imports Google.Protobuf.WellKnownTypes
Imports System.IO
Imports System.Linq
Imports System.Collections.Generic
Imports System.Reflection
Imports Microsoft.VisualBasic.Language
Namespace Google.Protobuf
''' <summary>
''' Reflection-based converter from messages to JSON.
''' </summary>
''' <remarks>
''' <para>
''' Instances of this class are thread-safe, with no mutable state.
''' </para>
''' <para>
''' This is a simple start to get JSON formatting working. As it's reflection-based,
''' it's not as quick as baking calls into generated messages - but is a simpler implementation.
''' (This code is generally not heavily optimized.)
''' </para>
''' </remarks>
Public NotInheritable Class JsonFormatter
Friend Const AnyTypeUrlField As String = "@type"
Friend Const AnyDiagnosticValueField As String = "@value"
Friend Const AnyWellKnownTypeValueField As String = "value"
Private Const TypeUrlPrefix As String = "type.googleapis.com"
Private Const NameValueSeparator As String = ": "
Private Const PropertySeparator As String = ", "
''' <summary>
''' Returns a formatter using the default settings.
''' </summary>
Public Shared ReadOnly Property [Default] As JsonFormatter = New JsonFormatter(Settings.Default)
' A JSON formatter which *only* exists
Private Shared ReadOnly diagnosticFormatter As JsonFormatter = New JsonFormatter(Settings.Default)
''' <summary>
''' The JSON representation of the first 160 characters of Unicode.
''' Empty strings are replaced by the static constructor.
''' </summary>
' C0 (ASCII and derivatives) control characters
' Escaping of " and \ are required by www.json.org string definition.
' Escaping of < and > are required for HTML security.
' C1 (ISO 8859 and Unicode) extended control characters
Private Shared ReadOnly CommonRepresentations As String() = {"\u0000", "\u0001", "\u0002", "\u0003", "\u0004", "\u0005", "\u0006", "\u0007", "\b", "\t", "\n", "\u000b", "\f", "\r", "\u000e", "\u000f", "\u0010", "\u0011", "\u0012", "\u0013", "\u0014", "\u0015", "\u0016", "\u0017", "\u0018", "\u0019", "\u001a", "\u001b", "\u001c", "\u001d", "\u001e", "\u001f", "", "", "\""", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "\u003c", "", "\u003e", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "\\", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "\u007f", "\u0080", "\u0081", "\u0082", "\u0083", "\u0084", "\u0085", "\u0086", "\u0087", "\u0088", "\u0089", "\u008a", "\u008b", "\u008c", "\u008d", "\u008e", "\u008f", "\u0090", "\u0091", "\u0092", "\u0093", "\u0094", "\u0095", "\u0096", "\u0097", "\u0098", "\u0099", "\u009a", "\u009b", "\u009c", "\u009d", "\u009e", "\u009f"} ' 0x00
' 0x10
' 0x20
' 0x30
' 0x40
' 0x50
' 0x60
' 0x70
' 0x80
' 0x90
Shared Sub New()
For i = 0 To CommonRepresentations.Length - 1
If Equals(CommonRepresentations(i), "") Then
CommonRepresentations(i) = Microsoft.VisualBasic.ChrW(i).ToString()
End If
Next
End Sub
Private ReadOnly settingsField As Settings
Private ReadOnly Property DiagnosticOnly As Boolean
Get
Return ReferenceEquals(Me, diagnosticFormatter)
End Get
End Property
''' <summary>
''' Creates a new formatted with the given settings.
''' </summary>
''' <param name="settings">The settings.</param>
Public Sub New(settings As Settings)
settingsField = settings
End Sub
''' <summary>
''' Formats the specified message as JSON.
''' </summary>
''' <param name="message">The message to format.</param>
''' <returns>The formatted message.</returns>
Public Function Format(message As IMessage) As String
Dim writer = New StringWriter()
Format(message, writer)
Return writer.ToString()
End Function
''' <summary>
''' Formats the specified message as JSON.
''' </summary>
''' <param name="message">The message to format.</param>
''' <param name="writer">The TextWriter to write the formatted message to.</param>
''' <returns>The formatted message.</returns>
Public Sub Format(message As IMessage, writer As TextWriter)
CheckNotNull(message, NameOf(message))
CheckNotNull(writer, NameOf(writer))
If message.Descriptor.IsWellKnownType Then
WriteWellKnownTypeValue(writer, message.Descriptor, message)
Else
WriteMessage(writer, message)
End If
End Sub
''' <summary>
''' Converts a message to JSON for diagnostic purposes with no extra context.
''' </summary>
''' <remarks>
''' <para>
''' This differs from calling <see cref="Format(IMessage)"/> on the default JSON
''' formatter in its handling of <see cref="Any"/>. As no type registry is available
''' in <see cref="Object.ToString"/> calls, the normal way of resolving the type of
''' an <c>Any</c> message cannot be applied. Instead, a JSON property named <c>@value</c>
''' is included with the base64 data from the <see cref="Any.Value"/> property of the message.
''' </para>
''' <para>The value returned by this method is only designed to be used for diagnostic
''' purposes. It may not be parsable by <see cref="JsonParser"/>, and may not be parsable
''' by other Protocol Buffer implementations.</para>
''' </remarks>
''' <param name="message">The message to format for diagnostic purposes.</param>
''' <returns>The diagnostic-only JSON representation of the message</returns>
Public Shared Function ToDiagnosticString(message As IMessage) As String
CheckNotNull(message, NameOf(message))
Return diagnosticFormatter.Format(message)
End Function
Private Sub WriteMessage(writer As TextWriter, message As IMessage)
If message Is Nothing Then
WriteNull(writer)
Return
End If
If DiagnosticOnly Then
Dim customDiagnosticMessage As ICustomDiagnosticMessage = TryCast(message, ICustomDiagnosticMessage)
If customDiagnosticMessage IsNot Nothing Then
writer.Write(customDiagnosticMessage.ToDiagnosticString())
Return
End If
End If
writer.Write("{ ")
Dim writtenFields = WriteMessageFields(writer, message, False)
writer.Write(If(writtenFields, " }", "}"))
End Sub
Private Function WriteMessageFields(writer As TextWriter, message As IMessage, assumeFirstFieldWritten As Boolean) As Boolean
Dim fields = message.Descriptor.Fields
Dim first = Not assumeFirstFieldWritten
' First non-oneof fields
For Each field In fields.InFieldNumberOrder()
Dim accessor = field.Accessor
If field.ContainingOneof IsNot Nothing AndAlso field.ContainingOneof.Accessor.GetCaseFieldDescriptor(message) IsNot field Then
Continue For
End If
' Omit default values unless we're asked to format them, or they're oneofs (where the default
' value is still formatted regardless, because that's how we preserve the oneof case).
Dim value = accessor.GetValue(message)
If field.ContainingOneof Is Nothing AndAlso Not settingsField.FormatDefaultValues AndAlso IsDefaultValue(accessor, value) Then
Continue For
End If
' Okay, all tests complete: let's write the field value...
If Not first Then
writer.Write(PropertySeparator)
End If
WriteString(writer, accessor.Descriptor.JsonName)
writer.Write(NameValueSeparator)
WriteValue(writer, value)
first = False
Next
Return Not first
End Function
''' <summary>
''' Camel-case converter with added strictness for field mask formatting.
''' </summary>
''' <exception cref="InvalidOperationException">The field mask is invalid for JSON representation</exception>
Private Shared Function ToCamelCaseForFieldMask(input As String) As String
For i = 0 To input.Length - 1
Dim c = input(i)
If c >= "A"c AndAlso c <= "Z"c Then
Throw New InvalidOperationException($"Invalid field mask to be converted to JSON: {input}")
End If
If c = "_"c AndAlso i < input.Length - 1 Then
Dim [next] = input(i + 1)
If [next] < "a"c OrElse [next] > "z"c Then
Throw New InvalidOperationException($"Invalid field mask to be converted to JSON: {input}")
End If
End If
Next
Return ToCamelCase(input)
End Function
' Converted from src/google/protobuf/util/internal/utility.cc ToCamelCase
' TODO: Use the new field in FieldDescriptor.
Friend Shared Function ToCamelCase(input As String) As String
Dim capitalizeNext = False
Dim wasCap = True
Dim isCap = False
Dim firstWord = True
Dim result As StringBuilder = New StringBuilder(input.Length)
Dim i = 0
While i < input.Length
isCap = Char.IsUpper(input(i))
If input(i) = "_"c Then
capitalizeNext = True
If result.Length <> 0 Then
firstWord = False
End If
Continue While
ElseIf firstWord Then
' Consider when the current character B is capitalized,
' first word ends when:
' 1) following a lowercase: "...aB..."
' 2) followed by a lowercase: "...ABc..."
If result.Length <> 0 AndAlso isCap AndAlso (Not wasCap OrElse i + 1 < input.Length AndAlso Char.IsLower(input(i + 1))) Then
firstWord = False
Else
result.Append(Char.ToLowerInvariant(input(i)))
Continue While
End If
ElseIf capitalizeNext Then
capitalizeNext = False
If Char.IsLower(input(i)) Then
result.Append(Char.ToUpperInvariant(input(i)))
Continue While
End If
End If
result.Append(input(i))
i += 1
wasCap = isCap
End While
Return result.ToString()
End Function
Private Shared Sub WriteNull(writer As TextWriter)
writer.Write("null")
End Sub
Private Shared Function IsDefaultValue(accessor As IFieldAccessor, value As Object) As Boolean
If accessor.Descriptor.IsMap Then
Dim dictionary = CType(value, IDictionary)
Return dictionary.Count = 0
End If
If accessor.Descriptor.IsRepeated Then
Dim list = CType(value, IList)
Return list.Count = 0
End If
Select Case accessor.Descriptor.FieldType
Case FieldType.Bool
Return CBool(value) = False
Case FieldType.Bytes
Return CType(value, ByteString) Is ByteString.Empty
Case FieldType.String
Return Equals(CStr(value), "")
Case FieldType.Double
Return CDbl(value) = 0.0
Case FieldType.SInt32, FieldType.Int32, FieldType.SFixed32, FieldType.Enum
Return CInt(value) = 0
Case FieldType.Fixed32, FieldType.UInt32
Return CUInt(value) = 0
Case FieldType.Fixed64, FieldType.UInt64
Return CULng(value) = 0
Case FieldType.SFixed64, FieldType.Int64, FieldType.SInt64
Return CLng(value) = 0
Case FieldType.Float
Return CSng(value) = 0F
Case FieldType.Message, FieldType.Group ' Never expect to get this, but...
Return value Is Nothing
Case Else
Throw New ArgumentException("Invalid field type")
End Select
End Function
''' <summary>
''' Writes a single value to the given writer as JSON. Only types understood by
''' Protocol Buffers can be written in this way. This method is only exposed for
''' advanced use cases; most users should be using <see cref="Format(IMessage)"/>
''' or <see cref="Format(IMessage,TextWriter)"/>.
''' </summary>
''' <param name="writer">The writer to write the value to. Must not be null.</param>
''' <param name="value">The value to write. May be null.</param>
Public Sub WriteValue(writer As TextWriter, value As Object)
If value Is Nothing Then
WriteNull(writer)
ElseIf TypeOf value Is Boolean Then
writer.Write(If(value, "true", "false"))
ElseIf TypeOf value Is ByteString Then
' Nothing in Base64 needs escaping
writer.Write(""""c)
writer.Write(CType(value, ByteString).ToBase64())
writer.Write(""""c)
ElseIf TypeOf value Is String Then
WriteString(writer, CStr(value))
ElseIf TypeOf value Is IDictionary Then
WriteDictionary(writer, CType(value, IDictionary))
ElseIf TypeOf value Is IList Then
WriteList(writer, CType(value, IList))
ElseIf TypeOf value Is Integer OrElse TypeOf value Is UInteger Then
Dim formattable = CType(value, IFormattable)
writer.Write(formattable.ToString("d", CultureInfo.InvariantCulture))
ElseIf TypeOf value Is Long OrElse TypeOf value Is ULong Then
writer.Write(""""c)
Dim formattable = CType(value, IFormattable)
writer.Write(formattable.ToString("d", CultureInfo.InvariantCulture))
writer.Write(""""c)
ElseIf TypeOf value Is System.Enum Then
Dim name = OriginalEnumValueHelper.GetOriginalName(value)
If Not Equals(name, Nothing) Then
WriteString(writer, name)
Else
WriteValue(writer, CInt(value))
End If
ElseIf TypeOf value Is Single OrElse TypeOf value Is Double Then
Dim text = CType(value, IFormattable).ToString("r", CultureInfo.InvariantCulture)
If Equals(text, "NaN") OrElse Equals(text, "Infinity") OrElse Equals(text, "-Infinity") Then
writer.Write(""""c)
writer.Write(text)
writer.Write(""""c)
Else
writer.Write(text)
End If
ElseIf TypeOf value Is IMessage Then
Format(CType(value, IMessage), writer)
Else
Throw New ArgumentException("Unable to format value of type " & value.GetType().ToString)
End If
End Sub
''' <summary>
''' Central interception point for well-known type formatting. Any well-known types which
''' don't need special handling can fall back to WriteMessage. We avoid assuming that the
''' values are using the embedded well-known types, in order to allow for dynamic messages
''' in the future.
''' </summary>
Private Sub WriteWellKnownTypeValue(writer As TextWriter, descriptor As MessageDescriptor, value As Object)
' Currently, we can never actually get here, because null values are always handled by the caller. But if we *could*,
' this would do the right thing.
If value Is Nothing Then
WriteNull(writer)
Return
End If
' For wrapper types, the value will either be the (possibly boxed) "native" value,
' or the message itself if we're formatting it at the top level (e.g. just calling ToString on the object itself).
' If it's the message form, we can extract the value first, which *will* be the (possibly boxed) native value,
' and then proceed, writing it as if we were definitely in a field. (We never need to wrap it in an extra string...
' WriteValue will do the right thing.)
If descriptor.IsWrapperType Then
If TypeOf value Is IMessage Then
Dim message = CType(value, IMessage)
value = message.Descriptor.Fields(WrapperValueFieldNumber).Accessor.GetValue(message)
End If
WriteValue(writer, value)
Return
End If
If Equals(descriptor.FullName, Timestamp.DescriptorProp.FullName) Then
WriteTimestamp(writer, CType(value, IMessage))
Return
End If
If Equals(descriptor.FullName, Duration.DescriptorProp.FullName) Then
WriteDuration(writer, CType(value, IMessage))
Return
End If
If Equals(descriptor.FullName, FieldMask.DescriptorProp.FullName) Then
WriteFieldMask(writer, CType(value, IMessage))
Return
End If
If Equals(descriptor.FullName, Struct.DescriptorProp.FullName) Then
WriteStruct(writer, CType(value, IMessage))
Return
End If
If Equals(descriptor.FullName, ListValue.DescriptorProp.FullName) Then
Dim fieldAccessor = descriptor.Fields(ListValue.ValuesFieldNumber).Accessor
WriteList(writer, CType(fieldAccessor.GetValue(CType(value, IMessage)), IList))
Return
End If
If Equals(descriptor.FullName, WellKnownTypes.Value.DescriptorProp.FullName) Then
WriteStructFieldValue(writer, CType(value, IMessage))
Return
End If
If Equals(descriptor.FullName, Any.DescriptorProp.FullName) Then
WriteAny(writer, CType(value, IMessage))
Return
End If
WriteMessage(writer, CType(value, IMessage))
End Sub
Private Sub WriteTimestamp(writer As TextWriter, value As IMessage)
' TODO: In the common case where this *is* using the built-in Timestamp type, we could
' avoid all the reflection at this point, by casting to Timestamp. In the interests of
' avoiding subtle bugs, don't do that until we've implemented DynamicMessage so that we can prove
' it still works in that case.
Dim nanos As Integer = value.Descriptor.Fields(Timestamp.NanosFieldNumber).Accessor.GetValue(value)
Dim seconds As Long = value.Descriptor.Fields(Timestamp.SecondsFieldNumber).Accessor.GetValue(value)
writer.Write(Timestamp.ToJson(seconds, nanos, DiagnosticOnly))
End Sub
Private Sub WriteDuration(writer As TextWriter, value As IMessage)
' TODO: Same as for WriteTimestamp
Dim nanos As Integer = value.Descriptor.Fields(Duration.NanosFieldNumber).Accessor.GetValue(value)
Dim seconds As Long = value.Descriptor.Fields(Duration.SecondsFieldNumber).Accessor.GetValue(value)
writer.Write(Duration.ToJson(seconds, nanos, DiagnosticOnly))
End Sub
Private Sub WriteFieldMask(writer As TextWriter, value As IMessage)
Dim paths = CType(value.Descriptor.Fields(FieldMask.PathsFieldNumber).Accessor.GetValue(value), IList(Of String))
writer.Write(FieldMask.ToJson(paths, DiagnosticOnly))
End Sub
Private Sub WriteAny(writer As TextWriter, value As IMessage)
If DiagnosticOnly Then
WriteDiagnosticOnlyAny(writer, value)
Return
End If
Dim typeUrl = CStr(value.Descriptor.Fields(Any.TypeUrlFieldNumber).Accessor.GetValue(value))
Dim data = CType(value.Descriptor.Fields(Any.ValueFieldNumber).Accessor.GetValue(value), ByteString)
Dim typeName = Any.GetTypeName(typeUrl)
Dim descriptor = settingsField.TypeRegistry.Find(typeName)
If descriptor Is Nothing Then
Throw New InvalidOperationException($"Type registry has no descriptor for type name '{typeName}'")
End If
Dim message = descriptor.Parser.ParseFrom(data)
writer.Write("{ ")
WriteString(writer, AnyTypeUrlField)
writer.Write(NameValueSeparator)
WriteString(writer, typeUrl)
If descriptor.IsWellKnownType Then
writer.Write(PropertySeparator)
WriteString(writer, AnyWellKnownTypeValueField)
writer.Write(NameValueSeparator)
WriteWellKnownTypeValue(writer, descriptor, message)
Else
WriteMessageFields(writer, message, True)
End If
writer.Write(" }")
End Sub
Private Sub WriteDiagnosticOnlyAny(writer As TextWriter, value As IMessage)
Dim typeUrl = CStr(value.Descriptor.Fields(Any.TypeUrlFieldNumber).Accessor.GetValue(value))
Dim data = CType(value.Descriptor.Fields(Any.ValueFieldNumber).Accessor.GetValue(value), ByteString)
writer.Write("{ ")
WriteString(writer, AnyTypeUrlField)
writer.Write(NameValueSeparator)
WriteString(writer, typeUrl)
writer.Write(PropertySeparator)
WriteString(writer, AnyDiagnosticValueField)
writer.Write(NameValueSeparator)
writer.Write(""""c)
writer.Write(data.ToBase64())
writer.Write(""""c)
writer.Write(" }")
End Sub
Private Sub WriteStruct(writer As TextWriter, message As IMessage)
writer.Write("{ ")
Dim fields = CType(message.Descriptor.Fields(Struct.FieldsFieldNumber).Accessor.GetValue(message), IDictionary)
Dim first = True
For Each entry As DictionaryEntry In fields
Dim key = CStr(entry.Key)
Dim value = CType(entry.Value, IMessage)
If String.IsNullOrEmpty(key) OrElse value Is Nothing Then
Throw New InvalidOperationException("Struct fields cannot have an empty key or a null value.")
End If
If Not first Then
writer.Write(PropertySeparator)
End If
WriteString(writer, key)
writer.Write(NameValueSeparator)
WriteStructFieldValue(writer, value)
first = False
Next
writer.Write(If(first, "}", " }"))
End Sub
Private Sub WriteStructFieldValue(writer As TextWriter, message As IMessage)
Dim specifiedField = message.Descriptor.Oneofs(0).Accessor.GetCaseFieldDescriptor(message)
If specifiedField Is Nothing Then
Throw New InvalidOperationException("Value message must contain a value for the oneof.")
End If
Dim value = specifiedField.Accessor.GetValue(message)
Select Case specifiedField.FieldNumber
Case WellKnownTypes.Value.BoolValueFieldNumber, WellKnownTypes.Value.StringValueFieldNumber, WellKnownTypes.Value.NumberValueFieldNumber
WriteValue(writer, value)
Return
Case WellKnownTypes.Value.StructValueFieldNumber, WellKnownTypes.Value.ListValueFieldNumber
' Structs and ListValues are nested messages, and already well-known types.
Dim nestedMessage = CType(specifiedField.Accessor.GetValue(message), IMessage)
WriteWellKnownTypeValue(writer, nestedMessage.Descriptor, nestedMessage)
Return
Case WellKnownTypes.Value.NullValueFieldNumber
WriteNull(writer)
Return
Case Else
Throw New InvalidOperationException("Unexpected case in struct field: " & specifiedField.FieldNumber)
End Select
End Sub
Friend Sub WriteList(writer As TextWriter, list As IList)
writer.Write("[ ")
Dim first = True
For Each value In list
If Not first Then
writer.Write(PropertySeparator)
End If
WriteValue(writer, value)
first = False
Next
writer.Write(If(first, "]", " ]"))
End Sub
Friend Sub WriteDictionary(writer As TextWriter, dictionary As IDictionary)
writer.Write("{ ")
Dim first = True
' This will box each pair. Could use IDictionaryEnumerator, but that's ugly in terms of disposal.
For Each pair As DictionaryEntry In dictionary
If Not first Then
writer.Write(PropertySeparator)
End If
Dim keyText As String
If TypeOf pair.Key Is String Then
keyText = CStr(pair.Key)
ElseIf TypeOf pair.Key Is Boolean Then
keyText = If(pair.Key, "true", "false")
ElseIf TypeOf pair.Key Is Integer OrElse TypeOf pair.Key Is UInteger Or TypeOf pair.Key Is Long OrElse TypeOf pair.Key Is ULong Then
keyText = CType(pair.Key, IFormattable).ToString("d", CultureInfo.InvariantCulture)
Else
If pair.Key Is Nothing Then
Throw New ArgumentException("Dictionary has entry with null key")
End If
Throw New ArgumentException("Unhandled dictionary key type: " & pair.Key.GetType().ToString)
End If
WriteString(writer, keyText)
writer.Write(NameValueSeparator)
WriteValue(writer, pair.Value)
first = False
Next
writer.Write(If(first, "}", " }"))
End Sub
''' <summary>
''' Writes a string (including leading and trailing double quotes) to a builder, escaping as required.
''' </summary>
''' <remarks>
''' Other than surrogate pair handling, this code is mostly taken from src/google/protobuf/util/internal/json_escaping.cc.
''' </remarks>
Friend Shared Sub WriteString(writer As TextWriter, text As String)
writer.Write(""""c)
For i = 0 To text.Length - 1
Dim c As chr = text(i)
If c < &HA0 Then
writer.Write(CommonRepresentations(c))
Continue For
End If
If Char.IsHighSurrogate(c) Then
' Encountered first part of a surrogate pair.
' Check that we have the whole pair, and encode both parts as hex.
i += 1
If i = text.Length OrElse Not Char.IsLowSurrogate(text(i)) Then
Throw New ArgumentException("String contains low surrogate not followed by high surrogate")
End If
HexEncodeUtf16CodeUnit(writer, c)
HexEncodeUtf16CodeUnit(writer, text(i))
Continue For
ElseIf Char.IsLowSurrogate(c) Then
Throw New ArgumentException("String contains high surrogate not preceded by low surrogate")
End If
Select Case CInt(c)
' These are not required by json spec
' but used to prevent security bugs in javascript.
Case &HFEFF, &HFFF9, &HFFFA, &HFFFB, &HAD, &H6DD, &H70F, &H17B4, &H17B5 ' Zero width no-break space
' Interlinear annotation anchor
' Interlinear annotation separator
' Interlinear annotation terminator
' Soft-hyphen
' Arabic end of ayah
' Syriac abbreviation mark
' Khmer vowel inherent Aq
' Khmer vowel inherent Aa
HexEncodeUtf16CodeUnit(writer, c)
Case Else
If c >= &H600 AndAlso c <= &H603 OrElse c >= &H200B AndAlso c <= &H200F OrElse c >= &H2028 AndAlso c <= &H202E OrElse c >= &H2060 AndAlso c <= &H2064 OrElse c >= &H206A AndAlso c <= &H206F Then ' Arabic signs
' Zero width etc.
' Separators etc.
' Invisible etc.
HexEncodeUtf16CodeUnit(writer, c)
Else
' No handling of surrogates here - that's done earlier
writer.Write(c)
End If
End Select
Next
writer.Write(""""c)
End Sub
Private Const Hex As String = "0123456789abcdef"
Private Shared Sub HexEncodeUtf16CodeUnit(writer As TextWriter, c As chr)
writer.Write("\u")
writer.Write(Hex(c >> 12 And &HF))
writer.Write(Hex(c >> 8 And &HF))
writer.Write(Hex(c >> 4 And &HF))
writer.Write(Hex(c >> 0 And &HF))
End Sub
''' <summary>
''' Settings controlling JSON formatting.
''' </summary>
Public NotInheritable Class Settings
''' <summary>
''' Default settings, as used by <see cref="JsonFormatter.Default"/>
''' </summary>
Public Shared ReadOnly Property [Default] As Settings
' Workaround for the Mono compiler complaining about XML comments not being on
' valid language elements.
Shared Sub New()
[Default] = New Settings(False)
End Sub
''' <summary>
''' Whether fields whose values are the default for the field type (e.g. 0 for integers)
''' should be formatted (true) or omitted (false).
''' </summary>
Public ReadOnly Property FormatDefaultValues As Boolean
''' <summary>
''' The type registry used to format <see cref="Any"/> messages.
''' </summary>
Public ReadOnly Property TypeRegistry As TypeRegistry
' TODO: Work out how we're going to scale this to multiple settings. "WithXyz" methods?
''' <summary>
''' Creates a new <see cref="Settings"/> object with the specified formatting of default values
''' and an empty type registry.
''' </summary>
''' <param name="formatDefaultValues"><c>true</c> if default values (0, empty strings etc) should be formatted; <c>false</c> otherwise.</param>
Public Sub New(formatDefaultValues As Boolean)
Me.New(formatDefaultValues, TypeRegistry.Empty)
End Sub
''' <summary>
''' Creates a new <see cref="Settings"/> object with the specified formatting of default values
''' and type registry.
''' </summary>
''' <param name="formatDefaultValues"><c>true</c> if default values (0, empty strings etc) should be formatted; <c>false</c> otherwise.</param>
''' <param name="typeRegistry">The <see cref="TypeRegistry"/> to use when formatting <see cref="Any"/> messages.</param>
Public Sub New(formatDefaultValues As Boolean, typeRegistry As TypeRegistry)
Me.FormatDefaultValues = formatDefaultValues
Me.TypeRegistry = CheckNotNull(typeRegistry, NameOf(typeRegistry))
End Sub
End Class
' Effectively a cache of mapping from enum values to the original name as specified in the proto file,
' fetched by reflection.
' The need for this is unfortunate, as is its unbounded size, but realistically it shouldn't cause issues.
Private NotInheritable Class OriginalEnumValueHelper
' TODO: In the future we might want to use ConcurrentDictionary, at the point where all
' the platforms we target have it.
Private Shared ReadOnly dictionaries As Dictionary(Of System.Type, Dictionary(Of Object, String)) = New Dictionary(Of System.Type, Dictionary(Of Object, String))()
Friend Shared Function GetOriginalName(value As Object) As String
Dim enumType = value.GetType()
Dim nameMapping As Dictionary(Of Object, String)
SyncLock dictionaries
If Not dictionaries.TryGetValue(enumType, nameMapping) Then
nameMapping = GetNameMapping(enumType)
dictionaries(enumType) = nameMapping
End If
End SyncLock
Dim originalName As String
' If this returns false, originalName will be null, which is what we want.
nameMapping.TryGetValue(value, originalName)
Return originalName
End Function
#If DOTNET35
// TODO: Consider adding functionality to TypeExtensions to avoid this difference.
private static Dictionary<object, string> GetNameMapping(System.Type enumType) =>
enumType.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)
.ToDictionary(f => f.GetValue(null),
f => (f.GetCustomAttributes(typeof(OriginalNameAttribute), false)
.FirstOrDefault() as OriginalNameAttribute)
// If the attribute hasn't been applied, fall back to the name of the field.
?.Name ?? f.Name);
#Else
Private Shared Function GetNameMapping(enumType As System.Type) As Dictionary(Of Object, String)
' If the attribute hasn't been applied, fall back to the name of the field.
Return enumType.GetTypeInfo().DeclaredFields.Where(Function(f) f.IsStatic).ToDictionary(Function(f) f.GetValue(Nothing), Function(f) If(f.GetCustomAttributes(Of OriginalNameAttribute)().FirstOrDefault()?.Name, f.Name))
End Function
#End If
End Class
End Class
End Namespace

@ -0,0 +1,928 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2015 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports Google.Protobuf.Reflection
Imports Google.Protobuf.WellKnownTypes
Imports System
Imports System.Collections
Imports System.Collections.Generic
Imports System.Globalization
Imports System.IO
Imports System.Text
Imports System.Text.RegularExpressions
Namespace Google.Protobuf
''' <summary>
''' Reflection-based converter from JSON to messages.
''' </summary>
''' <remarks>
''' <para>
''' Instances of this class are thread-safe, with no mutable state.
''' </para>
''' <para>
''' This is a simple start to get JSON parsing working. As it's reflection-based,
''' it's not as quick as baking calls into generated messages - but is a simpler implementation.
''' (This code is generally not heavily optimized.)
''' </para>
''' </remarks>
Public NotInheritable Class JsonParser
' Note: using 0-9 instead of \d to ensure no non-ASCII digits.
' This regex isn't a complete validator, but will remove *most* invalid input. We rely on parsing to do the rest.
Private Shared ReadOnly TimestampRegex As Regex = New Regex("^(?<datetime>[0-9]{4}-[01][0-9]-[0-3][0-9]T[012][0-9]:[0-5][0-9]:[0-5][0-9])(?<subseconds>\.[0-9]{1,9})?(?<offset>(Z|[+-][0-1][0-9]:[0-5][0-9]))$", CompiledRegexWhereAvailable)
Private Shared ReadOnly DurationRegex As Regex = New Regex("^(?<sign>-)?(?<int>[0-9]{1,12})(?<subseconds>\.[0-9]{1,9})?s$", CompiledRegexWhereAvailable)
Private Shared ReadOnly SubsecondScalingFactors As Integer() = {0, 100000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1}
Private Shared ReadOnly FieldMaskPathSeparators As Char() = {","c}
Private Shared ReadOnly defaultInstance As JsonParser = New JsonParser(Settings.Default)
' TODO: Consider introducing a class containing parse state of the parser, tokenizer and depth. That would simplify these handlers
' and the signatures of various methods.
Private Shared ReadOnly WellKnownTypeHandlers As Dictionary(Of String, Action(Of JsonParser, IMessage, JsonTokenizer)) = New Dictionary(Of String, Action(Of JsonParser, IMessage, JsonTokenizer)) From {
{Timestamp.DescriptorProp.FullName, Sub(parser, message, tokenizer) MergeTimestamp(message, tokenizer.Next())},
{Duration.DescriptorProp.FullName, Sub(parser, message, tokenizer) MergeDuration(message, tokenizer.Next())},
{Value.DescriptorProp.FullName, Sub(parser, message, tokenizer) parser.MergeStructValue(message, tokenizer)},
{ListValue.DescriptorProp.FullName, Sub(parser, message, tokenizer) parser.MergeRepeatedField(message, message.Descriptor.Fields(ListValue.ValuesFieldNumber), tokenizer)},
{Struct.DescriptorProp.FullName, Sub(parser, message, tokenizer) parser.MergeStruct(message, tokenizer)},
{Any.DescriptorProp.FullName, Sub(parser, message, tokenizer) parser.MergeAny(message, tokenizer)},
{FieldMask.DescriptorProp.FullName, Sub(parser, message, tokenizer) MergeFieldMask(message, tokenizer.Next())},
{Int32Value.DescriptorProp.FullName, AddressOf MergeWrapperField},
{Int64Value.DescriptorProp.FullName, AddressOf MergeWrapperField},
{UInt32Value.DescriptorProp.FullName, AddressOf MergeWrapperField},
{UInt64Value.DescriptorProp.FullName, AddressOf MergeWrapperField},
{FloatValue.DescriptorProp.FullName, AddressOf MergeWrapperField},
{DoubleValue.DescriptorProp.FullName, AddressOf MergeWrapperField},
{BytesValue.DescriptorProp.FullName, AddressOf MergeWrapperField},
{StringValue.DescriptorProp.FullName, AddressOf MergeWrapperField},
{BoolValue.DescriptorProp.FullName, AddressOf MergeWrapperField}
}
' Convenience method to avoid having to repeat the same code multiple times in the above
' dictionary initialization.
Private Shared Sub MergeWrapperField(parser As JsonParser, message As IMessage, tokenizer As JsonTokenizer)
parser.MergeField(message, message.Descriptor.Fields(WrapperValueFieldNumber), tokenizer)
End Sub
''' <summary>
''' Returns a formatter using the default settings.
''' </summary>
Public Shared ReadOnly Property [Default] As JsonParser
Get
Return defaultInstance
End Get
End Property
Private ReadOnly settingsField As Settings
''' <summary>
''' Creates a new formatted with the given settings.
''' </summary>
''' <param name="settings">The settings.</param>
Public Sub New(settings As Settings)
settingsField = settings
End Sub
''' <summary>
''' Parses <paramrefname="json"/> and merges the information into the given message.
''' </summary>
''' <param name="message">The message to merge the JSON information into.</param>
''' <param name="json">The JSON to parse.</param>
Friend Sub Merge(message As IMessage, json As String)
Merge(message, New StringReader(json))
End Sub
''' <summary>
''' Parses JSON read from <paramrefname="jsonReader"/> and merges the information into the given message.
''' </summary>
''' <param name="message">The message to merge the JSON information into.</param>
''' <param name="jsonReader">Reader providing the JSON to parse.</param>
Friend Sub Merge(message As IMessage, jsonReader As TextReader)
Dim tokenizer = JsonTokenizer.FromTextReader(jsonReader)
Merge(message, tokenizer)
Dim lastToken = tokenizer.Next()
If lastToken IsNot JsonToken.EndDocument Then
Throw New InvalidProtocolBufferException("Expected end of JSON after object")
End If
End Sub
''' <summary>
''' Merges the given message using data from the given tokenizer. In most cases, the next
''' token should be a "start object" token, but wrapper types and nullity can invalidate
''' that assumption. This is implemented as an LL(1) recursive descent parser over the stream
''' of tokens provided by the tokenizer. This token stream is assumed to be valid JSON, with the
''' tokenizer performing that validation - but not every token stream is valid "protobuf JSON".
''' </summary>
Private Sub Merge(message As IMessage, tokenizer As JsonTokenizer)
If tokenizer.ObjectDepth > settingsField.RecursionLimit Then
Throw InvalidProtocolBufferException.JsonRecursionLimitExceeded()
End If
If message.Descriptor.IsWellKnownType Then
Dim handler As Action(Of JsonParser, IMessage, JsonTokenizer)
If WellKnownTypeHandlers.TryGetValue(message.Descriptor.FullName, handler) Then
handler(Me, message, tokenizer)
Return
End If
' Well-known types with no special handling continue in the normal way.
End If
Dim token = tokenizer.Next()
If token.Type <> JsonToken.TokenType.StartObject Then
Throw New InvalidProtocolBufferException("Expected an object")
End If
Dim descriptor = message.Descriptor
Dim jsonFieldMap = descriptor.Fields.ByJsonName()
' All the oneof fields we've already accounted for - we can only see each of them once.
' The set is created lazily to avoid the overhead of creating a set for every message
' we parsed, when oneofs are relatively rare.
Dim seenOneofs As HashSet(Of OneofDescriptor) = Nothing
While True
token = tokenizer.Next()
If token.Type = JsonToken.TokenType.EndObject Then
Return
End If
If token.Type <> JsonToken.TokenType.Name Then
Throw New InvalidOperationException("Unexpected token type " & token.Type)
End If
Dim name = token.StringValue
Dim field As FieldDescriptor
If jsonFieldMap.TryGetValue(name, field) Then
If field.ContainingOneof IsNot Nothing Then
If seenOneofs Is Nothing Then
seenOneofs = New HashSet(Of OneofDescriptor)()
End If
If Not seenOneofs.Add(field.ContainingOneof) Then
Throw New InvalidProtocolBufferException($"Multiple values specified for oneof {field.ContainingOneof.Name}")
End If
End If
MergeField(message, field, tokenizer)
Else
' TODO: Is this what we want to do? If not, we'll need to skip the value,
' which may be an object or array. (We might want to put code in the tokenizer
' to do that.)
Throw New InvalidProtocolBufferException("Unknown field: " & name)
End If
End While
End Sub
Private Sub MergeField(message As IMessage, field As FieldDescriptor, tokenizer As JsonTokenizer)
Dim token = tokenizer.Next()
If token.Type = JsonToken.TokenType.Null Then
' Clear the field if we see a null token, unless it's for a singular field of type
' google.protobuf.Value.
' Note: different from Java API, which just ignores it.
' TODO: Bring it more in line? Discuss...
If field.IsMap OrElse field.IsRepeated OrElse Not IsGoogleProtobufValueField(field) Then
field.Accessor.Clear(message)
Return
End If
End If
tokenizer.PushBack(token)
If field.IsMap Then
MergeMapField(message, field, tokenizer)
ElseIf field.IsRepeated Then
MergeRepeatedField(message, field, tokenizer)
Else
Dim value = ParseSingleValue(field, tokenizer)
field.Accessor.SetValue(message, value)
End If
End Sub
Private Sub MergeRepeatedField(message As IMessage, field As FieldDescriptor, tokenizer As JsonTokenizer)
Dim token = tokenizer.Next()
If token.Type <> JsonToken.TokenType.StartArray Then
Throw New InvalidProtocolBufferException("Repeated field value was not an array. Token type: " & token.Type)
End If
Dim list = CType(field.Accessor.GetValue(message), IList)
While True
token = tokenizer.Next()
If token.Type = JsonToken.TokenType.EndArray Then
Return
End If
tokenizer.PushBack(token)
If token.Type = JsonToken.TokenType.Null Then
Throw New InvalidProtocolBufferException("Repeated field elements cannot be null")
End If
list.Add(ParseSingleValue(field, tokenizer))
End While
End Sub
Private Sub MergeMapField(message As IMessage, field As FieldDescriptor, tokenizer As JsonTokenizer)
' Map fields are always objects, even if the values are well-known types: ParseSingleValue handles those.
Dim token = tokenizer.Next()
If token.Type <> JsonToken.TokenType.StartObject Then
Throw New InvalidProtocolBufferException("Expected an object to populate a map")
End If
Dim type = field.MessageType
Dim keyField = type.FindFieldByNumber(1)
Dim valueField = type.FindFieldByNumber(2)
If keyField Is Nothing OrElse valueField Is Nothing Then
Throw New InvalidProtocolBufferException("Invalid map field: " & field.FullName)
End If
Dim dictionary = CType(field.Accessor.GetValue(message), IDictionary)
While True
token = tokenizer.Next()
If token.Type = JsonToken.TokenType.EndObject Then
Return
End If
Dim key = ParseMapKey(keyField, token.StringValue)
Dim value = ParseSingleValue(valueField, tokenizer)
If value Is Nothing Then
Throw New InvalidProtocolBufferException("Map values must not be null")
End If
dictionary(key) = value
End While
End Sub
Private Shared Function IsGoogleProtobufValueField(field As FieldDescriptor) As Boolean
Return field.FieldType = FieldType.Message AndAlso Equals(field.MessageType.FullName, Value.DescriptorProp.FullName)
End Function
Private Function ParseSingleValue(field As FieldDescriptor, tokenizer As JsonTokenizer) As Object
Dim token = tokenizer.Next()
If token.Type = JsonToken.TokenType.Null Then
' TODO: In order to support dynamic messages, we should really build this up
' dynamically.
If IsGoogleProtobufValueField(field) Then
Return Value.ForNull()
End If
Return Nothing
End If
Dim fieldType = field.FieldType
If fieldType = FieldType.Message Then
' Parse wrapper types as their constituent types.
' TODO: What does this mean for null?
If field.MessageType.IsWrapperType Then
field = field.MessageType.Fields(WrapperValueFieldNumber)
fieldType = field.FieldType
Else
' TODO: Merge the current value in message? (Public API currently doesn't make this relevant as we don't expose merging.)
tokenizer.PushBack(token)
Dim subMessage = NewMessageForField(field)
Merge(subMessage, tokenizer)
Return subMessage
End If
End If
Select Case token.Type
Case JsonToken.TokenType.True, JsonToken.TokenType.False
If fieldType = FieldType.Bool Then
Return token.Type = JsonToken.TokenType.True
End If
' Fall through to "we don't support this type for this case"; could duplicate the behaviour of the default
' case instead, but this way we'd only need to change one place.
GoTo _Select0_CaseDefault
Case JsonToken.TokenType.StringValue
Return ParseSingleStringValue(field, token.StringValue)
' Note: not passing the number value itself here, as we may end up storing the string value in the token too.
Case JsonToken.TokenType.Number
Return ParseSingleNumberValue(field, token)
Case JsonToken.TokenType.Null
Throw New NotImplementedException("Haven't worked out what to do for null yet")
Case Else
_Select0_CaseDefault:
Throw New InvalidProtocolBufferException("Unsupported JSON token type " & token.Type & " for field type " & fieldType)
End Select
End Function
''' <summary>
''' Parses <paramrefname="json"/> into a new message.
''' </summary>
''' <typeparamname="T">The type of message to create.</typeparam>
''' <param name="json">The JSON to parse.</param>
''' <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
''' <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception>
Public Function Parse(Of T As {IMessage, New})(json As String) As T
CheckNotNull(json, NameOf(json))
Return Parse(Of T)(New StringReader(json))
End Function
''' <summary>
''' Parses JSON read from <paramrefname="jsonReader"/> into a new message.
''' </summary>
''' <typeparamname="T">The type of message to create.</typeparam>
''' <param name="jsonReader">Reader providing the JSON to parse.</param>
''' <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
''' <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception>
Public Function Parse(Of T As {IMessage, New})(jsonReader As TextReader) As T
CheckNotNull(jsonReader, NameOf(jsonReader))
Dim message As T = New T()
Merge(message, jsonReader)
Return message
End Function
''' <summary>
''' Parses <paramrefname="json"/> into a new message.
''' </summary>
''' <param name="json">The JSON to parse.</param>
''' <param name="descriptor">Descriptor of message type to parse.</param>
''' <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
''' <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception>
Public Function Parse(json As String, descriptor As MessageDescriptor) As IMessage
CheckNotNull(json, NameOf(json))
CheckNotNull(descriptor, NameOf(descriptor))
Return Parse(New StringReader(json), descriptor)
End Function
''' <summary>
''' Parses JSON read from <paramrefname="jsonReader"/> into a new message.
''' </summary>
''' <param name="jsonReader">Reader providing the JSON to parse.</param>
''' <param name="descriptor">Descriptor of message type to parse.</param>
''' <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
''' <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception>
Public Function Parse(jsonReader As TextReader, descriptor As MessageDescriptor) As IMessage
CheckNotNull(jsonReader, NameOf(jsonReader))
CheckNotNull(descriptor, NameOf(descriptor))
Dim message As IMessage = descriptor.Parser.CreateTemplate()
Merge(message, jsonReader)
Return message
End Function
Private Sub MergeStructValue(message As IMessage, tokenizer As JsonTokenizer)
Dim firstToken = tokenizer.Next()
Dim fields = message.Descriptor.Fields
Select Case firstToken.Type
Case JsonToken.TokenType.Null
fields(Value.NullValueFieldNumber).Accessor.SetValue(message, 0)
Return
Case JsonToken.TokenType.StringValue
fields(Value.StringValueFieldNumber).Accessor.SetValue(message, firstToken.StringValue)
Return
Case JsonToken.TokenType.Number
fields(Value.NumberValueFieldNumber).Accessor.SetValue(message, firstToken.NumberValue)
Return
Case JsonToken.TokenType.False, JsonToken.TokenType.True
fields(Value.BoolValueFieldNumber).Accessor.SetValue(message, firstToken.Type = JsonToken.TokenType.True)
Return
Case JsonToken.TokenType.StartObject
Dim field = fields(Value.StructValueFieldNumber)
Dim structMessage = NewMessageForField(field)
tokenizer.PushBack(firstToken)
Merge(structMessage, tokenizer)
field.Accessor.SetValue(message, structMessage)
Return
Case JsonToken.TokenType.StartArray
Dim field = fields(Value.ListValueFieldNumber)
Dim list = NewMessageForField(field)
tokenizer.PushBack(firstToken)
Merge(list, tokenizer)
field.Accessor.SetValue(message, list)
Return
Case Else
Throw New InvalidOperationException("Unexpected token type: " & firstToken.Type)
End Select
End Sub
Private Sub MergeStruct(message As IMessage, tokenizer As JsonTokenizer)
Dim token = tokenizer.Next()
If token.Type <> JsonToken.TokenType.StartObject Then
Throw New InvalidProtocolBufferException("Expected object value for Struct")
End If
tokenizer.PushBack(token)
Dim field = message.Descriptor.Fields(Struct.FieldsFieldNumber)
MergeMapField(message, field, tokenizer)
End Sub
Private Sub MergeAny(message As IMessage, tokenizer As JsonTokenizer)
' Record the token stream until we see the @type property. At that point, we can take the value, consult
' the type registry for the relevant message, and replay the stream, omitting the @type property.
Dim tokens = New List(Of JsonToken)()
Dim token = tokenizer.Next()
If token.Type <> JsonToken.TokenType.StartObject Then
Throw New InvalidProtocolBufferException("Expected object value for Any")
End If
Dim typeUrlObjectDepth = tokenizer.ObjectDepth
' The check for the property depth protects us from nested Any values which occur before the type URL
' for *this* Any.
While token.Type <> JsonToken.TokenType.Name OrElse Not Equals(token.StringValue, JsonFormatter.AnyTypeUrlField) OrElse tokenizer.ObjectDepth <> typeUrlObjectDepth
tokens.Add(token)
token = tokenizer.Next()
If tokenizer.ObjectDepth < typeUrlObjectDepth Then
Throw New InvalidProtocolBufferException("Any message with no @type")
End If
End While
' Don't add the @type property or its value to the recorded token list
token = tokenizer.Next()
If token.Type <> JsonToken.TokenType.StringValue Then
Throw New InvalidProtocolBufferException("Expected string value for Any.@type")
End If
Dim typeUrl = token.StringValue
Dim typeName = Any.GetTypeName(typeUrl)
Dim descriptor = settingsField.TypeRegistry.Find(typeName)
If descriptor Is Nothing Then
Throw New InvalidOperationException($"Type registry has no descriptor for type name '{typeName}'")
End If
' Now replay the token stream we've already read and anything that remains of the object, just parsing it
' as normal. Our original tokenizer should end up at the end of the object.
Dim replay = JsonTokenizer.FromReplayedTokens(tokens, tokenizer)
Dim body = descriptor.Parser.CreateTemplate()
If descriptor.IsWellKnownType Then
MergeWellKnownTypeAnyBody(body, replay)
Else
Merge(body, replay)
End If
Dim data = body.ToByteString()
' Now that we have the message data, we can pack it into an Any (the message received as a parameter).
message.Descriptor.Fields(Any.TypeUrlFieldNumber).Accessor.SetValue(message, typeUrl)
message.Descriptor.Fields(Any.ValueFieldNumber).Accessor.SetValue(message, data)
End Sub
' Well-known types end up in a property called "value" in the JSON. As there's no longer a @type property
' in the given JSON token stream, we should *only* have tokens of start-object, name("value"), the value
' itself, and then end-object.
Private Sub MergeWellKnownTypeAnyBody(body As IMessage, tokenizer As JsonTokenizer)
Dim token = tokenizer.Next() ' Definitely start-object; checked in previous method
token = tokenizer.Next()
' TODO: What about an absent Int32Value, for example?
If token.Type <> JsonToken.TokenType.Name OrElse Not Equals(token.StringValue, JsonFormatter.AnyWellKnownTypeValueField) Then
Throw New InvalidProtocolBufferException($"Expected '{JsonFormatter.AnyWellKnownTypeValueField}' property for well-known type Any body")
End If
Merge(body, tokenizer)
token = tokenizer.Next()
If token.Type <> JsonToken.TokenType.EndObject Then
Throw New InvalidProtocolBufferException($"Expected end-object token after @type/value for well-known type")
End If
End Sub
#Region "Utility methods which don't depend on the state (or settings) of the parser."
Private Shared Function ParseMapKey(field As FieldDescriptor, keyText As String) As Object
Select Case field.FieldType
Case FieldType.Bool
If Equals(keyText, "true") Then
Return True
End If
If Equals(keyText, "false") Then
Return False
End If
Throw New InvalidProtocolBufferException("Invalid string for bool map key: " & keyText)
Case FieldType.String
Return keyText
Case FieldType.Int32, FieldType.SInt32, FieldType.SFixed32
Return ParseNumericString(keyText, New Func(Of String, NumberStyles, IFormatProvider, Integer)(AddressOf Integer.Parse))
Case FieldType.UInt32, FieldType.Fixed32
Return ParseNumericString(keyText, New Func(Of String, NumberStyles, IFormatProvider, UInteger)(AddressOf UInteger.Parse))
Case FieldType.Int64, FieldType.SInt64, FieldType.SFixed64
Return ParseNumericString(keyText, New Func(Of String, NumberStyles, IFormatProvider, Long)(AddressOf Long.Parse))
Case FieldType.UInt64, FieldType.Fixed64
Return ParseNumericString(keyText, New Func(Of String, NumberStyles, IFormatProvider, ULong)(AddressOf ULong.Parse))
Case Else
Throw New InvalidProtocolBufferException("Invalid field type for map: " & field.FieldType)
End Select
End Function
Private Shared Function ParseSingleNumberValue(field As FieldDescriptor, token As JsonToken) As Object
Dim value = token.NumberValue
' BEGIN TODO : Visual Basic does not support checked statements!
Try
Select Case field.FieldType
Case FieldType.Int32, FieldType.SInt32, FieldType.SFixed32
CheckInteger(value)
Return CInt(value)
Case FieldType.UInt32, FieldType.Fixed32
CheckInteger(value)
Return CUInt(value)
Case FieldType.Int64, FieldType.SInt64, FieldType.SFixed64
CheckInteger(value)
Return CLng(value)
Case FieldType.UInt64, FieldType.Fixed64
CheckInteger(value)
Return CULng(value)
Case FieldType.Double
Return value
Case FieldType.Float
If Double.IsNaN(value) Then
Return Single.NaN
End If
If value > Single.MaxValue OrElse value < Single.MinValue Then
If Double.IsPositiveInfinity(value) Then
Return Single.PositiveInfinity
End If
If Double.IsNegativeInfinity(value) Then
Return Single.NegativeInfinity
End If
Throw New InvalidProtocolBufferException($"Value out of range: {value}")
End If
Return CSng(value)
Case FieldType.Enum
CheckInteger(value)
' Just return it as an int, and let the CLR convert it.
' Note that we deliberately don't check that it's a known value.
Return CInt(value)
Case Else
Throw New InvalidProtocolBufferException($"Unsupported conversion from JSON number for field type {field.FieldType}")
End Select
Catch __unusedOverflowException1__ As OverflowException
Throw New InvalidProtocolBufferException($"Value out of range: {value}")
End Try
' END TODO : Visual Basic does not support checked statements!
End Function
Private Shared Sub CheckInteger(value As Double)
If Double.IsInfinity(value) OrElse Double.IsNaN(value) Then
Throw New InvalidProtocolBufferException($"Value not an integer: {value}")
End If
If value <> Math.Floor(value) Then
Throw New InvalidProtocolBufferException($"Value not an integer: {value}")
End If
End Sub
Private Shared Function ParseSingleStringValue(field As FieldDescriptor, text As String) As Object
Select Case field.FieldType
Case FieldType.String
Return text
Case FieldType.Bytes
Try
Return ByteString.FromBase64(text)
Catch e As FormatException
Throw InvalidProtocolBufferException.InvalidBase64(e)
End Try
Case FieldType.Int32, FieldType.SInt32, FieldType.SFixed32
Return ParseNumericString(text, New Func(Of String, NumberStyles, IFormatProvider, Integer)(AddressOf Integer.Parse))
Case FieldType.UInt32, FieldType.Fixed32
Return ParseNumericString(text, New Func(Of String, NumberStyles, IFormatProvider, UInteger)(AddressOf UInteger.Parse))
Case FieldType.Int64, FieldType.SInt64, FieldType.SFixed64
Return ParseNumericString(text, New Func(Of String, NumberStyles, IFormatProvider, Long)(AddressOf Long.Parse))
Case FieldType.UInt64, FieldType.Fixed64
Return ParseNumericString(text, New Func(Of String, NumberStyles, IFormatProvider, ULong)(AddressOf ULong.Parse))
Case FieldType.Double
Dim d As Double = ParseNumericString(text, New Func(Of String, NumberStyles, IFormatProvider, Double)(AddressOf Double.Parse))
ValidateInfinityAndNan(text, Double.IsPositiveInfinity(d), Double.IsNegativeInfinity(d), Double.IsNaN(d))
Return d
Case FieldType.Float
Dim f As Single = ParseNumericString(text, New Func(Of String, NumberStyles, IFormatProvider, Single)(AddressOf Single.Parse))
ValidateInfinityAndNan(text, Single.IsPositiveInfinity(f), Single.IsNegativeInfinity(f), Single.IsNaN(f))
Return f
Case FieldType.Enum
Dim enumValue = field.EnumType.FindValueByName(text)
If enumValue Is Nothing Then
Throw New InvalidProtocolBufferException($"Invalid enum value: {text} for enum type: {field.EnumType.FullName}")
End If
' Just return it as an int, and let the CLR convert it.
Return enumValue.Number
Case Else
Throw New InvalidProtocolBufferException($"Unsupported conversion from JSON string for field type {field.FieldType}")
End Select
End Function
''' <summary>
''' Creates a new instance of the message type for the given field.
''' </summary>
Private Shared Function NewMessageForField(field As FieldDescriptor) As IMessage
Return field.MessageType.Parser.CreateTemplate()
End Function
Private Shared Function ParseNumericString(Of T)(text As String, parser As Func(Of String, NumberStyles, IFormatProvider, T)) As T
' Can't prohibit this with NumberStyles.
If text.StartsWith("+") Then
Throw New InvalidProtocolBufferException($"Invalid numeric value: {text}")
End If
If text.StartsWith("0") AndAlso text.Length > 1 Then
If text(1) >= "0"c AndAlso text(1) <= "9"c Then
Throw New InvalidProtocolBufferException($"Invalid numeric value: {text}")
End If
ElseIf text.StartsWith("-0") AndAlso text.Length > 2 Then
If text(2) >= "0"c AndAlso text(2) <= "9"c Then
Throw New InvalidProtocolBufferException($"Invalid numeric value: {text}")
End If
End If
Try
Return parser(text, NumberStyles.AllowLeadingSign Or NumberStyles.AllowDecimalPoint Or NumberStyles.AllowExponent, CultureInfo.InvariantCulture)
Catch __unusedFormatException1__ As FormatException
Throw New InvalidProtocolBufferException($"Invalid numeric value for type: {text}")
Catch __unusedOverflowException2__ As OverflowException
Throw New InvalidProtocolBufferException($"Value out of range: {text}")
End Try
End Function
''' <summary>
''' Checks that any infinite/NaN values originated from the correct text.
''' This corrects the lenient whitespace handling of double.Parse/float.Parse, as well as the
''' way that Mono parses out-of-range values as infinity.
''' </summary>
Private Shared Sub ValidateInfinityAndNan(text As String, isPositiveInfinity As Boolean, isNegativeInfinity As Boolean, isNaN As Boolean)
If isPositiveInfinity AndAlso Not Equals(text, "Infinity") OrElse isNegativeInfinity AndAlso Not Equals(text, "-Infinity") OrElse isNaN AndAlso Not Equals(text, "NaN") Then
Throw New InvalidProtocolBufferException($"Invalid numeric value: {text}")
End If
End Sub
Private Shared Sub MergeTimestamp(message As IMessage, token As JsonToken)
If token.Type <> JsonToken.TokenType.StringValue Then
Throw New InvalidProtocolBufferException("Expected string value for Timestamp")
End If
Dim match = TimestampRegex.Match(token.StringValue)
If Not match.Success Then
Throw New InvalidProtocolBufferException($"Invalid Timestamp value: {token.StringValue}")
End If
Dim dateTime = match.Groups("datetime").Value
Dim subseconds = match.Groups("subseconds").Value
Dim offset = match.Groups("offset").Value
Try
Dim parsed = Date.ParseExact(dateTime, "yyyy-MM-dd'T'HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal Or DateTimeStyles.AdjustToUniversal)
' TODO: It would be nice not to have to create all these objects... easy to optimize later though.
Dim timestamp As Timestamp = Timestamp.FromDateTime(parsed)
Dim nanosToAdd = 0
If Not Equals(subseconds, "") Then
' This should always work, as we've got 1-9 digits.
Dim parsedFraction = Integer.Parse(subseconds.Substring(1), CultureInfo.InvariantCulture)
nanosToAdd = parsedFraction * SubsecondScalingFactors(subseconds.Length)
End If
Dim secondsToAdd = 0
If Not Equals(offset, "Z") Then
' This is the amount we need to *subtract* from the local time to get to UTC - hence - => +1 and vice versa.
Dim sign = If(offset(0) = "-"c, 1, -1)
Dim hours = Integer.Parse(offset.Substring(1, 2), CultureInfo.InvariantCulture)
Dim minutes = Integer.Parse(offset.Substring(4, 2))
Dim totalMinutes = hours * 60 + minutes
If totalMinutes > 18 * 60 Then
Throw New InvalidProtocolBufferException("Invalid Timestamp value: " & token.StringValue)
End If
If totalMinutes = 0 AndAlso sign = 1 Then
' This is an offset of -00:00, which means "unknown local offset". It makes no sense for a timestamp.
Throw New InvalidProtocolBufferException("Invalid Timestamp value: " & token.StringValue)
End If
' We need to *subtract* the offset from local time to get UTC.
secondsToAdd = sign * totalMinutes * 60
End If
' Ensure we've got the right signs. Currently unnecessary, but easy to do.
If secondsToAdd < 0 AndAlso nanosToAdd > 0 Then
secondsToAdd += 1
nanosToAdd = nanosToAdd - Duration.NanosecondsPerSecond
End If
If secondsToAdd <> 0 OrElse nanosToAdd <> 0 Then
timestamp += New Duration With {
.Nanos = nanosToAdd,
.Seconds = secondsToAdd
}
' The resulting timestamp after offset change would be out of our expected range. Currently the Timestamp message doesn't validate this
' anywhere, but we shouldn't parse it.
If timestamp.Seconds < Timestamp.UnixSecondsAtBclMinValue OrElse timestamp.Seconds > Timestamp.UnixSecondsAtBclMaxValue Then
Throw New InvalidProtocolBufferException("Invalid Timestamp value: " & token.StringValue)
End If
End If
message.Descriptor.Fields(Timestamp.SecondsFieldNumber).Accessor.SetValue(message, timestamp.Seconds)
message.Descriptor.Fields(Timestamp.NanosFieldNumber).Accessor.SetValue(message, timestamp.Nanos)
Catch __unusedFormatException1__ As FormatException
Throw New InvalidProtocolBufferException("Invalid Timestamp value: " & token.StringValue)
End Try
End Sub
Private Shared Sub MergeDuration(message As IMessage, token As JsonToken)
If token.Type <> JsonToken.TokenType.StringValue Then
Throw New InvalidProtocolBufferException("Expected string value for Duration")
End If
Dim match = DurationRegex.Match(token.StringValue)
If Not match.Success Then
Throw New InvalidProtocolBufferException("Invalid Duration value: " & token.StringValue)
End If
Dim sign = match.Groups("sign").Value
Dim secondsText = match.Groups("int").Value
' Prohibit leading insignficant zeroes
If secondsText(0) = "0"c AndAlso secondsText.Length > 1 Then
Throw New InvalidProtocolBufferException("Invalid Duration value: " & token.StringValue)
End If
Dim subseconds = match.Groups("subseconds").Value
Dim multiplier = If(Equals(sign, "-"), -1, 1)
Try
Dim seconds = Long.Parse(secondsText, CultureInfo.InvariantCulture) * multiplier
Dim nanos = 0
If Not Equals(subseconds, "") Then
' This should always work, as we've got 1-9 digits.
Dim parsedFraction = Integer.Parse(subseconds.Substring(1))
nanos = parsedFraction * SubsecondScalingFactors(subseconds.Length) * multiplier
End If
If Not Duration.IsNormalized(seconds, nanos) Then
Throw New InvalidProtocolBufferException($"Invalid Duration value: {token.StringValue}")
End If
message.Descriptor.Fields(Duration.SecondsFieldNumber).Accessor.SetValue(message, seconds)
message.Descriptor.Fields(Duration.NanosFieldNumber).Accessor.SetValue(message, nanos)
Catch __unusedFormatException1__ As FormatException
Throw New InvalidProtocolBufferException($"Invalid Duration value: {token.StringValue}")
End Try
End Sub
Private Shared Sub MergeFieldMask(message As IMessage, token As JsonToken)
If token.Type <> JsonToken.TokenType.StringValue Then
Throw New InvalidProtocolBufferException("Expected string value for FieldMask")
End If
' TODO: Do we *want* to remove empty entries? Probably okay to treat "" as "no paths", but "foo,,bar"?
Dim jsonPaths = token.StringValue.Split(FieldMaskPathSeparators, StringSplitOptions.RemoveEmptyEntries)
Dim messagePaths = CType(message.Descriptor.Fields(FieldMask.PathsFieldNumber).Accessor.GetValue(message), IList)
For Each path In jsonPaths
messagePaths.Add(ToSnakeCase(path))
Next
End Sub
' Ported from src/google/protobuf/util/internal/utility.cc
Private Shared Function ToSnakeCase(text As String) As String
Dim builder = New StringBuilder(text.Length * 2)
' Note: this is probably unnecessary now, but currently retained to be as close as possible to the
' C++, whilst still throwing an exception on underscores.
Dim wasNotUnderscore = False ' Initialize to false for case 1 (below)
Dim wasNotCap = False
For i = 0 To text.Length - 1
Dim c = text(i)
If c >= "A"c AndAlso c <= "Z"c Then ' ascii_isupper
' Consider when the current character B is capitalized:
' 1) At beginning of input: "B..." => "b..."
' (e.g. "Biscuit" => "biscuit")
' 2) Following a lowercase: "...aB..." => "...a_b..."
' (e.g. "gBike" => "g_bike")
' 3) At the end of input: "...AB" => "...ab"
' (e.g. "GoogleLAB" => "google_lab")
' 4) Followed by a lowercase: "...ABc..." => "...a_bc..."
' (e.g. "GBike" => "g_bike")
If wasNotUnderscore AndAlso (wasNotCap OrElse i + 1 < text.Length AndAlso text(i + 1) >= "a"c AndAlso text(i + 1) <= "z"c) Then ' case 1 out
' case 2 in, case 3 out
' case 3 out
' ascii_islower(text[i + 1])
' case 4 in
' We add an underscore for case 2 and case 4.
builder.Append("_"c)
End If
' ascii_tolower, but we already know that c *is* an upper case ASCII character...
builder.Append(Microsoft.VisualBasic.ChrW(AscW(c) + AscW("a"c) - AscW("A"c)))
wasNotUnderscore = True
wasNotCap = False
Else
builder.Append(c)
If c = "_"c Then
Throw New InvalidProtocolBufferException($"Invalid field mask: {text}")
End If
wasNotUnderscore = True
wasNotCap = True
End If
Next
Return builder.ToString()
End Function
#End Region
''' <summary>
''' Settings controlling JSON parsing.
''' </summary>
Public NotInheritable Class Settings
''' <summary>
''' Default settings, as used by <see cref="JsonParser.Default"/>. This has the same default
''' recursion limit as <see cref="CodedInputStream"/>, and an empty type registry.
''' </summary>
Public Shared ReadOnly Property [Default] As Settings
' Workaround for the Mono compiler complaining about XML comments not being on
' valid language elements.
Shared Sub New()
[Default] = New Settings(CodedInputStream.DefaultRecursionLimit)
End Sub
''' <summary>
''' The maximum depth of messages to parse. Note that this limit only applies to parsing
''' messages, not collections - so a message within a collection within a message only counts as
''' depth 2, not 3.
''' </summary>
Public ReadOnly Property RecursionLimit As Integer
''' <summary>
''' The type registry used to parse <see cref="Any"/> messages.
''' </summary>
Public ReadOnly Property TypeRegistry As TypeRegistry
''' <summary>
''' Creates a new <see cref="Settings"/> object with the specified recursion limit.
''' </summary>
''' <param name="recursionLimit">The maximum depth of messages to parse</param>
Public Sub New(recursionLimit As Integer)
Me.New(recursionLimit, TypeRegistry.Empty)
End Sub
''' <summary>
''' Creates a new <see cref="Settings"/> object with the specified recursion limit and type registry.
''' </summary>
''' <param name="recursionLimit">The maximum depth of messages to parse</param>
''' <param name="typeRegistry">The type registry used to parse <see cref="Any"/> messages</param>
Public Sub New(recursionLimit As Integer, typeRegistry As TypeRegistry)
Me.RecursionLimit = recursionLimit
Me.TypeRegistry = CheckNotNull(typeRegistry, NameOf(typeRegistry))
End Sub
End Class
End Class
End Namespace

@ -0,0 +1,206 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2008 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System
Namespace Google.Protobuf
Friend NotInheritable Class JsonToken
Implements IEquatable(Of JsonToken)
' Tokens with no value can be reused.
Private Shared ReadOnly _true As JsonToken = New JsonToken(TokenType.True)
Private Shared ReadOnly _false As JsonToken = New JsonToken(TokenType.False)
Private Shared ReadOnly _null As JsonToken = New JsonToken(TokenType.Null)
Private Shared ReadOnly startObjectField As JsonToken = New JsonToken(TokenType.StartObject)
Private Shared ReadOnly endObjectField As JsonToken = New JsonToken(TokenType.EndObject)
Private Shared ReadOnly startArrayField As JsonToken = New JsonToken(TokenType.StartArray)
Private Shared ReadOnly endArrayField As JsonToken = New JsonToken(TokenType.EndArray)
Private Shared ReadOnly endDocumentField As JsonToken = New JsonToken(TokenType.EndDocument)
Friend Shared ReadOnly Property Null As JsonToken
Get
Return _null
End Get
End Property
Friend Shared ReadOnly Property [False] As JsonToken
Get
Return _false
End Get
End Property
Friend Shared ReadOnly Property [True] As JsonToken
Get
Return _true
End Get
End Property
Friend Shared ReadOnly Property StartObject As JsonToken
Get
Return startObjectField
End Get
End Property
Friend Shared ReadOnly Property EndObject As JsonToken
Get
Return endObjectField
End Get
End Property
Friend Shared ReadOnly Property StartArray As JsonToken
Get
Return startArrayField
End Get
End Property
Friend Shared ReadOnly Property EndArray As JsonToken
Get
Return endArrayField
End Get
End Property
Friend Shared ReadOnly Property EndDocument As JsonToken
Get
Return endDocumentField
End Get
End Property
Friend Shared Function Name(pName As String) As JsonToken
Return New JsonToken(TokenType.Name, stringValue:=pName)
End Function
Friend Shared Function Value(pValue As String) As JsonToken
Return New JsonToken(TokenType.StringValue, stringValue:=pValue)
End Function
Friend Shared Function Value(pValue As Double) As JsonToken
Return New JsonToken(TokenType.Number, numberValue:=pValue)
End Function
Friend Enum TokenType
Null
[False]
[True]
StringValue
Number
Name
StartObject
EndObject
StartArray
EndArray
EndDocument
End Enum
' A value is a string, number, array, object, null, true or false
' Arrays and objects have start/end
' A document consists of a value
' Objects are name/value sequences.
Private ReadOnly typeField As TokenType
Private ReadOnly stringValueField As String
Private ReadOnly numberValueField As Double
Friend ReadOnly Property Type As TokenType
Get
Return typeField
End Get
End Property
Friend ReadOnly Property StringValue As String
Get
Return stringValueField
End Get
End Property
Friend ReadOnly Property NumberValue As Double
Get
Return numberValueField
End Get
End Property
Private Sub New(type As TokenType, Optional stringValue As String = Nothing, Optional numberValue As Double = 0)
typeField = type
stringValueField = stringValue
numberValueField = numberValue
End Sub
Public Overrides Function Equals(obj As Object) As Boolean
Return Equals(TryCast(obj, JsonToken))
End Function
Public Overrides Function GetHashCode() As Integer
' BEGIN TODO : Visual Basic does not support checked statements!
Dim hash = 17
hash = hash * 31 + typeField
hash = If(Equals(hash * 31 & stringValueField, Nothing), 0, stringValueField.GetHashCode())
hash = hash * 31 + numberValueField.GetHashCode()
Return hash
'END TODO : Visual Basic does not support checked statements!
End Function
Public Overrides Function ToString() As String
Select Case typeField
Case TokenType.Null
Return "null"
Case TokenType.True
Return "true"
Case TokenType.False
Return "false"
Case TokenType.Name
Return "name (" & stringValueField & ")"
Case TokenType.StringValue
Return "value (" & stringValueField & ")"
Case TokenType.Number
Return "number (" & numberValueField & ")"
Case TokenType.StartObject
Return "start-object"
Case TokenType.EndObject
Return "end-object"
Case TokenType.StartArray
Return "start-array"
Case TokenType.EndArray
Return "end-array"
Case TokenType.EndDocument
Return "end-document"
Case Else
Throw New InvalidOperationException("Token is of unknown type " & typeField)
End Select
End Function
Public Overloads Function Equals(other As JsonToken) As Boolean Implements IEquatable(Of JsonToken).Equals
If ReferenceEquals(other, Nothing) Then
Return False
End If
' Note use of other.numberValue.Equals rather than ==, so that NaN compares appropriately.
Return other.typeField = typeField AndAlso Equals(other.stringValueField, stringValueField) AndAlso other.numberValueField.Equals(numberValueField)
End Function
End Class
End Namespace

@ -0,0 +1,685 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2008 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System
Imports System.Collections.Generic
Imports System.Globalization
Imports System.IO
Imports System.Text
Imports System.Runtime.InteropServices
Imports Microsoft.VisualBasic.Language
Namespace Google.Protobuf
''' <summary>
''' Simple but strict JSON tokenizer, rigidly following RFC 7159.
''' </summary>
''' <remarks>
''' <para>
''' This tokenizer is stateful, and only returns "useful" tokens - names, values etc.
''' It does not create tokens for the separator between names and values, or for the comma
''' between values. It validates the token stream as it goes - so callers can assume that the
''' tokens it produces are appropriate. For example, it would never produce "start object, end array."
''' </para>
''' <para>Implementation details: the base class handles single token push-back and </para>
''' <para>Not thread-safe.</para>
''' </remarks>
Friend MustInherit Class JsonTokenizer
''' <summary>
''' Returns the depth of the stack, purely in objects (not collections).
''' Informally, this is the number of remaining unclosed '{' characters we have.
''' </summary>
Private _ObjectDepth As Integer
Private bufferedToken As JsonToken
''' <summary>
''' Creates a tokenizer that reads from the given text reader.
''' </summary>
Friend Shared Function FromTextReader(reader As TextReader) As JsonTokenizer
Return New JsonTextTokenizer(reader)
End Function
''' <summary>
''' Creates a tokenizer that first replays the given list of tokens, then continues reading
''' from another tokenizer. Note that if the returned tokenizer is "pushed back", that does not push back
''' on the continuation tokenizer, or vice versa. Care should be taken when using this method - it was
''' created for the sake of Any parsing.
''' </summary>
Friend Shared Function FromReplayedTokens(tokens As IList(Of JsonToken), continuation As JsonTokenizer) As JsonTokenizer
Return New JsonReplayTokenizer(tokens, continuation)
End Function
Friend Property ObjectDepth As Integer
Get
Return _ObjectDepth
End Get
Private Set(value As Integer)
_ObjectDepth = value
End Set
End Property
' TODO: Why do we allow a different token to be pushed back? It might be better to always remember the previous
' token returned, and allow a parameterless Rewind() method (which could only be called once, just like the current PushBack).
Friend Sub PushBack(token As JsonToken)
If bufferedToken IsNot Nothing Then
Throw New InvalidOperationException("Can't push back twice")
End If
bufferedToken = token
If token.Type = JsonToken.TokenType.StartObject Then
ObjectDepth -= 1
ElseIf token.Type = JsonToken.TokenType.EndObject Then
ObjectDepth += 1
End If
End Sub
''' <summary>
''' Returns the next JSON token in the stream. An EndDocument token is returned to indicate the end of the stream,
''' after which point <c>Next()</c> should not be called again.
''' </summary>
''' <remarks>This implementation provides single-token buffering, and calls <see cref="NextImpl"/> if there is no buffered token.</remarks>
''' <returns>The next token in the stream. This is never null.</returns>
''' <exception cref="InvalidOperationException">This method is called after an EndDocument token has been returned</exception>
''' <exception cref="InvalidJsonException">The input text does not comply with RFC 7159</exception>
Friend Function [Next]() As JsonToken
Dim tokenToReturn As JsonToken
If bufferedToken IsNot Nothing Then
tokenToReturn = bufferedToken
bufferedToken = Nothing
Else
tokenToReturn = NextImpl()
End If
If tokenToReturn.Type = JsonToken.TokenType.StartObject Then
ObjectDepth += 1
ElseIf tokenToReturn.Type = JsonToken.TokenType.EndObject Then
ObjectDepth -= 1
End If
Return tokenToReturn
End Function
''' <summary>
''' Returns the next JSON token in the stream, when requested by the base class. (The <see cref="Next"/> method delegates
''' to this if it doesn't have a buffered token.)
''' </summary>
''' <exception cref="InvalidOperationException">This method is called after an EndDocument token has been returned</exception>
''' <exception cref="InvalidJsonException">The input text does not comply with RFC 7159</exception>
Protected MustOverride Function NextImpl() As JsonToken
''' <summary>
''' Tokenizer which first exhausts a list of tokens, then consults another tokenizer.
''' </summary>
Private Class JsonReplayTokenizer
Inherits JsonTokenizer
Private ReadOnly tokens As IList(Of JsonToken)
Private ReadOnly nextTokenizer As JsonTokenizer
Private nextTokenIndex As Integer
Friend Sub New(tokens As IList(Of JsonToken), nextTokenizer As JsonTokenizer)
Me.tokens = tokens
Me.nextTokenizer = nextTokenizer
End Sub
' FIXME: Object depth not maintained...
Protected Overrides Function NextImpl() As JsonToken
If nextTokenIndex >= tokens.Count Then
Return nextTokenizer.Next()
End If
Return tokens(Math.Min(Threading.Interlocked.Increment(nextTokenIndex), nextTokenIndex - 1))
End Function
End Class
''' <summary>
''' Tokenizer which does all the *real* work of parsing JSON.
''' </summary>
Private NotInheritable Class JsonTextTokenizer
Inherits JsonTokenizer
' The set of states in which a value is valid next token.
Private Shared ReadOnly ValueStates As StateType = StateType.ArrayStart Or StateType.ArrayAfterComma Or StateType.ObjectAfterColon Or StateType.StartOfDocument
Private ReadOnly containerStack As Stack(Of ContainerType) = New Stack(Of ContainerType)()
Private ReadOnly reader As PushBackReader
Private state As StateType
Friend Sub New(reader As TextReader)
Me.reader = New PushBackReader(reader)
state = StateType.StartOfDocument
containerStack.Push(ContainerType.Document)
End Sub
''' <remarks>
''' This method essentially just loops through characters skipping whitespace, validating and
''' changing state (e.g. from ObjectBeforeColon to ObjectAfterColon)
''' until it reaches something which will be a genuine token (e.g. a start object, or a value) at which point
''' it returns the token. Although the method is large, it would be relatively hard to break down further... most
''' of it is the large switch statement, which sometimes returns and sometimes doesn't.
''' </remarks>
Protected Overrides Function NextImpl() As JsonToken
If state = StateType.ReaderExhausted Then
Throw New InvalidOperationException("Next() called after end of document")
End If
While True
Dim [next] = reader.Read()
If [next] Is Nothing Then
ValidateState(StateType.ExpectedEndOfDocument, "Unexpected end of document in state: ")
state = StateType.ReaderExhausted
Return JsonToken.EndDocument
End If
Select Case [next].Value
' Skip whitespace between tokens
Case " "c, Microsoft.VisualBasic.Strings.ChrW(9), Microsoft.VisualBasic.Strings.ChrW(13), Microsoft.VisualBasic.Strings.ChrW(10)
Case ":"c
ValidateState(StateType.ObjectBeforeColon, "Invalid state to read a colon: ")
state = StateType.ObjectAfterColon
Case ","c
ValidateState(StateType.ObjectAfterProperty Or StateType.ArrayAfterValue, "Invalid state to read a colon: ")
state = If(state = StateType.ObjectAfterProperty, StateType.ObjectAfterComma, StateType.ArrayAfterComma)
Case """"c
Dim stringValue As String = ReadString()
If (state And (StateType.ObjectStart Or StateType.ObjectAfterComma)) <> 0 Then
state = StateType.ObjectBeforeColon
Return JsonToken.Name(stringValue)
Else
ValidateAndModifyStateForValue("Invalid state to read a double quote: ")
Return JsonToken.Value(stringValue)
End If
Case "{"c
ValidateState(ValueStates, "Invalid state to read an open brace: ")
state = StateType.ObjectStart
containerStack.Push(ContainerType.Object)
Return JsonToken.StartObject
Case "}"c
ValidateState(StateType.ObjectAfterProperty Or StateType.ObjectStart, "Invalid state to read a close brace: ")
PopContainer()
Return JsonToken.EndObject
Case "["c
ValidateState(ValueStates, "Invalid state to read an open square bracket: ")
state = StateType.ArrayStart
containerStack.Push(ContainerType.Array)
Return JsonToken.StartArray
Case "]"c
ValidateState(StateType.ArrayAfterValue Or StateType.ArrayStart, "Invalid state to read a close square bracket: ")
PopContainer()
Return JsonToken.EndArray
Case "n"c ' Start of null
ConsumeLiteral("null")
ValidateAndModifyStateForValue("Invalid state to read a null literal: ")
Return JsonToken.Null
Case "t"c ' Start of true
ConsumeLiteral("true")
ValidateAndModifyStateForValue("Invalid state to read a true literal: ")
Return JsonToken.True
Case "f"c ' Start of false
ConsumeLiteral("false")
ValidateAndModifyStateForValue("Invalid state to read a false literal: ")
Return JsonToken.False
Case "-"c, "0"c, "1"c, "2"c, "3"c, "4"c, "5"c, "6"c, "7"c, "8"c, "9"c ' Start of a number
Dim number = ReadNumber([next].Value)
ValidateAndModifyStateForValue("Invalid state to read a number token: ")
Return JsonToken.Value(number)
Case Else
Throw New InvalidJsonException("Invalid first character of token: " & [next].Value)
End Select
End While
End Function
Private Sub ValidateState(validStates As StateType, errorPrefix As String)
If (validStates And state) = 0 Then
Throw reader.CreateException(errorPrefix & state)
End If
End Sub
''' <summary>
''' Reads a string token. It is assumed that the opening " has already been read.
''' </summary>
Private Function ReadString() As String
Dim value = New StringBuilder()
Dim haveHighSurrogate = False
While True
Dim c = reader.ReadOrFail("Unexpected end of text while reading string")
If c < " "c Then
Throw reader.CreateException(String.Format(CultureInfo.InvariantCulture, "Invalid character in string literal: U+{0:x4}", Microsoft.VisualBasic.AscW(c)))
End If
If c = """"c Then
If haveHighSurrogate Then
Throw reader.CreateException("Invalid use of surrogate pair code units")
End If
Return value.ToString()
End If
If c = "\"c Then
c = ReadEscapedCharacter()
End If
' TODO: Consider only allowing surrogate pairs that are either both escaped,
' or both not escaped. It would be a very odd text stream that contained a "lone" high surrogate
' followed by an escaped low surrogate or vice versa... and that couldn't even be represented in UTF-8.
If haveHighSurrogate <> Char.IsLowSurrogate(c) Then
Throw reader.CreateException("Invalid use of surrogate pair code units")
End If
haveHighSurrogate = Char.IsHighSurrogate(c)
value.Append(c)
End While
End Function
''' <summary>
''' Reads an escaped character. It is assumed that the leading backslash has already been read.
''' </summary>
Private Function ReadEscapedCharacter() As Char
Dim c = reader.ReadOrFail("Unexpected end of text while reading character escape sequence")
Select Case c
Case "n"c
Return Microsoft.VisualBasic.Strings.ChrW(10)
Case "\"c
Return "\"c
Case "b"c
Return Microsoft.VisualBasic.Strings.ChrW(8)
Case "f"c
Return Microsoft.VisualBasic.Strings.ChrW(12)
Case "r"c
Return Microsoft.VisualBasic.Strings.ChrW(13)
Case "t"c
Return Microsoft.VisualBasic.Strings.ChrW(9)
Case """"c
Return """"c
Case "/"c
Return "/"c
Case "u"c
Return ReadUnicodeEscape()
Case Else
Throw reader.CreateException(String.Format(CultureInfo.InvariantCulture, "Invalid character in character escape sequence: U+{0:x4}", Microsoft.VisualBasic.AscW(c)))
End Select
End Function
''' <summary>
''' Reads an escaped Unicode 4-nybble hex sequence. It is assumed that the leading \u has already been read.
''' </summary>
Private Function ReadUnicodeEscape() As Char
Dim result = 0
For i = 0 To 4 - 1
Dim c As chr = reader.ReadOrFail("Unexpected end of text while reading Unicode escape sequence")
Dim nybble As Integer
If c >= "0"c AndAlso c <= "9"c Then
nybble = c - "0"c
ElseIf c >= "a"c AndAlso c <= "f"c Then
nybble = c - "a"c + 10
ElseIf c >= "A"c AndAlso c <= "F"c Then
nybble = c - "A"c + 10
Else
Throw reader.CreateException(String.Format(CultureInfo.InvariantCulture, "Invalid character in character escape sequence: U+{0:x4}", CInt(c)))
End If
result = (result << 4) + nybble
Next
Return Microsoft.VisualBasic.ChrW(result)
End Function
''' <summary>
''' Consumes a text-only literal, throwing an exception if the read text doesn't match it.
''' It is assumed that the first letter of the literal has already been read.
''' </summary>
Private Sub ConsumeLiteral(text As String)
For i = 1 To text.Length - 1
Dim [next] As Char? = reader.Read()
If [next] Is Nothing Then
Throw reader.CreateException("Unexpected end of text while reading literal token " & text)
End If
If [next].Value <> text(i) Then
Throw reader.CreateException("Unexpected character while reading literal token " & text)
End If
Next
End Sub
Private Function ReadNumber(initialCharacter As Char) As Double
Dim builder As StringBuilder = New StringBuilder()
If initialCharacter = "-"c Then
builder.Append("-")
Else
reader.PushBack(initialCharacter)
End If
' Each method returns the character it read that doesn't belong in that part,
' so we know what to do next, including pushing the character back at the end.
' null is returned for "end of text".
Dim [next] = ReadInt(builder)
If [next] = "."c Then
[next] = ReadFrac(builder)
End If
If [next] = "e"c OrElse [next] = "E"c Then
[next] = ReadExp(builder)
End If
' If we read a character which wasn't part of the number, push it back so we can read it again
' to parse the next token.
If [next] IsNot Nothing Then
reader.PushBack([next].Value)
End If
' TODO: What exception should we throw if the value can't be represented as a double?
Try
Return Double.Parse(builder.ToString(), NumberStyles.AllowLeadingSign Or NumberStyles.AllowDecimalPoint Or NumberStyles.AllowExponent, CultureInfo.InvariantCulture)
Catch __unusedOverflowException1__ As OverflowException
Throw reader.CreateException("Numeric value out of range: " & builder.ToString)
End Try
End Function
Private Function ReadInt(builder As StringBuilder) As Char?
Dim first = reader.ReadOrFail("Invalid numeric literal")
If first < "0"c OrElse first > "9"c Then
Throw reader.CreateException("Invalid numeric literal")
End If
builder.Append(first)
Dim digitCount As Integer
Dim [next] = ConsumeDigits(builder, digitCount)
If first = "0"c AndAlso digitCount <> 0 Then
Throw reader.CreateException("Invalid numeric literal: leading 0 for non-zero value.")
End If
Return [next]
End Function
Private Function ReadFrac(builder As StringBuilder) As Char?
builder.Append("."c) ' Already consumed this
Dim digitCount As Integer
Dim [next] = ConsumeDigits(builder, digitCount)
If digitCount = 0 Then
Throw reader.CreateException("Invalid numeric literal: fraction with no trailing digits")
End If
Return [next]
End Function
Private Function ReadExp(builder As StringBuilder) As Char?
builder.Append("E"c) ' Already consumed this (or 'e')
Dim [next] As Char? = reader.Read()
If [next] Is Nothing Then
Throw reader.CreateException("Invalid numeric literal: exponent with no trailing digits")
End If
If [next] = "-"c OrElse [next] = "+"c Then
builder.Append([next].Value)
Else
reader.PushBack([next].Value)
End If
Dim digitCount As Integer
[next] = ConsumeDigits(builder, digitCount)
If digitCount = 0 Then
Throw reader.CreateException("Invalid numeric literal: exponent without value")
End If
Return [next]
End Function
Private Function ConsumeDigits(builder As StringBuilder, <Out> ByRef count As Integer) As Char?
count = 0
While True
Dim [next] As Char? = reader.Read()
If [next] Is Nothing OrElse [next].Value < "0"c OrElse [next].Value > "9"c Then
Return [next]
End If
count += 1
builder.Append([next].Value)
End While
End Function
''' <summary>
''' Validates that we're in a valid state to read a value (using the given error prefix if necessary)
''' and changes the state to the appropriate one, e.g. ObjectAfterColon to ObjectAfterProperty.
''' </summary>
Private Sub ValidateAndModifyStateForValue(errorPrefix As String)
ValidateState(ValueStates, errorPrefix)
Select Case state
Case StateType.StartOfDocument
state = StateType.ExpectedEndOfDocument
Return
Case StateType.ObjectAfterColon
state = StateType.ObjectAfterProperty
Return
Case StateType.ArrayStart, StateType.ArrayAfterComma
state = StateType.ArrayAfterValue
Return
Case Else
Throw New InvalidOperationException("ValidateAndModifyStateForValue does not handle all value states (and should)")
End Select
End Sub
''' <summary>
''' Pops the top-most container, and sets the state to the appropriate one for the end of a value
''' in the parent container.
''' </summary>
Private Sub PopContainer()
containerStack.Pop()
Dim parent = containerStack.Peek()
Select Case parent
Case ContainerType.Object
state = StateType.ObjectAfterProperty
Case ContainerType.Array
state = StateType.ArrayAfterValue
Case ContainerType.Document
state = StateType.ExpectedEndOfDocument
Case Else
Throw New InvalidOperationException("Unexpected container type: " & parent)
End Select
End Sub
Private Enum ContainerType
Document
[Object]
Array
End Enum
''' <summary>
''' Possible states of the tokenizer.
''' </summary>
''' <remarks>
''' <para>This is a flags enum purely so we can simply and efficiently represent a set of valid states
''' for checking.</para>
''' <para>
''' Each is documented with an example,
''' where ^ represents the current position within the text stream. The examples all use string values,
''' but could be any value, including nested objects/arrays.
''' The complete state of the tokenizer also includes a stack to indicate the contexts (arrays/objects).
''' Any additional notional state of "AfterValue" indicates that a value has been completed, at which
''' point there's an immediate transition to ExpectedEndOfDocument, ObjectAfterProperty or ArrayAfterValue.
''' </para>
''' <para>
''' These states were derived manually by reading RFC 7159 carefully.
''' </para>
''' </remarks>
<Flags>
Private Enum StateType
''' <summary>
''' ^ { "foo": "bar" }
''' Before the value in a document. Next states: ObjectStart, ArrayStart, "AfterValue"
''' </summary>
StartOfDocument = 1 << 0
''' <summary>
''' { "foo": "bar" } ^
''' After the value in a document. Next states: ReaderExhausted
''' </summary>
ExpectedEndOfDocument = 1 << 1
''' <summary>
''' { "foo": "bar" } ^ (and already read to the end of the reader)
''' Terminal state.
''' </summary>
ReaderExhausted = 1 << 2
''' <summary>
''' { ^ "foo": "bar" }
''' Before the *first* property in an object.
''' Next states:
''' "AfterValue" (empty object)
''' ObjectBeforeColon (read a name)
''' </summary>
ObjectStart = 1 << 3
''' <summary>
''' { "foo" ^ : "bar", "x": "y" }
''' Next state: ObjectAfterColon
''' </summary>
ObjectBeforeColon = 1 << 4
''' <summary>
''' { "foo" : ^ "bar", "x": "y" }
''' Before any property other than the first in an object.
''' (Equivalently: after any property in an object)
''' Next states:
''' "AfterValue" (value is simple)
''' ObjectStart (value is object)
''' ArrayStart (value is array)
''' </summary>
ObjectAfterColon = 1 << 5
''' <summary>
''' { "foo" : "bar" ^ , "x" : "y" }
''' At the end of a property, so expecting either a comma or end-of-object
''' Next states: ObjectAfterComma or "AfterValue"
''' </summary>
ObjectAfterProperty = 1 << 6
''' <summary>
''' { "foo":"bar", ^ "x":"y" }
''' Read the comma after the previous property, so expecting another property.
''' This is like ObjectStart, but closing brace isn't valid here
''' Next state: ObjectBeforeColon.
''' </summary>
ObjectAfterComma = 1 << 7
''' <summary>
''' [ ^ "foo", "bar" ]
''' Before the *first* value in an array.
''' Next states:
''' "AfterValue" (read a value)
''' "AfterValue" (end of array; will pop stack)
''' </summary>
ArrayStart = 1 << 8
''' <summary>
''' [ "foo" ^ , "bar" ]
''' After any value in an array, so expecting either a comma or end-of-array
''' Next states: ArrayAfterComma or "AfterValue"
''' </summary>
ArrayAfterValue = 1 << 9
''' <summary>
''' [ "foo", ^ "bar" ]
''' After a comma in an array, so there *must* be another value (simple or complex).
''' Next states: "AfterValue" (simple value), StartObject, StartArray
''' </summary>
ArrayAfterComma = 1 << 10
End Enum
''' <summary>
''' Wrapper around a text reader allowing small amounts of buffering and location handling.
''' </summary>
Private Class PushBackReader
' TODO: Add locations for errors etc.
Private ReadOnly reader As TextReader
Friend Sub New(reader As TextReader)
' TODO: Wrap the reader in a BufferedReader?
Me.reader = reader
End Sub
''' <summary>
''' The buffered next character, if we have one.
''' </summary>
Private nextChar As Char?
''' <summary>
''' Returns the next character in the stream, or null if we have reached the end.
''' </summary>
''' <returns></returns>
Friend Function Read() As Char?
If nextChar IsNot Nothing Then
Dim tmp = nextChar
nextChar = Nothing
Return tmp
End If
Dim [next] As Integer = reader.Read()
Return If([next] = -1, Nothing, ChrW([next]))
End Function
Friend Function ReadOrFail(messageOnFailure As String) As Char
Dim [next] As Char? = Read()
If [next] Is Nothing Then
Throw CreateException(messageOnFailure)
End If
Return [next].Value
End Function
Friend Sub PushBack(c As Char)
If nextChar IsNot Nothing Then
Throw New InvalidOperationException("Cannot push back when already buffering a character")
End If
nextChar = c
End Sub
''' <summary>
''' Creates a new exception appropriate for the current state of the reader.
''' </summary>
Friend Function CreateException(message As String) As InvalidJsonException
' TODO: Keep track of and use the location.
Return New InvalidJsonException(message)
End Function
End Class
End Class
End Class
End Namespace

@ -0,0 +1,111 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2015 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System
Imports System.IO
Namespace Google.Protobuf
''' <summary>
''' Stream implementation which proxies another stream, only allowing a certain amount
''' of data to be read. Note that this is only used to read delimited streams, so it
''' doesn't attempt to implement everything.
''' </summary>
Friend NotInheritable Class LimitedInputStream
Inherits Stream
Private ReadOnly proxied As Stream
Private bytesLeft As Integer
Friend Sub New(proxied As Stream, size As Integer)
Me.proxied = proxied
bytesLeft = size
End Sub
Public Overrides ReadOnly Property CanRead As Boolean
Get
Return True
End Get
End Property
Public Overrides ReadOnly Property CanSeek As Boolean
Get
Return False
End Get
End Property
Public Overrides ReadOnly Property CanWrite As Boolean
Get
Return False
End Get
End Property
Public Overrides Sub Flush()
End Sub
Public Overrides ReadOnly Property Length As Long
Get
Throw New NotSupportedException()
End Get
End Property
Public Overrides Property Position As Long
Get
Throw New NotSupportedException()
End Get
Set(value As Long)
Throw New NotSupportedException()
End Set
End Property
Public Overrides Function Read(buffer As Byte(), offset As Integer, count As Integer) As Integer
If bytesLeft > 0 Then
Dim bytesRead = proxied.Read(buffer, offset, Math.Min(bytesLeft, count))
bytesLeft -= bytesRead
Return bytesRead
End If
Return 0
End Function
Public Overrides Function Seek(offset As Long, origin As SeekOrigin) As Long
Throw New NotSupportedException()
End Function
Public Overrides Sub SetLength(value As Long)
Throw New NotSupportedException()
End Sub
Public Overrides Sub Write(buffer As Byte(), offset As Integer, count As Integer)
Throw New NotSupportedException()
End Sub
End Class
End Namespace

@ -0,0 +1,156 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2015 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System.IO
Imports System.Runtime.CompilerServices
Namespace Google.Protobuf
''' <summary>
''' Extension methods on <see cref="IMessage"/> and <see cref="IMessageType(OfT)"/>.
''' </summary>
Public Module MessageExtensions
''' <summary>
''' Merges data from the given byte array into an existing message.
''' </summary>
''' <param name="message">The message to merge the data into.</param>
''' <param name="data">The data to merge, which must be protobuf-encoded binary data.</param>
<Extension()>
Public Sub MergeFrom(message As IMessage, data As Byte())
CheckNotNull(message, "message")
CheckNotNull(data, "data")
Dim input As CodedInputStream = New CodedInputStream(data)
message.MergeFrom(input)
input.CheckReadEndOfStreamTag()
End Sub
''' <summary>
''' Merges data from the given byte string into an existing message.
''' </summary>
''' <param name="message">The message to merge the data into.</param>
''' <param name="data">The data to merge, which must be protobuf-encoded binary data.</param>
<Extension()>
Public Sub MergeFrom(message As IMessage, data As ByteString)
CheckNotNull(message, "message")
CheckNotNull(data, "data")
Dim input As CodedInputStream = data.CreateCodedInput()
message.MergeFrom(input)
input.CheckReadEndOfStreamTag()
End Sub
''' <summary>
''' Merges data from the given stream into an existing message.
''' </summary>
''' <param name="message">The message to merge the data into.</param>
''' <param name="input">Stream containing the data to merge, which must be protobuf-encoded binary data.</param>
<Extension()>
Public Sub MergeFrom(message As IMessage, input As Stream)
CheckNotNull(message, "message")
CheckNotNull(input, "input")
Dim codedInput As CodedInputStream = New CodedInputStream(input)
message.MergeFrom(codedInput)
codedInput.CheckReadEndOfStreamTag()
End Sub
''' <summary>
''' Merges length-delimited data from the given stream into an existing message.
''' </summary>
''' <remarks>
''' The stream is expected to contain a length and then the data. Only the amount of data
''' specified by the length will be consumed.
''' </remarks>
''' <param name="message">The message to merge the data into.</param>
''' <param name="input">Stream containing the data to merge, which must be protobuf-encoded binary data.</param>
<Extension()>
Public Sub MergeDelimitedFrom(message As IMessage, input As Stream)
CheckNotNull(message, "message")
CheckNotNull(input, "input")
Dim size As Integer = CodedInputStream.ReadRawVarint32(input)
Dim limitedStream As Stream = New LimitedInputStream(input, size)
message.MergeFrom(limitedStream)
End Sub
''' <summary>
''' Converts the given message into a byte array in protobuf encoding.
''' </summary>
''' <param name="message">The message to convert.</param>
''' <returns>The message data as a byte array.</returns>
<Extension()>
Public Function ToByteArray(message As IMessage) As Byte()
CheckNotNull(message, "message")
Dim result As Byte() = New Byte(message.CalculateSize() - 1) {}
Dim output As CodedOutputStream = New CodedOutputStream(result)
message.WriteTo(output)
output.CheckNoSpaceLeft()
Return result
End Function
''' <summary>
''' Writes the given message data to the given stream in protobuf encoding.
''' </summary>
''' <param name="message">The message to write to the stream.</param>
''' <param name="output">The stream to write to.</param>
<Extension()>
Public Sub WriteTo(message As IMessage, output As Stream)
CheckNotNull(message, "message")
CheckNotNull(output, "output")
Dim codedOutput As CodedOutputStream = New CodedOutputStream(output)
message.WriteTo(codedOutput)
codedOutput.Flush()
End Sub
''' <summary>
''' Writes the length and then data of the given message to a stream.
''' </summary>
''' <param name="message">The message to write.</param>
''' <param name="output">The output stream to write to.</param>
<Extension()>
Public Sub WriteDelimitedTo(message As IMessage, output As Stream)
CheckNotNull(message, "message")
CheckNotNull(output, "output")
Dim codedOutput As CodedOutputStream = New CodedOutputStream(output)
codedOutput.WriteRawVarint32(CUInt(message.CalculateSize()))
message.WriteTo(codedOutput)
codedOutput.Flush()
End Sub
''' <summary>
''' Converts the given message into a byte string in protobuf encoding.
''' </summary>
''' <param name="message">The message to convert.</param>
''' <returns>The message data as a byte string.</returns>
<Extension()>
Public Function ToByteString(message As IMessage) As ByteString
CheckNotNull(message, "message")
Return ByteString.AttachBytes(message.ToByteArray())
End Function
End Module
End Namespace

@ -0,0 +1,251 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2015 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System
Imports System.IO
Namespace Google.Protobuf
''' <summary>
''' A general message parser, typically used by reflection-based code as all the methods
''' return simple <see cref="IMessage"/>.
''' </summary>
Public Class MessageParser
Private factory As Func(Of IMessage)
Sub New(factory As Func(Of IMessage))
Me.factory = factory
End Sub
''' <summary>
''' Creates a template instance ready for population.
''' </summary>
''' <returns>An empty message.</returns>
Friend Function CreateTemplate() As IMessage
Return factory()
End Function
''' <summary>
''' Parses a message from a byte array.
''' </summary>
''' <param name="data">The byte array containing the message. Must not be null.</param>
''' <returns>The newly parsed message.</returns>
Public Function ParseFrom(data As Byte()) As IMessage
CheckNotNull(data, "data")
Dim message As IMessage = factory()
message.MergeFrom(data)
Return message
End Function
''' <summary>
''' Parses a message from the given byte string.
''' </summary>
''' <param name="data">The data to parse.</param>
''' <returns>The parsed message.</returns>
Public Function ParseFrom(data As ByteString) As IMessage
CheckNotNull(data, "data")
Dim message As IMessage = factory()
message.MergeFrom(data)
Return message
End Function
''' <summary>
''' Parses a message from the given stream.
''' </summary>
''' <param name="input">The stream to parse.</param>
''' <returns>The parsed message.</returns>
Public Function ParseFrom(input As Stream) As IMessage
Dim message As IMessage = factory()
message.MergeFrom(input)
Return message
End Function
''' <summary>
''' Parses a length-delimited message from the given stream.
''' </summary>
''' <remarks>
''' The stream is expected to contain a length and then the data. Only the amount of data
''' specified by the length will be consumed.
''' </remarks>
''' <param name="input">The stream to parse.</param>
''' <returns>The parsed message.</returns>
Public Function ParseDelimitedFrom(input As Stream) As IMessage
Dim message As IMessage = factory()
message.MergeDelimitedFrom(input)
Return message
End Function
''' <summary>
''' Parses a message from the given coded input stream.
''' </summary>
''' <param name="input">The stream to parse.</param>
''' <returns>The parsed message.</returns>
Public Function ParseFrom(input As CodedInputStream) As IMessage
Dim message As IMessage = factory()
message.MergeFrom(input)
Return message
End Function
''' <summary>
''' Parses a message from the given JSON.
''' </summary>
''' <param name="json">The JSON to parse.</param>
''' <returns>The parsed message.</returns>
''' <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
''' <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception>
Public Function ParseJson(json As String) As IMessage
Dim message As IMessage = factory()
JsonParser.Default.Merge(message, json)
Return message
End Function
End Class
''' <summary>
''' A parser for a specific message type.
''' </summary>
''' <remarks>
''' <p>
''' This delegates most behavior to the
''' <see cref="IMessage.MergeFrom"/> implementation within the original type, but
''' provides convenient overloads to parse from a variety of sources.
''' </p>
''' <p>
''' Most applications will never need to create their own instances of this type;
''' instead, use the static <c>Parser</c> property of a generated message type to obtain a
''' parser for that type.
''' </p>
''' </remarks>
''' <typeparamname="T">The type of message to be parsed.</typeparam>
Public NotInheritable Class MessageParserType(Of T As IMessageType(Of T))
Inherits MessageParser
' Implementation note: all the methods here *could* just delegate up to the base class and cast the result.
' The current implementation avoids a virtual method call and a cast, which *may* be significant in some cases.
' Benchmarking work is required to measure the significance - but it's only a few lines of code in any case.
' The API wouldn't change anyway - just the implementation - so this work can be deferred.
Private ReadOnly factory As Func(Of T)
''' <summary>
''' Creates a new parser.
''' </summary>
''' <remarks>
''' The factory method is effectively an optimization over using a generic constraint
''' to require a parameterless constructor: delegates are significantly faster to execute.
''' </remarks>
''' <param name="factory">Function to invoke when a new, empty message is required.</param>
Public Sub New(factory As Func(Of T))
MyBase.New(Function() factory())
Me.factory = factory
End Sub
''' <summary>
''' Creates a template instance ready for population.
''' </summary>
''' <returns>An empty message.</returns>
Friend Overloads Function CreateTemplate() As T
Return factory()
End Function
''' <summary>
''' Parses a message from a byte array.
''' </summary>
''' <param name="data">The byte array containing the message. Must not be null.</param>
''' <returns>The newly parsed message.</returns>
Public Overloads Function ParseFrom(data As Byte()) As T
CheckNotNull(data, "data")
Dim message As T = factory()
message.MergeFrom(data)
Return message
End Function
''' <summary>
''' Parses a message from the given byte string.
''' </summary>
''' <param name="data">The data to parse.</param>
''' <returns>The parsed message.</returns>
Public Overloads Function ParseFrom(data As ByteString) As T
CheckNotNull(data, "data")
Dim message As T = factory()
message.MergeFrom(data)
Return message
End Function
''' <summary>
''' Parses a message from the given stream.
''' </summary>
''' <param name="input">The stream to parse.</param>
''' <returns>The parsed message.</returns>
Public Overloads Function ParseFrom(input As Stream) As T
Dim message As T = factory()
message.MergeFrom(input)
Return message
End Function
''' <summary>
''' Parses a length-delimited message from the given stream.
''' </summary>
''' <remarks>
''' The stream is expected to contain a length and then the data. Only the amount of data
''' specified by the length will be consumed.
''' </remarks>
''' <param name="input">The stream to parse.</param>
''' <returns>The parsed message.</returns>
Public Overloads Function ParseDelimitedFrom(input As Stream) As T
Dim message As T = factory()
message.MergeDelimitedFrom(input)
Return message
End Function
''' <summary>
''' Parses a message from the given coded input stream.
''' </summary>
''' <param name="input">The stream to parse.</param>
''' <returns>The parsed message.</returns>
Public Overloads Function ParseFrom(input As CodedInputStream) As T
Dim message As T = factory()
message.MergeFrom(input)
Return message
End Function
''' <summary>
''' Parses a message from the given JSON.
''' </summary>
''' <param name="json">The JSON to parse.</param>
''' <returns>The parsed message.</returns>
''' <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
''' <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception>
Public Overloads Function ParseJson(json As String) As T
Dim message As T = factory()
JsonParser.Default.Merge(message, json)
Return message
End Function
End Class
End Namespace

@ -0,0 +1,44 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2008 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System.Runtime.CompilerServices
Imports System.Security
' General Information about an assembly is controlled through the following
' set of attributes. Change these attribute values to modify the information
' associated with an assembly.
#If Not NCRUNCH
<Assembly: AllowPartiallyTrustedCallers>
#End If
<Assembly: InternalsVisibleTo("Google.Protobuf.Test, PublicKey=" & "002400000480000094000000060200000024000052534131000400000100010025800fbcfc63a1" & "7c66b303aae80b03a6beaa176bb6bef883be436f2a1579edd80ce23edf151a1f4ced97af83abcd" & "981207041fd5b2da3b498346fcfcd94910d52f25537c4a43ce3fbe17dc7d43e6cbdb4d8f1242dc" & "b6bd9b5906be74da8daa7d7280f97130f318a16c07baf118839b156299a48522f9fae2371c9665" & "c5ae9cb6")>

@ -0,0 +1,75 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2008 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System
Namespace Google.Protobuf
''' <summary>
''' Helper methods for throwing exceptions when preconditions are not met.
''' </summary>
''' <remarks>
''' This class is used internally and by generated code; it is not particularly
''' expected to be used from application code, although nothing prevents it
''' from being used that way.
''' </remarks>
Public Module ProtoPreconditions
''' <summary>
''' Throws an ArgumentNullException if the given value is null, otherwise
''' return the value to the caller.
''' </summary>
Public Function CheckNotNull(Of T As Class)(value As T, name As String) As T
If value Is Nothing Then
Throw New ArgumentNullException(name)
End If
Return value
End Function
''' <summary>
''' Throws an ArgumentNullException if the given value is null, otherwise
''' return the value to the caller.
''' </summary>
''' <remarks>
''' This is equivalent to <see cref="CheckNotNull(OfT)(T,String)"/> but without the type parameter
''' constraint. In most cases, the constraint is useful to prevent you from calling CheckNotNull
''' with a value type - but it gets in the way if either you want to use it with a nullable
''' value type, or you want to use it with an unconstrained type parameter.
''' </remarks>
Friend Function CheckNotNullUnconstrained(Of T)(value As T, name As String) As T
If value Is Nothing Then
Throw New ArgumentNullException(name)
End If
Return value
End Function
End Module
End Namespace

File diff suppressed because one or more lines are too long

@ -0,0 +1,87 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2008 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Namespace Google.Protobuf.Reflection
''' <summary>
''' Base class for nearly all descriptors, providing common functionality.
''' </summary>
Public MustInherit Class DescriptorBase
Implements IDescriptor
Private ReadOnly fileField As FileDescriptor
Private ReadOnly fullNameField As String
Private ReadOnly indexField As Integer
Friend Sub New(file As FileDescriptor, fullName As String, index As Integer)
fileField = file
fullNameField = fullName
indexField = index
End Sub
''' <value>
''' The index of this descriptor within its parent descriptor.
''' </value>
''' <remarks>
''' This returns the index of this descriptor within its parent, for
''' this descriptor's type. (There can be duplicate values for different
''' types, e.g. one enum type with index 0 and one message type with index 0.)
''' </remarks>
Public ReadOnly Property Index As Integer
Get
Return indexField
End Get
End Property
''' <summary>
''' Returns the name of the entity (field, message etc) being described.
''' </summary>
Public MustOverride ReadOnly Property Name As String Implements IDescriptor.Name
''' <summary>
''' The fully qualified name of the descriptor's target.
''' </summary>
Public ReadOnly Property FullName As String Implements IDescriptor.FullName
Get
Return fullNameField
End Get
End Property
''' <value>
''' The file this descriptor was declared in.
''' </value>
Public ReadOnly Property File As FileDescriptor Implements IDescriptor.File
Get
Return fileField
End Get
End Property
End Class
End Namespace

@ -0,0 +1,318 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2008 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System
Imports System.Collections.Generic
Imports System.Text
Imports System.Text.RegularExpressions
Namespace Google.Protobuf.Reflection
''' <summary>
''' Contains lookup tables containing all the descriptors defined in a particular file.
''' </summary>
Friend NotInheritable Class DescriptorPool
Private ReadOnly descriptorsByName As IDictionary(Of String, IDescriptor) = New Dictionary(Of String, IDescriptor)()
Private ReadOnly fieldsByNumber As IDictionary(Of DescriptorIntPair, FieldDescriptor) = New Dictionary(Of DescriptorIntPair, FieldDescriptor)()
Private ReadOnly enumValuesByNumber As IDictionary(Of DescriptorIntPair, EnumValueDescriptor) = New Dictionary(Of DescriptorIntPair, EnumValueDescriptor)()
Private ReadOnly dependencies As HashSet(Of FileDescriptor)
Friend Sub New(dependencyFiles As FileDescriptor())
dependencies = New HashSet(Of FileDescriptor)()
For i = 0 To dependencyFiles.Length - 1
dependencies.Add(dependencyFiles(i))
ImportPublicDependencies(dependencyFiles(i))
Next
For Each dependency In dependencyFiles
AddPackage(dependency.Package, dependency)
Next
End Sub
Private Sub ImportPublicDependencies(file As FileDescriptor)
For Each dependency In file.PublicDependencies
If dependencies.Add(dependency) Then
ImportPublicDependencies(dependency)
End If
Next
End Sub
''' <summary>
''' Finds a symbol of the given name within the pool.
''' </summary>
''' <typeparamname="T">The type of symbol to look for</typeparam>
''' <param name="fullName">Fully-qualified name to look up</param>
''' <returns>The symbol with the given name and type,
''' or null if the symbol doesn't exist or has the wrong type</returns>
Friend Function FindSymbol(Of T As Class)(fullName As String) As T
Dim result As IDescriptor
descriptorsByName.TryGetValue(fullName, result)
Dim descriptor As T = TryCast(result, T)
If descriptor IsNot Nothing Then
Return descriptor
End If
' dependencies contains direct dependencies and any *public* dependencies
' of those dependencies (transitively)... so we don't need to recurse here.
For Each dependency In dependencies
dependency.DescriptorPool.descriptorsByName.TryGetValue(fullName, result)
descriptor = TryCast(result, T)
If descriptor IsNot Nothing Then
Return descriptor
End If
Next
Return Nothing
End Function
''' <summary>
''' Adds a package to the symbol tables. If a package by the same name
''' already exists, that is fine, but if some other kind of symbol
''' exists under the same name, an exception is thrown. If the package
''' has multiple components, this also adds the parent package(s).
''' </summary>
Friend Sub AddPackage(fullName As String, file As FileDescriptor)
Dim dotpos = fullName.LastIndexOf("."c)
Dim name As String
If dotpos <> -1 Then
AddPackage(fullName.Substring(0, dotpos), file)
name = fullName.Substring(dotpos + 1)
Else
name = fullName
End If
Dim old As IDescriptor
If descriptorsByName.TryGetValue(fullName, old) Then
If Not (TypeOf old Is PackageDescriptor) Then
Throw New DescriptorValidationException(file, """" & name & """ is already defined (as something other than a " & "package) in file """ & old.File.Name & """.")
End If
End If
descriptorsByName(fullName) = New PackageDescriptor(name, fullName, file)
End Sub
''' <summary>
''' Adds a symbol to the symbol table.
''' </summary>
''' <exception cref="DescriptorValidationException">The symbol already existed
''' in the symbol table.</exception>
Friend Sub AddSymbol(descriptor As IDescriptor)
ValidateSymbolName(descriptor)
Dim fullName = descriptor.FullName
Dim old As IDescriptor
If descriptorsByName.TryGetValue(fullName, old) Then
Dim dotPos = fullName.LastIndexOf("."c)
Dim message As String
If descriptor.File Is old.File Then
If dotPos = -1 Then
message = """" & fullName & """ is already defined."
Else
message = """" & fullName.Substring(dotPos + 1) & """ is already defined in """ & fullName.Substring(0, dotPos) & """."
End If
Else
message = """" & fullName & """ is already defined in file """ & old.File.Name & """."
End If
Throw New DescriptorValidationException(descriptor, message)
End If
descriptorsByName(fullName) = descriptor
End Sub
Private Shared ReadOnly ValidationRegex As Regex = New Regex("^[_A-Za-z][_A-Za-z0-9]*$", CompiledRegexWhereAvailable)
''' <summary>
''' Verifies that the descriptor's name is valid (i.e. it contains
''' only letters, digits and underscores, and does not start with a digit).
''' </summary>
''' <param name="descriptor"></param>
Private Shared Sub ValidateSymbolName(descriptor As IDescriptor)
If Equals(descriptor.Name, "") Then
Throw New DescriptorValidationException(descriptor, "Missing name.")
End If
If Not ValidationRegex.IsMatch(descriptor.Name) Then
Throw New DescriptorValidationException(descriptor, """" & descriptor.Name & """ is not a valid identifier.")
End If
End Sub
''' <summary>
''' Returns the field with the given number in the given descriptor,
''' or null if it can't be found.
''' </summary>
Friend Function FindFieldByNumber(messageDescriptor As MessageDescriptor, number As Integer) As FieldDescriptor
Dim ret As FieldDescriptor
fieldsByNumber.TryGetValue(New DescriptorIntPair(messageDescriptor, number), ret)
Return ret
End Function
Friend Function FindEnumValueByNumber(enumDescriptor As EnumDescriptor, number As Integer) As EnumValueDescriptor
Dim ret As EnumValueDescriptor
enumValuesByNumber.TryGetValue(New DescriptorIntPair(enumDescriptor, number), ret)
Return ret
End Function
''' <summary>
''' Adds a field to the fieldsByNumber table.
''' </summary>
''' <exception cref="DescriptorValidationException">A field with the same
''' containing type and number already exists.</exception>
Friend Sub AddFieldByNumber(field As FieldDescriptor)
Dim key As DescriptorIntPair = New DescriptorIntPair(field.ContainingType, field.FieldNumber)
Dim old As FieldDescriptor
If fieldsByNumber.TryGetValue(key, old) Then
Throw New DescriptorValidationException(field, "Field number " & field.FieldNumber & "has already been used in """ & field.ContainingType.FullName & """ by field """ & old.Name & """.")
End If
fieldsByNumber(key) = field
End Sub
''' <summary>
''' Adds an enum value to the enumValuesByNumber table. If an enum value
''' with the same type and number already exists, this method does nothing.
''' (This is allowed; the first value defined with the number takes precedence.)
''' </summary>
Friend Sub AddEnumValueByNumber(enumValue As EnumValueDescriptor)
Dim key As DescriptorIntPair = New DescriptorIntPair(enumValue.EnumDescriptor, enumValue.Number)
If Not enumValuesByNumber.ContainsKey(key) Then
enumValuesByNumber(key) = enumValue
End If
End Sub
''' <summary>
''' Looks up a descriptor by name, relative to some other descriptor.
''' The name may be fully-qualified (with a leading '.'), partially-qualified,
''' or unqualified. C++-like name lookup semantics are used to search for the
''' matching descriptor.
''' </summary>
''' <remarks>
''' This isn't heavily optimized, but it's only used during cross linking anyway.
''' If it starts being used more widely, we should look at performance more carefully.
''' </remarks>
Friend Function LookupSymbol(name As String, relativeTo As IDescriptor) As IDescriptor
Dim result As IDescriptor
If name.StartsWith(".") Then
' Fully-qualified name.
result = FindSymbol(Of IDescriptor)(name.Substring(1))
Else
' If "name" is a compound identifier, we want to search for the
' first component of it, then search within it for the rest.
Dim firstPartLength = name.IndexOf("."c)
Dim firstPart = If(firstPartLength = -1, name, name.Substring(0, firstPartLength))
' We will search each parent scope of "relativeTo" looking for the
' symbol.
Dim scopeToTry As StringBuilder = New StringBuilder(relativeTo.FullName)
While True
' Chop off the last component of the scope.
Dim dotpos As Integer = scopeToTry.ToString().LastIndexOf(".")
If dotpos = -1 Then
result = FindSymbol(Of IDescriptor)(name)
Exit While
Else
scopeToTry.Length = dotpos + 1
' Append firstPart and try to find.
scopeToTry.Append(firstPart)
result = FindSymbol(Of IDescriptor)(scopeToTry.ToString())
If result IsNot Nothing Then
If firstPartLength <> -1 Then
' We only found the first part of the symbol. Now look for
' the whole thing. If this fails, we *don't* want to keep
' searching parent scopes.
scopeToTry.Length = dotpos + 1
scopeToTry.Append(name)
result = FindSymbol(Of IDescriptor)(scopeToTry.ToString())
End If
Exit While
End If
' Not found. Remove the name so we can try again.
scopeToTry.Length = dotpos
End If
End While
End If
If result Is Nothing Then
Throw New DescriptorValidationException(relativeTo, """" & name & """ is not defined.")
Else
Return result
End If
End Function
''' <summary>
''' Struct used to hold the keys for the fieldByNumber table.
''' </summary>
Private Structure DescriptorIntPair
Implements IEquatable(Of DescriptorIntPair)
Private ReadOnly number As Integer
Private ReadOnly descriptor As IDescriptor
Friend Sub New(descriptor As IDescriptor, number As Integer)
Me.number = number
Me.descriptor = descriptor
End Sub
Public Overloads Function Equals(other As DescriptorIntPair) As Boolean Implements IEquatable(Of DescriptorIntPair).Equals
Return descriptor Is other.descriptor AndAlso number = other.number
End Function
Public Overrides Function Equals(obj As Object) As Boolean
If TypeOf obj Is DescriptorIntPair Then
Return Equals(CType(obj, DescriptorIntPair))
End If
Return False
End Function
Public Overrides Function GetHashCode() As Integer
Return descriptor.GetHashCode() * ((1 << 16) - 1) + number
End Function
End Structure
End Class
End Namespace

@ -0,0 +1,61 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2008 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Namespace Google.Protobuf.Reflection
''' <summary>
''' Internal class containing utility methods when working with descriptors.
''' </summary>
Friend Module DescriptorUtil
''' <summary>
''' Equivalent to Func[TInput, int, TOutput] but usable in .NET 2.0. Only used to convert
''' arrays.
''' </summary>
Friend Delegate Function IndexedConverter(Of TInput, TOutput)(element As TInput, index As Integer) As TOutput
''' <summary>
''' Converts the given array into a read-only list, applying the specified conversion to
''' each input element.
''' </summary>
Friend Function ConvertAndMakeReadOnly(Of TInput, TOutput)(input As IList(Of TInput), converter As IndexedConverter(Of TInput, TOutput)) As IList(Of TOutput)
Dim array = New TOutput(input.Count - 1) {}
For i = 0 To array.Length - 1
array(i) = converter(input(i), i)
Next
Return New ReadOnlyCollection(Of TOutput)(array)
End Function
End Module
End Namespace

@ -0,0 +1,80 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2008 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System
Namespace Google.Protobuf.Reflection
''' <summary>
''' Thrown when building descriptors fails because the source DescriptorProtos
''' are not valid.
''' </summary>
Public NotInheritable Class DescriptorValidationException
Inherits Exception
Private ReadOnly name As String
Private ReadOnly descriptionField As String
''' <value>
''' The full name of the descriptor where the error occurred.
''' </value>
Public ReadOnly Property ProblemSymbolName As String
Get
Return name
End Get
End Property
''' <value>
''' A human-readable description of the error. (The Message property
''' is made up of the descriptor's name and this description.)
''' </value>
Public ReadOnly Property Description As String
Get
Return descriptionField
End Get
End Property
Friend Sub New(problemDescriptor As IDescriptor, description As String)
MyBase.New(problemDescriptor.FullName & ": " & description)
' Note that problemDescriptor may be partially uninitialized, so we
' don't want to expose it directly to the user. So, we only provide
' the name and the original proto.
name = problemDescriptor.FullName
descriptionField = description
End Sub
Friend Sub New(problemDescriptor As IDescriptor, description As String, cause As Exception)
MyBase.New(problemDescriptor.FullName & ": " & description, cause)
name = problemDescriptor.FullName
descriptionField = description
End Sub
End Class
End Namespace

@ -0,0 +1,124 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2008 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System
Imports System.Collections.Generic
Namespace Google.Protobuf.Reflection
''' <summary>
''' Descriptor for an enum type in a .proto file.
''' </summary>
Public NotInheritable Class EnumDescriptor
Inherits DescriptorBase
Private ReadOnly protoField As EnumDescriptorProto
Private ReadOnly containingTypeField As MessageDescriptor
Private ReadOnly valuesField As IList(Of EnumValueDescriptor)
Private ReadOnly clrTypeField As Type
Friend Sub New(proto As EnumDescriptorProto, file As FileDescriptor, parent As MessageDescriptor, index As Integer, clrType As Type)
MyBase.New(file, file.ComputeFullName(parent, proto.Name), index)
protoField = proto
clrTypeField = clrType
containingTypeField = parent
If proto.Value.Count = 0 Then
' We cannot allow enums with no values because this would mean there
' would be no valid default value for fields of this type.
Throw New DescriptorValidationException(Me, "Enums must contain at least one value.")
End If
valuesField = DescriptorUtil.ConvertAndMakeReadOnly(proto.Value, Function(value, i) New EnumValueDescriptor(value, file, Me, i))
MyBase.File.DescriptorPool.AddSymbol(Me)
End Sub
Friend ReadOnly Property Proto As EnumDescriptorProto
Get
Return protoField
End Get
End Property
''' <summary>
''' The brief name of the descriptor's target.
''' </summary>
Public Overrides ReadOnly Property Name As String
Get
Return protoField.Name
End Get
End Property
''' <summary>
''' The CLR type for this enum. For generated code, this will be a CLR enum type.
''' </summary>
Public ReadOnly Property ClrType As Type
Get
Return clrTypeField
End Get
End Property
''' <value>
''' If this is a nested type, get the outer descriptor, otherwise null.
''' </value>
Public ReadOnly Property ContainingType As MessageDescriptor
Get
Return containingTypeField
End Get
End Property
''' <value>
''' An unmodifiable list of defined value descriptors for this enum.
''' </value>
Public ReadOnly Property Values As IList(Of EnumValueDescriptor)
Get
Return valuesField
End Get
End Property
''' <summary>
''' Finds an enum value by number. If multiple enum values have the
''' same number, this returns the first defined value with that number.
''' If there is no value for the given number, this returns <c>null</c>.
''' </summary>
Public Function FindValueByNumber(number As Integer) As EnumValueDescriptor
Return File.DescriptorPool.FindEnumValueByNumber(Me, number)
End Function
''' <summary>
''' Finds an enum value by name.
''' </summary>
''' <param name="name">The unqualified name of the value (e.g. "FOO").</param>
''' <returns>The value's descriptor, or null if not found.</returns>
Public Function FindValueByName(name As String) As EnumValueDescriptor
Return File.DescriptorPool.FindSymbol(Of EnumValueDescriptor)(FullName & "." & name)
End Function
End Class
End Namespace

@ -0,0 +1,84 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2008 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Namespace Google.Protobuf.Reflection
''' <summary>
''' Descriptor for a single enum value within an enum in a .proto file.
''' </summary>
Public NotInheritable Class EnumValueDescriptor
Inherits DescriptorBase
Private ReadOnly enumDescriptorField As EnumDescriptor
Private ReadOnly protoField As EnumValueDescriptorProto
Friend Sub New(proto As EnumValueDescriptorProto, file As FileDescriptor, parent As EnumDescriptor, index As Integer)
MyBase.New(file, parent.FullName & "." & proto.Name, index)
protoField = proto
enumDescriptorField = parent
file.DescriptorPool.AddSymbol(Me)
file.DescriptorPool.AddEnumValueByNumber(Me)
End Sub
Friend ReadOnly Property Proto As EnumValueDescriptorProto
Get
Return protoField
End Get
End Property
''' <summary>
''' Returns the name of the enum value described by this object.
''' </summary>
Public Overrides ReadOnly Property Name As String
Get
Return protoField.Name
End Get
End Property
''' <summary>
''' Returns the number associated with this enum value.
''' </summary>
Public ReadOnly Property Number As Integer
Get
Return Proto.Number
End Get
End Property
''' <summary>
''' Returns the enum descriptor that this value is part of.
''' </summary>
Public ReadOnly Property EnumDescriptor As EnumDescriptor
Get
Return enumDescriptorField
End Get
End Property
End Class
End Namespace

@ -0,0 +1,64 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2015 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System
Imports System.Reflection
Namespace Google.Protobuf.Reflection
''' <summary>
''' Base class for field accessors.
''' </summary>
Friend MustInherit Class FieldAccessorBase
Implements IFieldAccessor
Private ReadOnly getValueDelegate As Func(Of IMessage, Object)
Private ReadOnly descriptorField As FieldDescriptor
Friend Sub New([property] As PropertyInfo, descriptor As FieldDescriptor)
descriptorField = descriptor
getValueDelegate = CreateFuncIMessageObject([property].GetGetMethod())
End Sub
Public ReadOnly Property Descriptor As FieldDescriptor Implements IFieldAccessor.Descriptor
Get
Return descriptorField
End Get
End Property
Public Function GetValue(message As IMessage) As Object Implements IFieldAccessor.GetValue
Return getValueDelegate(message)
End Function
Public MustOverride Sub Clear(message As IMessage) Implements IFieldAccessor.Clear
Public MustOverride Sub SetValue(message As IMessage, value As Object) Implements IFieldAccessor.SetValue
End Class
End Namespace

@ -0,0 +1,341 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2008 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System
Namespace Google.Protobuf.Reflection
''' <summary>
''' Descriptor for a field or extension within a message in a .proto file.
''' </summary>
Public NotInheritable Class FieldDescriptor
Inherits DescriptorBase
Implements IComparable(Of FieldDescriptor)
Private enumTypeField As EnumDescriptor
Private messageTypeField As MessageDescriptor
Private fieldTypeField As FieldType
Private ReadOnly propertyName As String ' Annoyingly, needed in Crosslink.
Private accessorField As IFieldAccessor
''' <summary>
''' Get the field's containing message type.
''' </summary>
Public ReadOnly Property ContainingType As MessageDescriptor
''' <summary>
''' Returns the oneof containing this field, or <c>null</c> if it is not part of a oneof.
''' </summary>
Public ReadOnly Property ContainingOneof As OneofDescriptor
''' <summary>
''' The effective JSON name for this field. This is usually the lower-camel-cased form of the field name,
''' but can be overridden using the <c>json_name</c> option in the .proto file.
''' </summary>
Public ReadOnly Property JsonName As String
Friend ReadOnly Property Proto As FieldDescriptorProto
Friend Sub New(proto As FieldDescriptorProto, file As FileDescriptor, parent As MessageDescriptor, index As Integer, propertyName As String)
MyBase.New(file, file.ComputeFullName(parent, proto.Name), index)
Me.Proto = proto
If proto.Type <> 0 Then
fieldTypeField = FieldDescriptor.GetFieldTypeFromProtoType(proto.Type)
End If
If FieldNumber <= 0 Then
Throw New DescriptorValidationException(Me, "Field numbers must be positive integers.")
End If
ContainingType = parent
' OneofIndex "defaults" to -1 due to a hack in FieldDescriptor.OnConstruction.
If proto.OneofIndex <> -1 Then
If proto.OneofIndex < 0 OrElse proto.OneofIndex >= parent.Proto.OneofDecl.Count Then
Throw New DescriptorValidationException(Me, $"FieldDescriptorProto.oneof_index is out of range for type {parent.Name}")
End If
ContainingOneof = parent.Oneofs(proto.OneofIndex)
End If
file.DescriptorPool.AddSymbol(Me)
' We can't create the accessor until we've cross-linked, unfortunately, as we
' may not know whether the type of the field is a map or not. Remember the property name
' for later.
' We could trust the generated code and check whether the type of the property is
' a MapField, but that feels a tad nasty.
Me.propertyName = propertyName
JsonName = If(Equals(Me.Proto.JsonName, ""), JsonFormatter.ToCamelCase(Me.Proto.Name), Me.Proto.JsonName)
End Sub
''' <summary>
''' The brief name of the descriptor's target.
''' </summary>
Public Overrides ReadOnly Property Name As String
Get
Return Proto.Name
End Get
End Property
''' <summary>
''' Returns the accessor for this field.
''' </summary>
''' <remarks>
''' <para>
''' While a <see cref="FieldDescriptor"/> describes the field, it does not provide
''' any way of obtaining or changing the value of the field within a specific message;
''' that is the responsibility of the accessor.
''' </para>
''' <para>
''' The value returned by this property will be non-null for all regular fields. However,
''' if a message containing a map field is introspected, the list of nested messages will include
''' an auto-generated nested key/value pair message for the field. This is not represented in any
''' generated type, and the value of the map field itself is represented by a dictionary in the
''' reflection API. There are never instances of those "hidden" messages, so no accessor is provided
''' and this property will return null.
''' </para>
''' </remarks>
Public ReadOnly Property Accessor As IFieldAccessor
Get
Return accessorField
End Get
End Property
''' <summary>
''' Maps a field type as included in the .proto file to a FieldType.
''' </summary>
Private Shared Function GetFieldTypeFromProtoType(type As FieldDescriptorProto.Types.Type) As FieldType
Select Case type
Case FieldDescriptorProto.Types.Type.Double
Return FieldType.Double
Case FieldDescriptorProto.Types.Type.Float
Return FieldType.Float
Case FieldDescriptorProto.Types.Type.Int64
Return FieldType.Int64
Case FieldDescriptorProto.Types.Type.Uint64
Return FieldType.UInt64
Case FieldDescriptorProto.Types.Type.Int32
Return FieldType.Int32
Case FieldDescriptorProto.Types.Type.Fixed64
Return FieldType.Fixed64
Case FieldDescriptorProto.Types.Type.Fixed32
Return FieldType.Fixed32
Case FieldDescriptorProto.Types.Type.Bool
Return FieldType.Bool
Case FieldDescriptorProto.Types.Type.String
Return FieldType.String
Case FieldDescriptorProto.Types.Type.Group
Return FieldType.Group
Case FieldDescriptorProto.Types.Type.Message
Return FieldType.Message
Case FieldDescriptorProto.Types.Type.Bytes
Return FieldType.Bytes
Case FieldDescriptorProto.Types.Type.Uint32
Return FieldType.UInt32
Case FieldDescriptorProto.Types.Type.Enum
Return FieldType.Enum
Case FieldDescriptorProto.Types.Type.Sfixed32
Return FieldType.SFixed32
Case FieldDescriptorProto.Types.Type.Sfixed64
Return FieldType.SFixed64
Case FieldDescriptorProto.Types.Type.Sint32
Return FieldType.SInt32
Case FieldDescriptorProto.Types.Type.Sint64
Return FieldType.SInt64
Case Else
Throw New ArgumentException("Invalid type specified")
End Select
End Function
''' <summary>
''' Returns <c>true</c> if this field is a repeated field; <c>false</c> otherwise.
''' </summary>
Public ReadOnly Property IsRepeated As Boolean
Get
Return Proto.Label = FieldDescriptorProto.Types.Label.Repeated
End Get
End Property
''' <summary>
''' Returns <c>true</c> if this field is a map field; <c>false</c> otherwise.
''' </summary>
Public ReadOnly Property IsMap As Boolean
Get
Return fieldTypeField = FieldType.Message AndAlso messageTypeField.Proto.Options IsNot Nothing AndAlso messageTypeField.Proto.Options.MapEntry
End Get
End Property
''' <summary>
''' Returns <c>true</c> if this field is a packed, repeated field; <c>false</c> otherwise.
''' </summary>
Public ReadOnly Property IsPacked As Boolean
Get
' Note the || rather than && here - we're effectively defaulting to packed, because that *is*
' the default in proto3, which is all we support. We may give the wrong result for the protos
' within descriptor.proto, but that's okay, as they're never exposed and we don't use IsPacked
' within the runtime.
Return Proto.Options Is Nothing OrElse Proto.Options.Packed
End Get
End Property
''' <summary>
''' Returns the type of the field.
''' </summary>
Public ReadOnly Property FieldType As FieldType
Get
Return fieldTypeField
End Get
End Property
''' <summary>
''' Returns the field number declared in the proto file.
''' </summary>
Public ReadOnly Property FieldNumber As Integer
Get
Return Proto.Number
End Get
End Property
''' <summary>
''' Compares this descriptor with another one, ordering in "canonical" order
''' which simply means ascending order by field number. <paramrefname="other"/>
''' must be a field of the same type, i.e. the <see cref="ContainingType"/> of
''' both fields must be the same.
''' </summary>
Public Function CompareTo(other As FieldDescriptor) As Integer Implements IComparable(Of FieldDescriptor).CompareTo
If other.ContainingType IsNot ContainingType Then
Throw New ArgumentException("FieldDescriptors can only be compared to other FieldDescriptors " & "for fields of the same message type.")
End If
Return FieldNumber - other.FieldNumber
End Function
''' <summary>
''' For enum fields, returns the field's type.
''' </summary>
Public ReadOnly Property EnumType As EnumDescriptor
Get
If fieldTypeField <> FieldType.Enum Then
Throw New InvalidOperationException("EnumType is only valid for enum fields.")
End If
Return enumTypeField
End Get
End Property
''' <summary>
''' For embedded message and group fields, returns the field's type.
''' </summary>
Public ReadOnly Property MessageType As MessageDescriptor
Get
If fieldTypeField <> FieldType.Message Then
Throw New InvalidOperationException("MessageType is only valid for message fields.")
End If
Return messageTypeField
End Get
End Property
''' <summary>
''' Look up and cross-link all field types etc.
''' </summary>
Friend Sub CrossLink()
If Not Equals(Proto.TypeName, "") Then
Dim typeDescriptor = File.DescriptorPool.LookupSymbol(Proto.TypeName, Me)
If Proto.Type <> 0 Then
' Choose field type based on symbol.
If TypeOf typeDescriptor Is MessageDescriptor Then
fieldTypeField = FieldType.Message
ElseIf TypeOf typeDescriptor Is EnumDescriptor Then
fieldTypeField = FieldType.Enum
Else
Throw New DescriptorValidationException(Me, $"""{Proto.TypeName}"" is not a type.")
End If
End If
If fieldTypeField = FieldType.Message Then
If Not (TypeOf typeDescriptor Is MessageDescriptor) Then
Throw New DescriptorValidationException(Me, $"""{Proto.TypeName}"" is not a message type.")
End If
messageTypeField = CType(typeDescriptor, MessageDescriptor)
If Not Equals(Proto.DefaultValue, "") Then
Throw New DescriptorValidationException(Me, "Messages can't have default values.")
End If
ElseIf fieldTypeField = FieldType.Enum Then
If Not (TypeOf typeDescriptor Is EnumDescriptor) Then
Throw New DescriptorValidationException(Me, $"""{Proto.TypeName}"" is not an enum type.")
End If
enumTypeField = CType(typeDescriptor, EnumDescriptor)
Else
Throw New DescriptorValidationException(Me, "Field with primitive type has type_name.")
End If
Else
If fieldTypeField = FieldType.Message OrElse fieldTypeField = FieldType.Enum Then
Throw New DescriptorValidationException(Me, "Field with message or enum type missing type_name.")
End If
End If
' Note: no attempt to perform any default value parsing
File.DescriptorPool.AddFieldByNumber(Me)
If ContainingType IsNot Nothing AndAlso ContainingType.Proto.Options IsNot Nothing AndAlso ContainingType.Proto.Options.MessageSetWireFormat Then
Throw New DescriptorValidationException(Me, "MessageSet format is not supported.")
End If
accessorField = CreateAccessor()
End Sub
Private Function CreateAccessor() As IFieldAccessor
' If we're given no property name, that's because we really don't want an accessor.
' (At the moment, that means it's a map entry message...)
If Equals(propertyName, Nothing) Then
Return Nothing
End If
Dim [property] = ContainingType.ClrType.GetProperty(propertyName)
If [property] Is Nothing Then
Throw New DescriptorValidationException(Me, $"Property {propertyName} not found in {ContainingType.ClrType}")
End If
Return If(IsMap, New MapFieldAccessor([property], Me), If(IsRepeated, New RepeatedFieldAccessor([property], Me), CType(New SingleFieldAccessor([property], Me), IFieldAccessor)))
End Function
End Class
End Namespace

@ -0,0 +1,111 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2008 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Namespace Google.Protobuf.Reflection
''' <summary>
''' Enumeration of all the possible field types.
''' </summary>
Public Enum FieldType
''' <summary>
''' The <c>double</c> field type.
''' </summary>
[Double]
''' <summary>
''' The <c>float</c> field type.
''' </summary>
Float
''' <summary>
''' The <c>int64</c> field type.
''' </summary>
Int64
''' <summary>
''' The <c>uint64</c> field type.
''' </summary>
UInt64
''' <summary>
''' The <c>int32</c> field type.
''' </summary>
Int32
''' <summary>
''' The <c>fixed64</c> field type.
''' </summary>
Fixed64
''' <summary>
''' The <c>fixed32</c> field type.
''' </summary>
Fixed32
''' <summary>
''' The <c>bool</c> field type.
''' </summary>
Bool
''' <summary>
''' The <c>string</c> field type.
''' </summary>
[String]
''' <summary>
''' The field type used for groups (not supported in this implementation).
''' </summary>
Group
''' <summary>
''' The field type used for message fields.
''' </summary>
Message
''' <summary>
''' The <c>bytes</c> field type.
''' </summary>
Bytes
''' <summary>
''' The <c>uint32</c> field type.
''' </summary>
UInt32
''' <summary>
''' The <c>sfixed32</c> field type.
''' </summary>
SFixed32
''' <summary>
''' The <c>sfixed64</c> field type.
''' </summary>
SFixed64
''' <summary>
''' The <c>sint32</c> field type.
''' </summary>
SInt32
''' <summary>
''' The <c>sint64</c> field type.
''' </summary>
SInt64
''' <summary>
''' The field type used for enum fields.
''' </summary>
[Enum]
End Enum
End Namespace

@ -0,0 +1,326 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2008 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Namespace Google.Protobuf.Reflection
''' <summary>
''' Describes a .proto file, including everything defined within.
''' IDescriptor is implemented such that the File property returns this descriptor,
''' and the FullName is the same as the Name.
''' </summary>
Public NotInheritable Class FileDescriptor
Implements IDescriptor
Private Sub New(descriptorData As ByteString, proto As FileDescriptorProto, dependencies As FileDescriptor(), pool As DescriptorPool, allowUnknownDependencies As Boolean, generatedCodeInfo As GeneratedClrTypeInfo)
SerializedData = descriptorData
DescriptorPool = pool
Me.Proto = proto
Me.Dependencies = New ReadOnlyCollection(Of FileDescriptor)(CType(dependencies.Clone(), FileDescriptor()))
PublicDependencies = DeterminePublicDependencies(Me, proto, dependencies, allowUnknownDependencies)
pool.AddPackage(Package, Me)
MessageTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.MessageType, Function(message, index) New MessageDescriptor(message, Me, Nothing, index, generatedCodeInfo.NestedTypes(index)))
EnumTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.EnumType, Function(enumType, index) New EnumDescriptor(enumType, Me, Nothing, index, generatedCodeInfo.NestedEnums(index)))
Services = DescriptorUtil.ConvertAndMakeReadOnly(proto.Service, Function(service, index) New ServiceDescriptor(service, Me, index))
End Sub
''' <summary>
''' Computes the full name of a descriptor within this file, with an optional parent message.
''' </summary>
Friend Function ComputeFullName(parent As MessageDescriptor, name As String) As String
If parent IsNot Nothing Then
Return parent.FullName & "." & name
End If
If Package.Length > 0 Then
Return Package & "." & name
End If
Return name
End Function
''' <summary>
''' Extracts public dependencies from direct dependencies. This is a static method despite its
''' first parameter, as the value we're in the middle of constructing is only used for exceptions.
''' </summary>
Private Shared Function DeterminePublicDependencies(this As FileDescriptor, proto As FileDescriptorProto, dependencies As FileDescriptor(), allowUnknownDependencies As Boolean) As IList(Of FileDescriptor)
Dim nameToFileMap = New Dictionary(Of String, FileDescriptor)()
For Each file As FileDescriptor In dependencies
nameToFileMap(file.Name) = file
Next
Dim publicDependencies = New List(Of FileDescriptor)()
For i = 0 To proto.PublicDependency.Count - 1
Dim index = proto.PublicDependency(i)
If index < 0 OrElse index >= proto.Dependency.Count Then
Throw New DescriptorValidationException(this, "Invalid public dependency index.")
End If
Dim name = proto.Dependency(index)
Dim file = nameToFileMap(name)
If file Is Nothing Then
If Not allowUnknownDependencies Then
Throw New DescriptorValidationException(this, "Invalid public dependency: " & name)
' Ignore unknown dependencies.
End If
Else
publicDependencies.Add(file)
End If
Next
Return New ReadOnlyCollection(Of FileDescriptor)(publicDependencies)
End Function
''' <value>
''' The descriptor in its protocol message representation.
''' </value>
Friend ReadOnly Property Proto As FileDescriptorProto
''' <value>
''' The file name.
''' </value>
Public ReadOnly Property Name As String Implements IDescriptor.Name
Get
Return Proto.Name
End Get
End Property
''' <summary>
''' The package as declared in the .proto file. This may or may not
''' be equivalent to the .NET namespace of the generated classes.
''' </summary>
Public ReadOnly Property Package As String
Get
Return Proto.Package
End Get
End Property
''' <value>
''' Unmodifiable list of top-level message types declared in this file.
''' </value>
Public ReadOnly Property MessageTypes As IList(Of MessageDescriptor)
''' <value>
''' Unmodifiable list of top-level enum types declared in this file.
''' </value>
Public ReadOnly Property EnumTypes As IList(Of EnumDescriptor)
''' <value>
''' Unmodifiable list of top-level services declared in this file.
''' </value>
Public ReadOnly Property Services As IList(Of ServiceDescriptor)
''' <value>
''' Unmodifiable list of this file's dependencies (imports).
''' </value>
Public ReadOnly Property Dependencies As IList(Of FileDescriptor)
''' <value>
''' Unmodifiable list of this file's public dependencies (public imports).
''' </value>
Public ReadOnly Property PublicDependencies As IList(Of FileDescriptor)
''' <value>
''' The original serialized binary form of this descriptor.
''' </value>
Public ReadOnly Property SerializedData As ByteString
''' <value>
''' Implementation of IDescriptor.FullName - just returns the same as Name.
''' </value>
Private ReadOnly Property FullName As String Implements IDescriptor.FullName
Get
Return Name
End Get
End Property
''' <value>
''' Implementation of IDescriptor.File - just returns this descriptor.
''' </value>
Private ReadOnly Property File As FileDescriptor Implements IDescriptor.File
Get
Return Me
End Get
End Property
''' <value>
''' Pool containing symbol descriptors.
''' </value>
Friend ReadOnly Property DescriptorPool As DescriptorPool
''' <summary>
''' Finds a type (message, enum, service or extension) in the file by name. Does not find nested types.
''' </summary>
''' <param name="name">The unqualified type name to look for.</param>
''' <typeparamname="T">The type of descriptor to look for</typeparam>
''' <returns>The type's descriptor, or null if not found.</returns>
Public Function FindTypeByName(Of T As {Class, IDescriptor})(name As String) As T
' Don't allow looking up nested types. This will make optimization
' easier later.
If name.IndexOf("."c) <> -1 Then
Return Nothing
End If
If Package.Length > 0 Then
name = Package & "." & name
End If
Dim result = DescriptorPool.FindSymbol(Of T)(name)
If result IsNot Nothing AndAlso result.File Is Me Then
Return result
End If
Return Nothing
End Function
''' <summary>
''' Builds a FileDescriptor from its protocol buffer representation.
''' </summary>
''' <param name="descriptorData">The original serialized descriptor data.
''' We have only limited proto2 support, so serializing FileDescriptorProto
''' would not necessarily give us this.</param>
''' <param name="proto">The protocol message form of the FileDescriptor.</param>
''' <param name="dependencies">FileDescriptors corresponding to all of the
''' file's dependencies, in the exact order listed in the .proto file. May be null,
''' in which case it is treated as an empty array.</param>
''' <param name="allowUnknownDependencies">Whether unknown dependencies are ignored (true) or cause an exception to be thrown (false).</param>
''' <param name="generatedCodeInfo">Details about generated code, for the purposes of reflection.</param>
''' <exception cref="DescriptorValidationException">If <paramrefname="proto"/> is not
''' a valid descriptor. This can occur for a number of reasons, such as a field
''' having an undefined type or because two messages were defined with the same name.</exception>
Private Shared Function BuildFrom(descriptorData As ByteString, proto As FileDescriptorProto, dependencies As FileDescriptor(), allowUnknownDependencies As Boolean, generatedCodeInfo As GeneratedClrTypeInfo) As FileDescriptor
' Building descriptors involves two steps: translating and linking.
' In the translation step (implemented by FileDescriptor's
' constructor), we build an object tree mirroring the
' FileDescriptorProto's tree and put all of the descriptors into the
' DescriptorPool's lookup tables. In the linking step, we look up all
' type references in the DescriptorPool, so that, for example, a
' FieldDescriptor for an embedded message contains a pointer directly
' to the Descriptor for that message's type. We also detect undefined
' types in the linking step.
If dependencies Is Nothing Then
dependencies = New FileDescriptor(-1) {}
End If
Dim pool As DescriptorPool = New DescriptorPool(dependencies)
Dim result As FileDescriptor = New FileDescriptor(descriptorData, proto, dependencies, pool, allowUnknownDependencies, generatedCodeInfo)
' Validate that the dependencies we've been passed (as FileDescriptors) are actually the ones we
' need.
If dependencies.Length <> proto.Dependency.Count Then
Throw New DescriptorValidationException(result, "Dependencies passed to FileDescriptor.BuildFrom() don't match " & "those listed in the FileDescriptorProto.")
End If
For i = 0 To proto.Dependency.Count - 1
If Not Equals(dependencies(i).Name, proto.Dependency(i)) Then
Throw New DescriptorValidationException(result, "Dependencies passed to FileDescriptor.BuildFrom() don't match " & "those listed in the FileDescriptorProto. Expected: " & proto.Dependency(i) & " but was: " & dependencies(i).Name)
End If
Next
result.CrossLink()
Return result
End Function
Private Sub CrossLink()
For Each message In MessageTypes
message.CrossLink()
Next
For Each service In Services
service.CrossLink()
Next
End Sub
''' <summary>
''' Creates a descriptor for generated code.
''' </summary>
''' <remarks>
''' This method is only designed to be used by the results of generating code with protoc,
''' which creates the appropriate dependencies etc. It has to be public because the generated
''' code is "external", but should not be called directly by end users.
''' </remarks>
Public Shared Function FromGeneratedCode(descriptorData As Byte(), dependencies As FileDescriptor(), generatedCodeInfo As GeneratedClrTypeInfo) As FileDescriptor
Dim proto As FileDescriptorProto
Try
proto = FileDescriptorProto.Parser.ParseFrom(descriptorData)
Catch e As InvalidProtocolBufferException
Throw New ArgumentException("Failed to parse protocol buffer descriptor for generated code.", e)
End Try
Try
' When building descriptors for generated code, we allow unknown
' dependencies by default.
Return BuildFrom(ByteString.CopyFrom(descriptorData), proto, dependencies, True, generatedCodeInfo)
Catch e As DescriptorValidationException
Throw New ArgumentException($"Invalid embedded descriptor for ""{proto.Name}"".", e)
End Try
End Function
''' <summary>
''' Returns a <see cref="System.String"/> that represents this instance.
''' </summary>
''' <returns>
''' A <see cref="System.String"/> that represents this instance.
''' </returns>
Public Overrides Function ToString() As String
Return $"FileDescriptor for {Name}"
End Function
''' <summary>
''' Returns the file descriptor for descriptor.proto.
''' </summary>
''' <remarks>
''' This is used for protos which take a direct dependency on <c>descriptor.proto</c>, typically for
''' annotations. While <c>descriptor.proto</c> is a proto2 file, it is built into the Google.Protobuf
''' runtime for reflection purposes. The messages are internal to the runtime as they would require
''' proto2 semantics for full support, but the file descriptor is available via this property. The
''' C# codegen in protoc automatically uses this property when it detects a dependency on <c>descriptor.proto</c>.
''' </remarks>
''' <value>
''' The file descriptor for <c>descriptor.proto</c>.
''' </value>
Public Shared ReadOnly Property DescriptorProtoFileDescriptor As FileDescriptor
Get
Return Descriptor
End Get
End Property
End Class
End Namespace

@ -0,0 +1,108 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2015 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System
Namespace Google.Protobuf.Reflection
''' <summary>
''' Extra information provided by generated code when initializing a message or file descriptor.
''' These are constructed as required, and are not long-lived. Hand-written code should
''' never need to use this type.
''' </summary>
Public NotInheritable Class GeneratedClrTypeInfo
''' <summary>
''' Irrelevant for file descriptors; the CLR type for the message for message descriptors.
''' </summary>
Private _ClrType As System.Type
Private Shared ReadOnly EmptyNames As String() = New String(-1) {}
Private Shared ReadOnly EmptyCodeInfo As GeneratedClrTypeInfo() = New GeneratedClrTypeInfo(-1) {}
Public Property ClrType As Type
Get
Return _ClrType
End Get
Private Set(value As Type)
_ClrType = value
End Set
End Property
''' <summary>
''' Irrelevant for file descriptors; the parser for message descriptors.
''' </summary>
Public ReadOnly Property Parser As MessageParser
''' <summary>
''' Irrelevant for file descriptors; the CLR property names (in message descriptor field order)
''' for fields in the message for message descriptors.
''' </summary>
Public ReadOnly Property PropertyNames As String()
''' <summary>
''' Irrelevant for file descriptors; the CLR property "base" names (in message descriptor oneof order)
''' for oneofs in the message for message descriptors. It is expected that for a oneof name of "Foo",
''' there will be a "FooCase" property and a "ClearFoo" method.
''' </summary>
Public ReadOnly Property OneofNames As String()
''' <summary>
''' The reflection information for types within this file/message descriptor. Elements may be null
''' if there is no corresponding generated type, e.g. for map entry types.
''' </summary>
Public ReadOnly Property NestedTypes As GeneratedClrTypeInfo()
''' <summary>
''' The CLR types for enums within this file/message descriptor.
''' </summary>
Public ReadOnly Property NestedEnums As Type()
''' <summary>
''' Creates a GeneratedClrTypeInfo for a message descriptor, with nested types, nested enums, the CLR type, property names and oneof names.
''' Each array parameter may be null, to indicate a lack of values.
''' The parameter order is designed to make it feasible to format the generated code readably.
''' </summary>
Public Sub New(clrType As Type, parser As MessageParser, propertyNames As String(), oneofNames As String(), nestedEnums As Type(), nestedTypes As GeneratedClrTypeInfo())
Me.NestedTypes = If(nestedTypes, EmptyCodeInfo)
Me.NestedEnums = If(nestedEnums, EmptyTypes)
Me.ClrType = clrType
Me.Parser = parser
Me.PropertyNames = If(propertyNames, EmptyNames)
Me.OneofNames = If(oneofNames, EmptyNames)
End Sub
''' <summary>
''' Creates a GeneratedClrTypeInfo for a file descriptor, with only types and enums.
''' </summary>
Public Sub New(nestedEnums As Type(), nestedTypes As GeneratedClrTypeInfo())
Me.New(Nothing, Nothing, Nothing, Nothing, nestedEnums, nestedTypes)
End Sub
End Class
End Namespace

@ -0,0 +1,53 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2008 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Namespace Google.Protobuf.Reflection
''' <summary>
''' Interface implemented by all descriptor types.
''' </summary>
Public Interface IDescriptor
''' <summary>
''' Returns the name of the entity (message, field etc) being described.
''' </summary>
ReadOnly Property Name As String
''' <summary>
''' Returns the fully-qualified name of the entity being described.
''' </summary>
ReadOnly Property FullName As String
''' <summary>
''' Returns the descriptor for the .proto file that this entity is part of.
''' </summary>
ReadOnly Property File As FileDescriptor
End Interface
End Namespace

@ -0,0 +1,67 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2008 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Namespace Google.Protobuf.Reflection
''' <summary>
''' Allows fields to be reflectively accessed.
''' </summary>
Public Interface IFieldAccessor
''' <summary>
''' Returns the descriptor associated with this field.
''' </summary>
ReadOnly Property Descriptor As FieldDescriptor
''' <summary>
''' Clears the field in the specified message. (For repeated fields,
''' this clears the list.)
''' </summary>
Sub Clear(message As IMessage)
''' <summary>
''' Fetches the field value. For repeated values, this will be an
''' <see cref="IList"/> implementation. For map values, this will be an
''' <see cref="IDictionary"/> implementation.
''' </summary>
Function GetValue(message As IMessage) As Object
''' <summary>
''' Mutator for single "simple" fields only.
''' </summary>
''' <remarks>
''' Repeated fields are mutated by fetching the value and manipulating it as a list.
''' Map fields are mutated by fetching the value and manipulating it as a dictionary.
''' </remarks>
''' <exception cref="InvalidOperationException">The field is not a "simple" field.</exception>
Sub SetValue(message As IMessage, value As Object)
End Interface
End Namespace

@ -0,0 +1,57 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2015 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System
Imports System.Collections
Imports System.Reflection
Namespace Google.Protobuf.Reflection
''' <summary>
''' Accessor for map fields.
''' </summary>
Friend NotInheritable Class MapFieldAccessor
Inherits FieldAccessorBase
Friend Sub New([property] As PropertyInfo, descriptor As FieldDescriptor)
MyBase.New([property], descriptor)
End Sub
Public Overrides Sub Clear(message As IMessage)
Dim list = CType(GetValue(message), IDictionary)
list.Clear()
End Sub
Public Overrides Sub SetValue(message As IMessage, value As Object)
Throw New InvalidOperationException("SetValue is not implemented for map fields")
End Sub
End Class
End Namespace

@ -0,0 +1,318 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2008 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Imports System.Linq
#If DOTNET35
// Needed for ReadOnlyDictionary, which does not exist in .NET 3.5
using Google.Protobuf.Collections;
#End If
Namespace Google.Protobuf.Reflection
''' <summary>
''' Describes a message type.
''' </summary>
Public NotInheritable Class MessageDescriptor
Inherits DescriptorBase
Private Shared ReadOnly WellKnownTypeNames As HashSet(Of String) = New HashSet(Of String) From {
"google/protobuf/any.proto",
"google/protobuf/api.proto",
"google/protobuf/duration.proto",
"google/protobuf/empty.proto",
"google/protobuf/wrappers.proto",
"google/protobuf/timestamp.proto",
"google/protobuf/field_mask.proto",
"google/protobuf/source_context.proto",
"google/protobuf/struct.proto",
"google/protobuf/type.proto"
}
Private ReadOnly fieldsInDeclarationOrder As IList(Of FieldDescriptor)
Private ReadOnly fieldsInNumberOrder As IList(Of FieldDescriptor)
Private ReadOnly jsonFieldMap As IDictionary(Of String, FieldDescriptor)
Friend Sub New(proto As DescriptorProto, file As FileDescriptor, parent As MessageDescriptor, typeIndex As Integer, generatedCodeInfo As GeneratedClrTypeInfo)
MyBase.New(file, file.ComputeFullName(parent, proto.Name), typeIndex)
Me.Proto = proto
Parser = generatedCodeInfo?.Parser
ClrType = generatedCodeInfo?.ClrType
ContainingType = parent
' Note use of generatedCodeInfo. rather than generatedCodeInfo?. here... we don't expect
' to see any nested oneofs, types or enums in "not actually generated" code... we do
' expect fields though (for map entry messages).
Oneofs = DescriptorUtil.ConvertAndMakeReadOnly(proto.OneofDecl, Function(oneof, index) New OneofDescriptor(oneof, file, Me, index, generatedCodeInfo.OneofNames(index)))
NestedTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.NestedType, Function(type, index) New MessageDescriptor(type, file, Me, index, generatedCodeInfo.NestedTypes(index)))
EnumTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.EnumType, Function(type, index) New EnumDescriptor(type, file, Me, index, generatedCodeInfo.NestedEnums(index)))
fieldsInDeclarationOrder = DescriptorUtil.ConvertAndMakeReadOnly(proto.Field, Function(field, index) New FieldDescriptor(field, file, Me, index, generatedCodeInfo?.PropertyNames(index)))
fieldsInNumberOrder = New ReadOnlyCollection(Of FieldDescriptor)(fieldsInDeclarationOrder.OrderBy(Function(field) field.FieldNumber).ToArray())
' TODO: Use field => field.Proto.JsonName when we're confident it's appropriate. (And then use it in the formatter, too.)
jsonFieldMap = CreateJsonFieldMap(fieldsInNumberOrder)
file.DescriptorPool.AddSymbol(Me)
Fields = New FieldCollection(Me)
End Sub
Private Shared Function CreateJsonFieldMap(fields As IList(Of FieldDescriptor)) As ReadOnlyDictionary(Of String, FieldDescriptor)
Dim map = New Dictionary(Of String, FieldDescriptor)()
For Each field In fields
map(field.Name) = field
map(field.JsonName) = field
Next
Return New ReadOnlyDictionary(Of String, FieldDescriptor)(map)
End Function
''' <summary>
''' The brief name of the descriptor's target.
''' </summary>
Public Overrides ReadOnly Property Name As String
Get
Return Proto.Name
End Get
End Property
Friend ReadOnly Property Proto As DescriptorProto
''' <summary>
''' The CLR type used to represent message instances from this descriptor.
''' </summary>
''' <remarks>
''' <para>
''' The value returned by this property will be non-null for all regular fields. However,
''' if a message containing a map field is introspected, the list of nested messages will include
''' an auto-generated nested key/value pair message for the field. This is not represented in any
''' generated type, so this property will return null in such cases.
''' </para>
''' <para>
''' For wrapper types (<see cref="Google.Protobuf.WellKnownTypes.StringValue"/> and the like), the type returned here
''' will be the generated message type, not the native type used by reflection for fields of those types. Code
''' using reflection should call <see cref="IsWrapperType"/> to determine whether a message descriptor represents
''' a wrapper type, and handle the result appropriately.
''' </para>
''' </remarks>
Public ReadOnly Property ClrType As Type
''' <summary>
''' A parser for this message type.
''' </summary>
''' <remarks>
''' <para>
''' As <see cref="MessageDescriptor"/> is not generic, this cannot be statically
''' typed to the relevant type, but it should produce objects of a type compatible with <see cref="ClrType"/>.
''' </para>
''' <para>
''' The value returned by this property will be non-null for all regular fields. However,
''' if a message containing a map field is introspected, the list of nested messages will include
''' an auto-generated nested key/value pair message for the field. No message parser object is created for
''' such messages, so this property will return null in such cases.
''' </para>
''' <para>
''' For wrapper types (<see cref="Google.Protobuf.WellKnownTypes.StringValue"/> and the like), the parser returned here
''' will be the generated message type, not the native type used by reflection for fields of those types. Code
''' using reflection should call <see cref="IsWrapperType"/> to determine whether a message descriptor represents
''' a wrapper type, and handle the result appropriately.
''' </para>
''' </remarks>
Public ReadOnly Property Parser As MessageParser
''' <summary>
''' Returns whether this message is one of the "well known types" which may have runtime/protoc support.
''' </summary>
Friend ReadOnly Property IsWellKnownType As Boolean
Get
Return Equals(File.Package, "google.protobuf") AndAlso WellKnownTypeNames.Contains(File.Name)
End Get
End Property
''' <summary>
''' Returns whether this message is one of the "wrapper types" used for fields which represent primitive values
''' with the addition of presence.
''' </summary>
Friend ReadOnly Property IsWrapperType As Boolean
Get
Return Equals(File.Package, "google.protobuf") AndAlso Equals(File.Name, "google/protobuf/wrappers.proto")
End Get
End Property
''' <value>
''' If this is a nested type, get the outer descriptor, otherwise null.
''' </value>
Public ReadOnly Property ContainingType As MessageDescriptor
''' <value>
''' A collection of fields, which can be retrieved by name or field number.
''' </value>
Public ReadOnly Property Fields As FieldCollection
''' <value>
''' An unmodifiable list of this message type's nested types.
''' </value>
Public ReadOnly Property NestedTypes As IList(Of MessageDescriptor)
''' <value>
''' An unmodifiable list of this message type's enum types.
''' </value>
Public ReadOnly Property EnumTypes As IList(Of EnumDescriptor)
''' <value>
''' An unmodifiable list of the "oneof" field collections in this message type.
''' </value>
Public ReadOnly Property Oneofs As IList(Of OneofDescriptor)
''' <summary>
''' Finds a field by field name.
''' </summary>
''' <param name="name">The unqualified name of the field (e.g. "foo").</param>
''' <returns>The field's descriptor, or null if not found.</returns>
Public Function FindFieldByName(name As String) As FieldDescriptor
Return File.DescriptorPool.FindSymbol(Of FieldDescriptor)(FullName & "." & name)
End Function
''' <summary>
''' Finds a field by field number.
''' </summary>
''' <param name="number">The field number within this message type.</param>
''' <returns>The field's descriptor, or null if not found.</returns>
Public Function FindFieldByNumber(number As Integer) As FieldDescriptor
Return File.DescriptorPool.FindFieldByNumber(Me, number)
End Function
''' <summary>
''' Finds a nested descriptor by name. The is valid for fields, nested
''' message types, oneofs and enums.
''' </summary>
''' <param name="name">The unqualified name of the descriptor, e.g. "Foo"</param>
''' <returns>The descriptor, or null if not found.</returns>
Public Function FindDescriptor(Of T As {Class, IDescriptor})(name As String) As T
Return File.DescriptorPool.FindSymbol(Of T)(FullName & "." & name)
End Function
''' <summary>
''' Looks up and cross-links all fields and nested types.
''' </summary>
Friend Sub CrossLink()
For Each message In NestedTypes
message.CrossLink()
Next
For Each field In fieldsInDeclarationOrder
field.CrossLink()
Next
For Each oneof In Oneofs
oneof.CrossLink()
Next
End Sub
''' <summary>
''' A collection to simplify retrieving the field accessor for a particular field.
''' </summary>
Public NotInheritable Class FieldCollection
Private ReadOnly messageDescriptor As MessageDescriptor
Friend Sub New(messageDescriptor As MessageDescriptor)
Me.messageDescriptor = messageDescriptor
End Sub
''' <value>
''' Returns the fields in the message as an immutable list, in the order in which they
''' are declared in the source .proto file.
''' </value>
Public Function InDeclarationOrder() As IList(Of FieldDescriptor)
Return messageDescriptor.fieldsInDeclarationOrder
End Function
''' <value>
''' Returns the fields in the message as an immutable list, in ascending field number
''' order. Field numbers need not be contiguous, so there is no direct mapping from the
''' index in the list to the field number; to retrieve a field by field number, it is better
''' to use the <see cref="FieldCollection"/> indexer.
''' </value>
Public Function InFieldNumberOrder() As IList(Of FieldDescriptor)
Return messageDescriptor.fieldsInNumberOrder
End Function
' TODO: consider making this public in the future. (Being conservative for now...)
''' <value>
''' Returns a read-only dictionary mapping the field names in this message as they're available
''' in the JSON representation to the field descriptors. For example, a field <c>foo_bar</c>
''' in the message would result two entries, one with a key <c>fooBar</c> and one with a key
''' <c>foo_bar</c>, both referring to the same field.
''' </value>
Friend Function ByJsonName() As IDictionary(Of String, FieldDescriptor)
Return messageDescriptor.jsonFieldMap
End Function
''' <summary>
''' Retrieves the descriptor for the field with the given number.
''' </summary>
''' <param name="number">Number of the field to retrieve the descriptor for</param>
''' <returns>The accessor for the given field</returns>
''' <exception cref="KeyNotFoundException">The message descriptor does not contain a field
''' with the given number</exception>
Default Public ReadOnly Property Item(number As Integer) As FieldDescriptor
Get
Dim fieldDescriptor = messageDescriptor.FindFieldByNumber(number)
If fieldDescriptor Is Nothing Then
Throw New KeyNotFoundException("No such field number")
End If
Return fieldDescriptor
End Get
End Property
''' <summary>
''' Retrieves the descriptor for the field with the given name.
''' </summary>
''' <param name="name">Name of the field to retrieve the descriptor for</param>
''' <returns>The descriptor for the given field</returns>
''' <exception cref="KeyNotFoundException">The message descriptor does not contain a field
''' with the given name</exception>
Default Public ReadOnly Property Item(name As String) As FieldDescriptor
Get
Dim fieldDescriptor = messageDescriptor.FindFieldByName(name)
If fieldDescriptor Is Nothing Then
Throw New KeyNotFoundException("No such field name")
End If
Return fieldDescriptor
End Get
End Property
End Class
End Class
End Namespace

@ -0,0 +1,129 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2008 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Namespace Google.Protobuf.Reflection
''' <summary>
''' Describes a single method in a service.
''' </summary>
Public NotInheritable Class MethodDescriptor
Inherits DescriptorBase
Private ReadOnly protoField As MethodDescriptorProto
Private ReadOnly serviceField As ServiceDescriptor
Private inputTypeField As MessageDescriptor
Private outputTypeField As MessageDescriptor
''' <value>
''' The service this method belongs to.
''' </value>
Public ReadOnly Property Service As ServiceDescriptor
Get
Return serviceField
End Get
End Property
''' <value>
''' The method's input type.
''' </value>
Public ReadOnly Property InputType As MessageDescriptor
Get
Return inputTypeField
End Get
End Property
''' <value>
''' The method's input type.
''' </value>
Public ReadOnly Property OutputType As MessageDescriptor
Get
Return outputTypeField
End Get
End Property
''' <value>
''' Indicates if client streams multiple requests.
''' </value>
Public ReadOnly Property IsClientStreaming As Boolean
Get
Return protoField.ClientStreaming
End Get
End Property
''' <value>
''' Indicates if server streams multiple responses.
''' </value>
Public ReadOnly Property IsServerStreaming As Boolean
Get
Return protoField.ServerStreaming
End Get
End Property
Friend Sub New(proto As MethodDescriptorProto, file As FileDescriptor, parent As ServiceDescriptor, index As Integer)
MyBase.New(file, parent.FullName & "." & proto.Name, index)
protoField = proto
serviceField = parent
file.DescriptorPool.AddSymbol(Me)
End Sub
Friend ReadOnly Property Proto As MethodDescriptorProto
Get
Return protoField
End Get
End Property
''' <summary>
''' The brief name of the descriptor's target.
''' </summary>
Public Overrides ReadOnly Property Name As String
Get
Return protoField.Name
End Get
End Property
Friend Sub CrossLink()
Dim lookup = File.DescriptorPool.LookupSymbol(Proto.InputType, Me)
If Not (TypeOf lookup Is MessageDescriptor) Then
Throw New DescriptorValidationException(Me, """" & Proto.InputType & """ is not a message type.")
End If
inputTypeField = CType(lookup, MessageDescriptor)
lookup = File.DescriptorPool.LookupSymbol(Proto.OutputType, Me)
If Not (TypeOf lookup Is MessageDescriptor) Then
Throw New DescriptorValidationException(Me, """" & Proto.OutputType & """ is not a message type.")
End If
outputTypeField = CType(lookup, MessageDescriptor)
End Sub
End Class
End Namespace

@ -0,0 +1,88 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2015 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System
Imports System.Reflection
Namespace Google.Protobuf.Reflection
''' <summary>
''' Reflection access for a oneof, allowing clear and "get case" actions.
''' </summary>
Public NotInheritable Class OneofAccessor
Private ReadOnly caseDelegate As Func(Of IMessage, Integer)
Private ReadOnly clearDelegate As Action(Of IMessage)
Private descriptorField As OneofDescriptor
Friend Sub New(caseProperty As PropertyInfo, clearMethod As MethodInfo, descriptor As OneofDescriptor)
If Not caseProperty.CanRead Then
Throw New ArgumentException("Cannot read from property")
End If
descriptorField = descriptor
caseDelegate = CreateFuncIMessageT(Of Integer)(caseProperty.GetGetMethod())
descriptorField = descriptor
clearDelegate = CreateActionIMessage(clearMethod)
End Sub
''' <summary>
''' Gets the descriptor for this oneof.
''' </summary>
''' <value>
''' The descriptor of the oneof.
''' </value>
Public ReadOnly Property Descriptor As OneofDescriptor
Get
Return descriptorField
End Get
End Property
''' <summary>
''' Clears the oneof in the specified message.
''' </summary>
Public Sub Clear(message As IMessage)
clearDelegate(message)
End Sub
''' <summary>
''' Indicates which field in the oneof is set for specified message
''' </summary>
Public Function GetCaseFieldDescriptor(message As IMessage) As FieldDescriptor
Dim fieldNumber = caseDelegate(message)
If fieldNumber > 0 Then
Return descriptorField.ContainingType.FindFieldByNumber(fieldNumber)
End If
Return Nothing
End Function
End Class
End Namespace

@ -0,0 +1,132 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2015 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Namespace Google.Protobuf.Reflection
''' <summary>
''' Describes a "oneof" field collection in a message type: a set of
''' fields of which at most one can be set in any particular message.
''' </summary>
Public NotInheritable Class OneofDescriptor
Inherits DescriptorBase
Private ReadOnly proto As OneofDescriptorProto
Private containingTypeField As MessageDescriptor
Private fieldsField As IList(Of FieldDescriptor)
Private ReadOnly accessorField As OneofAccessor
Friend Sub New(proto As OneofDescriptorProto, file As FileDescriptor, parent As MessageDescriptor, index As Integer, clrName As String)
MyBase.New(file, file.ComputeFullName(parent, proto.Name), index)
Me.proto = proto
containingTypeField = parent
file.DescriptorPool.AddSymbol(Me)
accessorField = CreateAccessor(clrName)
End Sub
''' <summary>
''' The brief name of the descriptor's target.
''' </summary>
Public Overrides ReadOnly Property Name As String
Get
Return proto.Name
End Get
End Property
''' <summary>
''' Gets the message type containing this oneof.
''' </summary>
''' <value>
''' The message type containing this oneof.
''' </value>
Public ReadOnly Property ContainingType As MessageDescriptor
Get
Return containingTypeField
End Get
End Property
''' <summary>
''' Gets the fields within this oneof, in declaration order.
''' </summary>
''' <value>
''' The fields within this oneof, in declaration order.
''' </value>
Public ReadOnly Property Fields As IList(Of FieldDescriptor)
Get
Return fieldsField
End Get
End Property
''' <summary>
''' Gets an accessor for reflective access to the values associated with the oneof
''' in a particular message.
''' </summary>
''' <value>
''' The accessor used for reflective access.
''' </value>
Public ReadOnly Property Accessor As OneofAccessor
Get
Return accessorField
End Get
End Property
Friend Sub CrossLink()
Dim fieldCollection As List(Of FieldDescriptor) = New List(Of FieldDescriptor)()
For Each field In ContainingType.Fields.InDeclarationOrder()
If field.ContainingOneof Is Me Then
fieldCollection.Add(field)
End If
Next
fieldsField = New ReadOnlyCollection(Of FieldDescriptor)(fieldCollection)
End Sub
Private Function CreateAccessor(clrName As String) As OneofAccessor
Dim caseProperty = containingTypeField.ClrType.GetProperty(clrName & "Case")
If caseProperty Is Nothing Then
Throw New DescriptorValidationException(Me, $"Property {clrName}Case not found in {containingTypeField.ClrType}")
End If
Dim clearMethod = containingTypeField.ClrType.GetMethod("Clear" & clrName)
If clearMethod Is Nothing Then
Throw New DescriptorValidationException(Me, $"Method Clear{clrName} not found in {containingTypeField.ClrType}")
End If
Return New OneofAccessor(caseProperty, clearMethod, Me)
End Function
End Class
End Namespace

@ -0,0 +1,56 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2008 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System
Namespace Google.Protobuf.Reflection
''' <summary>
''' Specifies the original name (in the .proto file) of a named element,
''' such as an enum value.
''' </summary>
<AttributeUsage(AttributeTargets.Field)>
Public Class OriginalNameAttribute
Inherits Attribute
''' <summary>
''' The name of the element in the .proto file.
''' </summary>
Public Property Name As String
''' <summary>
''' Constructs a new attribute instance for the given name.
''' </summary>
''' <param name="name">The name of the element in the .proto file.</param>
Public Sub New(name As String)
Me.Name = CheckNotNull(name, NameOf(name))
End Sub
End Class
End Namespace

@ -0,0 +1,70 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2008 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Namespace Google.Protobuf.Reflection
''' <summary>
''' Represents a package in the symbol table. We use PackageDescriptors
''' just as placeholders so that someone cannot define, say, a message type
''' that has the same name as an existing package.
''' </summary>
Friend NotInheritable Class PackageDescriptor
Implements IDescriptor
Private ReadOnly nameField As String
Private ReadOnly fullNameField As String
Private ReadOnly fileField As FileDescriptor
Friend Sub New(name As String, fullName As String, file As FileDescriptor)
fileField = file
fullNameField = fullName
nameField = name
End Sub
Public ReadOnly Property Name As String Implements IDescriptor.Name
Get
Return nameField
End Get
End Property
Public ReadOnly Property FullName As String Implements IDescriptor.FullName
Get
Return fullNameField
End Get
End Property
Public ReadOnly Property File As FileDescriptor Implements IDescriptor.File
Get
Return fileField
End Get
End Property
End Class
End Namespace

@ -0,0 +1,54 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2008 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
' This file just contains partial classes for any autogenerated classes that need additional support.
Namespace Google.Protobuf.Reflection
Friend Partial Class FieldDescriptorProto
' We can't tell the difference between "explicitly set to 0" and "not set"
' in proto3, but we need to tell the difference for OneofIndex. descriptor.proto
' is really a proto2 file, but the runtime doesn't know about proto2 semantics...
' We fake it by defaulting to -1.
Private Sub OnConstruction()
OneofIndex = -1
End Sub
End Class
Friend Partial Class FieldOptions
' We can't tell the difference between "explicitly set to false" and "not set"
' in proto3, but we need to tell the difference for FieldDescriptor.IsPacked.
' This won't work if we ever need to support proto2, but at that point we'll be
' able to remove this hack and use field presence instead.
Private Sub OnConstruction()
Packed = True
End Sub
End Class
End Namespace

@ -0,0 +1,91 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2008 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System
Imports System.Reflection
Namespace Google.Protobuf.Reflection
''' <summary>
''' In order to run on iOS (no JIT) we had to use Invoke which results in a bit
''' of a performance cost. The original description is as follows:
''' The methods in this class are somewhat evil, and should not be tampered with lightly.
''' Basically they allow the creation of relatively weakly typed delegates from MethodInfos
''' which are more strongly typed. They do this by creating an appropriate strongly typed
''' delegate from the MethodInfo, and then calling that within an anonymous method.
''' Mind-bending stuff (at least to your humble narrator) but the resulting delegates are
''' very fast compared with calling Invoke later on.
''' </summary>
Friend Module ReflectionUtil
''' <summary>
''' Empty Type[] used when calling GetProperty to force property instead of indexer fetching.
''' </summary>
Friend ReadOnly EmptyTypes As Type() = New Type(-1) {}
''' <summary>
''' Creates a delegate which will cast the argument to the appropriate method target type,
''' call the method on it, then convert the result to object.
''' </summary>
Friend Function CreateFuncIMessageObject(method As MethodInfo) As Func(Of IMessage, Object)
Return Function(message)
Dim returnValue = TryCast(method.Invoke(message, Nothing), Object)
Return returnValue
End Function
End Function
''' <summary>
''' Creates a delegate which will cast the argument to the appropriate method target type,
''' call the method on it, then convert the result to the specified type.
''' </summary>
Friend Function CreateFuncIMessageT(Of T)(method As MethodInfo) As Func(Of IMessage, T)
Return Function(message)
Dim returnValue = CType(method.Invoke(message, Nothing), T)
Return returnValue
End Function
End Function
''' <summary>
''' Creates a delegate which will execute the given method after casting the first argument to
''' the target type of the method, and the second argument to the first parameter type of the method.
''' </summary>
Friend Function CreateActionIMessageObject(method As MethodInfo) As Action(Of IMessage, Object)
Return Sub(arg1, arg2) method.Invoke(arg1, New Object() {arg2})
End Function
''' <summary>
''' Creates a delegate which will execute the given method after casting the first argument to
''' the target type of the method.
''' </summary>
Friend Function CreateActionIMessage(method As MethodInfo) As Action(Of IMessage)
Return Sub(obj) method.Invoke(obj, Nothing)
End Function
End Module
End Namespace

@ -0,0 +1,57 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2015 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System
Imports System.Collections
Imports System.Reflection
Namespace Google.Protobuf.Reflection
''' <summary>
''' Accessor for repeated fields.
''' </summary>
Friend NotInheritable Class RepeatedFieldAccessor
Inherits FieldAccessorBase
Friend Sub New([property] As PropertyInfo, descriptor As FieldDescriptor)
MyBase.New([property], descriptor)
End Sub
Public Overrides Sub Clear(message As IMessage)
Dim list = CType(GetValue(message), IList)
list.Clear()
End Sub
Public Overrides Sub SetValue(message As IMessage, value As Object)
Throw New InvalidOperationException("SetValue is not implemented for repeated fields")
End Sub
End Class
End Namespace

@ -0,0 +1,91 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2008 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System.Collections.Generic
Namespace Google.Protobuf.Reflection
''' <summary>
''' Describes a service type.
''' </summary>
Public NotInheritable Class ServiceDescriptor
Inherits DescriptorBase
Private ReadOnly protoField As ServiceDescriptorProto
Private ReadOnly methodsField As IList(Of MethodDescriptor)
Friend Sub New(proto As ServiceDescriptorProto, file As FileDescriptor, index As Integer)
MyBase.New(file, file.ComputeFullName(Nothing, proto.Name), index)
protoField = proto
methodsField = DescriptorUtil.ConvertAndMakeReadOnly(proto.Method, Function(method, i) New MethodDescriptor(method, file, Me, i))
file.DescriptorPool.AddSymbol(Me)
End Sub
''' <summary>
''' The brief name of the descriptor's target.
''' </summary>
Public Overrides ReadOnly Property Name As String
Get
Return protoField.Name
End Get
End Property
Friend ReadOnly Property Proto As ServiceDescriptorProto
Get
Return protoField
End Get
End Property
''' <value>
''' An unmodifiable list of methods in this service.
''' </value>
Public ReadOnly Property Methods As IList(Of MethodDescriptor)
Get
Return methodsField
End Get
End Property
''' <summary>
''' Finds a method by name.
''' </summary>
''' <param name="name">The unqualified name of the method (e.g. "Foo").</param>
''' <returns>The method's decsriptor, or null if not found.</returns>
Public Function FindMethodByName(name As String) As MethodDescriptor
Return File.DescriptorPool.FindSymbol(Of MethodDescriptor)(FullName & "." & name)
End Function
Friend Sub CrossLink()
For Each method In methodsField
method.CrossLink()
Next
End Sub
End Class
End Namespace

@ -0,0 +1,73 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2015 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System
Imports System.Reflection
Namespace Google.Protobuf.Reflection
''' <summary>
''' Accessor for single fields.
''' </summary>
Friend NotInheritable Class SingleFieldAccessor
Inherits FieldAccessorBase
' All the work here is actually done in the constructor - it creates the appropriate delegates.
' There are various cases to consider, based on the property type (message, string/bytes, or "genuine" primitive)
' and proto2 vs proto3 for non-message types, as proto3 doesn't support "full" presence detection or default
' values.
Private ReadOnly setValueDelegate As Action(Of IMessage, Object)
Private ReadOnly clearDelegate As Action(Of IMessage)
Friend Sub New([property] As PropertyInfo, descriptor As FieldDescriptor)
MyBase.New([property], descriptor)
If Not [property].CanWrite Then
Throw New ArgumentException("Not all required properties/methods available")
End If
setValueDelegate = CreateActionIMessageObject([property].GetSetMethod())
Dim clrType = [property].PropertyType
' TODO: Validate that this is a reasonable single field? (Should be a value type, a message type, or string/ByteString.)
Dim defaultValue = If(descriptor.FieldType = FieldType.Message, Nothing, If(clrType Is GetType(String), "", If(clrType Is GetType(ByteString), ByteString.Empty, Activator.CreateInstance(clrType))))
clearDelegate = Sub(message) SetValue(message, defaultValue)
End Sub
Public Overrides Sub Clear(message As IMessage)
clearDelegate(message)
End Sub
Public Overrides Sub SetValue(message As IMessage, value As Object)
setValueDelegate(message, value)
End Sub
End Class
End Namespace

@ -0,0 +1,168 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2015 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System.Collections.Generic
Imports System.Linq
Namespace Google.Protobuf.Reflection
''' <summary>
''' An immutable registry of types which can be looked up by their full name.
''' </summary>
Public NotInheritable Class TypeRegistry
''' <summary>
''' An empty type registry, containing no types.
''' </summary>
Public Shared ReadOnly Property Empty As TypeRegistry = New TypeRegistry(New Dictionary(Of String, MessageDescriptor)())
Private ReadOnly fullNameToMessageMap As Dictionary(Of String, MessageDescriptor)
Private Sub New(fullNameToMessageMap As Dictionary(Of String, MessageDescriptor))
Me.fullNameToMessageMap = fullNameToMessageMap
End Sub
''' <summary>
''' Attempts to find a message descriptor by its full name.
''' </summary>
''' <param name="fullName">The full name of the message, which is the dot-separated
''' combination of package, containing messages and message name</param>
''' <returns>The message descriptor corresponding to <paramrefname="fullName"/> or null
''' if there is no such message descriptor.</returns>
Public Function Find(fullName As String) As MessageDescriptor
Dim ret As MessageDescriptor
' Ignore the return value as ret will end up with the right value either way.
fullNameToMessageMap.TryGetValue(fullName, ret)
Return ret
End Function
''' <summary>
''' Creates a type registry from the specified set of file descriptors.
''' </summary>
''' <remarks>
''' This is a convenience overload for <see cref="FromFiles(IEnumerable(OfFileDescriptor))"/>
''' to allow calls such as <c>TypeRegistry.FromFiles(descriptor1, descriptor2)</c>.
''' </remarks>
''' <param name="fileDescriptors">The set of files to include in the registry. Must not contain null values.</param>
''' <returns>A type registry for the given files.</returns>
Public Shared Function FromFiles(ParamArray fileDescriptors As FileDescriptor()) As TypeRegistry
Return FromFiles(CType(fileDescriptors, IEnumerable(Of FileDescriptor)))
End Function
''' <summary>
''' Creates a type registry from the specified set of file descriptors.
''' </summary>
''' <remarks>
''' All message types within all the specified files are added to the registry, and
''' the dependencies of the specified files are also added, recursively.
''' </remarks>
''' <param name="fileDescriptors">The set of files to include in the registry. Must not contain null values.</param>
''' <returns>A type registry for the given files.</returns>
Public Shared Function FromFiles(fileDescriptors As IEnumerable(Of FileDescriptor)) As TypeRegistry
CheckNotNull(fileDescriptors, NameOf(fileDescriptors))
Dim builder = New Builder()
For Each file In fileDescriptors
builder.AddFile(file)
Next
Return builder.Build()
End Function
''' <summary>
''' Creates a type registry from the file descriptor parents of the specified set of message descriptors.
''' </summary>
''' <remarks>
''' This is a convenience overload for <see cref="FromMessages(IEnumerable(OfMessageDescriptor))"/>
''' to allow calls such as <c>TypeRegistry.FromFiles(descriptor1, descriptor2)</c>.
''' </remarks>
''' <param name="messageDescriptors">The set of message descriptors to use to identify file descriptors to include in the registry.
''' Must not contain null values.</param>
''' <returns>A type registry for the given files.</returns>
Public Shared Function FromMessages(ParamArray messageDescriptors As MessageDescriptor()) As TypeRegistry
Return FromMessages(CType(messageDescriptors, IEnumerable(Of MessageDescriptor)))
End Function
''' <summary>
''' Creates a type registry from the file descriptor parents of the specified set of message descriptors.
''' </summary>
''' <remarks>
''' The specified message descriptors are only used to identify their file descriptors; the returned registry
''' contains all the types within the file descriptors which contain the specified message descriptors (and
''' the dependencies of those files), not just the specified messages.
''' </remarks>
''' <param name="messageDescriptors">The set of message descriptors to use to identify file descriptors to include in the registry.
''' Must not contain null values.</param>
''' <returns>A type registry for the given files.</returns>
Public Shared Function FromMessages(messageDescriptors As IEnumerable(Of MessageDescriptor)) As TypeRegistry
CheckNotNull(messageDescriptors, NameOf(messageDescriptors))
Return FromFiles(messageDescriptors.Select(Function(md) md.File))
End Function
''' <summary>
''' Builder class which isn't exposed, but acts as a convenient alternative to passing round two dictionaries in recursive calls.
''' </summary>
Private Class Builder
Private ReadOnly types As Dictionary(Of String, MessageDescriptor)
Private ReadOnly fileDescriptorNames As HashSet(Of String)
Friend Sub New()
types = New Dictionary(Of String, MessageDescriptor)()
fileDescriptorNames = New HashSet(Of String)()
End Sub
Friend Sub AddFile(fileDescriptor As FileDescriptor)
If Not fileDescriptorNames.Add(fileDescriptor.Name) Then
Return
End If
For Each dependency In fileDescriptor.Dependencies
AddFile(dependency)
Next
For Each message In fileDescriptor.MessageTypes
AddMessage(message)
Next
End Sub
Private Sub AddMessage(messageDescriptor As MessageDescriptor)
For Each nestedType In messageDescriptor.NestedTypes
AddMessage(nestedType)
Next
' This will overwrite any previous entry. Given that each file should
' only be added once, this could be a problem such as package A.B with type C,
' and package A with type B.C... it's unclear what we should do in that case.
types(messageDescriptor.FullName) = messageDescriptor
End Sub
Friend Function Build() As TypeRegistry
Return New TypeRegistry(types)
End Function
End Class
End Class
End Namespace

@ -0,0 +1,305 @@
' Generated by the protocol buffer compiler. DO NOT EDIT!
' source: google/protobuf/any.proto
#Region "Designer generated code"
Imports pbr = Google.Protobuf.Reflection
Namespace Google.Protobuf.WellKnownTypes
''' <summary>Holder for reflection information generated from google/protobuf/any.proto</summary>
Public Partial Module AnyReflection
#Region "Descriptor"
''' <summary>File descriptor for google/protobuf/any.proto</summary>
Public ReadOnly Property Descriptor As pbr.FileDescriptor
Get
Return descriptorField
End Get
End Property
Private descriptorField As pbr.FileDescriptor
Sub New()
Dim descriptorData As Byte() = Global.System.Convert.FromBase64String(String.Concat("Chlnb29nbGUvcHJvdG9idWYvYW55LnByb3RvEg9nb29nbGUucHJvdG9idWYi", "JgoDQW55EhAKCHR5cGVfdXJsGAEgASgJEg0KBXZhbHVlGAIgASgMQnIKE2Nv", "bS5nb29nbGUucHJvdG9idWZCCEFueVByb3RvUAFaJWdpdGh1Yi5jb20vZ29s", "YW5nL3Byb3RvYnVmL3B0eXBlcy9hbnmgAQGiAgNHUEKqAh5Hb29nbGUuUHJv", "dG9idWYuV2VsbEtub3duVHlwZXNiBnByb3RvMw=="))
descriptorField = pbr.FileDescriptor.FromGeneratedCode(descriptorData, New pbr.FileDescriptor() {}, New pbr.GeneratedClrTypeInfo(Nothing, New pbr.GeneratedClrTypeInfo() {New pbr.GeneratedClrTypeInfo(GetType(Global.Google.Protobuf.WellKnownTypes.Any), Global.Google.Protobuf.WellKnownTypes.Any.Parser, {"TypeUrl", "Value"}, Nothing, Nothing, Nothing)}))
End Sub
#End Region
End Module
#Region "Messages"
''' <summary>
''' `Any` contains an arbitrary serialized protocol buffer message along with a
''' URL that describes the type of the serialized message.
'''
''' Protobuf library provides support to pack/unpack Any values in the form
''' of utility functions or additional generated methods of the Any type.
'''
''' Example 1: Pack and unpack a message in C++.
'''
''' Foo foo = ...;
''' Any any;
''' any.PackFrom(foo);
''' ...
''' if (any.UnpackTo(&amp;foo)) {
''' ...
''' }
'''
''' Example 2: Pack and unpack a message in Java.
'''
''' Foo foo = ...;
''' Any any = Any.pack(foo);
''' ...
''' if (any.is(Foo.class)) {
''' foo = any.unpack(Foo.class);
''' }
'''
''' Example 3: Pack and unpack a message in Python.
'''
''' foo = Foo(...)
''' any = Any()
''' any.Pack(foo)
''' ...
''' if any.Is(Foo.DESCRIPTOR):
''' any.Unpack(foo)
''' ...
'''
''' The pack methods provided by protobuf library will by default use
''' 'type.googleapis.com/full.type.name' as the type URL and the unpack
''' methods only use the fully qualified type name after the last '/'
''' in the type URL, for example "foo.bar.com/x/y.z" will yield type
''' name "y.z".
'''
''' JSON
''' ====
''' The JSON representation of an `Any` value uses the regular
''' representation of the deserialized, embedded message, with an
''' additional field `@type` which contains the type URL. Example:
'''
''' package google.profile;
''' message Person {
''' string first_name = 1;
''' string last_name = 2;
''' }
'''
''' {
''' "@type": "type.googleapis.com/google.profile.Person",
''' "firstName": &lt;string>,
''' "lastName": &lt;string>
''' }
'''
''' If the embedded message type is well-known and has a custom JSON
''' representation, that representation will be embedded adding a field
''' `value` which holds the custom JSON in addition to the `@type`
''' field. Example (for message [google.protobuf.Duration][]):
'''
''' {
''' "@type": "type.googleapis.com/google.protobuf.Duration",
''' "value": "1.212s"
''' }
''' </summary>
Public NotInheritable Partial Class Any
Implements IMessageType(Of Any)
Private Shared ReadOnly _parser As MessageParserType(Of Any) = New MessageParserType(Of Any)(Function() New Any())
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Shared ReadOnly Property Parser As MessageParserType(Of Any)
Get
Return _parser
End Get
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Shared ReadOnly Property DescriptorProp As pbr.MessageDescriptor
Get
Return Global.Google.Protobuf.WellKnownTypes.AnyReflection.Descriptor.MessageTypes(0)
End Get
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Private ReadOnly Property Descriptor As pbr.MessageDescriptor Implements IMessage.Descriptor
Get
Return DescriptorProp
End Get
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub New()
OnConstruction()
End Sub
Partial Private Sub OnConstruction()
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub New(other As Any)
Me.New()
typeUrl_ = other.typeUrl_
value_ = other.value_
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Function Clone() As Any Implements IDeepCloneable(Of Any).Clone
Return New Any(Me)
End Function
''' <summary>Field number for the "type_url" field.</summary>
Public Const TypeUrlFieldNumber As Integer = 1
Private typeUrl_ As String = ""
''' <summary>
''' A URL/resource name whose content describes the type of the
''' serialized protocol buffer message.
'''
''' For URLs which use the scheme `http`, `https`, or no scheme, the
''' following restrictions and interpretations apply:
'''
''' * If no scheme is provided, `https` is assumed.
''' * The last segment of the URL's path must represent the fully
''' qualified name of the type (as in `path/google.protobuf.Duration`).
''' The name should be in a canonical form (e.g., leading "." is
''' not accepted).
''' * An HTTP GET on the URL must yield a [google.protobuf.Type][]
''' value in binary format, or produce an error.
''' * Applications are allowed to cache lookup results based on the
''' URL, or have them precompiled into a binary to avoid any
''' lookup. Therefore, binary compatibility needs to be preserved
''' on changes to types. (Use versioned type names to manage
''' breaking changes.)
'''
''' Schemes other than `http`, `https` (or the empty scheme) might be
''' used with implementation specific semantics.
''' </summary>
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Property TypeUrl As String
Get
Return typeUrl_
End Get
Set(value As String)
typeUrl_ = CheckNotNull(value, "value")
End Set
End Property
''' <summary>Field number for the "value" field.</summary>
Public Const ValueFieldNumber As Integer = 2
Private value_ As ByteString = ByteString.Empty
''' <summary>
''' Must be a valid serialized protocol buffer of the above specified type.
''' </summary>
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Property Value As ByteString
Get
Return value_
End Get
Set(value As ByteString)
value_ = CheckNotNull(value, "value")
End Set
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overrides Function Equals(other As Object) As Boolean
Return Equals(TryCast(other, Any))
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overloads Function Equals(other As Any) As Boolean Implements IEquatable(Of Any).Equals
If ReferenceEquals(other, Nothing) Then
Return False
End If
If ReferenceEquals(other, Me) Then
Return True
End If
If Not Equals(TypeUrl, other.TypeUrl) Then Return False
If Value IsNot other.Value Then Return False
Return True
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overrides Function GetHashCode() As Integer
Dim hash = 1
If TypeUrl.Length <> 0 Then hash = hash Xor TypeUrl.GetHashCode()
If Value.Length <> 0 Then hash = hash Xor Value.GetHashCode()
Return hash
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overrides Function ToString() As String
Return JsonFormatter.ToDiagnosticString(Me)
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub WriteTo(output As CodedOutputStream) Implements IMessage.WriteTo
If TypeUrl.Length <> 0 Then
output.WriteRawTag(10)
output.WriteString(TypeUrl)
End If
If Value.Length <> 0 Then
output.WriteRawTag(18)
output.WriteBytes(Value)
End If
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Function CalculateSize() As Integer Implements IMessage.CalculateSize
Dim size = 0
If TypeUrl.Length <> 0 Then
size += 1 + CodedOutputStream.ComputeStringSize(TypeUrl)
End If
If Value.Length <> 0 Then
size += 1 + CodedOutputStream.ComputeBytesSize(Value)
End If
Return size
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub MergeFrom(other As Any) Implements IMessageType(Of Any).MergeFrom
If other Is Nothing Then
Return
End If
If other.TypeUrl.Length <> 0 Then
TypeUrl = other.TypeUrl
End If
If other.Value.Length <> 0 Then
Value = other.Value
End If
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub MergeFrom(input As CodedInputStream) Implements IMessage.MergeFrom
Dim tag As UInteger
While (CSharpImpl.__Assign(tag, input.ReadTag())) <> 0
Select Case tag
Case 10
TypeUrl = input.ReadString()
Exit Select
Case 18
Value = input.ReadBytes()
Exit Select
Case Else
input.SkipLastField()
End Select
End While
End Sub
Private Class CSharpImpl
<Obsolete("Please refactor calling code to use normal Visual Basic assignment")>
Shared Function __Assign(Of T)(ByRef target As T, value As T) As T
target = value
Return value
End Function
End Class
End Class
#End Region
End Namespace
#End Region

@ -0,0 +1,104 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2015 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports Google.Protobuf.Reflection
Namespace Google.Protobuf.WellKnownTypes
Public Partial Class Any
Private Const DefaultPrefix As String = "type.googleapis.com"
' This could be moved to MessageDescriptor if we wanted to, but keeping it here means
' all the Any-specific code is in the same place.
Private Shared Function GetTypeUrl(descriptor As MessageDescriptor, prefix As String) As String
Return If(prefix.EndsWith("/"), prefix & descriptor.FullName, prefix & "/" & descriptor.FullName)
End Function
''' <summary>
''' Retrieves the type name for a type URL. This is always just the last part of the URL,
''' after the trailing slash. No validation of anything before the trailing slash is performed.
''' If the type URL does not include a slash, an empty string is returned rather than an exception
''' being thrown; this won't match any types, and the calling code is probably in a better position
''' to give a meaningful error.
''' There is no handling of fragments or queries at the moment.
''' </summary>
''' <param name="typeUrl">The URL to extract the type name from</param>
''' <returns>The type name</returns>
Friend Shared Function GetTypeName(typeUrl As String) As String
Dim lastSlash = typeUrl.LastIndexOf("/"c)
Return If(lastSlash = -1, "", typeUrl.Substring(lastSlash + 1))
End Function
''' <summary>
''' Unpacks the content of this Any message into the target message type,
''' which must match the type URL within this Any message.
''' </summary>
''' <typeparamname="T">The type of message to unpack the content into.</typeparam>
''' <returns>The unpacked message.</returns>
''' <exception cref="InvalidProtocolBufferException">The target message type doesn't match the type URL in this message</exception>
Public Function Unpack(Of T As {IMessage, New})() As T
' Note: this doesn't perform as well is it might. We could take a MessageParser<T> in an alternative overload,
' which would be expected to perform slightly better... although the difference is likely to be negligible.
Dim target As T = New T()
If Not Equals(GetTypeName(TypeUrl), target.Descriptor.FullName) Then
Throw New InvalidProtocolBufferException($"Full type name for {target.Descriptor.Name} is {target.Descriptor.FullName}; Any message's type url is {TypeUrl}")
End If
target.MergeFrom(Value)
Return target
End Function
''' <summary>
''' Packs the specified message into an Any message using a type URL prefix of "type.googleapis.com".
''' </summary>
''' <param name="message">The message to pack.</param>
''' <returns>An Any message with the content and type URL of <paramrefname="message"/>.</returns>
Public Shared Function Pack(message As IMessage) As Any
Return Pack(message, DefaultPrefix)
End Function
''' <summary>
''' Packs the specified message into an Any message using the specified type URL prefix.
''' </summary>
''' <param name="message">The message to pack.</param>
''' <param name="typeUrlPrefix">The prefix for the type URL.</param>
''' <returns>An Any message with the content and type URL of <paramrefname="message"/>.</returns>
Public Shared Function Pack(message As IMessage, typeUrlPrefix As String) As Any
CheckNotNull(message, NameOf(message))
CheckNotNull(typeUrlPrefix, NameOf(typeUrlPrefix))
Return New Any With {
.TypeUrl = GetTypeUrl(message.Descriptor, typeUrlPrefix),
.Value = message.ToByteString()
}
End Function
End Class
End Namespace

File diff suppressed because it is too large Load Diff

@ -0,0 +1,263 @@
' Generated by the protocol buffer compiler. DO NOT EDIT!
' source: google/protobuf/duration.proto
#Region "Designer generated code"
Imports pbr = Google.Protobuf.Reflection
Namespace Google.Protobuf.WellKnownTypes
''' <summary>Holder for reflection information generated from google/protobuf/duration.proto</summary>
Public Partial Module DurationReflection
#Region "Descriptor"
''' <summary>File descriptor for google/protobuf/duration.proto</summary>
Public ReadOnly Property Descriptor As pbr.FileDescriptor
Get
Return descriptorField
End Get
End Property
Private descriptorField As pbr.FileDescriptor
Sub New()
Dim descriptorData As Byte() = Global.System.Convert.FromBase64String(String.Concat("Ch5nb29nbGUvcHJvdG9idWYvZHVyYXRpb24ucHJvdG8SD2dvb2dsZS5wcm90", "b2J1ZiIqCghEdXJhdGlvbhIPCgdzZWNvbmRzGAEgASgDEg0KBW5hbm9zGAIg", "ASgFQnwKE2NvbS5nb29nbGUucHJvdG9idWZCDUR1cmF0aW9uUHJvdG9QAVoq", "Z2l0aHViLmNvbS9nb2xhbmcvcHJvdG9idWYvcHR5cGVzL2R1cmF0aW9uoAEB", "ogIDR1BCqgIeR29vZ2xlLlByb3RvYnVmLldlbGxLbm93blR5cGVzYgZwcm90", "bzM="))
descriptorField = pbr.FileDescriptor.FromGeneratedCode(descriptorData, New pbr.FileDescriptor() {}, New pbr.GeneratedClrTypeInfo(Nothing, New pbr.GeneratedClrTypeInfo() {New pbr.GeneratedClrTypeInfo(GetType(Global.Google.Protobuf.WellKnownTypes.Duration), Global.Google.Protobuf.WellKnownTypes.Duration.Parser, {"Seconds", "Nanos"}, Nothing, Nothing, Nothing)}))
End Sub
#End Region
End Module
#Region "Messages"
''' <summary>
''' A Duration represents a signed, fixed-length span of time represented
''' as a count of seconds and fractions of seconds at nanosecond
''' resolution. It is independent of any calendar and concepts like "day"
''' or "month". It is related to Timestamp in that the difference between
''' two Timestamp values is a Duration and it can be added or subtracted
''' from a Timestamp. Range is approximately +-10,000 years.
'''
''' Example 1: Compute Duration from two Timestamps in pseudo code.
'''
''' Timestamp start = ...;
''' Timestamp end = ...;
''' Duration duration = ...;
'''
''' duration.seconds = end.seconds - start.seconds;
''' duration.nanos = end.nanos - start.nanos;
'''
''' if (duration.seconds &lt; 0 &amp;&amp; duration.nanos > 0) {
''' duration.seconds += 1;
''' duration.nanos -= 1000000000;
''' } else if (durations.seconds > 0 &amp;&amp; duration.nanos &lt; 0) {
''' duration.seconds -= 1;
''' duration.nanos += 1000000000;
''' }
'''
''' Example 2: Compute Timestamp from Timestamp + Duration in pseudo code.
'''
''' Timestamp start = ...;
''' Duration duration = ...;
''' Timestamp end = ...;
'''
''' end.seconds = start.seconds + duration.seconds;
''' end.nanos = start.nanos + duration.nanos;
'''
''' if (end.nanos &lt; 0) {
''' end.seconds -= 1;
''' end.nanos += 1000000000;
''' } else if (end.nanos >= 1000000000) {
''' end.seconds += 1;
''' end.nanos -= 1000000000;
''' }
''' </summary>
Public NotInheritable Partial Class Duration
Implements IMessageType(Of Duration)
Private Shared ReadOnly _parser As MessageParserType(Of Duration) = New MessageParserType(Of Duration)(Function() New Duration())
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Shared ReadOnly Property Parser As MessageParserType(Of Duration)
Get
Return _parser
End Get
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Shared ReadOnly Property DescriptorProp As pbr.MessageDescriptor
Get
Return Global.Google.Protobuf.WellKnownTypes.DurationReflection.Descriptor.MessageTypes(0)
End Get
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Private ReadOnly Property Descriptor As pbr.MessageDescriptor Implements IMessage.Descriptor
Get
Return DescriptorProp
End Get
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub New()
OnConstruction()
End Sub
Partial Private Sub OnConstruction()
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub New(other As Duration)
Me.New()
seconds_ = other.seconds_
nanos_ = other.nanos_
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Function Clone() As Duration Implements IDeepCloneable(Of Duration).Clone
Return New Duration(Me)
End Function
''' <summary>Field number for the "seconds" field.</summary>
Public Const SecondsFieldNumber As Integer = 1
Private seconds_ As Long
''' <summary>
''' Signed seconds of the span of time. Must be from -315,576,000,000
''' to +315,576,000,000 inclusive.
''' </summary>
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Property Seconds As Long
Get
Return seconds_
End Get
Set(value As Long)
seconds_ = value
End Set
End Property
''' <summary>Field number for the "nanos" field.</summary>
Public Const NanosFieldNumber As Integer = 2
Private nanos_ As Integer
''' <summary>
''' Signed fractions of a second at nanosecond resolution of the span
''' of time. Durations less than one second are represented with a 0
''' `seconds` field and a positive or negative `nanos` field. For durations
''' of one second or more, a non-zero value for the `nanos` field must be
''' of the same sign as the `seconds` field. Must be from -999,999,999
''' to +999,999,999 inclusive.
''' </summary>
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Property Nanos As Integer
Get
Return nanos_
End Get
Set(value As Integer)
nanos_ = value
End Set
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overrides Function Equals(other As Object) As Boolean
Return Equals(TryCast(other, Duration))
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overloads Function Equals(other As Duration) As Boolean Implements IEquatable(Of Duration).Equals
If ReferenceEquals(other, Nothing) Then
Return False
End If
If ReferenceEquals(other, Me) Then
Return True
End If
If Seconds <> other.Seconds Then Return False
If Nanos <> other.Nanos Then Return False
Return True
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overrides Function GetHashCode() As Integer
Dim hash = 1
If Seconds <> 0L Then hash = hash Xor Seconds.GetHashCode()
If Nanos <> 0 Then hash = hash Xor Nanos.GetHashCode()
Return hash
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overrides Function ToString() As String
Return JsonFormatter.ToDiagnosticString(Me)
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub WriteTo(output As CodedOutputStream) Implements IMessage.WriteTo
If Seconds <> 0L Then
output.WriteRawTag(8)
output.WriteInt64(Seconds)
End If
If Nanos <> 0 Then
output.WriteRawTag(16)
output.WriteInt32(Nanos)
End If
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Function CalculateSize() As Integer Implements IMessage.CalculateSize
Dim size = 0
If Seconds <> 0L Then
size += 1 + CodedOutputStream.ComputeInt64Size(Seconds)
End If
If Nanos <> 0 Then
size += 1 + CodedOutputStream.ComputeInt32Size(Nanos)
End If
Return size
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub MergeFrom(other As Duration) Implements IMessageType(Of Duration).MergeFrom
If other Is Nothing Then
Return
End If
If other.Seconds <> 0L Then
Seconds = other.Seconds
End If
If other.Nanos <> 0 Then
Nanos = other.Nanos
End If
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub MergeFrom(input As CodedInputStream) Implements IMessage.MergeFrom
Dim tag As UInteger
While (CSharpImpl.__Assign(tag, input.ReadTag())) <> 0
Select Case tag
Case 8
Seconds = input.ReadInt64()
Exit Select
Case 16
Nanos = input.ReadInt32()
Exit Select
Case Else
input.SkipLastField()
End Select
End While
End Sub
Private Class CSharpImpl
<Obsolete("Please refactor calling code to use normal Visual Basic assignment")>
Shared Function __Assign(Of T)(ByRef target As T, value As T) As T
target = value
Return value
End Function
End Class
End Class
#End Region
End Namespace
#End Region

@ -0,0 +1,242 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2015 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System
Imports System.Globalization
Imports System.Text
Namespace Google.Protobuf.WellKnownTypes
' Manually-written partial class for the Duration well-known type,
' providing a conversion to TimeSpan and convenience operators.
Public Partial Class Duration
Implements ICustomDiagnosticMessage
''' <summary>
''' The number of nanoseconds in a second.
''' </summary>
Public Const NanosecondsPerSecond As Integer = 1000000000
''' <summary>
''' The number of nanoseconds in a BCL tick (as used by <see cref="TimeSpan"/> and <see cref="DateTime"/>).
''' </summary>
Public Const NanosecondsPerTick As Integer = 100
''' <summary>
''' The maximum permitted number of seconds.
''' </summary>
Public Const MaxSeconds As Long = 315576000000L
''' <summary>
''' The minimum permitted number of seconds.
''' </summary>
Public Const MinSeconds As Long = -315576000000L
Friend Const MaxNanoseconds As Integer = NanosecondsPerSecond - 1
Friend Const MinNanoseconds As Integer = -NanosecondsPerSecond + 1
Friend Shared Function IsNormalized(seconds As Long, nanoseconds As Integer) As Boolean
' Simple boundaries
If seconds < MinSeconds OrElse seconds > MaxSeconds OrElse nanoseconds < MinNanoseconds OrElse nanoseconds > MaxNanoseconds Then
Return False
End If
' We only have a problem is one is strictly negative and the other is
' strictly positive.
Return Math.Sign(seconds) * Math.Sign(nanoseconds) <> -1
End Function
''' <summary>
''' Converts this <see cref="Duration"/> to a <see cref="TimeSpan"/>.
''' </summary>
''' <remarks>If the duration is not a precise number of ticks, it is truncated towards 0.</remarks>
''' <returns>The value of this duration, as a <c>TimeSpan</c>.</returns>
''' <exception cref="InvalidOperationException">This value isn't a valid normalized duration, as
''' described in the documentation.</exception>
Public Function ToTimeSpan() As TimeSpan
'BEGIN TODO : Visual Basic does not support checked statements!
If Not IsNormalized(Seconds, Nanos) Then
Throw New InvalidOperationException("Duration was not a valid normalized duration")
End If
Dim ticks As Long = Seconds * TimeSpan.TicksPerSecond + Nanos / NanosecondsPerTick
Return TimeSpan.FromTicks(ticks)
'END TODO : Visual Basic does not support checked statements!
End Function
''' <summary>
''' Converts the given <see cref="TimeSpan"/> to a <see cref="Duration"/>.
''' </summary>
''' <param name="timeSpan">The <c>TimeSpan</c> to convert.</param>
''' <returns>The value of the given <c>TimeSpan</c>, as a <c>Duration</c>.</returns>
Public Shared Function FromTimeSpan(timeSpan As TimeSpan) As Duration
'BEGIN TODO : Visual Basic does not support checked statements!
Dim ticks = timeSpan.Ticks
Dim seconds As Long = ticks / TimeSpan.TicksPerSecond
Dim nanos = CInt(ticks Mod TimeSpan.TicksPerSecond) * NanosecondsPerTick
Return New Duration With {
.Seconds = seconds,
.Nanos = nanos
}
'END TODO : Visual Basic does not support checked statements!
End Function
''' <summary>
''' Returns the result of negating the duration. For example, the negation of 5 minutes is -5 minutes.
''' </summary>
''' <param name="value">The duration to negate. Must not be null.</param>
''' <returns>The negated value of this duration.</returns>
Public Shared Operator -(value As Duration) As Duration
CheckNotNull(value, "value")
'BEGIN TODO : Visual Basic does not support checked statements!
Return Normalize(-value.Seconds, -value.Nanos)
'END TODO : Visual Basic does not support checked statements!
End Operator
''' <summary>
''' Adds the two specified <see cref="Duration"/> values together.
''' </summary>
''' <param name="lhs">The first value to add. Must not be null.</param>
''' <param name="rhs">The second value to add. Must not be null.</param>
''' <returns></returns>
Public Shared Operator +(lhs As Duration, rhs As Duration) As Duration
CheckNotNull(lhs, "lhs")
CheckNotNull(rhs, "rhs")
'BEGIN TODO : Visual Basic does not support checked statements!
Return Normalize(lhs.Seconds + rhs.Seconds, lhs.Nanos + rhs.Nanos)
'END TODO : Visual Basic does not support checked statements!
End Operator
''' <summary>
''' Subtracts one <see cref="Duration"/> from another.
''' </summary>
''' <param name="lhs">The duration to subtract from. Must not be null.</param>
''' <param name="rhs">The duration to subtract. Must not be null.</param>
''' <returns>The difference between the two specified durations.</returns>
Public Shared Operator -(lhs As Duration, rhs As Duration) As Duration
CheckNotNull(lhs, "lhs")
CheckNotNull(rhs, "rhs")
'BEGIN TODO : Visual Basic does not support checked statements!
Return Normalize(lhs.Seconds - rhs.Seconds, lhs.Nanos - rhs.Nanos)
' END TODO : Visual Basic does not support checked statements!
End Operator
''' <summary>
''' Creates a duration with the normalized values from the given number of seconds and
''' nanoseconds, conforming with the description in the proto file.
''' </summary>
Friend Shared Function Normalize(seconds As Long, nanoseconds As Integer) As Duration
' Ensure that nanoseconds is in the range (-1,000,000,000, +1,000,000,000)
Dim extraSeconds As Integer = nanoseconds / NanosecondsPerSecond
seconds += extraSeconds
nanoseconds -= extraSeconds * NanosecondsPerSecond
' Now make sure that Sign(seconds) == Sign(nanoseconds) if Sign(seconds) != 0.
If seconds < 0 AndAlso nanoseconds > 0 Then
seconds += 1
nanoseconds -= NanosecondsPerSecond
ElseIf seconds > 0 AndAlso nanoseconds < 0 Then
seconds -= 1
nanoseconds += NanosecondsPerSecond
End If
Return New Duration With {
.Seconds = seconds,
.Nanos = nanoseconds
}
End Function
''' <summary>
''' Converts a duration specified in seconds/nanoseconds to a string.
''' </summary>
''' <remarks>
''' If the value is a normalized duration in the range described in <c>duration.proto</c>,
''' <paramrefname="diagnosticOnly"/> is ignored. Otherwise, if the parameter is <c>true</c>,
''' a JSON object with a warning is returned; if it is <c>false</c>, an <see cref="InvalidOperationException"/> is thrown.
''' </remarks>
''' <param name="seconds">Seconds portion of the duration.</param>
''' <param name="nanoseconds">Nanoseconds portion of the duration.</param>
''' <param name="diagnosticOnly">Determines the handling of non-normalized values</param>
''' <exception cref="InvalidOperationException">The represented duration is invalid, and <paramrefname="diagnosticOnly"/> is <c>false</c>.</exception>
Friend Shared Function ToJson(seconds As Long, nanoseconds As Integer, diagnosticOnly As Boolean) As String
If IsNormalized(seconds, nanoseconds) Then
Dim builder = New StringBuilder()
builder.Append(""""c)
' The seconds part will normally provide the minus sign if we need it, but not if it's 0...
If seconds = 0 AndAlso nanoseconds < 0 Then
builder.Append("-"c)
End If
builder.Append(seconds.ToString("d", CultureInfo.InvariantCulture))
AppendNanoseconds(builder, Math.Abs(nanoseconds))
builder.Append("s""")
Return builder.ToString()
End If
If diagnosticOnly Then
' Note: the double braces here are escaping for braces in format strings.
Return String.Format(CultureInfo.InvariantCulture, "{{ ""@warning"": ""Invalid Duration"", ""seconds"": ""{0}"", ""nanos"": {1} }}", seconds, nanoseconds)
Else
Throw New InvalidOperationException("Non-normalized duration value")
End If
End Function
''' <summary>
''' Returns a string representation of this <see cref="Duration"/> for diagnostic purposes.
''' </summary>
''' <remarks>
''' Normally the returned value will be a JSON string value (including leading and trailing quotes) but
''' when the value is non-normalized or out of range, a JSON object representation will be returned
''' instead, including a warning. This is to avoid exceptions being thrown when trying to
''' diagnose problems - the regular JSON formatter will still throw an exception for non-normalized
''' values.
''' </remarks>
''' <returns>A string representation of this value.</returns>
Public Function ToDiagnosticString() As String Implements ICustomDiagnosticMessage.ToDiagnosticString
Return ToJson(Seconds, Nanos, True)
End Function
''' <summary>
''' Appends a number of nanoseconds to a StringBuilder. Either 0 digits are added (in which
''' case no "." is appended), or 3 6 or 9 digits. This is internal for use in Timestamp as well
''' as Duration.
''' </summary>
Friend Shared Sub AppendNanoseconds(builder As StringBuilder, nanos As Integer)
If nanos <> 0 Then
builder.Append("."c)
' Output to 3, 6 or 9 digits.
If nanos Mod 1000000 = 0 Then
builder.Append((nanos / 1000000).ToString("d3", CultureInfo.InvariantCulture))
ElseIf nanos Mod 1000 = 0 Then
builder.Append((nanos / 1000).ToString("d6", CultureInfo.InvariantCulture))
Else
builder.Append(nanos.ToString("d9", CultureInfo.InvariantCulture))
End If
End If
End Sub
End Class
End Namespace

@ -0,0 +1,156 @@
' Generated by the protocol buffer compiler. DO NOT EDIT!
' source: google/protobuf/empty.proto
#Region "Designer generated code"
Imports pbr = Google.Protobuf.Reflection
Namespace Google.Protobuf.WellKnownTypes
''' <summary>Holder for reflection information generated from google/protobuf/empty.proto</summary>
Public Partial Module EmptyReflection
#Region "Descriptor"
''' <summary>File descriptor for google/protobuf/empty.proto</summary>
Public ReadOnly Property Descriptor As pbr.FileDescriptor
Get
Return descriptorField
End Get
End Property
Private descriptorField As pbr.FileDescriptor
Sub New()
Dim descriptorData As Byte() = Global.System.Convert.FromBase64String(String.Concat("Chtnb29nbGUvcHJvdG9idWYvZW1wdHkucHJvdG8SD2dvb2dsZS5wcm90b2J1", "ZiIHCgVFbXB0eUJ5ChNjb20uZ29vZ2xlLnByb3RvYnVmQgpFbXB0eVByb3Rv", "UAFaJ2dpdGh1Yi5jb20vZ29sYW5nL3Byb3RvYnVmL3B0eXBlcy9lbXB0eaAB", "AfgBAaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IG", "cHJvdG8z"))
descriptorField = pbr.FileDescriptor.FromGeneratedCode(descriptorData, New pbr.FileDescriptor() {}, New pbr.GeneratedClrTypeInfo(Nothing, New pbr.GeneratedClrTypeInfo() {New pbr.GeneratedClrTypeInfo(GetType(Global.Google.Protobuf.WellKnownTypes.Empty), Global.Google.Protobuf.WellKnownTypes.Empty.Parser, Nothing, Nothing, Nothing, Nothing)}))
End Sub
#End Region
End Module
#Region "Messages"
''' <summary>
''' A generic empty message that you can re-use to avoid defining duplicated
''' empty messages in your APIs. A typical example is to use it as the request
''' or the response type of an API method. For instance:
'''
''' service Foo {
''' rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);
''' }
'''
''' The JSON representation for `Empty` is empty JSON object `{}`.
''' </summary>
Public NotInheritable Partial Class Empty
Implements IMessageType(Of Empty)
Private Shared ReadOnly _parser As MessageParserType(Of Empty) = New MessageParserType(Of Empty)(Function() New Empty())
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Shared ReadOnly Property Parser As MessageParserType(Of Empty)
Get
Return _parser
End Get
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Shared ReadOnly Property DescriptorProp As pbr.MessageDescriptor
Get
Return Global.Google.Protobuf.WellKnownTypes.EmptyReflection.Descriptor.MessageTypes(0)
End Get
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Private ReadOnly Property Descriptor As pbr.MessageDescriptor Implements IMessage.Descriptor
Get
Return DescriptorProp
End Get
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub New()
OnConstruction()
End Sub
Partial Private Sub OnConstruction()
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub New(other As Empty)
Me.New()
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Function Clone() As Empty Implements IDeepCloneable(Of Empty).Clone
Return New Empty(Me)
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overrides Function Equals(other As Object) As Boolean
Return Equals(TryCast(other, Empty))
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overloads Function Equals(other As Empty) As Boolean Implements IEquatable(Of Empty).Equals
If ReferenceEquals(other, Nothing) Then
Return False
End If
If ReferenceEquals(other, Me) Then
Return True
End If
Return True
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overrides Function GetHashCode() As Integer
Dim hash = 1
Return hash
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overrides Function ToString() As String
Return JsonFormatter.ToDiagnosticString(Me)
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub WriteTo(output As CodedOutputStream) Implements IMessage.WriteTo
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Function CalculateSize() As Integer Implements IMessage.CalculateSize
Dim size = 0
Return size
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub MergeFrom(other As Empty) Implements IMessageType(Of Empty).MergeFrom
If other Is Nothing Then
Return
End If
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub MergeFrom(input As CodedInputStream) Implements IMessage.MergeFrom
Dim tag As UInteger
While (CSharpImpl.__Assign(tag, input.ReadTag())) <> 0
Select Case tag
Case Else
input.SkipLastField()
End Select
End While
End Sub
Private Class CSharpImpl
<Obsolete("Please refactor calling code to use normal Visual Basic assignment")>
Shared Function __Assign(Of T)(ByRef target As T, value As T) As T
target = value
Return value
End Function
End Class
End Class
#End Region
End Namespace
#End Region

@ -0,0 +1,372 @@
' Generated by the protocol buffer compiler. DO NOT EDIT!
' source: google/protobuf/field_mask.proto
#Region "Designer generated code"
Imports pbc = Google.Protobuf.Collections
Imports pbr = Google.Protobuf.Reflection
Namespace Google.Protobuf.WellKnownTypes
''' <summary>Holder for reflection information generated from google/protobuf/field_mask.proto</summary>
Public Partial Module FieldMaskReflection
#Region "Descriptor"
''' <summary>File descriptor for google/protobuf/field_mask.proto</summary>
Public ReadOnly Property Descriptor As pbr.FileDescriptor
Get
Return descriptorField
End Get
End Property
Private descriptorField As pbr.FileDescriptor
Sub New()
Dim descriptorData As Byte() = Global.System.Convert.FromBase64String(String.Concat("CiBnb29nbGUvcHJvdG9idWYvZmllbGRfbWFzay5wcm90bxIPZ29vZ2xlLnBy", "b3RvYnVmIhoKCUZpZWxkTWFzaxINCgVwYXRocxgBIAMoCUJRChNjb20uZ29v", "Z2xlLnByb3RvYnVmQg5GaWVsZE1hc2tQcm90b1ABoAEBogIDR1BCqgIeR29v", "Z2xlLlByb3RvYnVmLldlbGxLbm93blR5cGVzYgZwcm90bzM="))
descriptorField = pbr.FileDescriptor.FromGeneratedCode(descriptorData, New pbr.FileDescriptor() {}, New pbr.GeneratedClrTypeInfo(Nothing, New pbr.GeneratedClrTypeInfo() {New pbr.GeneratedClrTypeInfo(GetType(Global.Google.Protobuf.WellKnownTypes.FieldMask), Global.Google.Protobuf.WellKnownTypes.FieldMask.Parser, {"Paths"}, Nothing, Nothing, Nothing)}))
End Sub
#End Region
End Module
#Region "Messages"
''' <summary>
''' `FieldMask` represents a set of symbolic field paths, for example:
'''
''' paths: "f.a"
''' paths: "f.b.d"
'''
''' Here `f` represents a field in some root message, `a` and `b`
''' fields in the message found in `f`, and `d` a field found in the
''' message in `f.b`.
'''
''' Field masks are used to specify a subset of fields that should be
''' returned by a get operation or modified by an update operation.
''' Field masks also have a custom JSON encoding (see below).
'''
''' # Field Masks in Projections
'''
''' When used in the context of a projection, a response message or
''' sub-message is filtered by the API to only contain those fields as
''' specified in the mask. For example, if the mask in the previous
''' example is applied to a response message as follows:
'''
''' f {
''' a : 22
''' b {
''' d : 1
''' x : 2
''' }
''' y : 13
''' }
''' z: 8
'''
''' The result will not contain specific values for fields x,y and z
''' (their value will be set to the default, and omitted in proto text
''' output):
'''
''' f {
''' a : 22
''' b {
''' d : 1
''' }
''' }
'''
''' A repeated field is not allowed except at the last position of a
''' field mask.
'''
''' If a FieldMask object is not present in a get operation, the
''' operation applies to all fields (as if a FieldMask of all fields
''' had been specified).
'''
''' Note that a field mask does not necessarily apply to the
''' top-level response message. In case of a REST get operation, the
''' field mask applies directly to the response, but in case of a REST
''' list operation, the mask instead applies to each individual message
''' in the returned resource list. In case of a REST custom method,
''' other definitions may be used. Where the mask applies will be
''' clearly documented together with its declaration in the API. In
''' any case, the effect on the returned resource/resources is required
''' behavior for APIs.
'''
''' # Field Masks in Update Operations
'''
''' A field mask in update operations specifies which fields of the
''' targeted resource are going to be updated. The API is required
''' to only change the values of the fields as specified in the mask
''' and leave the others untouched. If a resource is passed in to
''' describe the updated values, the API ignores the values of all
''' fields not covered by the mask.
'''
''' If a repeated field is specified for an update operation, the existing
''' repeated values in the target resource will be overwritten by the new values.
''' Note that a repeated field is only allowed in the last position of a field
''' mask.
'''
''' If a sub-message is specified in the last position of the field mask for an
''' update operation, then the existing sub-message in the target resource is
''' overwritten. Given the target message:
'''
''' f {
''' b {
''' d : 1
''' x : 2
''' }
''' c : 1
''' }
'''
''' And an update message:
'''
''' f {
''' b {
''' d : 10
''' }
''' }
'''
''' then if the field mask is:
'''
''' paths: "f.b"
'''
''' then the result will be:
'''
''' f {
''' b {
''' d : 10
''' }
''' c : 1
''' }
'''
''' However, if the update mask was:
'''
''' paths: "f.b.d"
'''
''' then the result would be:
'''
''' f {
''' b {
''' d : 10
''' x : 2
''' }
''' c : 1
''' }
'''
''' In order to reset a field's value to the default, the field must
''' be in the mask and set to the default value in the provided resource.
''' Hence, in order to reset all fields of a resource, provide a default
''' instance of the resource and set all fields in the mask, or do
''' not provide a mask as described below.
'''
''' If a field mask is not present on update, the operation applies to
''' all fields (as if a field mask of all fields has been specified).
''' Note that in the presence of schema evolution, this may mean that
''' fields the client does not know and has therefore not filled into
''' the request will be reset to their default. If this is unwanted
''' behavior, a specific service may require a client to always specify
''' a field mask, producing an error if not.
'''
''' As with get operations, the location of the resource which
''' describes the updated values in the request message depends on the
''' operation kind. In any case, the effect of the field mask is
''' required to be honored by the API.
'''
''' ## Considerations for HTTP REST
'''
''' The HTTP kind of an update operation which uses a field mask must
''' be set to PATCH instead of PUT in order to satisfy HTTP semantics
''' (PUT must only be used for full updates).
'''
''' # JSON Encoding of Field Masks
'''
''' In JSON, a field mask is encoded as a single string where paths are
''' separated by a comma. Fields name in each path are converted
''' to/from lower-camel naming conventions.
'''
''' As an example, consider the following message declarations:
'''
''' message Profile {
''' User user = 1;
''' Photo photo = 2;
''' }
''' message User {
''' string display_name = 1;
''' string address = 2;
''' }
'''
''' In proto a field mask for `Profile` may look as such:
'''
''' mask {
''' paths: "user.display_name"
''' paths: "photo"
''' }
'''
''' In JSON, the same mask is represented as below:
'''
''' {
''' mask: "user.displayName,photo"
''' }
'''
''' # Field Masks and Oneof Fields
'''
''' Field masks treat fields in oneofs just as regular fields. Consider the
''' following message:
'''
''' message SampleMessage {
''' oneof test_oneof {
''' string name = 4;
''' SubMessage sub_message = 9;
''' }
''' }
'''
''' The field mask can be:
'''
''' mask {
''' paths: "name"
''' }
'''
''' Or:
'''
''' mask {
''' paths: "sub_message"
''' }
'''
''' Note that oneof type names ("test_oneof" in this case) cannot be used in
''' paths.
''' </summary>
Public NotInheritable Partial Class FieldMask
Implements IMessageType(Of FieldMask)
Private Shared ReadOnly _parser As MessageParserType(Of FieldMask) = New MessageParserType(Of FieldMask)(Function() New FieldMask())
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Shared ReadOnly Property Parser As MessageParserType(Of FieldMask)
Get
Return _parser
End Get
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Shared ReadOnly Property DescriptorProp As pbr.MessageDescriptor
Get
Return Global.Google.Protobuf.WellKnownTypes.FieldMaskReflection.Descriptor.MessageTypes(0)
End Get
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Private ReadOnly Property Descriptor As pbr.MessageDescriptor Implements IMessage.Descriptor
Get
Return DescriptorProp
End Get
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub New()
OnConstruction()
End Sub
Partial Private Sub OnConstruction()
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub New(other As FieldMask)
Me.New()
paths_ = other.paths_.Clone()
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Function Clone() As FieldMask Implements IDeepCloneable(Of FieldMask).Clone
Return New FieldMask(Me)
End Function
''' <summary>Field number for the "paths" field.</summary>
Public Const PathsFieldNumber As Integer = 1
Private Shared ReadOnly _repeated_paths_codec As FieldCodecType(Of String) = ForString(10)
Private ReadOnly paths_ As pbc.RepeatedField(Of String) = New pbc.RepeatedField(Of String)()
''' <summary>
''' The set of field mask paths.
''' </summary>
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public ReadOnly Property Paths As pbc.RepeatedField(Of String)
Get
Return paths_
End Get
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overrides Function Equals(other As Object) As Boolean
Return Equals(TryCast(other, FieldMask))
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overloads Function Equals(other As FieldMask) As Boolean Implements IEquatable(Of FieldMask).Equals
If ReferenceEquals(other, Nothing) Then
Return False
End If
If ReferenceEquals(other, Me) Then
Return True
End If
If Not paths_.Equals(other.paths_) Then Return False
Return True
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overrides Function GetHashCode() As Integer
Dim hash = 1
hash = hash Xor paths_.GetHashCode()
Return hash
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overrides Function ToString() As String
Return JsonFormatter.ToDiagnosticString(Me)
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub WriteTo(output As CodedOutputStream) Implements IMessage.WriteTo
paths_.WriteTo(output, _repeated_paths_codec)
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Function CalculateSize() As Integer Implements IMessage.CalculateSize
Dim size = 0
size += paths_.CalculateSize(_repeated_paths_codec)
Return size
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub MergeFrom(other As FieldMask) Implements IMessageType(Of FieldMask).MergeFrom
If other Is Nothing Then
Return
End If
paths_.Add(other.paths_)
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub MergeFrom(input As CodedInputStream) Implements IMessage.MergeFrom
Dim tag As UInteger
While (CSharpImpl.__Assign(tag, input.ReadTag())) <> 0
Select Case tag
Case 10
paths_.AddEntriesFrom(input, _repeated_paths_codec)
Exit Select
Case Else
input.SkipLastField()
End Select
End While
End Sub
Private Class CSharpImpl
<Obsolete("Please refactor calling code to use normal Visual Basic assignment")>
Shared Function __Assign(Of T)(ByRef target As T, value As T) As T
target = value
Return value
End Function
End Class
End Class
#End Region
End Namespace
#End Region

@ -0,0 +1,119 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2016 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System
Imports System.Collections
Imports System.Collections.Generic
Imports System.IO
Imports System.Linq
Namespace Google.Protobuf.WellKnownTypes
' Manually-written partial class for the FieldMask well-known type.
Public Partial Class FieldMask
Implements ICustomDiagnosticMessage
''' <summary>
''' Converts a timestamp specified in seconds/nanoseconds to a string.
''' </summary>
''' <remarks>
''' If the value is a normalized duration in the range described in <c>field_mask.proto</c>,
''' <paramrefname="diagnosticOnly"/> is ignored. Otherwise, if the parameter is <c>true</c>,
''' a JSON object with a warning is returned; if it is <c>false</c>, an <see cref="InvalidOperationException"/> is thrown.
''' </remarks>
''' <param name="paths">Paths in the field mask</param>
''' <param name="diagnosticOnly">Determines the handling of non-normalized values</param>
''' <exception cref="InvalidOperationException">The represented duration is invalid, and <paramrefname="diagnosticOnly"/> is <c>false</c>.</exception>
Friend Shared Function ToJson(paths As IList(Of String), diagnosticOnly As Boolean) As String
Dim firstInvalid = paths.FirstOrDefault(Function(p) Not ValidatePath(p))
If Equals(firstInvalid, Nothing) Then
Dim writer = New StringWriter()
#If DOTNET35
var query = paths.Select(JsonFormatter.ToCamelCase);
JsonFormatter.WriteString(writer, string.Join(",", query.ToArray()));
#Else
JsonFormatter.WriteString(writer, String.Join(",", paths.[Select](New Func(Of String, String)(AddressOf JsonFormatter.ToCamelCase))))
#End If
Return writer.ToString()
Else
If diagnosticOnly Then
Dim writer = New StringWriter()
writer.Write("{ ""@warning"": ""Invalid FieldMask"", ""paths"": ")
JsonFormatter.Default.WriteList(writer, CType(paths, IList))
writer.Write(" }")
Return writer.ToString()
Else
Throw New InvalidOperationException($"Invalid field mask to be converted to JSON: {firstInvalid}")
End If
End If
End Function
''' <summary>
''' Camel-case converter with added strictness for field mask formatting.
''' </summary>
''' <exception cref="InvalidOperationException">The field mask is invalid for JSON representation</exception>
Private Shared Function ValidatePath(input As String) As Boolean
For i = 0 To input.Length - 1
Dim c = input(i)
If c >= "A"c AndAlso c <= "Z"c Then
Return False
End If
If c = "_"c AndAlso i < input.Length - 1 Then
Dim [next] = input(i + 1)
If [next] < "a"c OrElse [next] > "z"c Then
Return False
End If
End If
Next
Return True
End Function
''' <summary>
''' Returns a string representation of this <see cref="FieldMask"/> for diagnostic purposes.
''' </summary>
''' <remarks>
''' Normally the returned value will be a JSON string value (including leading and trailing quotes) but
''' when the value is non-normalized or out of range, a JSON object representation will be returned
''' instead, including a warning. This is to avoid exceptions being thrown when trying to
''' diagnose problems - the regular JSON formatter will still throw an exception for non-normalized
''' values.
''' </remarks>
''' <returns>A string representation of this value.</returns>
Public Function ToDiagnosticString() As String Implements ICustomDiagnosticMessage.ToDiagnosticString
Return ToJson(Paths, True)
End Function
End Class
End Namespace

@ -0,0 +1,185 @@
' Generated by the protocol buffer compiler. DO NOT EDIT!
' source: google/protobuf/source_context.proto
#Region "Designer generated code"
Imports pbr = Google.Protobuf.Reflection
Namespace Google.Protobuf.WellKnownTypes
''' <summary>Holder for reflection information generated from google/protobuf/source_context.proto</summary>
Public Partial Module SourceContextReflection
#Region "Descriptor"
''' <summary>File descriptor for google/protobuf/source_context.proto</summary>
Public ReadOnly Property Descriptor As pbr.FileDescriptor
Get
Return descriptorField
End Get
End Property
Private descriptorField As pbr.FileDescriptor
Sub New()
Dim descriptorData As Byte() = Global.System.Convert.FromBase64String(String.Concat("CiRnb29nbGUvcHJvdG9idWYvc291cmNlX2NvbnRleHQucHJvdG8SD2dvb2ds", "ZS5wcm90b2J1ZiIiCg1Tb3VyY2VDb250ZXh0EhEKCWZpbGVfbmFtZRgBIAEo", "CUJVChNjb20uZ29vZ2xlLnByb3RvYnVmQhJTb3VyY2VDb250ZXh0UHJvdG9Q", "AaABAaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IG", "cHJvdG8z"))
descriptorField = pbr.FileDescriptor.FromGeneratedCode(descriptorData, New pbr.FileDescriptor() {}, New pbr.GeneratedClrTypeInfo(Nothing, New pbr.GeneratedClrTypeInfo() {New pbr.GeneratedClrTypeInfo(GetType(Global.Google.Protobuf.WellKnownTypes.SourceContext), Global.Google.Protobuf.WellKnownTypes.SourceContext.Parser, {"FileName"}, Nothing, Nothing, Nothing)}))
End Sub
#End Region
End Module
#Region "Messages"
''' <summary>
''' `SourceContext` represents information about the source of a
''' protobuf element, like the file in which it is defined.
''' </summary>
Public NotInheritable Partial Class SourceContext
Implements IMessageType(Of SourceContext)
Private Shared ReadOnly _parser As MessageParserType(Of SourceContext) = New MessageParserType(Of SourceContext)(Function() New SourceContext())
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Shared ReadOnly Property Parser As MessageParserType(Of SourceContext)
Get
Return _parser
End Get
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Shared ReadOnly Property DescriptorProp As pbr.MessageDescriptor
Get
Return Global.Google.Protobuf.WellKnownTypes.SourceContextReflection.Descriptor.MessageTypes(0)
End Get
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Private ReadOnly Property Descriptor As pbr.MessageDescriptor Implements IMessage.Descriptor
Get
Return DescriptorProp
End Get
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub New()
OnConstruction()
End Sub
Partial Private Sub OnConstruction()
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub New(other As SourceContext)
Me.New()
fileName_ = other.fileName_
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Function Clone() As SourceContext Implements IDeepCloneable(Of SourceContext).Clone
Return New SourceContext(Me)
End Function
''' <summary>Field number for the "file_name" field.</summary>
Public Const FileNameFieldNumber As Integer = 1
Private fileName_ As String = ""
''' <summary>
''' The path-qualified name of the .proto file that contained the associated
''' protobuf element. For example: `"google/protobuf/source_context.proto"`.
''' </summary>
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Property FileName As String
Get
Return fileName_
End Get
Set(value As String)
fileName_ = CheckNotNull(value, "value")
End Set
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overrides Function Equals(other As Object) As Boolean
Return Equals(TryCast(other, SourceContext))
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overloads Function Equals(other As SourceContext) As Boolean Implements IEquatable(Of SourceContext).Equals
If ReferenceEquals(other, Nothing) Then
Return False
End If
If ReferenceEquals(other, Me) Then
Return True
End If
If Not Equals(FileName, other.FileName) Then Return False
Return True
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overrides Function GetHashCode() As Integer
Dim hash = 1
If FileName.Length <> 0 Then hash = hash Xor FileName.GetHashCode()
Return hash
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overrides Function ToString() As String
Return JsonFormatter.ToDiagnosticString(Me)
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub WriteTo(output As CodedOutputStream) Implements IMessage.WriteTo
If FileName.Length <> 0 Then
output.WriteRawTag(10)
output.WriteString(FileName)
End If
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Function CalculateSize() As Integer Implements IMessage.CalculateSize
Dim size = 0
If FileName.Length <> 0 Then
size += 1 + CodedOutputStream.ComputeStringSize(FileName)
End If
Return size
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub MergeFrom(other As SourceContext) Implements IMessageType(Of SourceContext).MergeFrom
If other Is Nothing Then
Return
End If
If other.FileName.Length <> 0 Then
FileName = other.FileName
End If
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub MergeFrom(input As CodedInputStream) Implements IMessage.MergeFrom
Dim tag As UInteger
While (CSharpImpl.__Assign(tag, input.ReadTag())) <> 0
Select Case tag
Case 10
FileName = input.ReadString()
Exit Select
Case Else
input.SkipLastField()
End Select
End While
End Sub
Private Class CSharpImpl
<Obsolete("Please refactor calling code to use normal Visual Basic assignment")>
Shared Function __Assign(Of T)(ByRef target As T, value As T) As T
target = value
Return value
End Function
End Class
End Class
#End Region
End Namespace
#End Region

@ -0,0 +1,712 @@
' Generated by the protocol buffer compiler. DO NOT EDIT!
' source: google/protobuf/struct.proto
#Region "Designer generated code"
Imports pbc = Google.Protobuf.Collections
Imports pbr = Google.Protobuf.Reflection
Namespace Google.Protobuf.WellKnownTypes
''' <summary>Holder for reflection information generated from google/protobuf/struct.proto</summary>
Public Partial Module StructReflection
#Region "Descriptor"
''' <summary>File descriptor for google/protobuf/struct.proto</summary>
Public ReadOnly Property Descriptor As pbr.FileDescriptor
Get
Return descriptorField
End Get
End Property
Private descriptorField As pbr.FileDescriptor
Sub New()
Dim descriptorData As Byte() = Global.System.Convert.FromBase64String(String.Concat("Chxnb29nbGUvcHJvdG9idWYvc3RydWN0LnByb3RvEg9nb29nbGUucHJvdG9i", "dWYihAEKBlN0cnVjdBIzCgZmaWVsZHMYASADKAsyIy5nb29nbGUucHJvdG9i", "dWYuU3RydWN0LkZpZWxkc0VudHJ5GkUKC0ZpZWxkc0VudHJ5EgsKA2tleRgB", "IAEoCRIlCgV2YWx1ZRgCIAEoCzIWLmdvb2dsZS5wcm90b2J1Zi5WYWx1ZToC", "OAEi6gEKBVZhbHVlEjAKCm51bGxfdmFsdWUYASABKA4yGi5nb29nbGUucHJv", "dG9idWYuTnVsbFZhbHVlSAASFgoMbnVtYmVyX3ZhbHVlGAIgASgBSAASFgoM", "c3RyaW5nX3ZhbHVlGAMgASgJSAASFAoKYm9vbF92YWx1ZRgEIAEoCEgAEi8K", "DHN0cnVjdF92YWx1ZRgFIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3RI", "ABIwCgpsaXN0X3ZhbHVlGAYgASgLMhouZ29vZ2xlLnByb3RvYnVmLkxpc3RW", "YWx1ZUgAQgYKBGtpbmQiMwoJTGlzdFZhbHVlEiYKBnZhbHVlcxgBIAMoCzIW", "Lmdvb2dsZS5wcm90b2J1Zi5WYWx1ZSobCglOdWxsVmFsdWUSDgoKTlVMTF9W", "QUxVRRAAQoEBChNjb20uZ29vZ2xlLnByb3RvYnVmQgtTdHJ1Y3RQcm90b1AB", "WjFnaXRodWIuY29tL2dvbGFuZy9wcm90b2J1Zi9wdHlwZXMvc3RydWN0O3N0", "cnVjdHBioAEBogIDR1BCqgIeR29vZ2xlLlByb3RvYnVmLldlbGxLbm93blR5", "cGVzYgZwcm90bzM="))
descriptorField = pbr.FileDescriptor.FromGeneratedCode(descriptorData, New pbr.FileDescriptor() {}, New pbr.GeneratedClrTypeInfo({GetType(Global.Google.Protobuf.WellKnownTypes.NullValue)}, New pbr.GeneratedClrTypeInfo() {New pbr.GeneratedClrTypeInfo(GetType(Global.Google.Protobuf.WellKnownTypes.Struct), Global.Google.Protobuf.WellKnownTypes.Struct.Parser, {"Fields"}, Nothing, Nothing, New pbr.GeneratedClrTypeInfo() {Nothing}), New pbr.GeneratedClrTypeInfo(GetType(Global.Google.Protobuf.WellKnownTypes.Value), Global.Google.Protobuf.WellKnownTypes.Value.Parser, {"NullValue", "NumberValue", "StringValue", "BoolValue", "StructValue", "ListValue"}, {"Kind"}, Nothing, Nothing), New pbr.GeneratedClrTypeInfo(GetType(Global.Google.Protobuf.WellKnownTypes.ListValue), Global.Google.Protobuf.WellKnownTypes.ListValue.Parser, {"Values"}, Nothing, Nothing, Nothing)}))
End Sub
#End Region
End Module
#Region "Enums"
''' <summary>
''' `NullValue` is a singleton enumeration to represent the null value for the
''' `Value` type union.
'''
''' The JSON representation for `NullValue` is JSON `null`.
''' </summary>
Public Enum NullValue
''' <summary>
''' Null value.
''' </summary>
<pbr.OriginalName("NULL_VALUE")>
NullValue = 0
End Enum
#End Region
#Region "Messages"
''' <summary>
''' `Struct` represents a structured data value, consisting of fields
''' which map to dynamically typed values. In some languages, `Struct`
''' might be supported by a native representation. For example, in
''' scripting languages like JS a struct is represented as an
''' object. The details of that representation are described together
''' with the proto support for the language.
'''
''' The JSON representation for `Struct` is JSON object.
''' </summary>
Public NotInheritable Partial Class Struct
Implements IMessageType(Of Struct)
Private Shared ReadOnly _parser As MessageParserType(Of Struct) = New MessageParserType(Of Struct)(Function() New Struct())
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Shared ReadOnly Property Parser As MessageParserType(Of Struct)
Get
Return _parser
End Get
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Shared ReadOnly Property DescriptorProp As pbr.MessageDescriptor
Get
Return Global.Google.Protobuf.WellKnownTypes.StructReflection.Descriptor.MessageTypes(0)
End Get
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Private ReadOnly Property Descriptor As pbr.MessageDescriptor Implements IMessage.Descriptor
Get
Return DescriptorProp
End Get
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub New()
OnConstruction()
End Sub
Partial Private Sub OnConstruction()
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub New(other As Struct)
Me.New()
fields_ = other.fields_.Clone()
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Function Clone() As Struct Implements IDeepCloneable(Of Struct).Clone
Return New Struct(Me)
End Function
''' <summary>Field number for the "fields" field.</summary>
Public Const FieldsFieldNumber As Integer = 1
Private Shared ReadOnly _map_fields_codec As pbc.MapField(Of String, Global.Google.Protobuf.WellKnownTypes.Value).Codec = New pbc.MapField(Of String, Global.Google.Protobuf.WellKnownTypes.Value).Codec(ForString(10), FieldCodec.ForMessage(18, Global.Google.Protobuf.WellKnownTypes.Value.Parser), 10)
Private ReadOnly fields_ As pbc.MapField(Of String, Global.Google.Protobuf.WellKnownTypes.Value) = New pbc.MapField(Of String, Global.Google.Protobuf.WellKnownTypes.Value)()
''' <summary>
''' Unordered map of dynamically typed values.
''' </summary>
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public ReadOnly Property Fields As pbc.MapField(Of String, Global.Google.Protobuf.WellKnownTypes.Value)
Get
Return fields_
End Get
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overrides Function Equals(other As Object) As Boolean
Return Equals(TryCast(other, Struct))
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overloads Function Equals(other As Struct) As Boolean Implements IEquatable(Of Struct).Equals
If ReferenceEquals(other, Nothing) Then
Return False
End If
If ReferenceEquals(other, Me) Then
Return True
End If
If Not Fields.Equals(other.Fields) Then Return False
Return True
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overrides Function GetHashCode() As Integer
Dim hash = 1
hash = hash Xor Fields.GetHashCode()
Return hash
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overrides Function ToString() As String
Return JsonFormatter.ToDiagnosticString(Me)
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub WriteTo(output As CodedOutputStream) Implements IMessage.WriteTo
fields_.WriteTo(output, _map_fields_codec)
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Function CalculateSize() As Integer Implements IMessage.CalculateSize
Dim size = 0
size += fields_.CalculateSize(_map_fields_codec)
Return size
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub MergeFrom(other As Struct) Implements IMessageType(Of Struct).MergeFrom
If other Is Nothing Then
Return
End If
fields_.Add(other.fields_)
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub MergeFrom(input As CodedInputStream) Implements IMessage.MergeFrom
Dim tag As UInteger
While (CSharpImpl.__Assign(tag, input.ReadTag())) <> 0
Select Case tag
Case 10
fields_.AddEntriesFrom(input, _map_fields_codec)
Exit Select
Case Else
input.SkipLastField()
End Select
End While
End Sub
Private Class CSharpImpl
<Obsolete("Please refactor calling code to use normal Visual Basic assignment")>
Shared Function __Assign(Of T)(ByRef target As T, value As T) As T
target = value
Return value
End Function
End Class
End Class
''' <summary>
''' `Value` represents a dynamically typed value which can be either
''' null, a number, a string, a boolean, a recursive struct value, or a
''' list of values. A producer of value is expected to set one of that
''' variants, absence of any variant indicates an error.
'''
''' The JSON representation for `Value` is JSON value.
''' </summary>
Public NotInheritable Partial Class Value
Implements IMessageType(Of Value)
Private Shared ReadOnly _parser As MessageParserType(Of Value) = New MessageParserType(Of Value)(Function() New Value())
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Shared ReadOnly Property Parser As MessageParserType(Of Value)
Get
Return _parser
End Get
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Shared ReadOnly Property DescriptorProp As pbr.MessageDescriptor
Get
Return Global.Google.Protobuf.WellKnownTypes.StructReflection.Descriptor.MessageTypes(1)
End Get
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Private ReadOnly Property Descriptor As pbr.MessageDescriptor Implements IMessage.Descriptor
Get
Return DescriptorProp
End Get
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub New()
OnConstruction()
End Sub
Partial Private Sub OnConstruction()
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub New(other As Value)
Me.New()
Select Case other.KindCase
Case KindOneofCase.NullValue
NullValue = other.NullValue
Case KindOneofCase.NumberValue
NumberValue = other.NumberValue
Case KindOneofCase.StringValue
StringValue = other.StringValue
Case KindOneofCase.BoolValue
BoolValue = other.BoolValue
Case KindOneofCase.StructValue
StructValue = other.StructValue.Clone()
Case KindOneofCase.ListValue
ListValue = other.ListValue.Clone()
End Select
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Function Clone() As Value Implements IDeepCloneable(Of Value).Clone
Return New Value(Me)
End Function
''' <summary>Field number for the "null_value" field.</summary>
Public Const NullValueFieldNumber As Integer = 1
''' <summary>
''' Represents a null value.
''' </summary>
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Property NullValue As Global.Google.Protobuf.WellKnownTypes.NullValue
Get
Return If(kindCase_ = KindOneofCase.NullValue, CType(kind_, Global.Google.Protobuf.WellKnownTypes.NullValue), 0)
End Get
Set(value As Global.Google.Protobuf.WellKnownTypes.NullValue)
kind_ = value
kindCase_ = KindOneofCase.NullValue
End Set
End Property
''' <summary>Field number for the "number_value" field.</summary>
Public Const NumberValueFieldNumber As Integer = 2
''' <summary>
''' Represents a double value.
''' </summary>
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Property NumberValue As Double
Get
Return If(kindCase_ = KindOneofCase.NumberValue, CDbl(kind_), 0R)
End Get
Set(value As Double)
kind_ = value
kindCase_ = KindOneofCase.NumberValue
End Set
End Property
''' <summary>Field number for the "string_value" field.</summary>
Public Const StringValueFieldNumber As Integer = 3
''' <summary>
''' Represents a string value.
''' </summary>
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Property StringValue As String
Get
Return If(kindCase_ = KindOneofCase.StringValue, CStr(kind_), "")
End Get
Set(value As String)
kind_ = CheckNotNull(value, "value")
kindCase_ = KindOneofCase.StringValue
End Set
End Property
''' <summary>Field number for the "bool_value" field.</summary>
Public Const BoolValueFieldNumber As Integer = 4
''' <summary>
''' Represents a boolean value.
''' </summary>
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Property BoolValue As Boolean
Get
Return If(kindCase_ = KindOneofCase.BoolValue, CBool(kind_), False)
End Get
Set(value As Boolean)
kind_ = value
kindCase_ = KindOneofCase.BoolValue
End Set
End Property
''' <summary>Field number for the "struct_value" field.</summary>
Public Const StructValueFieldNumber As Integer = 5
''' <summary>
''' Represents a structured value.
''' </summary>
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Property StructValue As Global.Google.Protobuf.WellKnownTypes.Struct
Get
Return If(kindCase_ = KindOneofCase.StructValue, CType(kind_, Global.Google.Protobuf.WellKnownTypes.Struct), Nothing)
End Get
Set(value As Global.Google.Protobuf.WellKnownTypes.Struct)
kind_ = value
kindCase_ = If(value Is Nothing, KindOneofCase.None, KindOneofCase.StructValue)
End Set
End Property
''' <summary>Field number for the "list_value" field.</summary>
Public Const ListValueFieldNumber As Integer = 6
''' <summary>
''' Represents a repeated `Value`.
''' </summary>
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Property ListValue As Global.Google.Protobuf.WellKnownTypes.ListValue
Get
Return If(kindCase_ = KindOneofCase.ListValue, CType(kind_, Global.Google.Protobuf.WellKnownTypes.ListValue), Nothing)
End Get
Set(value As Global.Google.Protobuf.WellKnownTypes.ListValue)
kind_ = value
kindCase_ = If(value Is Nothing, KindOneofCase.None, KindOneofCase.ListValue)
End Set
End Property
Private kind_ As Object
''' <summary>Enum of possible cases for the "kind" oneof.</summary>
Public Enum KindOneofCase
None = 0
NullValue = 1
NumberValue = 2
StringValue = 3
BoolValue = 4
StructValue = 5
ListValue = 6
End Enum
Private kindCase_ As KindOneofCase = KindOneofCase.None
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public ReadOnly Property KindCase As KindOneofCase
Get
Return kindCase_
End Get
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub ClearKind()
kindCase_ = KindOneofCase.None
kind_ = Nothing
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overrides Function Equals(other As Object) As Boolean
Return Equals(TryCast(other, Value))
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overloads Function Equals(other As Value) As Boolean Implements IEquatable(Of Value).Equals
If ReferenceEquals(other, Nothing) Then
Return False
End If
If ReferenceEquals(other, Me) Then
Return True
End If
If NullValue <> other.NullValue Then Return False
If NumberValue <> other.NumberValue Then Return False
If Not Equals(StringValue, other.StringValue) Then Return False
If BoolValue <> other.BoolValue Then Return False
If Not Object.Equals(StructValue, other.StructValue) Then Return False
If Not Object.Equals(ListValue, other.ListValue) Then Return False
If KindCase <> other.KindCase Then Return False
Return True
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overrides Function GetHashCode() As Integer
Dim hash = 1
If kindCase_ = KindOneofCase.NullValue Then hash = hash Xor NullValue.GetHashCode()
If kindCase_ = KindOneofCase.NumberValue Then hash = hash Xor NumberValue.GetHashCode()
If kindCase_ = KindOneofCase.StringValue Then hash = hash Xor StringValue.GetHashCode()
If kindCase_ = KindOneofCase.BoolValue Then hash = hash Xor BoolValue.GetHashCode()
If kindCase_ = KindOneofCase.StructValue Then hash = hash Xor StructValue.GetHashCode()
If kindCase_ = KindOneofCase.ListValue Then hash = hash Xor ListValue.GetHashCode()
hash = hash Xor kindCase_
Return hash
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overrides Function ToString() As String
Return JsonFormatter.ToDiagnosticString(Me)
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub WriteTo(output As CodedOutputStream) Implements IMessage.WriteTo
If kindCase_ = KindOneofCase.NullValue Then
output.WriteRawTag(8)
output.WriteEnum(CInt(NullValue))
End If
If kindCase_ = KindOneofCase.NumberValue Then
output.WriteRawTag(17)
output.WriteDouble(NumberValue)
End If
If kindCase_ = KindOneofCase.StringValue Then
output.WriteRawTag(26)
output.WriteString(StringValue)
End If
If kindCase_ = KindOneofCase.BoolValue Then
output.WriteRawTag(32)
output.WriteBool(BoolValue)
End If
If kindCase_ = KindOneofCase.StructValue Then
output.WriteRawTag(42)
output.WriteMessage(StructValue)
End If
If kindCase_ = KindOneofCase.ListValue Then
output.WriteRawTag(50)
output.WriteMessage(ListValue)
End If
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Function CalculateSize() As Integer Implements IMessage.CalculateSize
Dim size = 0
If kindCase_ = KindOneofCase.NullValue Then
size += 1 + CodedOutputStream.ComputeEnumSize(CInt(NullValue))
End If
If kindCase_ = KindOneofCase.NumberValue Then
size += 1 + 8
End If
If kindCase_ = KindOneofCase.StringValue Then
size += 1 + CodedOutputStream.ComputeStringSize(StringValue)
End If
If kindCase_ = KindOneofCase.BoolValue Then
size += 1 + 1
End If
If kindCase_ = KindOneofCase.StructValue Then
size += 1 + CodedOutputStream.ComputeMessageSize(StructValue)
End If
If kindCase_ = KindOneofCase.ListValue Then
size += 1 + CodedOutputStream.ComputeMessageSize(ListValue)
End If
Return size
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub MergeFrom(other As Value) Implements IMessageType(Of Value).MergeFrom
If other Is Nothing Then
Return
End If
Select Case other.KindCase
Case KindOneofCase.NullValue
NullValue = other.NullValue
Case KindOneofCase.NumberValue
NumberValue = other.NumberValue
Case KindOneofCase.StringValue
StringValue = other.StringValue
Case KindOneofCase.BoolValue
BoolValue = other.BoolValue
Case KindOneofCase.StructValue
StructValue = other.StructValue
Case KindOneofCase.ListValue
ListValue = other.ListValue
End Select
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub MergeFrom(input As CodedInputStream) Implements IMessage.MergeFrom
Dim tag As UInteger
While (CSharpImpl.__Assign(tag, input.ReadTag())) <> 0
Select Case tag
Case 8
kind_ = input.ReadEnum()
kindCase_ = KindOneofCase.NullValue
Exit Select
Case 17
NumberValue = input.ReadDouble()
Exit Select
Case 26
StringValue = input.ReadString()
Exit Select
Case 32
BoolValue = input.ReadBool()
Exit Select
Case 42
Dim subBuilder As Global.Google.Protobuf.WellKnownTypes.Struct = New Global.Google.Protobuf.WellKnownTypes.Struct()
If kindCase_ = KindOneofCase.StructValue Then
subBuilder.MergeFrom(StructValue)
End If
input.ReadMessage(subBuilder)
StructValue = subBuilder
Exit Select
Case 50
Dim subBuilder As Global.Google.Protobuf.WellKnownTypes.ListValue = New Global.Google.Protobuf.WellKnownTypes.ListValue()
If kindCase_ = KindOneofCase.ListValue Then
subBuilder.MergeFrom(ListValue)
End If
input.ReadMessage(subBuilder)
ListValue = subBuilder
Exit Select
Case Else
input.SkipLastField()
End Select
End While
End Sub
Private Class CSharpImpl
<Obsolete("Please refactor calling code to use normal Visual Basic assignment")>
Shared Function __Assign(Of T)(ByRef target As T, value As T) As T
target = value
Return value
End Function
End Class
End Class
''' <summary>
''' `ListValue` is a wrapper around a repeated field of values.
'''
''' The JSON representation for `ListValue` is JSON array.
''' </summary>
Public NotInheritable Partial Class ListValue
Implements IMessageType(Of ListValue)
Private Shared ReadOnly _parser As MessageParserType(Of ListValue) = New MessageParserType(Of ListValue)(Function() New ListValue())
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Shared ReadOnly Property Parser As MessageParserType(Of ListValue)
Get
Return _parser
End Get
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Shared ReadOnly Property DescriptorProp As pbr.MessageDescriptor
Get
Return Global.Google.Protobuf.WellKnownTypes.StructReflection.Descriptor.MessageTypes(2)
End Get
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Private ReadOnly Property Descriptor As pbr.MessageDescriptor Implements IMessage.Descriptor
Get
Return DescriptorProp
End Get
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub New()
OnConstruction()
End Sub
Partial Private Sub OnConstruction()
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub New(other As ListValue)
Me.New()
values_ = other.values_.Clone()
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Function Clone() As ListValue Implements IDeepCloneable(Of ListValue).Clone
Return New ListValue(Me)
End Function
''' <summary>Field number for the "values" field.</summary>
Public Const ValuesFieldNumber As Integer = 1
Private Shared ReadOnly _repeated_values_codec As FieldCodecType(Of Global.Google.Protobuf.WellKnownTypes.Value) = FieldCodec.ForMessage(10, Global.Google.Protobuf.WellKnownTypes.Value.Parser)
Friend values_ As pbc.RepeatedField(Of Global.Google.Protobuf.WellKnownTypes.Value) = New pbc.RepeatedField(Of Global.Google.Protobuf.WellKnownTypes.Value)()
''' <summary>
''' Repeated field of dynamically typed values.
''' </summary>
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public ReadOnly Property Values As pbc.RepeatedField(Of Global.Google.Protobuf.WellKnownTypes.Value)
Get
Return values_
End Get
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overrides Function Equals(other As Object) As Boolean
Return Equals(TryCast(other, ListValue))
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overloads Function Equals(other As ListValue) As Boolean Implements IEquatable(Of ListValue).Equals
If ReferenceEquals(other, Nothing) Then
Return False
End If
If ReferenceEquals(other, Me) Then
Return True
End If
If Not values_.Equals(other.values_) Then Return False
Return True
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overrides Function GetHashCode() As Integer
Dim hash = 1
hash = hash Xor values_.GetHashCode()
Return hash
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overrides Function ToString() As String
Return JsonFormatter.ToDiagnosticString(Me)
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub WriteTo(output As CodedOutputStream) Implements IMessage.WriteTo
values_.WriteTo(output, _repeated_values_codec)
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Function CalculateSize() As Integer Implements IMessage.CalculateSize
Dim size = 0
size += values_.CalculateSize(_repeated_values_codec)
Return size
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub MergeFrom(other As ListValue) Implements IMessageType(Of ListValue).MergeFrom
If other Is Nothing Then
Return
End If
values_.Add(other.values_)
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub MergeFrom(input As CodedInputStream) Implements IMessage.MergeFrom
Dim tag As UInteger
While (CSharpImpl.__Assign(tag, input.ReadTag())) <> 0
Select Case tag
Case 10
values_.AddEntriesFrom(input, _repeated_values_codec)
Exit Select
Case Else
input.SkipLastField()
End Select
End While
End Sub
Private Class CSharpImpl
<Obsolete("Please refactor calling code to use normal Visual Basic assignment")>
Shared Function __Assign(Of T)(ByRef target As T, value As T) As T
target = value
Return value
End Function
End Class
End Class
#End Region
End Namespace
#End Region

@ -0,0 +1,75 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2015 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System
Imports System.Runtime.CompilerServices
Namespace Google.Protobuf.WellKnownTypes
''' <summary>
''' Extension methods on BCL time-related types, converting to protobuf types.
''' </summary>
Public Module TimeExtensions
''' <summary>
''' Converts the given <see cref="DateTime"/> to a <see cref="Timestamp"/>.
''' </summary>
''' <param name="dateTime">The date and time to convert to a timestamp.</param>
''' <exception cref="ArgumentException">The <paramrefname="dateTime"/> value has a <see cref="DateTime.Kind"/>other than <c>Utc</c>.</exception>
''' <returns>The converted timestamp.</returns>
<Extension()>
Public Function ToTimestamp(dateTime As Date) As Timestamp
Return Timestamp.FromDateTime(dateTime)
End Function
''' <summary>
''' Converts the given <see cref="DateTimeOffset"/> to a <see cref="Timestamp"/>
''' </summary>
''' <remarks>The offset is taken into consideration when converting the value (so the same instant in time
''' is represented) but is not a separate part of the resulting value. In other words, there is no
''' roundtrip operation to retrieve the original <c>DateTimeOffset</c>.</remarks>
''' <param name="dateTimeOffset">The date and time (with UTC offset) to convert to a timestamp.</param>
''' <returns>The converted timestamp.</returns>
<Extension()>
Public Function ToTimestamp(dateTimeOffset As DateTimeOffset) As Timestamp
Return Timestamp.FromDateTimeOffset(dateTimeOffset)
End Function
''' <summary>
''' Converts the given <see cref="TimeSpan"/> to a <see cref="Duration"/>.
''' </summary>
''' <param name="timeSpan">The time span to convert.</param>
''' <returns>The converted duration.</returns>
<Extension()>
Public Function ToDuration(timeSpan As TimeSpan) As Duration
Return Duration.FromTimeSpan(timeSpan)
End Function
End Module
End Namespace

@ -0,0 +1,274 @@
' Generated by the protocol buffer compiler. DO NOT EDIT!
' source: google/protobuf/timestamp.proto
#Region "Designer generated code"
Imports pbr = Google.Protobuf.Reflection
Namespace Google.Protobuf.WellKnownTypes
''' <summary>Holder for reflection information generated from google/protobuf/timestamp.proto</summary>
Public Partial Module TimestampReflection
#Region "Descriptor"
''' <summary>File descriptor for google/protobuf/timestamp.proto</summary>
Public ReadOnly Property Descriptor As pbr.FileDescriptor
Get
Return descriptorField
End Get
End Property
Private descriptorField As pbr.FileDescriptor
Sub New()
Dim descriptorData As Byte() = Global.System.Convert.FromBase64String(String.Concat("Ch9nb29nbGUvcHJvdG9idWYvdGltZXN0YW1wLnByb3RvEg9nb29nbGUucHJv", "dG9idWYiKwoJVGltZXN0YW1wEg8KB3NlY29uZHMYASABKAMSDQoFbmFub3MY", "AiABKAVCgQEKE2NvbS5nb29nbGUucHJvdG9idWZCDlRpbWVzdGFtcFByb3Rv", "UAFaK2dpdGh1Yi5jb20vZ29sYW5nL3Byb3RvYnVmL3B0eXBlcy90aW1lc3Rh", "bXCgAQH4AQGiAgNHUEKqAh5Hb29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlw", "ZXNiBnByb3RvMw=="))
descriptorField = pbr.FileDescriptor.FromGeneratedCode(descriptorData, New pbr.FileDescriptor() {}, New pbr.GeneratedClrTypeInfo(Nothing, New pbr.GeneratedClrTypeInfo() {New pbr.GeneratedClrTypeInfo(GetType(Global.Google.Protobuf.WellKnownTypes.Timestamp), Global.Google.Protobuf.WellKnownTypes.Timestamp.Parser, {"Seconds", "Nanos"}, Nothing, Nothing, Nothing)}))
End Sub
#End Region
End Module
#Region "Messages"
''' <summary>
''' A Timestamp represents a point in time independent of any time zone
''' or calendar, represented as seconds and fractions of seconds at
''' nanosecond resolution in UTC Epoch time. It is encoded using the
''' Proleptic Gregorian Calendar which extends the Gregorian calendar
''' backwards to year one. It is encoded assuming all minutes are 60
''' seconds long, i.e. leap seconds are "smeared" so that no leap second
''' table is needed for interpretation. Range is from
''' 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z.
''' By restricting to that range, we ensure that we can convert to
''' and from RFC 3339 date strings.
''' See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt).
'''
''' Example 1: Compute Timestamp from POSIX `time()`.
'''
''' Timestamp timestamp;
''' timestamp.set_seconds(time(NULL));
''' timestamp.set_nanos(0);
'''
''' Example 2: Compute Timestamp from POSIX `gettimeofday()`.
'''
''' struct timeval tv;
''' gettimeofday(&amp;tv, NULL);
'''
''' Timestamp timestamp;
''' timestamp.set_seconds(tv.tv_sec);
''' timestamp.set_nanos(tv.tv_usec * 1000);
'''
''' Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
'''
''' FILETIME ft;
''' GetSystemTimeAsFileTime(&amp;ft);
''' UINT64 ticks = (((UINT64)ft.dwHighDateTime) &lt;&lt; 32) | ft.dwLowDateTime;
'''
''' // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
''' // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
''' Timestamp timestamp;
''' timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
''' timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
'''
''' Example 4: Compute Timestamp from Java `System.currentTimeMillis()`.
'''
''' long millis = System.currentTimeMillis();
'''
''' Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
''' .setNanos((int) ((millis % 1000) * 1000000)).build();
'''
''' Example 5: Compute Timestamp from current time in Python.
'''
''' now = time.time()
''' seconds = int(now)
''' nanos = int((now - seconds) * 10**9)
''' timestamp = Timestamp(seconds=seconds, nanos=nanos)
''' </summary>
Public NotInheritable Partial Class Timestamp
Implements IMessageType(Of Timestamp)
Private Shared ReadOnly _parser As MessageParserType(Of Timestamp) = New MessageParserType(Of Timestamp)(Function() New Timestamp())
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Shared ReadOnly Property Parser As MessageParserType(Of Timestamp)
Get
Return _parser
End Get
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Shared ReadOnly Property DescriptorProp As pbr.MessageDescriptor
Get
Return Global.Google.Protobuf.WellKnownTypes.TimestampReflection.Descriptor.MessageTypes(0)
End Get
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Private ReadOnly Property Descriptor As pbr.MessageDescriptor Implements IMessage.Descriptor
Get
Return DescriptorProp
End Get
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub New()
OnConstruction()
End Sub
Partial Private Sub OnConstruction()
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub New(other As Timestamp)
Me.New()
seconds_ = other.seconds_
nanos_ = other.nanos_
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Function Clone() As Timestamp Implements IDeepCloneable(Of Timestamp).Clone
Return New Timestamp(Me)
End Function
''' <summary>Field number for the "seconds" field.</summary>
Public Const SecondsFieldNumber As Integer = 1
Private seconds_ As Long
''' <summary>
''' Represents seconds of UTC time since Unix epoch
''' 1970-01-01T00:00:00Z. Must be from from 0001-01-01T00:00:00Z to
''' 9999-12-31T23:59:59Z inclusive.
''' </summary>
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Property Seconds As Long
Get
Return seconds_
End Get
Set(value As Long)
seconds_ = value
End Set
End Property
''' <summary>Field number for the "nanos" field.</summary>
Public Const NanosFieldNumber As Integer = 2
Private nanos_ As Integer
''' <summary>
''' Non-negative fractions of a second at nanosecond resolution. Negative
''' second values with fractions must still have non-negative nanos values
''' that count forward in time. Must be from 0 to 999,999,999
''' inclusive.
''' </summary>
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Property Nanos As Integer
Get
Return nanos_
End Get
Set(value As Integer)
nanos_ = value
End Set
End Property
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overrides Function Equals(other As Object) As Boolean
Return Equals(TryCast(other, Timestamp))
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overloads Function Equals(other As Timestamp) As Boolean Implements IEquatable(Of Timestamp).Equals
If ReferenceEquals(other, Nothing) Then
Return False
End If
If ReferenceEquals(other, Me) Then
Return True
End If
If Seconds <> other.Seconds Then Return False
If Nanos <> other.Nanos Then Return False
Return True
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overrides Function GetHashCode() As Integer
Dim hash = 1
If Seconds <> 0L Then hash = hash Xor Seconds.GetHashCode()
If Nanos <> 0 Then hash = hash Xor Nanos.GetHashCode()
Return hash
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Overrides Function ToString() As String
Return JsonFormatter.ToDiagnosticString(Me)
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub WriteTo(output As CodedOutputStream) Implements IMessage.WriteTo
If Seconds <> 0L Then
output.WriteRawTag(8)
output.WriteInt64(Seconds)
End If
If Nanos <> 0 Then
output.WriteRawTag(16)
output.WriteInt32(Nanos)
End If
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Function CalculateSize() As Integer Implements IMessage.CalculateSize
Dim size = 0
If Seconds <> 0L Then
size += 1 + CodedOutputStream.ComputeInt64Size(Seconds)
End If
If Nanos <> 0 Then
size += 1 + CodedOutputStream.ComputeInt32Size(Nanos)
End If
Return size
End Function
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub MergeFrom(other As Timestamp) Implements IMessageType(Of Timestamp).MergeFrom
If other Is Nothing Then
Return
End If
If other.Seconds <> 0L Then
Seconds = other.Seconds
End If
If other.Nanos <> 0 Then
Nanos = other.Nanos
End If
End Sub
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute>
Public Sub MergeFrom(input As CodedInputStream) Implements IMessage.MergeFrom
Dim tag As UInteger
While (CSharpImpl.__Assign(tag, input.ReadTag())) <> 0
Select Case tag
Case 8
Seconds = input.ReadInt64()
Exit Select
Case 16
Nanos = input.ReadInt32()
Exit Select
Case Else
input.SkipLastField()
End Select
End While
End Sub
Private Class CSharpImpl
<Obsolete("Please refactor calling code to use normal Visual Basic assignment")>
Shared Function __Assign(Of T)(ByRef target As T, value As T) As T
target = value
Return value
End Function
End Class
End Class
#End Region
End Namespace
#End Region

@ -0,0 +1,225 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2015 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Imports System
Imports System.Globalization
Imports System.Text
Namespace Google.Protobuf.WellKnownTypes
Public Partial Class Timestamp
Implements ICustomDiagnosticMessage
Private Shared ReadOnly UnixEpoch As Date = New DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)
' Constants determined programmatically, but then hard-coded so they can be constant expressions.
Private Const BclSecondsAtUnixEpoch As Long = 62135596800
Friend Const UnixSecondsAtBclMaxValue As Long = 253402300799
Friend Const UnixSecondsAtBclMinValue As Long = -BclSecondsAtUnixEpoch
Friend Const MaxNanos As Integer = Duration.NanosecondsPerSecond - 1
Private Shared Function IsNormalized(seconds As Long, nanoseconds As Integer) As Boolean
Return nanoseconds >= 0 AndAlso nanoseconds <= MaxNanos AndAlso seconds >= UnixSecondsAtBclMinValue AndAlso seconds <= UnixSecondsAtBclMaxValue
End Function
''' <summary>
''' Returns the difference between one <see cref="Timestamp"/> and another, as a <see cref="Duration"/>.
''' </summary>
''' <param name="lhs">The timestamp to subtract from. Must not be null.</param>
''' <param name="rhs">The timestamp to subtract. Must not be null.</param>
''' <returns>The difference between the two specified timestamps.</returns>
Public Shared Operator -(lhs As Timestamp, rhs As Timestamp) As Duration
CheckNotNull(lhs, "lhs")
CheckNotNull(rhs, "rhs")
'BEGIN TODO : Visual Basic does not support checked statements!
Return Duration.Normalize(lhs.Seconds - rhs.Seconds, lhs.Nanos - rhs.Nanos)
'END TODO : Visual Basic does not support checked statements!
End Operator
''' <summary>
''' Adds a <see cref="Duration"/> to a <see cref="Timestamp"/>, to obtain another <c>Timestamp</c>.
''' </summary>
''' <param name="lhs">The timestamp to add the duration to. Must not be null.</param>
''' <param name="rhs">The duration to add. Must not be null.</param>
''' <returns>The result of adding the duration to the timestamp.</returns>
Public Shared Operator +(lhs As Timestamp, rhs As Duration) As Timestamp
CheckNotNull(lhs, "lhs")
CheckNotNull(rhs, "rhs")
'BEGIN TODO : Visual Basic does not support checked statements!
Return Normalize(lhs.Seconds + rhs.Seconds, lhs.Nanos + rhs.Nanos)
'END TODO : Visual Basic does not support checked statements!
End Operator
''' <summary>
''' Subtracts a <see cref="Duration"/> from a <see cref="Timestamp"/>, to obtain another <c>Timestamp</c>.
''' </summary>
''' <param name="lhs">The timestamp to subtract the duration from. Must not be null.</param>
''' <param name="rhs">The duration to subtract.</param>
''' <returns>The result of subtracting the duration from the timestamp.</returns>
Public Shared Operator -(lhs As Timestamp, rhs As Duration) As Timestamp
CheckNotNull(lhs, "lhs")
CheckNotNull(rhs, "rhs")
' BEGIN TODO : Visual Basic does not support checked statements!
Return Normalize(lhs.Seconds - rhs.Seconds, lhs.Nanos - rhs.Nanos)
' END TODO : Visual Basic does not support checked statements!
End Operator
''' <summary>
''' Converts this timestamp into a <see cref="DateTime"/>.
''' </summary>
''' <remarks>
''' The resulting <c>DateTime</c> will always have a <c>Kind</c> of <c>Utc</c>.
''' If the timestamp is not a precise number of ticks, it will be truncated towards the start
''' of time. For example, a timestamp with a <see cref="Nanos"/> value of 99 will result in a
''' <see cref="DateTime"/> value precisely on a second.
''' </remarks>
''' <returns>This timestamp as a <c>DateTime</c>.</returns>
''' <exception cref="InvalidOperationException">The timestamp contains invalid values; either it is
''' incorrectly normalized or is outside the valid range.</exception>
Public Function ToDateTime() As Date
If Not IsNormalized(Seconds, Nanos) Then
Throw New InvalidOperationException("Timestamp contains invalid values: Seconds={Seconds}; Nanos={Nanos}")
End If
Return UnixEpoch.AddSeconds(Seconds).AddTicks(Nanos / Duration.NanosecondsPerTick)
End Function
''' <summary>
''' Converts this timestamp into a <see cref="DateTimeOffset"/>.
''' </summary>
''' <remarks>
''' The resulting <c>DateTimeOffset</c> will always have an <c>Offset</c> of zero.
''' If the timestamp is not a precise number of ticks, it will be truncated towards the start
''' of time. For example, a timestamp with a <see cref="Nanos"/> value of 99 will result in a
''' <see cref="DateTimeOffset"/> value precisely on a second.
''' </remarks>
''' <returns>This timestamp as a <c>DateTimeOffset</c>.</returns>
''' <exception cref="InvalidOperationException">The timestamp contains invalid values; either it is
''' incorrectly normalized or is outside the valid range.</exception>
Public Function ToDateTimeOffset() As DateTimeOffset
Return New DateTimeOffset(ToDateTime(), TimeSpan.Zero)
End Function
''' <summary>
''' Converts the specified <see cref="DateTime"/> to a <see cref="Timestamp"/>.
''' </summary>
''' <param name="dateTime"></param>
''' <exception cref="ArgumentException">The <c>Kind</c> of <paramrefname="dateTime"/> is not <c>DateTimeKind.Utc</c>.</exception>
''' <returns>The converted timestamp.</returns>
Public Shared Function FromDateTime(dateTime As Date) As Timestamp
If dateTime.Kind <> DateTimeKind.Utc Then
Throw New ArgumentException("Conversion from DateTime to Timestamp requires the DateTime kind to be Utc", "dateTime")
End If
' Do the arithmetic using DateTime.Ticks, which is always non-negative, making things simpler.
Dim secondsSinceBclEpoch As Long = dateTime.Ticks / TimeSpan.TicksPerSecond
Dim nanoseconds = CInt(dateTime.Ticks Mod TimeSpan.TicksPerSecond) * Duration.NanosecondsPerTick
Return New Timestamp With {
.Seconds = secondsSinceBclEpoch - BclSecondsAtUnixEpoch,
.Nanos = nanoseconds
}
End Function
''' <summary>
''' Converts the given <see cref="DateTimeOffset"/> to a <see cref="Timestamp"/>
''' </summary>
''' <remarks>The offset is taken into consideration when converting the value (so the same instant in time
''' is represented) but is not a separate part of the resulting value. In other words, there is no
''' roundtrip operation to retrieve the original <c>DateTimeOffset</c>.</remarks>
''' <param name="dateTimeOffset">The date and time (with UTC offset) to convert to a timestamp.</param>
''' <returns>The converted timestamp.</returns>
Public Shared Function FromDateTimeOffset(dateTimeOffset As DateTimeOffset) As Timestamp
' We don't need to worry about this having negative ticks: DateTimeOffset is constrained to handle
' values whose *UTC* value is in the range of DateTime.
Return FromDateTime(dateTimeOffset.UtcDateTime)
End Function
Friend Shared Function Normalize(seconds As Long, nanoseconds As Integer) As Timestamp
Dim extraSeconds As Integer = nanoseconds / Duration.NanosecondsPerSecond
seconds += extraSeconds
nanoseconds -= extraSeconds * Duration.NanosecondsPerSecond
If nanoseconds < 0 Then
nanoseconds += Duration.NanosecondsPerSecond
seconds -= 1
End If
Return New Timestamp With {
.Seconds = seconds,
.Nanos = nanoseconds
}
End Function
''' <summary>
''' Converts a timestamp specified in seconds/nanoseconds to a string.
''' </summary>
''' <remarks>
''' If the value is a normalized duration in the range described in <c>timestamp.proto</c>,
''' <paramrefname="diagnosticOnly"/> is ignored. Otherwise, if the parameter is <c>true</c>,
''' a JSON object with a warning is returned; if it is <c>false</c>, an <see cref="InvalidOperationException"/> is thrown.
''' </remarks>
''' <param name="seconds">Seconds portion of the duration.</param>
''' <param name="nanoseconds">Nanoseconds portion of the duration.</param>
''' <param name="diagnosticOnly">Determines the handling of non-normalized values</param>
''' <exception cref="InvalidOperationException">The represented duration is invalid, and <paramrefname="diagnosticOnly"/> is <c>false</c>.</exception>
Friend Shared Function ToJson(seconds As Long, nanoseconds As Integer, diagnosticOnly As Boolean) As String
If IsNormalized(seconds, nanoseconds) Then
' Use .NET's formatting for the value down to the second, including an opening double quote (as it's a string value)
Dim dateTime = UnixEpoch.AddSeconds(seconds)
Dim builder = New StringBuilder()
builder.Append(""""c)
builder.Append(dateTime.ToString("yyyy'-'MM'-'dd'T'HH:mm:ss", CultureInfo.InvariantCulture))
Duration.AppendNanoseconds(builder, nanoseconds)
builder.Append("Z""")
Return builder.ToString()
End If
If diagnosticOnly Then
Return String.Format(CultureInfo.InvariantCulture, "{{ ""@warning"": ""Invalid Timestamp"", ""seconds"": ""{0}"", ""nanos"": {1} }}", seconds, nanoseconds)
Else
Throw New InvalidOperationException("Non-normalized timestamp value")
End If
End Function
''' <summary>
''' Returns a string representation of this <see cref="Timestamp"/> for diagnostic purposes.
''' </summary>
''' <remarks>
''' Normally the returned value will be a JSON string value (including leading and trailing quotes) but
''' when the value is non-normalized or out of range, a JSON object representation will be returned
''' instead, including a warning. This is to avoid exceptions being thrown when trying to
''' diagnose problems - the regular JSON formatter will still throw an exception for non-normalized
''' values.
''' </remarks>
''' <returns>A string representation of this value.</returns>
Public Function ToDiagnosticString() As String Implements ICustomDiagnosticMessage.ToDiagnosticString
Return ToJson(Seconds, Nanos, True)
End Function
End Class
End Namespace

File diff suppressed because it is too large Load Diff

@ -0,0 +1,101 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2008 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Namespace Google.Protobuf.WellKnownTypes
Public Partial Class Value
''' <summary>
''' Convenience method to create a Value message with a string value.
''' </summary>
''' <param name="value">Value to set for the StringValue property.</param>
''' <returns>A newly-created Value message with the given value.</returns>
Public Shared Function ForString(value As String) As Value
CheckNotNull(value, "value")
Return New Value With {
.StringValue = value
}
End Function
''' <summary>
''' Convenience method to create a Value message with a number value.
''' </summary>
''' <param name="value">Value to set for the NumberValue property.</param>
''' <returns>A newly-created Value message with the given value.</returns>
Public Shared Function ForNumber(value As Double) As Value
Return New Value With {
.NumberValue = value
}
End Function
''' <summary>
''' Convenience method to create a Value message with a Boolean value.
''' </summary>
''' <param name="value">Value to set for the BoolValue property.</param>
''' <returns>A newly-created Value message with the given value.</returns>
Public Shared Function ForBool(value As Boolean) As Value
Return New Value With {
.BoolValue = value
}
End Function
''' <summary>
''' Convenience method to create a Value message with a null initial value.
''' </summary>
''' <returns>A newly-created Value message a null initial value.</returns>
Public Shared Function ForNull() As Value
Return New Value With {
.NullValue = 0
}
End Function
''' <summary>
''' Convenience method to create a Value message with an initial list of values.
''' </summary>
''' <remarks>The values provided are not cloned; the references are copied directly.</remarks>
''' <returns>A newly-created Value message an initial list value.</returns>
Public Shared Function ForList(ParamArray values As Value()) As Value
CheckNotNull(values, "values")
Return New Value With {.ListValue = New ListValue With {.values_ = New Collections.RepeatedField(Of Value)(values)}}
End Function
''' <summary>
''' Convenience method to create a Value message with an initial struct value
''' </summary>
''' <remarks>The value provided is not cloned; the reference is copied directly.</remarks>
''' <returns>A newly-created Value message an initial struct value.</returns>
Public Shared Function ForStruct(value As Struct) As Value
CheckNotNull(value, "value")
Return New Value With {
.StructValue = value
}
End Function
End Class
End Namespace

File diff suppressed because it is too large Load Diff

@ -0,0 +1,40 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2008 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Namespace Google.Protobuf.WellKnownTypes
Public Partial Module WrappersReflection
''' <summary>
''' Field number for the single "value" field in all wrapper types.
''' </summary>
Friend Const WrapperValueFieldNumber As Integer = Int32Value.ValueFieldNumber
End Module
End Namespace

@ -0,0 +1,98 @@
#Region "Copyright notice and license"
' Protocol Buffers - Google's data interchange format
' Copyright 2008 Google Inc. All rights reserved.
' https://developers.google.com/protocol-buffers/
'
' Redistribution and use in source and binary forms, with or without
' modification, are permitted provided that the following conditions are
' met:
'
' * Redistributions of source code must retain the above copyright
' notice, this list of conditions and the following disclaimer.
' * Redistributions in binary form must reproduce the above
' copyright notice, this list of conditions and the following disclaimer
' in the documentation and/or other materials provided with the
' distribution.
' * Neither the name of Google Inc. nor the names of its
' contributors may be used to endorse or promote products derived from
' this software without specific prior written permission.
'
' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
' "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
' LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
' A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
' OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
' SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
' LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
' DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
' THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
' OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#End Region
Namespace Google.Protobuf
''' <summary>
''' This class is used internally by the Protocol Buffer Library and generated
''' message implementations. It is public only for the sake of those generated
''' messages. Others should not use this class directly.
''' <para>
''' This class contains constants and helper functions useful for dealing with
''' the Protocol Buffer wire format.
''' </para>
''' </summary>
Public Module WireFormat
''' <summary>
''' Wire types within protobuf encoding.
''' </summary>
Public Enum WireType As UInteger
''' <summary>
''' Variable-length integer.
''' </summary>
Varint = 0
''' <summary>
''' A fixed-length 64-bit value.
''' </summary>
Fixed64 = 1
''' <summary>
''' A length-delimited value, i.e. a length followed by that many bytes of data.
''' </summary>
LengthDelimited = 2
''' <summary>
''' A "start group" value - not supported by this implementation.
''' </summary>
StartGroup = 3
''' <summary>
''' An "end group" value - not supported by this implementation.
''' </summary>
EndGroup = 4
''' <summary>
''' A fixed-length 32-bit value.
''' </summary>
Fixed32 = 5
End Enum
Private Const TagTypeBits As Integer = 3
Private Const TagTypeMask As UInteger = (1 << TagTypeBits) - 1
''' <summary>
''' Given a tag value, determines the wire type (lower 3 bits).
''' </summary>
Public Function GetTagWireType(tag As UInteger) As WireType
Return tag And TagTypeMask
End Function
''' <summary>
''' Given a tag value, determines the field number (the upper 29 bits).
''' </summary>
Public Function GetTagFieldNumber(tag As UInteger) As Integer
Return CInt(tag) >> TagTypeBits
End Function
''' <summary>
''' Makes a tag value given a field number and wire type.
''' </summary>
Public Function MakeTag(fieldNumber As Integer, wireType As WireType) As UInteger
Return CUInt(fieldNumber << TagTypeBits) Or wireType
End Function
End Module
End Namespace
Loading…
Cancel
Save