001 /* ImageOutputStream.java -- 002 Copyright (C) 2004 Free Software Foundation, Inc. 003 004 This file is part of GNU Classpath. 005 006 GNU Classpath is free software; you can redistribute it and/or modify 007 it under the terms of the GNU General Public License as published by 008 the Free Software Foundation; either version 2, or (at your option) 009 any later version. 010 011 GNU Classpath is distributed in the hope that it will be useful, but 012 WITHOUT ANY WARRANTY; without even the implied warranty of 013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 General Public License for more details. 015 016 You should have received a copy of the GNU General Public License 017 along with GNU Classpath; see the file COPYING. If not, write to the 018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 019 02110-1301 USA. 020 021 Linking this library statically or dynamically with other modules is 022 making a combined work based on this library. Thus, the terms and 023 conditions of the GNU General Public License cover the whole 024 combination. 025 026 As a special exception, the copyright holders of this library give you 027 permission to link this library with independent modules to produce an 028 executable, regardless of the license terms of these independent 029 modules, and to copy and distribute the resulting executable under 030 terms of your choice, provided that you also meet, for each linked 031 independent module, the terms and conditions of the license of that 032 module. An independent module is a module which is not derived from 033 or based on this library. If you modify this library, you may extend 034 this exception to your version of the library, but you are not 035 obligated to do so. If you do not wish to do so, delete this 036 exception statement from your version. */ 037 038 039 package javax.imageio.stream; 040 041 import java.io.IOException; 042 import java.io.UTFDataFormatException; 043 import java.nio.ByteOrder; 044 045 /** 046 * @author Michael Koch (konqueror@gmx.de) 047 */ 048 public abstract class ImageOutputStreamImpl extends ImageInputStreamImpl 049 implements ImageOutputStream 050 { 051 public ImageOutputStreamImpl() 052 { 053 // Do nothing here. 054 } 055 056 protected final void flushBits() 057 throws IOException 058 { 059 checkClosed(); 060 if (bitOffset != 0) 061 { 062 int offset = bitOffset; 063 int partial = read(); 064 if (partial < 0) 065 { 066 partial = 0; 067 bitOffset = 0; 068 } 069 else 070 { 071 seek(getStreamPosition() - 1); 072 partial &= -1 << (8 - offset); 073 } 074 write(partial); 075 } 076 } 077 078 public void write(byte[] data) 079 throws IOException 080 { 081 write(data, 0, data.length); 082 } 083 084 public abstract void write(byte[] data, int offset, int len) 085 throws IOException; 086 087 public abstract void write(int value) 088 throws IOException; 089 090 public void writeBit(int bit) 091 throws IOException 092 { 093 writeBits(1L & bit, 1); 094 } 095 096 public void writeBits(long bits, int numBits) 097 throws IOException 098 { 099 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 169 public void writeBoolean(boolean value) 170 throws IOException 171 { 172 writeByte(value ? 1 : 0); 173 } 174 175 public void writeByte(int value) 176 throws IOException 177 { 178 write(value & 0xff); 179 } 180 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 191 public void writeChar(int value) 192 throws IOException 193 { 194 writeShort(value); 195 } 196 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 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 212 public void writeDouble(double value) 213 throws IOException 214 { 215 writeLong(Double.doubleToLongBits(value)); 216 } 217 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 225 public void writeFloat(float value) 226 throws IOException 227 { 228 writeInt(Float.floatToIntBits(value)); 229 } 230 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 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 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 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 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 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 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 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 }