blob: 22346460d1c20e2afa3c88e3a70a2b0898511c7e [file] [log] [blame]
Jon Skeet0aac0e42009-09-09 18:48:02 +01001#region Copyright notice and license
Jon Skeet60c059b2008-10-23 21:17:56 +01002// Protocol Buffers - Google's data interchange format
3// Copyright 2008 Google Inc. All rights reserved.
4// http://github.com/jskeet/dotnet-protobufs/
5// Original C++/Java/Python code:
Jon Skeet68036862008-10-22 13:30:34 +01006// http://code.google.com/p/protobuf/
7//
Jon Skeet60c059b2008-10-23 21:17:56 +01008// Redistribution and use in source and binary forms, with or without
9// modification, are permitted provided that the following conditions are
10// met:
Jon Skeet68036862008-10-22 13:30:34 +010011//
Jon Skeet60c059b2008-10-23 21:17:56 +010012// * Redistributions of source code must retain the above copyright
13// notice, this list of conditions and the following disclaimer.
14// * Redistributions in binary form must reproduce the above
15// copyright notice, this list of conditions and the following disclaimer
16// in the documentation and/or other materials provided with the
17// distribution.
18// * Neither the name of Google Inc. nor the names of its
19// contributors may be used to endorse or promote products derived from
20// this software without specific prior written permission.
Jon Skeet68036862008-10-22 13:30:34 +010021//
Jon Skeet60c059b2008-10-23 21:17:56 +010022// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Jon Skeet0aac0e42009-09-09 18:48:02 +010033#endregion
34
Jon Skeet68036862008-10-22 13:30:34 +010035using System;
Jon Skeet68036862008-10-22 13:30:34 +010036using Google.ProtocolBuffers.Descriptors;
Jon Skeet0aac0e42009-09-09 18:48:02 +010037
Jon Skeet68036862008-10-22 13:30:34 +010038namespace Google.ProtocolBuffers {
39
40 /// <summary>
41 /// This class is used internally by the Protocol Buffer Library and generated
42 /// message implementations. It is public only for the sake of those generated
43 /// messages. Others should not use this class directly.
44 /// <para>
45 /// This class contains constants and helper functions useful for dealing with
46 /// the Protocol Buffer wire format.
47 /// </para>
48 /// </summary>
49 public static class WireFormat {
Jon Skeet25a28582009-02-18 16:06:22 +000050
51#region Fixed sizes.
52 // TODO(jonskeet): Move these somewhere else. They're messy. Consider making FieldType a smarter kind of enum
53 internal const int Fixed32Size = 4;
54 internal const int Fixed64Size = 8;
55 internal const int SFixed32Size = 4;
56 internal const int SFixed64Size = 8;
57 internal const int FloatSize = 4;
58 internal const int DoubleSize = 8;
59 internal const int BoolSize = 1;
60#endregion
61
Jon Skeetd6dd0a42009-06-05 22:00:05 +010062 [CLSCompliant(false)]
Jon Skeet68036862008-10-22 13:30:34 +010063 public enum WireType : uint {
64 Varint = 0,
65 Fixed64 = 1,
66 LengthDelimited = 2,
67 StartGroup = 3,
68 EndGroup = 4,
69 Fixed32 = 5
70 }
71
72 internal static class MessageSetField {
73 internal const int Item = 1;
74 internal const int TypeID = 2;
75 internal const int Message = 3;
76 }
77
78 internal static class MessageSetTag {
79 internal static readonly uint ItemStart = MakeTag(MessageSetField.Item, WireType.StartGroup);
80 internal static readonly uint ItemEnd = MakeTag(MessageSetField.Item, WireType.EndGroup);
81 internal static readonly uint TypeID = MakeTag(MessageSetField.TypeID, WireType.Varint);
82 internal static readonly uint Message = MakeTag(MessageSetField.Message, WireType.LengthDelimited);
83 }
84
85 private const int TagTypeBits = 3;
86 private const uint TagTypeMask = (1 << TagTypeBits) - 1;
87
88 /// <summary>
89 /// Given a tag value, determines the wire type (lower 3 bits).
90 /// </summary>
Jon Skeetd6dd0a42009-06-05 22:00:05 +010091 [CLSCompliant(false)]
Jon Skeet68036862008-10-22 13:30:34 +010092 public static WireType GetTagWireType(uint tag) {
93 return (WireType) (tag & TagTypeMask);
94 }
95
Jon Skeetd6dd0a42009-06-05 22:00:05 +010096 [CLSCompliant(false)]
Jon Skeet7de1aef2009-03-05 14:23:17 +000097 public static bool IsEndGroupTag(uint tag) {
98 return (WireType)(tag & TagTypeMask) == WireType.EndGroup;
99 }
100
Jon Skeet68036862008-10-22 13:30:34 +0100101 /// <summary>
102 /// Given a tag value, determines the field number (the upper 29 bits).
103 /// </summary>
Jon Skeetd6dd0a42009-06-05 22:00:05 +0100104 [CLSCompliant(false)]
Jon Skeet68036862008-10-22 13:30:34 +0100105 public static int GetTagFieldNumber(uint tag) {
106 return (int) tag >> TagTypeBits;
107 }
108
109 /// <summary>
110 /// Makes a tag value given a field number and wire type.
111 /// TODO(jonskeet): Should we just have a Tag structure?
112 /// </summary>
Jon Skeetd6dd0a42009-06-05 22:00:05 +0100113 [CLSCompliant(false)]
Jon Skeet68036862008-10-22 13:30:34 +0100114 public static uint MakeTag(int fieldNumber, WireType wireType) {
115 return (uint) (fieldNumber << TagTypeBits) | (uint) wireType;
116 }
117
Jon Skeetd6dd0a42009-06-05 22:00:05 +0100118 [CLSCompliant(false)]
Jon Skeet25a28582009-02-18 16:06:22 +0000119 public static uint MakeTag(FieldDescriptor field) {
120 return MakeTag(field.FieldNumber, GetWireType(field));
121 }
122
123 /// <summary>
124 /// Returns the wire type for the given field descriptor. This differs
125 /// from GetWireType(FieldType) for packed repeated fields.
126 /// </summary>
127 internal static WireType GetWireType(FieldDescriptor descriptor) {
128 return descriptor.IsPacked ? WireType.LengthDelimited : GetWireType(descriptor.FieldType);
129 }
130
Jon Skeet68036862008-10-22 13:30:34 +0100131 /// <summary>
132 /// Converts a field type to its wire type. Done with a switch for the sake
133 /// of speed - this is significantly faster than a dictionary lookup.
134 /// </summary>
Jon Skeetd6dd0a42009-06-05 22:00:05 +0100135 [CLSCompliant(false)]
Jon Skeet68036862008-10-22 13:30:34 +0100136 public static WireType GetWireType(FieldType fieldType) {
137 switch (fieldType) {
138 case FieldType.Double:
139 return WireType.Fixed64;
140 case FieldType.Float:
141 return WireType.Fixed32;
142 case FieldType.Int64:
143 case FieldType.UInt64:
144 case FieldType.Int32:
145 return WireType.Varint;
146 case FieldType.Fixed64:
147 return WireType.Fixed64;
148 case FieldType.Fixed32:
149 return WireType.Fixed32;
150 case FieldType.Bool:
151 return WireType.Varint;
152 case FieldType.String:
153 return WireType.LengthDelimited;
154 case FieldType.Group:
155 return WireType.StartGroup;
156 case FieldType.Message:
157 case FieldType.Bytes:
158 return WireType.LengthDelimited;
159 case FieldType.UInt32:
160 return WireType.Varint;
161 case FieldType.SFixed32:
162 return WireType.Fixed32;
163 case FieldType.SFixed64:
164 return WireType.Fixed64;
165 case FieldType.SInt32:
166 case FieldType.SInt64:
167 case FieldType.Enum:
168 return WireType.Varint;
169 default:
170 throw new ArgumentOutOfRangeException("No such field type");
171 }
172 }
173 }
174}