001 //Protocol Buffers - Google's data interchange format
002 //Copyright 2008 Google Inc.
003 //http://code.google.com/p/protobuf/
004 //
005 //Licensed under the Apache License, Version 2.0 (the "License");
006 //you may not use this file except in compliance with the License.
007 //You may obtain a copy of the License at
008 //
009 // http://www.apache.org/licenses/LICENSE-2.0
010 //
011 //Unless required by applicable law or agreed to in writing, software
012 //distributed under the License is distributed on an "AS IS" BASIS,
013 //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 //See the License for the specific language governing permissions and
015 //limitations under the License.
016 package org.fusesource.hawtbuf.proto;
017
018 import java.io.FilterOutputStream;
019 import java.io.IOException;
020 import java.io.OutputStream;
021
022 import org.fusesource.hawtbuf.Buffer;
023 import org.fusesource.hawtbuf.BufferOutputStream;
024
025 /**
026 * Encodes and writes protocol message fields.
027 *
028 * <p>
029 * This class contains two kinds of methods: methods that write specific
030 * protocol message constructs and field types (e.g. {@link #writeTag} and
031 * {@link #writeInt32}) and methods that write low-level values (e.g.
032 * {@link #writeRawVarint32} and {@link #writeRawBytes}). If you are writing
033 * encoded protocol messages, you should use the former methods, but if you are
034 * writing some other format of your own design, use the latter.
035 *
036 * <p>
037 * This class is totally unsynchronized.
038 *
039 * @author kneton@google.com Kenton Varda
040 */
041 public final class CodedOutputStream extends FilterOutputStream {
042
043 private BufferOutputStream bos;
044
045 public CodedOutputStream(OutputStream os) {
046 super(os);
047 if( os instanceof BufferOutputStream ) {
048 bos = (BufferOutputStream)os;
049 }
050 }
051
052 public CodedOutputStream(byte[] data) {
053 super(new BufferOutputStream(data));
054 }
055
056 public CodedOutputStream(Buffer data) {
057 super(new BufferOutputStream(data));
058 }
059
060 // -----------------------------------------------------------------
061
062 /** Write a {@code double} field, including tag, to the stream. */
063 public void writeDouble(int fieldNumber, double value) throws IOException {
064 writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
065 writeRawLittleEndian64(Double.doubleToRawLongBits(value));
066 }
067
068 /** Write a {@code float} field, including tag, to the stream. */
069 public void writeFloat(int fieldNumber, float value) throws IOException {
070 writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
071 writeRawLittleEndian32(Float.floatToRawIntBits(value));
072 }
073
074 /** Write a {@code uint64} field, including tag, to the stream. */
075 public void writeUInt64(int fieldNumber, long value) throws IOException {
076 writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
077 writeRawVarint64(value);
078 }
079
080 /** Write an {@code int64} field, including tag, to the stream. */
081 public void writeInt64(int fieldNumber, long value) throws IOException {
082 writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
083 writeRawVarint64(value);
084 }
085
086 /** Write an {@code int32} field, including tag, to the stream. */
087 public void writeInt32(int fieldNumber, int value) throws IOException {
088 writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
089 if (value >= 0) {
090 writeRawVarint32(value);
091 } else {
092 // Must sign-extend.
093 writeRawVarint64(value);
094 }
095 }
096
097 /** Write a {@code fixed64} field, including tag, to the stream. */
098 public void writeFixed64(int fieldNumber, long value) throws IOException {
099 writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
100 writeRawLittleEndian64(value);
101 }
102
103 /** Write a {@code fixed32} field, including tag, to the stream. */
104 public void writeFixed32(int fieldNumber, int value) throws IOException {
105 writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
106 writeRawLittleEndian32(value);
107 }
108
109 /** Write a {@code bool} field, including tag, to the stream. */
110 public void writeBool(int fieldNumber, boolean value) throws IOException {
111 writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
112 writeRawByte(value ? 1 : 0);
113 }
114
115 /** Write a {@code string} field, including tag, to the stream. */
116 public void writeString(int fieldNumber, String value) throws IOException {
117 writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
118 // Unfortunately there does not appear to be any way to tell Java to
119 // encode
120 // UTF-8 directly into our buffer, so we have to let it create its own
121 // byte
122 // array and then copy.
123 byte[] bytes = value.getBytes("UTF-8");
124 writeRawVarint32(bytes.length);
125 writeRawBytes(bytes);
126 }
127
128 /** Write a {@code bytes} field, including tag, to the stream. */
129 public void writeBytes(int fieldNumber, Buffer value) throws IOException {
130 writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
131 writeRawVarint32(value.length);
132 writeRawBytes(value.data, value.offset, value.length);
133 }
134
135 /** Write a {@code uint32} field, including tag, to the stream. */
136 public void writeUInt32(int fieldNumber, int value) throws IOException {
137 writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
138 writeRawVarint32(value);
139 }
140
141 /**
142 * Write an enum field, including tag, to the stream. Caller is responsible
143 * for converting the enum value to its numeric value.
144 */
145 public void writeEnum(int fieldNumber, int value) throws IOException {
146 writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
147 writeRawVarint32(value);
148 }
149
150 /** Write an {@code sfixed32} field, including tag, to the stream. */
151 public void writeSFixed32(int fieldNumber, int value) throws IOException {
152 writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
153 writeRawLittleEndian32(value);
154 }
155
156 /** Write an {@code sfixed64} field, including tag, to the stream. */
157 public void writeSFixed64(int fieldNumber, long value) throws IOException {
158 writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
159 writeRawLittleEndian64(value);
160 }
161
162 /** Write an {@code sint32} field, including tag, to the stream. */
163 public void writeSInt32(int fieldNumber, int value) throws IOException {
164 writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
165 writeRawVarint32(encodeZigZag32(value));
166 }
167
168 /** Write an {@code sint64} field, including tag, to the stream. */
169 public void writeSInt64(int fieldNumber, long value) throws IOException {
170 writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
171 writeRawVarint64(encodeZigZag64(value));
172 }
173
174 // =================================================================
175
176 /**
177 * Compute the number of bytes that would be needed to encode a {@code
178 * double} field, including tag.
179 */
180 public static int computeDoubleSize(int fieldNumber, double value) {
181 return computeTagSize(fieldNumber) + LITTLE_ENDIAN_64_SIZE;
182 }
183
184 /**
185 * Compute the number of bytes that would be needed to encode a {@code
186 * float} field, including tag.
187 */
188 public static int computeFloatSize(int fieldNumber, float value) {
189 return computeTagSize(fieldNumber) + LITTLE_ENDIAN_32_SIZE;
190 }
191
192 /**
193 * Compute the number of bytes that would be needed to encode a {@code
194 * uint64} field, including tag.
195 */
196 public static int computeUInt64Size(int fieldNumber, long value) {
197 return computeTagSize(fieldNumber) + computeRawVarint64Size(value);
198 }
199
200 /**
201 * Compute the number of bytes that would be needed to encode an {@code
202 * int64} field, including tag.
203 */
204 public static int computeInt64Size(int fieldNumber, long value) {
205 return computeTagSize(fieldNumber) + computeRawVarint64Size(value);
206 }
207
208 /**
209 * Compute the number of bytes that would be needed to encode an {@code
210 * int32} field, including tag.
211 */
212 public static int computeInt32Size(int fieldNumber, int value) {
213 if (value >= 0) {
214 return computeTagSize(fieldNumber) + computeRawVarint32Size(value);
215 } else {
216 // Must sign-extend.
217 return computeTagSize(fieldNumber) + 10;
218 }
219 }
220
221 /**
222 * Compute the number of bytes that would be needed to encode a {@code
223 * fixed64} field, including tag.
224 */
225 public static int computeFixed64Size(int fieldNumber, long value) {
226 return computeTagSize(fieldNumber) + LITTLE_ENDIAN_64_SIZE;
227 }
228
229 /**
230 * Compute the number of bytes that would be needed to encode a {@code
231 * fixed32} field, including tag.
232 */
233 public static int computeFixed32Size(int fieldNumber, int value) {
234 return computeTagSize(fieldNumber) + LITTLE_ENDIAN_32_SIZE;
235 }
236
237 /**
238 * Compute the number of bytes that would be needed to encode a {@code bool}
239 * field, including tag.
240 */
241 public static int computeBoolSize(int fieldNumber, boolean value) {
242 return computeTagSize(fieldNumber) + 1;
243 }
244
245 /**
246 * Compute the number of bytes that would be needed to encode a {@code
247 * string} field, including tag.
248 */
249 public static int computeStringSize(int fieldNumber, String value) {
250 try {
251 byte[] bytes = value.getBytes("UTF-8");
252 return computeTagSize(fieldNumber) + computeRawVarint32Size(bytes.length) + bytes.length;
253 } catch (java.io.UnsupportedEncodingException e) {
254 throw new RuntimeException("UTF-8 not supported.", e);
255 }
256 }
257
258 /**
259 * Compute the number of bytes that would be needed to encode a {@code
260 * bytes} field, including tag.
261 */
262 public static int computeBytesSize(int fieldNumber, Buffer value) {
263 return computeTagSize(fieldNumber) + computeRawVarint32Size(value.length) + value.length;
264 }
265
266 /**
267 * Compute the number of bytes that would be needed to encode a {@code
268 * uint32} field, including tag.
269 */
270 public static int computeUInt32Size(int fieldNumber, int value) {
271 return computeTagSize(fieldNumber) + computeRawVarint32Size(value);
272 }
273
274 /**
275 * Compute the number of bytes that would be needed to encode an enum field,
276 * including tag. Caller is responsible for converting the enum value to its
277 * numeric value.
278 */
279 public static int computeEnumSize(int fieldNumber, int value) {
280 return computeTagSize(fieldNumber) + computeRawVarint32Size(value);
281 }
282
283 /**
284 * Compute the number of bytes that would be needed to encode an {@code
285 * sfixed32} field, including tag.
286 */
287 public static int computeSFixed32Size(int fieldNumber, int value) {
288 return computeTagSize(fieldNumber) + LITTLE_ENDIAN_32_SIZE;
289 }
290
291 /**
292 * Compute the number of bytes that would be needed to encode an {@code
293 * sfixed64} field, including tag.
294 */
295 public static int computeSFixed64Size(int fieldNumber, long value) {
296 return computeTagSize(fieldNumber) + LITTLE_ENDIAN_64_SIZE;
297 }
298
299 /**
300 * Compute the number of bytes that would be needed to encode an {@code
301 * sint32} field, including tag.
302 */
303 public static int computeSInt32Size(int fieldNumber, int value) {
304 return computeTagSize(fieldNumber) + computeRawVarint32Size(encodeZigZag32(value));
305 }
306
307 /**
308 * Compute the number of bytes that would be needed to encode an {@code
309 * sint64} field, including tag.
310 */
311 public static int computeSInt64Size(int fieldNumber, long value) {
312 return computeTagSize(fieldNumber) + computeRawVarint64Size(encodeZigZag64(value));
313 }
314
315 /** Write a single byte. */
316 public void writeRawByte(byte value) throws IOException {
317 out.write(value);
318 }
319
320 /** Write a single byte, represented by an integer value. */
321 public void writeRawByte(int value) throws IOException {
322 writeRawByte((byte) value);
323 }
324
325 /** Write an array of bytes. */
326 public void writeRawBytes(byte[] value) throws IOException {
327 writeRawBytes(value, 0, value.length);
328 }
329
330 /** Write part of an array of bytes. */
331 public void writeRawBytes(byte[] value, int offset, int length) throws IOException {
332 out.write(value, offset, length);
333 }
334
335 public void writeRawBytes(Buffer data) throws IOException {
336 out.write(data.data, data.offset, data.length);
337 }
338
339 /** Encode and write a tag. */
340 public void writeTag(int fieldNumber, int wireType) throws IOException {
341 writeRawVarint32(WireFormat.makeTag(fieldNumber, wireType));
342 }
343
344 /** Compute the number of bytes that would be needed to encode a tag. */
345 public static int computeTagSize(int fieldNumber) {
346 return computeRawVarint32Size(WireFormat.makeTag(fieldNumber, 0));
347 }
348
349 /**
350 * Encode and write a varint. {@code value} is treated as unsigned, so it
351 * won't be sign-extended if negative.
352 */
353 public void writeRawVarint32(int value) throws IOException {
354 while (true) {
355 if ((value & ~0x7F) == 0) {
356 writeRawByte(value);
357 return;
358 } else {
359 writeRawByte((value & 0x7F) | 0x80);
360 value >>>= 7;
361 }
362 }
363 }
364
365 /**
366 * Compute the number of bytes that would be needed to encode a varint.
367 * {@code value} is treated as unsigned, so it won't be sign-extended if
368 * negative.
369 */
370 public static int computeRawVarint32Size(int value) {
371 if ((value & (0xffffffff << 7)) == 0)
372 return 1;
373 if ((value & (0xffffffff << 14)) == 0)
374 return 2;
375 if ((value & (0xffffffff << 21)) == 0)
376 return 3;
377 if ((value & (0xffffffff << 28)) == 0)
378 return 4;
379 return 5;
380 }
381
382 /** Encode and write a varint. */
383 public void writeRawVarint64(long value) throws IOException {
384 while (true) {
385 if ((value & ~0x7FL) == 0) {
386 writeRawByte((int) value);
387 return;
388 } else {
389 writeRawByte(((int) value & 0x7F) | 0x80);
390 value >>>= 7;
391 }
392 }
393 }
394
395 /** Compute the number of bytes that would be needed to encode a varint. */
396 public static int computeRawVarint64Size(long value) {
397 if ((value & (0xffffffffffffffffL << 7)) == 0)
398 return 1;
399 if ((value & (0xffffffffffffffffL << 14)) == 0)
400 return 2;
401 if ((value & (0xffffffffffffffffL << 21)) == 0)
402 return 3;
403 if ((value & (0xffffffffffffffffL << 28)) == 0)
404 return 4;
405 if ((value & (0xffffffffffffffffL << 35)) == 0)
406 return 5;
407 if ((value & (0xffffffffffffffffL << 42)) == 0)
408 return 6;
409 if ((value & (0xffffffffffffffffL << 49)) == 0)
410 return 7;
411 if ((value & (0xffffffffffffffffL << 56)) == 0)
412 return 8;
413 if ((value & (0xffffffffffffffffL << 63)) == 0)
414 return 9;
415 return 10;
416 }
417
418 /** Write a little-endian 32-bit integer. */
419 public void writeRawLittleEndian32(int value) throws IOException {
420 writeRawByte((value) & 0xFF);
421 writeRawByte((value >> 8) & 0xFF);
422 writeRawByte((value >> 16) & 0xFF);
423 writeRawByte((value >> 24) & 0xFF);
424 }
425
426 public static final int LITTLE_ENDIAN_32_SIZE = 4;
427
428 /** Write a little-endian 64-bit integer. */
429 public void writeRawLittleEndian64(long value) throws IOException {
430 writeRawByte((int) (value) & 0xFF);
431 writeRawByte((int) (value >> 8) & 0xFF);
432 writeRawByte((int) (value >> 16) & 0xFF);
433 writeRawByte((int) (value >> 24) & 0xFF);
434 writeRawByte((int) (value >> 32) & 0xFF);
435 writeRawByte((int) (value >> 40) & 0xFF);
436 writeRawByte((int) (value >> 48) & 0xFF);
437 writeRawByte((int) (value >> 56) & 0xFF);
438 }
439
440 public static final int LITTLE_ENDIAN_64_SIZE = 8;
441
442 /**
443 * Encode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers into
444 * values that can be efficiently encoded with varint. (Otherwise, negative
445 * values must be sign-extended to 64 bits to be varint encoded, thus always
446 * taking 10 bytes on the wire.)
447 *
448 * @param n
449 * A signed 32-bit integer.
450 * @return An unsigned 32-bit integer, stored in a signed int because Java
451 * has no explicit unsigned support.
452 */
453 public static int encodeZigZag32(int n) {
454 // Note: the right-shift must be arithmetic
455 return (n << 1) ^ (n >> 31);
456 }
457
458 /**
459 * Encode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers into
460 * values that can be efficiently encoded with varint. (Otherwise, negative
461 * values must be sign-extended to 64 bits to be varint encoded, thus always
462 * taking 10 bytes on the wire.)
463 *
464 * @param n
465 * A signed 64-bit integer.
466 * @return An unsigned 64-bit integer, stored in a signed int because Java
467 * has no explicit unsigned support.
468 */
469 public static long encodeZigZag64(long n) {
470 // Note: the right-shift must be arithmetic
471 return (n << 1) ^ (n >> 63);
472 }
473
474 public void checkNoSpaceLeft() {
475 }
476
477 public Buffer getNextBuffer(int size) throws IOException {
478 if( bos==null ) {
479 return null;
480 }
481 return bos.getNextBuffer(size);
482 }
483
484 }