Mercurial > hg > ucis.core
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 } |