Source for javax.imageio.stream.ImageOutputStreamImpl

   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: {
  51:   public ImageOutputStreamImpl()
  52:   {
  53:     // Do nothing here.
  54:   }
  55: 
  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: 
  78:   public void write(byte[] data)
  79:     throws IOException
  80:   {
  81:     write(data, 0, data.length);
  82:   }
  83: 
  84:   public abstract void write(byte[] data, int offset, int len)
  85:     throws IOException;
  86: 
  87:   public abstract void write(int value)
  88:     throws IOException;
  89: 
  90:   public void writeBit(int bit)
  91:     throws IOException
  92:   {
  93:     writeBits(1L & bit, 1);
  94:   }
  95: 
  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: 
 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: }