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    }