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 }