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