1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 2000,2008 Oracle.  All rights reserved.
5 *
6 * $Id: TupleOutput.java,v 12.7 2008/01/08 20:58:36 bostic Exp $
7 */
8
9package com.sleepycat.bind.tuple;
10
11import java.math.BigInteger;
12
13import com.sleepycat.util.FastOutputStream;
14import com.sleepycat.util.PackedInteger;
15import com.sleepycat.util.UtfOps;
16
17/**
18 * An <code>OutputStream</code> with <code>DataOutput</code>-like methods for
19 * writing tuple fields.  It is used by <code>TupleBinding</code>.
20 *
21 * <p>This class has many methods that have the same signatures as methods in
22 * the {@link java.io.DataOutput} interface.  The reason this class does not
23 * implement {@link java.io.DataOutput} is because it would break the interface
24 * contract for those methods because of data format differences.</p>
25 *
26 * <p>Signed numbers are stored in the buffer in MSB (most significant byte
27 * first) order with their sign bit (high-order bit) inverted to cause negative
28 * numbers to be sorted first when comparing values as unsigned byte arrays,
29 * as done in a database.  Unsigned numbers, including characters, are stored
30 * in MSB order with no change to their sign bit.  BigInteger values are stored
31 * with a preceding length having the same sign as the value.</p>
32 *
33 * <p>Strings and character arrays are stored either as a fixed length array of
34 * unicode characters, where the length must be known by the application, or as
35 * a null-terminated UTF byte array.</p>
36 * <ul>
37 * <li>Null strings are UTF encoded as { 0xFF }, which is not allowed in a
38 * standard UTF encoding.  This allows null strings, as distinct from empty or
39 * zero length strings, to be represented in a tuple.  Using the default
40 * comparator, null strings will be ordered last.</li>
41 * <li>Zero (0x0000) character values are UTF encoded as non-zero values, and
42 * therefore embedded zeros in the string are supported.  The sequence { 0xC0,
43 * 0x80 } is used to encode a zero character.  This UTF encoding is the same
44 * one used by native Java UTF libraries.  However, this encoding of zero does
45 * impact the lexicographical ordering, and zeros will not be sorted first (the
46 * natural order) or last.  For all character values other than zero, the
47 * default UTF byte ordering is the same as the Unicode lexicographical
48 * character ordering.</li>
49 * </ul>
50 *
51 * <p>Floats and doubles are stored using two different representations: sorted
52 * representation and integer-bit (IEEE 754) representation.  If you use
53 * negative floating point numbers in a key, you should use sorted
54 * representation; alternatively you may use integer-bit representation but you
55 * will need to implement and configure a custom comparator to get correct
56 * numeric ordering for negative numbers.</p>
57 *
58 * <p>To use sorted representation use this set of methods:</p>
59 * <ul>
60 * <li>{@link TupleOutput#writeSortedFloat}</li>
61 * <li>{@link TupleInput#readSortedFloat}</li>
62 * <li>{@link TupleOutput#writeSortedDouble}</li>
63 * <li>{@link TupleInput#readSortedDouble}</li>
64 * </ul>
65 *
66 * <p>To use integer-bit representation use this set of methods:</p>
67 * <ul>
68 * <li>{@link TupleOutput#writeFloat}</li>
69 * <li>{@link TupleInput#readFloat}</li>
70 * <li>{@link TupleOutput#writeDouble}</li>
71 * <li>{@link TupleInput#readDouble}</li>
72 * </ul>
73 *
74 * @author Mark Hayes
75 */
76public class TupleOutput extends FastOutputStream {
77
78    /**
79     * We represent a null string as a single FF UTF character, which cannot
80     * occur in a UTF encoded string.
81     */
82    static final int NULL_STRING_UTF_VALUE = ((byte) 0xFF);
83
84    /**
85     * Creates a tuple output object for writing a byte array of tuple data.
86     */
87    public TupleOutput() {
88
89        super();
90    }
91
92    /**
93     * Creates a tuple output object for writing a byte array of tuple data,
94     * using a given buffer.  A new buffer will be allocated only if the number
95     * of bytes needed is greater than the length of this buffer.  A reference
96     * to the byte array will be kept by this object and therefore the byte
97     * array should not be modified while this object is in use.
98     *
99     * @param buffer is the byte array to use as the buffer.
100     */
101    public TupleOutput(byte[] buffer) {
102
103        super(buffer);
104    }
105
106    // --- begin DataOutput compatible methods ---
107
108    /**
109     * Writes the specified bytes to the buffer, converting each character to
110     * an unsigned byte value.
111     * Writes values that can be read using {@link TupleInput#readBytes}.
112     * Only characters with values below 0x100 may be written using this
113     * method, since the high-order 8 bits of all characters are discarded.
114     *
115     * @param val is the string containing the values to be written.
116     *
117     * @return this tuple output object.
118     *
119     * @throws NullPointerException if the val parameter is null.
120     */
121    public final TupleOutput writeBytes(String val) {
122
123        writeBytes(val.toCharArray());
124        return this;
125    }
126
127    /**
128     * Writes the specified characters to the buffer, converting each character
129     * to a two byte unsigned value.
130     * Writes values that can be read using {@link TupleInput#readChars}.
131     *
132     * @param val is the string containing the characters to be written.
133     *
134     * @return this tuple output object.
135     *
136     * @throws NullPointerException if the val parameter is null.
137     */
138    public final TupleOutput writeChars(String val) {
139
140        writeChars(val.toCharArray());
141        return this;
142    }
143
144    /**
145     * Writes the specified characters to the buffer, converting each character
146     * to UTF format, and adding a null terminator byte.
147     * Note that zero (0x0000) character values are encoded as non-zero values
148     * and a null String parameter is encoded as 0xFF.
149     * Writes values that can be read using {@link TupleInput#readString()}.
150     *
151     * @param val is the string containing the characters to be written.
152     *
153     * @return this tuple output object.
154     */
155    public final TupleOutput writeString(String val) {
156
157        if (val != null) {
158            writeString(val.toCharArray());
159        } else {
160            writeFast(NULL_STRING_UTF_VALUE);
161        }
162        writeFast(0);
163        return this;
164    }
165
166    /**
167     * Writes a char (two byte) unsigned value to the buffer.
168     * Writes values that can be read using {@link TupleInput#readChar}.
169     *
170     * @param val is the value to write to the buffer.
171     *
172     * @return this tuple output object.
173     */
174    public final TupleOutput writeChar(int val) {
175
176        writeFast((byte) (val >>> 8));
177        writeFast((byte) val);
178        return this;
179    }
180
181    /**
182     * Writes a boolean (one byte) unsigned value to the buffer, writing one
183     * if the value is true and zero if it is false.
184     * Writes values that can be read using {@link TupleInput#readBoolean}.
185     *
186     * @param val is the value to write to the buffer.
187     *
188     * @return this tuple output object.
189     */
190    public final TupleOutput writeBoolean(boolean val) {
191
192        writeFast(val ? (byte)1 : (byte)0);
193        return this;
194    }
195
196    /**
197     * Writes an signed byte (one byte) value to the buffer.
198     * Writes values that can be read using {@link TupleInput#readByte}.
199     *
200     * @param val is the value to write to the buffer.
201     *
202     * @return this tuple output object.
203     */
204    public final TupleOutput writeByte(int val) {
205
206        writeUnsignedByte(val ^ 0x80);
207        return this;
208    }
209
210    /**
211     * Writes an signed short (two byte) value to the buffer.
212     * Writes values that can be read using {@link TupleInput#readShort}.
213     *
214     * @param val is the value to write to the buffer.
215     *
216     * @return this tuple output object.
217     */
218    public final TupleOutput writeShort(int val) {
219
220        writeUnsignedShort(val ^ 0x8000);
221        return this;
222    }
223
224    /**
225     * Writes an signed int (four byte) value to the buffer.
226     * Writes values that can be read using {@link TupleInput#readInt}.
227     *
228     * @param val is the value to write to the buffer.
229     *
230     * @return this tuple output object.
231     */
232    public final TupleOutput writeInt(int val) {
233
234        writeUnsignedInt(val ^ 0x80000000);
235        return this;
236    }
237
238    /**
239     * Writes an signed long (eight byte) value to the buffer.
240     * Writes values that can be read using {@link TupleInput#readLong}.
241     *
242     * @param val is the value to write to the buffer.
243     *
244     * @return this tuple output object.
245     */
246    public final TupleOutput writeLong(long val) {
247
248        writeUnsignedLong(val ^ 0x8000000000000000L);
249        return this;
250    }
251
252    /**
253     * Writes an signed float (four byte) value to the buffer.
254     * Writes values that can be read using {@link TupleInput#readFloat}.
255     * <code>Float.floatToIntBits</code> is used to convert the signed float
256     * value.
257     *
258     * <p><em>Note:</em> This method produces byte array values that by default
259     * (without a custom comparator) do <em>not</em> sort correctly for
260     * negative values.  Only non-negative values are sorted correctly by
261     * default.  To sort all values correctly by default, use {@link
262     * #writeSortedFloat}.</p>
263     *
264     * @param val is the value to write to the buffer.
265     *
266     * @return this tuple output object.
267     */
268    public final TupleOutput writeFloat(float val) {
269
270        writeUnsignedInt(Float.floatToIntBits(val));
271        return this;
272    }
273
274    /**
275     * Writes an signed double (eight byte) value to the buffer.
276     * Writes values that can be read using {@link TupleInput#readDouble}.
277     * <code>Double.doubleToLongBits</code> is used to convert the signed
278     * double value.
279     *
280     * <p><em>Note:</em> This method produces byte array values that by default
281     * (without a custom comparator) do <em>not</em> sort correctly for
282     * negative values.  Only non-negative values are sorted correctly by
283     * default.  To sort all values correctly by default, use {@link
284     * #writeSortedDouble}.</p>
285     *
286     * @param val is the value to write to the buffer.
287     *
288     * @return this tuple output object.
289     */
290    public final TupleOutput writeDouble(double val) {
291
292        writeUnsignedLong(Double.doubleToLongBits(val));
293        return this;
294    }
295
296    /**
297     * Writes a signed float (four byte) value to the buffer, with support for
298     * correct default sorting of all values.
299     * Writes values that can be read using {@link TupleInput#readSortedFloat}.
300     *
301     * <p><code>Float.floatToIntBits</code> and the following bit manipulations
302     * are used to convert the signed float value to a representation that is
303     * sorted correctly by default.</p>
304     * <pre>
305     *  int intVal = Float.floatToIntBits(val);
306     *  intVal ^= (intVal &lt; 0) ? 0xffffffff : 0x80000000;
307     * </pre>
308     *
309     * @param val is the value to write to the buffer.
310     *
311     * @return this tuple output object.
312     */
313    public final TupleOutput writeSortedFloat(float val) {
314
315        int intVal = Float.floatToIntBits(val);
316        intVal ^= (intVal < 0) ? 0xffffffff : 0x80000000;
317        writeUnsignedInt(intVal);
318        return this;
319    }
320
321    /**
322     * Writes a signed double (eight byte) value to the buffer, with support
323     * for correct default sorting of all values.
324     * Writes values that can be read using {@link TupleInput#readSortedDouble}.
325     *
326     * <p><code>Float.doubleToLongBits</code> and the following bit
327     * manipulations are used to convert the signed double value to a
328     * representation that is sorted correctly by default.</p>
329     * <pre>
330     *  long longVal = Double.doubleToLongBits(val);
331     *  longVal ^= (longVal &lt; 0) ? 0xffffffffffffffffL : 0x8000000000000000L;
332     * </pre>
333     *
334     * @param val is the value to write to the buffer.
335     *
336     * @return this tuple output object.
337     */
338    public final TupleOutput writeSortedDouble(double val) {
339
340        long longVal = Double.doubleToLongBits(val);
341        longVal ^= (longVal < 0) ? 0xffffffffffffffffL : 0x8000000000000000L;
342        writeUnsignedLong(longVal);
343        return this;
344    }
345
346    // --- end DataOutput compatible methods ---
347
348    /**
349     * Writes the specified bytes to the buffer, converting each character to
350     * an unsigned byte value.
351     * Writes values that can be read using {@link TupleInput#readBytes}.
352     * Only characters with values below 0x100 may be written using this
353     * method, since the high-order 8 bits of all characters are discarded.
354     *
355     * @param chars is the array of values to be written.
356     *
357     * @return this tuple output object.
358     *
359     * @throws NullPointerException if the chars parameter is null.
360     */
361    public final TupleOutput writeBytes(char[] chars) {
362
363        for (int i = 0; i < chars.length; i++) {
364            writeFast((byte) chars[i]);
365        }
366        return this;
367    }
368
369    /**
370     * Writes the specified characters to the buffer, converting each character
371     * to a two byte unsigned value.
372     * Writes values that can be read using {@link TupleInput#readChars}.
373     *
374     * @param chars is the array of characters to be written.
375     *
376     * @return this tuple output object.
377     *
378     * @throws NullPointerException if the chars parameter is null.
379     */
380    public final TupleOutput writeChars(char[] chars) {
381
382        for (int i = 0; i < chars.length; i++) {
383            writeFast((byte) (chars[i] >>> 8));
384            writeFast((byte) chars[i]);
385        }
386        return this;
387    }
388
389    /**
390     * Writes the specified characters to the buffer, converting each character
391     * to UTF format.
392     * Note that zero (0x0000) character values are encoded as non-zero values.
393     * Writes values that can be read using {@link TupleInput#readString(int)}
394     * or {@link TupleInput#readString(char[])}.
395     *
396     * @param chars is the array of characters to be written.
397     *
398     * @return this tuple output object.
399     *
400     * @throws NullPointerException if the chars parameter is null.
401     */
402    public final TupleOutput writeString(char[] chars) {
403
404        if (chars.length == 0) return this;
405
406        int utfLength = UtfOps.getByteLength(chars);
407
408        makeSpace(utfLength);
409        UtfOps.charsToBytes(chars, 0, getBufferBytes(), getBufferLength(),
410                            chars.length);
411        addSize(utfLength);
412        return this;
413    }
414
415    /**
416     * Writes an unsigned byte (one byte) value to the buffer.
417     * Writes values that can be read using {@link
418     * TupleInput#readUnsignedByte}.
419     *
420     * @param val is the value to write to the buffer.
421     *
422     * @return this tuple output object.
423     */
424    public final TupleOutput writeUnsignedByte(int val) {
425
426        writeFast(val);
427        return this;
428    }
429
430    /**
431     * Writes an unsigned short (two byte) value to the buffer.
432     * Writes values that can be read using {@link
433     * TupleInput#readUnsignedShort}.
434     *
435     * @param val is the value to write to the buffer.
436     *
437     * @return this tuple output object.
438     */
439    public final TupleOutput writeUnsignedShort(int val) {
440
441        writeFast((byte) (val >>> 8));
442        writeFast((byte) val);
443        return this;
444    }
445
446    /**
447     * Writes an unsigned int (four byte) value to the buffer.
448     * Writes values that can be read using {@link
449     * TupleInput#readUnsignedInt}.
450     *
451     * @param val is the value to write to the buffer.
452     *
453     * @return this tuple output object.
454     */
455    public final TupleOutput writeUnsignedInt(long val) {
456
457        writeFast((byte) (val >>> 24));
458        writeFast((byte) (val >>> 16));
459        writeFast((byte) (val >>> 8));
460        writeFast((byte) val);
461        return this;
462    }
463
464    /**
465     * This method is private since an unsigned long cannot be treated as
466     * such in Java, nor converted to a BigInteger of the same value.
467     */
468    private final TupleOutput writeUnsignedLong(long val) {
469
470        writeFast((byte) (val >>> 56));
471        writeFast((byte) (val >>> 48));
472        writeFast((byte) (val >>> 40));
473        writeFast((byte) (val >>> 32));
474        writeFast((byte) (val >>> 24));
475        writeFast((byte) (val >>> 16));
476        writeFast((byte) (val >>> 8));
477        writeFast((byte) val);
478        return this;
479    }
480
481    /**
482     * Writes a packed integer.  Note that packed integers are not appropriate
483     * for sorted values (keys) unless a custom comparator is used.
484     *
485     * @see PackedInteger
486     */
487    public final void writePackedInt(int val) {
488
489        makeSpace(PackedInteger.MAX_LENGTH);
490
491        int oldLen = getBufferLength();
492        int newLen = PackedInteger.writeInt(getBufferBytes(), oldLen, val);
493
494        addSize(newLen - oldLen);
495    }
496
497    /**
498     * Writes a packed long integer.  Note that packed integers are not
499     * appropriate for sorted values (keys) unless a custom comparator is used.
500     *
501     * @see PackedInteger
502     */
503    public final void writePackedLong(long val) {
504
505        makeSpace(PackedInteger.MAX_LONG_LENGTH);
506
507        int oldLen = getBufferLength();
508        int newLen = PackedInteger.writeLong(getBufferBytes(), oldLen, val);
509
510        addSize(newLen - oldLen);
511    }
512
513    /**
514     * Writes a {@code BigInteger}.  Supported {@code BigInteger} values are
515     * limited to those with a byte array ({@link BigInteger#toByteArray})
516     * representation with a size of 0x7fff bytes or less.  The maximum {@code
517     * BigInteger} value is (2<sup>0x3fff7</sup> - 1) and the minimum value is
518     * (-2<sup>0x3fff7</sup>).
519     *
520     * <p>The byte format for a {@code BigInteger} value is:</p>
521     * <ul>
522     * <li>Byte 0 and 1: The length of the following bytes, negated if the
523     * {@code BigInteger} value is negative, and written as a sorted value as
524     * if {@link #writeShort} were called.</li>
525     * <li>Byte 2: The first byte of the {@link BigInteger#toByteArray} array,
526     * written as a sorted value as if {@link #writeByte} were called.</li>
527     * <li>Byte 3 to N: The second and remaining bytes, if any, of the {@link
528     * BigInteger#toByteArray} array, written without modification.</li>
529     * </ul>
530     * <p>This format provides correct default sorting when the default
531     * byte-by-byte comparison is used.</p>
532     *
533     * @throws NullPointerException if val is null.
534     *
535     * @throws IllegalArgumentException if the byte array representation of val
536     * is larger than 0x7fff bytes.
537     */
538    public final TupleOutput writeBigInteger(BigInteger val) {
539        byte[] a = val.toByteArray();
540        if (a.length > Short.MAX_VALUE) {
541            throw new IllegalArgumentException
542                ("BigInteger byte array is larger than 0x7fff bytes");
543        }
544        int firstByte = a[0];
545        writeShort((firstByte < 0) ? (- a.length) : a.length);
546        writeByte(firstByte);
547        writeFast(a, 1, a.length - 1);
548        return this;
549    }
550
551    /**
552     * Returns the byte length of a given {@code BigInteger} value.
553     *
554     * @see TupleOutput#writeBigInteger
555     */
556    public static int getBigIntegerByteLength(BigInteger val) {
557        return 2 /* length bytes */ +
558               (val.bitLength() + 1 /* sign bit */ + 7 /* round up */) / 8;
559    }
560}
561