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.Beta; 018import com.google.common.annotations.GwtIncompatible; 019import com.google.common.base.Preconditions; 020import com.google.common.primitives.Longs; 021import java.io.DataOutput; 022import java.io.DataOutputStream; 023import java.io.FilterOutputStream; 024import java.io.IOException; 025import java.io.OutputStream; 026 027/** 028 * An implementation of {@link DataOutput} that uses little-endian byte ordering for writing {@code 029 * char}, {@code short}, {@code int}, {@code float}, {@code double}, and {@code long} values. 030 * 031 * <p><b>Note:</b> This class intentionally violates the specification of its supertype {@code 032 * DataOutput}, which explicitly requires big-endian byte order. 033 * 034 * @author Chris Nokleberg 035 * @author Keith Bottner 036 * @since 8.0 037 */ 038@Beta 039@GwtIncompatible 040@ElementTypesAreNonnullByDefault 041public final class LittleEndianDataOutputStream extends FilterOutputStream implements DataOutput { 042 043 /** 044 * Creates a {@code LittleEndianDataOutputStream} that wraps the given stream. 045 * 046 * @param out the stream to delegate to 047 */ 048 public LittleEndianDataOutputStream(OutputStream out) { 049 super(new DataOutputStream(Preconditions.checkNotNull(out))); 050 } 051 052 @Override 053 public void write(byte[] b, int off, int len) throws IOException { 054 // Override slow FilterOutputStream impl 055 out.write(b, off, len); 056 } 057 058 @Override 059 public void writeBoolean(boolean v) throws IOException { 060 ((DataOutputStream) out).writeBoolean(v); 061 } 062 063 @Override 064 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 dangerous. Please use 070 * {@link #writeUTF(String s)}, {@link #writeChars(String s)} or another write method instead. 071 */ 072 @Deprecated 073 @Override 074 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)}, except using 080 * little-endian byte order. 081 * 082 * @throws IOException if an I/O error occurs 083 */ 084 @Override 085 public void writeChar(int v) throws IOException { 086 writeShort(v); 087 } 088 089 /** 090 * Writes a {@code String} as specified by {@link DataOutputStream#writeChars(String)}, except 091 * each character is written using little-endian byte order. 092 * 093 * @throws IOException if an I/O error occurs 094 */ 095 @Override 096 public void writeChars(String s) throws IOException { 097 for (int i = 0; i < s.length(); i++) { 098 writeChar(s.charAt(i)); 099 } 100 } 101 102 /** 103 * Writes a {@code double} as specified by {@link DataOutputStream#writeDouble(double)}, except 104 * using little-endian byte order. 105 * 106 * @throws IOException if an I/O error occurs 107 */ 108 @Override 109 public void writeDouble(double v) throws IOException { 110 writeLong(Double.doubleToLongBits(v)); 111 } 112 113 /** 114 * Writes a {@code float} as specified by {@link DataOutputStream#writeFloat(float)}, except using 115 * little-endian byte order. 116 * 117 * @throws IOException if an I/O error occurs 118 */ 119 @Override 120 public void writeFloat(float v) throws IOException { 121 writeInt(Float.floatToIntBits(v)); 122 } 123 124 /** 125 * Writes an {@code int} as specified by {@link DataOutputStream#writeInt(int)}, except using 126 * little-endian byte order. 127 * 128 * @throws IOException if an I/O error occurs 129 */ 130 @Override 131 public void writeInt(int v) throws IOException { 132 out.write(0xFF & v); 133 out.write(0xFF & (v >> 8)); 134 out.write(0xFF & (v >> 16)); 135 out.write(0xFF & (v >> 24)); 136 } 137 138 /** 139 * Writes a {@code long} as specified by {@link DataOutputStream#writeLong(long)}, except using 140 * little-endian byte order. 141 * 142 * @throws IOException if an I/O error occurs 143 */ 144 @Override 145 public void writeLong(long v) throws IOException { 146 byte[] bytes = Longs.toByteArray(Long.reverseBytes(v)); 147 write(bytes, 0, bytes.length); 148 } 149 150 /** 151 * Writes a {@code short} as specified by {@link DataOutputStream#writeShort(int)}, except using 152 * little-endian byte order. 153 * 154 * @throws IOException if an I/O error occurs 155 */ 156 @Override 157 public void writeShort(int v) throws IOException { 158 out.write(0xFF & v); 159 out.write(0xFF & (v >> 8)); 160 } 161 162 @Override 163 public void writeUTF(String str) throws IOException { 164 ((DataOutputStream) out).writeUTF(str); 165 } 166 167 // Overriding close() because FilterOutputStream's close() method pre-JDK8 has bad behavior: 168 // it silently ignores any exception thrown by flush(). Instead, just close the delegate stream. 169 // It should flush itself if necessary. 170 @Override 171 public void close() throws IOException { 172 out.close(); 173 } 174}