comparison ProtocolBuffers.cs @ 11:2e0ff842aa4a

Added Protocol Buffers encoding/decoding code
author Ivo Smits <Ivo@UCIS.nl>
date Mon, 04 Feb 2013 22:47:01 +0100
parents
children 5d9a7186c9f7
comparison
equal deleted inserted replaced
10:7269e91c6e26 11:2e0ff842aa4a
1 using System;
2 using System.IO;
3 using System.Text;
4
5 namespace UCIS.ProtocolBuffers {
6 public interface IPBReader {
7 void Reset();
8 Boolean NextField();
9 int FieldNumber { get; }
10 int WireType { get; }
11 Int64 GetVarint();
12 Int64 GetFixed64();
13 Byte[] GetBytes();
14 String GetString();
15 IPBReader GetMessageReader();
16 Int32 GetFixed32();
17 }
18 public interface IPBWriter {
19 void WriteVarint(int fieldNumber, Int64 value);
20 void WriteFixed64(int fieldNumber, Int64 value);
21 void WriteBytes(int fieldNumber, Byte[] bytes);
22 void WriteBytes(int fieldNumber, Byte[] bytes, int offset, int count);
23 void WriteFixed32(int fieldNumber, Int32 value);
24 }
25 public interface IPBMessage {
26 void Decode(IPBReader r);
27 void Encode(IPBWriter w);
28 }
29 public class ArrayPBReader : IPBReader {
30 Byte[] buffer;
31 int offset, length, index;
32 int currentField;
33 Boolean hasCurrentField;
34 int currentFieldLength;
35
36 public ArrayPBReader(Byte[] buffer) : this(buffer, 0, buffer.Length) { }
37 public ArrayPBReader(Byte[] buffer, int offset, int length) {
38 this.buffer = buffer;
39 this.offset = offset;
40 this.length = length;
41 Reset();
42 }
43
44 public void Reset() {
45 index = 0;
46 hasCurrentField = false;
47 }
48
49 public bool NextField() {
50 if (hasCurrentField) {
51 index += currentFieldLength;
52 hasCurrentField = false;
53 }
54 if (index >= length) return false;
55 index += ReadVarIntTo(out currentField);
56 int dummy;
57 switch (WireType) {
58 case 0: currentFieldLength = ReadVarIntTo(out dummy); ; break; //Varint
59 case 1: currentFieldLength = 8; break; //64bit
60 case 2: index += ReadVarIntTo(out currentFieldLength); break; //Bytes
61 case 5: currentFieldLength = 4; break; //32bit
62 default: throw new InvalidDataException();
63 }
64 if (index + currentFieldLength > length) throw new InvalidDataException();
65 hasCurrentField = true;
66 return true;
67 }
68
69 private int ReadVarIntTo(out int v) {
70 v = 0;
71 int h = 0;
72 int b = 0x80;
73 int l = 0;
74 while ((b & 0x80) != 0) {
75 b = buffer[offset + index + l];
76 v |= (b & 0x7F) << h;
77 h += 7;
78 l++;
79 }
80 return l;
81 }
82
83 public int FieldNumber { get { return (int)((UInt32)currentField >> 3); } }
84 public int WireType { get { return currentField & 7; } }
85
86 public long GetVarint() {
87 if (!hasCurrentField || WireType != 0) throw new InvalidOperationException();
88 int v;
89 ReadVarIntTo(out v);
90 return v;
91 }
92
93 public long GetFixed64() {
94 if (!hasCurrentField || WireType != 1) throw new InvalidOperationException();
95 int i = offset + index;
96 return ((long)buffer[i + 0] << 0) | ((long)buffer[i + 1] << 8) | ((long)buffer[i + 2] << 16) | ((long)buffer[i + 3] << 24) |
97 ((long)buffer[i + 4] << 32) | ((long)buffer[i + 5] << 40) | ((long)buffer[i + 6] << 48) | ((long)buffer[i + 7] << 56);
98 }
99
100 public byte[] GetBytes() {
101 if (!hasCurrentField || WireType != 2) throw new InvalidOperationException();
102 Byte[] bytes = new Byte[currentFieldLength];
103 Buffer.BlockCopy(buffer, offset + index, bytes, 0, currentFieldLength);
104 return bytes;
105 }
106
107 public string GetString() {
108 if (!hasCurrentField || WireType != 2) throw new InvalidOperationException();
109 return Encoding.UTF8.GetString(buffer, offset + index, currentFieldLength);
110 }
111
112 public IPBReader GetMessageReader() {
113 if (!hasCurrentField || WireType != 2) throw new InvalidOperationException();
114 return new ArrayPBReader(buffer, offset + index, currentFieldLength);
115 }
116
117 public int GetFixed32() {
118 if (!hasCurrentField || WireType != 5) throw new InvalidOperationException();
119 int i = offset + index;
120 return ((int)buffer[i + 0] << 0) | ((int)buffer[i + 1] << 8) | ((int)buffer[i + 2] << 16) | ((int)buffer[i + 3] << 24);
121 }
122 }
123 public class StreamPBWriter : IPBWriter {
124 Stream stream;
125
126 public StreamPBWriter(Stream stream) {
127 this.stream = stream;
128 }
129
130 public static Byte[] Encode(IPBMessage message) {
131 using (MemoryStream ms = new MemoryStream()) {
132 message.Encode(new StreamPBWriter(ms));
133 return ms.ToArray();
134 }
135 }
136
137 public static int EncodeToStreamBuffered(Stream stream, IPBMessage message) {
138 using (MemoryStream ms = new MemoryStream()) {
139 message.Encode(new StreamPBWriter(ms));
140 ms.WriteTo(stream);
141 return (int)ms.Length;
142 }
143 }
144
145 private void WriteVarint(long value) {
146 while ((value & ~0x7fL) != 0) {
147 stream.WriteByte((Byte)(0x80 | value));
148 value >>= 7;
149 }
150 stream.WriteByte((Byte)value);
151 }
152 private void WriteTag(int fieldNumber, int wireType) {
153 WriteVarint((fieldNumber << 3) | wireType);
154 }
155
156 public void WriteVarint(int fieldNumber, long value) {
157 WriteTag(fieldNumber, 0);
158 WriteVarint(value);
159 }
160
161 public void WriteFixed64(int fieldNumber, long value) {
162 WriteTag(fieldNumber, 1);
163 for (int i = 0; i < 8; i++) {
164 stream.WriteByte((Byte)value);
165 value >>= 8;
166 }
167 }
168
169 public void WriteBytes(int fieldNumber, byte[] bytes) {
170 WriteBytes(fieldNumber, bytes, 0, bytes.Length);
171 }
172
173 public void WriteBytes(int fieldNumber, byte[] bytes, int offset, int count) {
174 WriteTag(fieldNumber, 2);
175 WriteVarint(count);
176 stream.Write(bytes, offset, count);
177 }
178
179 public void WriteFixed32(int fieldNumber, int value) {
180 WriteTag(fieldNumber, 5);
181 for (int i = 0; i < 4; i++) {
182 stream.WriteByte((Byte)value);
183 value >>= 8;
184 }
185 }
186 }
187 }