1 /* ImageOutputStream.java -- 2 Copyright (C) 2004 Free Software Foundation, Inc. 3 4 This file is part of GNU Classpath. 5 6 GNU Classpath is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 GNU Classpath is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GNU Classpath; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19 02110-1301 USA. 20 21 Linking this library statically or dynamically with other modules is 22 making a combined work based on this library. Thus, the terms and 23 conditions of the GNU General Public License cover the whole 24 combination. 25 26 As a special exception, the copyright holders of this library give you 27 permission to link this library with independent modules to produce an 28 executable, regardless of the license terms of these independent 29 modules, and to copy and distribute the resulting executable under 30 terms of your choice, provided that you also meet, for each linked 31 independent module, the terms and conditions of the license of that 32 module. An independent module is a module which is not derived from 33 or based on this library. If you modify this library, you may extend 34 this exception to your version of the library, but you are not 35 obligated to do so. If you do not wish to do so, delete this 36 exception statement from your version. */ 37 38 39 package javax.imageio.stream; 40 41 import java.io.IOException; 42 import java.io.UTFDataFormatException; 43 import java.nio.ByteOrder; 44 45 /** 46 * @author Michael Koch (konqueror@gmx.de) 47 */ 48 public abstract class ImageOutputStreamImpl extends ImageInputStreamImpl 49 implements ImageOutputStream 50 { ImageOutputStreamImpl()51 public ImageOutputStreamImpl() 52 { 53 // Do nothing here. 54 } 55 flushBits()56 protected final void flushBits() 57 throws IOException 58 { 59 checkClosed(); 60 if (bitOffset != 0) 61 { 62 int offset = bitOffset; 63 int partial = read(); 64 if (partial < 0) 65 { 66 partial = 0; 67 bitOffset = 0; 68 } 69 else 70 { 71 seek(getStreamPosition() - 1); 72 partial &= -1 << (8 - offset); 73 } 74 write(partial); 75 } 76 } 77 write(byte[] data)78 public void write(byte[] data) 79 throws IOException 80 { 81 write(data, 0, data.length); 82 } 83 write(byte[] data, int offset, int len)84 public abstract void write(byte[] data, int offset, int len) 85 throws IOException; 86 write(int value)87 public abstract void write(int value) 88 throws IOException; 89 writeBit(int bit)90 public void writeBit(int bit) 91 throws IOException 92 { 93 writeBits(1L & bit, 1); 94 } 95 writeBits(long bits, int numBits)96 public void writeBits(long bits, int numBits) 97 throws IOException 98 { 99 checkClosed(); 100 // Append chunk of bits to any preexisting bits, if any. 101 if (getStreamPosition() > 0 || bitOffset > 0) 102 { 103 int offs = bitOffset; 104 int partial = read(); 105 if (partial != -1) 106 seek(getStreamPosition() - 1); 107 else 108 partial = 0; 109 if (numBits + offs < 8) 110 { 111 // Append complete bits to partial byte. 112 int shift = 8 - (offs + numBits); 113 int mask = -1 >>> (32 - numBits); 114 partial &= ~(mask << shift); 115 partial |= (bits & mask) << shift; 116 write(partial); 117 seek(getStreamPosition() - 1); 118 bitOffset = offs + numBits; 119 numBits = 0; 120 } 121 else 122 { 123 // Append bits and decrease numBits accordingly. 124 int num = 8 - offs; 125 int mask = -1 >>> (32 - num); 126 partial &= ~mask; 127 partial |= (bits >> (numBits - num)) & mask; 128 write(partial); 129 numBits -= num; 130 } 131 } 132 133 // Write out whole chunks, if any. 134 if (numBits > 7) 135 { 136 int remaining = numBits % 8; 137 for (int numBytes = numBits / 8; numBytes > 0; numBytes--) 138 { 139 int shift = (numBytes - 1) * 8 + remaining; 140 int value = (int) ((shift == 0) ? bits & 0xff 141 : (bits >> shift) & 0xff); 142 write(value); 143 } 144 numBits = remaining; 145 } 146 147 // Write remaing partial bytes. 148 if (numBits != 0) 149 { 150 int partial = read(); 151 if (partial == -1) 152 { 153 seek(getStreamPosition() - 1); 154 } 155 else 156 { 157 partial = 0; 158 } 159 int shift = 8 - numBits; 160 int mask = -1 >>> (32 - numBits); 161 partial &= ~(mask << shift); 162 partial |= (bits & mask) << shift; 163 write(partial); 164 seek(getStreamPosition() - 1); 165 bitOffset = numBits; 166 } 167 } 168 writeBoolean(boolean value)169 public void writeBoolean(boolean value) 170 throws IOException 171 { 172 writeByte(value ? 1 : 0); 173 } 174 writeByte(int value)175 public void writeByte(int value) 176 throws IOException 177 { 178 write(value & 0xff); 179 } 180 writeBytes(String data)181 public void writeBytes(String data) 182 throws IOException 183 { 184 // This is bogus, but it is how the method is specified. 185 // Sun ought to deprecate this method. 186 int len = data.length(); 187 for (int i = 0; i < len; ++i) 188 writeByte(data.charAt(i)); 189 } 190 writeChar(int value)191 public void writeChar(int value) 192 throws IOException 193 { 194 writeShort(value); 195 } 196 writeChars(char[] data, int offset, int len)197 public void writeChars(char[] data, int offset, int len) 198 throws IOException 199 { 200 for(int i = 0; i < len; ++len) 201 writeChar(data[offset + i]); 202 } 203 writeChars(String data)204 public void writeChars(String data) 205 throws IOException 206 { 207 int len = data.length(); 208 for (int i = 0; i < len; ++i) 209 writeChar(data.charAt(i)); 210 } 211 writeDouble(double value)212 public void writeDouble(double value) 213 throws IOException 214 { 215 writeLong(Double.doubleToLongBits(value)); 216 } 217 writeDoubles(double[] data, int offset, int len)218 public void writeDoubles(double[] data, int offset, int len) 219 throws IOException 220 { 221 for(int i = 0; i < len; ++len) 222 writeDouble(data[offset + i]); 223 } 224 writeFloat(float value)225 public void writeFloat(float value) 226 throws IOException 227 { 228 writeInt(Float.floatToIntBits(value)); 229 } 230 writeFloats(float[] data, int offset, int len)231 public void writeFloats(float[] data, int offset, int len) 232 throws IOException 233 { 234 for(int i = 0; i < len; ++len) 235 writeFloat(data[offset + i]); 236 } 237 writeInt(int value)238 public void writeInt(int value) 239 throws IOException 240 { 241 if (getByteOrder() == ByteOrder.LITTLE_ENDIAN) 242 { 243 buffer[0] = ((byte) value); 244 buffer[1] = ((byte) (value >> 8)); 245 buffer[2] = ((byte) (value >> 16)); 246 buffer[3] = ((byte) (value >> 24)); 247 } 248 else 249 { 250 buffer[0] = ((byte) (value >> 24)); 251 buffer[1] = ((byte) (value >> 16)); 252 buffer[2] = ((byte) (value >> 8)); 253 buffer[3] = ((byte) value); 254 } 255 256 write(buffer, 0, 4); 257 } 258 writeInts(int[] data, int offset, int len)259 public void writeInts(int[] data, int offset, int len) 260 throws IOException 261 { 262 for(int i = 0; i < len; ++len) 263 writeInt(data[offset + i]); 264 } 265 writeLong(long value)266 public void writeLong(long value) 267 throws IOException 268 { 269 if (getByteOrder() == ByteOrder.LITTLE_ENDIAN) 270 { 271 buffer[0] = ((byte) value); 272 buffer[1] = ((byte) (value >> 8)); 273 buffer[2] = ((byte) (value >> 16)); 274 buffer[3] = ((byte) (value >> 24)); 275 buffer[4] = ((byte) (value >> 32)); 276 buffer[5] = ((byte) (value >> 40)); 277 buffer[6] = ((byte) (value >> 48)); 278 buffer[7] = ((byte) (value >> 56)); 279 } 280 else 281 { 282 buffer[0] = ((byte) (value >> 56)); 283 buffer[1] = ((byte) (value >> 48)); 284 buffer[2] = ((byte) (value >> 40)); 285 buffer[3] = ((byte) (value >> 32)); 286 buffer[4] = ((byte) (value >> 24)); 287 buffer[5] = ((byte) (value >> 16)); 288 buffer[6] = ((byte) (value >> 8)); 289 buffer[7] = ((byte) value); 290 } 291 292 write(buffer, 0, 8); 293 } 294 writeLongs(long[] data, int offset, int len)295 public void writeLongs(long[] data, int offset, int len) 296 throws IOException 297 { 298 for(int i = 0; i < len; ++len) 299 writeLong(data[offset + i]); 300 } 301 writeShort(int value)302 public void writeShort(int value) 303 throws IOException 304 { 305 if (getByteOrder() == ByteOrder.LITTLE_ENDIAN) 306 { 307 buffer[0] = ((byte) value); 308 buffer[1] = ((byte) (value >> 8)); 309 } 310 else 311 { 312 buffer[0] = ((byte) (value >> 8)); 313 buffer[1] = ((byte) value); 314 } 315 316 write(buffer, 0, 2); 317 } 318 writeShorts(short[] data, int offset, int len)319 public void writeShorts(short[] data, int offset, int len) 320 throws IOException 321 { 322 for(int i = 0; i < len; ++len) 323 writeShort(data[offset + i]); 324 } 325 writeUTF(String value)326 public void writeUTF(String value) 327 throws IOException 328 { 329 // NOTE: this code comes directly from DataOutputStream. 330 int len = value.length(); 331 int sum = 0; 332 333 for (int i = 0; i < len && sum <= 65535; ++i) 334 { 335 char c = value.charAt(i); 336 if (c >= '\u0001' && c <= '\u007f') 337 sum += 1; 338 else if (c == '\u0000' || (c >= '\u0080' && c <= '\u07ff')) 339 sum += 2; 340 else 341 sum += 3; 342 } 343 344 if (sum > 65535) 345 throw new UTFDataFormatException (); 346 347 int pos = 0; 348 byte[] buf = new byte[sum]; 349 350 for (int i = 0; i < len; ++i) 351 { 352 char c = value.charAt(i); 353 if (c >= '\u0001' && c <= '\u007f') 354 buf[pos++] = (byte) c; 355 else if (c == '\u0000' || (c >= '\u0080' && c <= '\u07ff')) 356 { 357 buf[pos++] = (byte) (0xc0 | (0x1f & (c >> 6))); 358 buf[pos++] = (byte) (0x80 | (0x3f & c)); 359 } 360 else 361 { 362 // JSL says the first byte should be or'd with 0xc0, but 363 // that is a typo. Unicode says 0xe0, and that is what is 364 // consistent with DataInputStream. 365 buf[pos++] = (byte) (0xe0 | (0x0f & (c >> 12))); 366 buf[pos++] = (byte) (0x80 | (0x3f & (c >> 6))); 367 buf[pos++] = (byte) (0x80 | (0x3f & c)); 368 } 369 } 370 371 writeShort (sum); 372 write(buf, 0, sum); 373 } 374 } 375