001    /*
002     * Copyright (C) 2007 The Guava Authors
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package com.google.common.io;
018    
019    import com.google.common.annotations.Beta;
020    import com.google.common.base.Preconditions;
021    import com.google.common.primitives.Longs;
022    
023    import java.io.DataOutput;
024    import java.io.DataOutputStream;
025    import java.io.FilterOutputStream;
026    import java.io.IOException;
027    import java.io.OutputStream;
028    
029    /**
030     * An implementation of {@link DataOutput} that uses little-endian byte ordering
031     * for writing {@code char}, {@code short}, {@code int}, {@code float}, {@code
032     * double}, and {@code long} values.
033     * <p>
034     * <b>Note:</b> This class intentionally violates the specification of its
035     * supertype {@code DataOutput}, which explicitly requires big-endian byte
036     * order.
037     *
038     * @author chrisn@google.com (Chris Nokleberg)
039     * @author kbottner@google.com (Keith Bottner)
040     * @since 8
041     */
042    @Beta
043    public class LittleEndianDataOutputStream extends FilterOutputStream
044        implements DataOutput {
045    
046      /**
047       * Creates a {@code LittleEndianDataOutputStream} that wraps the given stream.
048       *
049       * @param out the stream to delegate to
050       */
051      public LittleEndianDataOutputStream(OutputStream out) {
052        super(new DataOutputStream(Preconditions.checkNotNull(out)));
053      }
054    
055      @Override public void write(byte[] b, int off, int len) throws IOException {
056        // Override slow FilterOutputStream impl
057        out.write(b, off, len);
058      }
059    
060      @Override public void writeBoolean(boolean v) throws IOException {
061        ((DataOutputStream) out).writeBoolean(v);
062      }
063    
064      @Override public void writeByte(int v) throws IOException {
065        ((DataOutputStream) out).writeByte(v);
066      }
067    
068      /**
069       * @deprecated The semantics of {@code writeBytes(String s)} are considered
070       *             dangerous. Please use {@link #writeUTF(String s)},
071       *             {@link #writeChars(String s)} or another write method instead.
072       */
073      @Deprecated
074      @Override public void writeBytes(String s) throws IOException {
075        ((DataOutputStream) out).writeBytes(s);
076      }
077    
078      /**
079       * Writes a char as specified by {@link DataOutputStream#writeChar(int)},
080       * except using little-endian byte order.
081       *
082       * @throws IOException if an I/O error occurs
083       */
084      @Override public void writeChar(int v) throws IOException {
085        writeShort(v);
086      }
087    
088      /**
089       * Writes a {@code String} as specified by
090       * {@link DataOutputStream#writeChars(String)}, except each character is
091       * written using little-endian byte order.
092       *
093       * @throws IOException if an I/O error occurs
094       */
095      @Override public void writeChars(String s) throws IOException {
096        for (int i = 0; i < s.length(); i++) {
097          writeChar(s.charAt(i));
098        }
099      }
100    
101      /**
102       * Writes a {@code double} as specified by
103       * {@link DataOutputStream#writeDouble(double)}, except using little-endian
104       * byte order.
105       *
106       * @throws IOException if an I/O error occurs
107       */
108      @Override public void writeDouble(double v) throws IOException {
109        writeLong(Double.doubleToLongBits(v));
110      }
111    
112      /**
113       * Writes a {@code float} as specified by
114       * {@link DataOutputStream#writeFloat(float)}, except using little-endian byte
115       * order.
116       *
117       * @throws IOException if an I/O error occurs
118       */
119      @Override public void writeFloat(float v) throws IOException {
120        writeInt(Float.floatToIntBits(v));
121      }
122    
123      /**
124       * Writes an {@code int} as specified by
125       * {@link DataOutputStream#writeInt(int)}, except using little-endian byte
126       * order.
127       *
128       * @throws IOException if an I/O error occurs
129       */
130      @Override public void writeInt(int v) throws IOException {
131        out.write(0xFF & v);
132        out.write(0xFF & (v >> 8));
133        out.write(0xFF & (v >> 16));
134        out.write(0xFF & (v >> 24));
135      }
136    
137      /**
138       * Writes a {@code long} as specified by
139       * {@link DataOutputStream#writeLong(long)}, except using little-endian byte
140       * order.
141       *
142       * @throws IOException if an I/O error occurs
143       */
144      @Override public void writeLong(long v) throws IOException {
145        byte[] bytes = Longs.toByteArray(Long.reverseBytes(v));
146        write(bytes, 0, bytes.length);
147      }
148    
149      /**
150       * Writes a {@code short} as specified by
151       * {@link DataOutputStream#writeShort(int)}, except using little-endian byte
152       * order.
153       *
154       * @throws IOException if an I/O error occurs
155       */
156      @Override public void writeShort(int v) throws IOException {
157        out.write(0xFF & v);
158        out.write(0xFF & (v >> 8));
159      }
160    
161      @Override public void writeUTF(String str) throws IOException {
162        ((DataOutputStream) out).writeUTF(str);
163      }
164    }