View Javadoc
1   /*
2    * Copyright (C) 2007 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5    * in compliance with the License. You may obtain a copy of the License at
6    *
7    * http://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software distributed under the License
10   * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11   * or implied. See the License for the specific language governing permissions and limitations under
12   * the License.
13   */
14  
15  package com.google.common.io;
16  
17  import com.google.common.annotations.Beta;
18  import com.google.common.annotations.GwtIncompatible;
19  import com.google.common.base.Preconditions;
20  import com.google.common.primitives.Longs;
21  import java.io.DataOutput;
22  import java.io.DataOutputStream;
23  import java.io.FilterOutputStream;
24  import java.io.IOException;
25  import java.io.OutputStream;
26  
27  /**
28   * An implementation of {@link DataOutput} that uses little-endian byte ordering for writing
29   * {@code char}, {@code short}, {@code int}, {@code float}, {@code double}, and {@code long} values.
30   *
31   * <p><b>Note:</b> This class intentionally violates the specification of its supertype
32   * {@code DataOutput}, which explicitly requires big-endian byte order.
33   *
34   * @author Chris Nokleberg
35   * @author Keith Bottner
36   * @since 8.0
37   */
38  @Beta
39  @GwtIncompatible
40  public final class LittleEndianDataOutputStream extends FilterOutputStream implements DataOutput {
41  
42    /**
43     * Creates a {@code LittleEndianDataOutputStream} that wraps the given stream.
44     *
45     * @param out the stream to delegate to
46     */
47    public LittleEndianDataOutputStream(OutputStream out) {
48      super(new DataOutputStream(Preconditions.checkNotNull(out)));
49    }
50  
51    @Override
52    public void write(byte[] b, int off, int len) throws IOException {
53      // Override slow FilterOutputStream impl
54      out.write(b, off, len);
55    }
56  
57    @Override
58    public void writeBoolean(boolean v) throws IOException {
59      ((DataOutputStream) out).writeBoolean(v);
60    }
61  
62    @Override
63    public void writeByte(int v) throws IOException {
64      ((DataOutputStream) out).writeByte(v);
65    }
66  
67    /**
68     * @deprecated The semantics of {@code writeBytes(String s)} are considered dangerous. Please use
69     *     {@link #writeUTF(String s)}, {@link #writeChars(String s)} or another write method instead.
70     */
71    @Deprecated
72    @Override
73    public void writeBytes(String s) throws IOException {
74      ((DataOutputStream) out).writeBytes(s);
75    }
76  
77    /**
78     * Writes a char as specified by {@link DataOutputStream#writeChar(int)}, except using
79     * little-endian byte order.
80     *
81     * @throws IOException if an I/O error occurs
82     */
83    @Override
84    public void writeChar(int v) throws IOException {
85      writeShort(v);
86    }
87  
88    /**
89     * Writes a {@code String} as specified by {@link DataOutputStream#writeChars(String)}, except
90     * each character is written using little-endian byte order.
91     *
92     * @throws IOException if an I/O error occurs
93     */
94    @Override
95    public void writeChars(String s) throws IOException {
96      for (int i = 0; i < s.length(); i++) {
97        writeChar(s.charAt(i));
98      }
99    }
100 
101   /**
102    * Writes a {@code double} as specified by {@link DataOutputStream#writeDouble(double)}, except
103    * using little-endian byte order.
104    *
105    * @throws IOException if an I/O error occurs
106    */
107   @Override
108   public void writeDouble(double v) throws IOException {
109     writeLong(Double.doubleToLongBits(v));
110   }
111 
112   /**
113    * Writes a {@code float} as specified by {@link DataOutputStream#writeFloat(float)}, except using
114    * little-endian byte order.
115    *
116    * @throws IOException if an I/O error occurs
117    */
118   @Override
119   public void writeFloat(float v) throws IOException {
120     writeInt(Float.floatToIntBits(v));
121   }
122 
123   /**
124    * Writes an {@code int} as specified by {@link DataOutputStream#writeInt(int)}, except using
125    * little-endian byte order.
126    *
127    * @throws IOException if an I/O error occurs
128    */
129   @Override
130   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 {@link DataOutputStream#writeLong(long)}, except using
139    * little-endian byte order.
140    *
141    * @throws IOException if an I/O error occurs
142    */
143   @Override
144   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 {@link DataOutputStream#writeShort(int)}, except using
151    * little-endian byte order.
152    *
153    * @throws IOException if an I/O error occurs
154    */
155   @Override
156   public void writeShort(int v) throws IOException {
157     out.write(0xFF & v);
158     out.write(0xFF & (v >> 8));
159   }
160 
161   @Override
162   public void writeUTF(String str) throws IOException {
163     ((DataOutputStream) out).writeUTF(str);
164   }
165 
166   // Overriding close() because FilterOutputStream's close() method pre-JDK8 has bad behavior:
167   // it silently ignores any exception thrown by flush(). Instead, just close the delegate stream.
168   // It should flush itself if necessary.
169   @Override
170   public void close() throws IOException {
171     out.close();
172   }
173 }