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 }