Overview Package Class Use Source Tree Index Deprecated About
GNU Classpath (0.95)
Frames | No Frames

Source for java.io.OutputStreamWriter

 1:  /* OutputStreamWriter.java -- Writer that converts chars to bytes
 2:  Copyright (C) 1998, 1999, 2000, 2001, 2003, 2005 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 java.io;
 40: 
 41:  import gnu.java.nio.charset.EncodingHelper;
 42: 
 43:  import java.nio.ByteBuffer;
 44:  import java.nio.CharBuffer;
 45:  import java.nio.charset.CharacterCodingException;
 46:  import java.nio.charset.Charset;
 47:  import java.nio.charset.CharsetEncoder;
 48:  import java.nio.charset.CodingErrorAction;
 49:  import java.nio.charset.MalformedInputException;
 50: 
 51:  /**
 52:  * This class writes characters to an output stream that is byte oriented
 53:  * It converts the chars that are written to bytes using an encoding layer,
 54:  * which is specific to a particular encoding standard. The desired
 55:  * encoding can either be specified by name, or if no encoding is specified,
 56:  * the system default encoding will be used. The system default encoding
 57:  * name is determined from the system property <code>file.encoding</code>.
 58:  * The only encodings that are guaranteed to be available are "8859_1"
 59:  * (the Latin-1 character set) and "UTF8". Unfortunately, Java does not
 60:  * provide a mechanism for listing the encodings that are supported in
 61:  * a given implementation.
 62:  * <p>
 63:  * Here is a list of standard encoding names that may be available:
 64:  * <p>
 65:  * <ul>
 66:  * <li>8859_1 (ISO-8859-1/Latin-1)
 67:  * <li>8859_2 (ISO-8859-2/Latin-2)
 68:  * <li>8859_3 (ISO-8859-3/Latin-3)
 69:  * <li>8859_4 (ISO-8859-4/Latin-4)
 70:  * <li>8859_5 (ISO-8859-5/Latin-5)
 71:  * <li>8859_6 (ISO-8859-6/Latin-6)
 72:  * <li>8859_7 (ISO-8859-7/Latin-7)
 73:  * <li>8859_8 (ISO-8859-8/Latin-8)
 74:  * <li>8859_9 (ISO-8859-9/Latin-9)
 75:  * <li>ASCII (7-bit ASCII)
 76:  * <li>UTF8 (UCS Transformation Format-8)
 77:  * <li>More Later
 78:  * </ul>
 79:  *
 80:  * @author Aaron M. Renn (arenn@urbanophile.com)
 81:  * @author Per Bothner (bothner@cygnus.com)
 82:  * @date April 17, 1998. 
 83:  */
 84:  public class OutputStreamWriter extends Writer
 85: {
 86:  /**
 87:  * The output stream.
 88:  */
 89:  private OutputStream out;
 90: 
 91:  /**
 92:  * The charset encoder.
 93:  */
 94:  private CharsetEncoder encoder;
 95: 
 96:  /**
 97:  * java.io canonical name of the encoding.
 98:  */
 99:  private String encodingName;
 100: 
 101:  /**
 102:  * Buffer output before character conversion as it has costly overhead.
 103:  */
 104:  private CharBuffer outputBuffer;
 105:  private final static int BUFFER_SIZE = 1024;
 106: 
 107:  /**
 108:  * This method initializes a new instance of <code>OutputStreamWriter</code>
 109:  * to write to the specified stream using a caller supplied character
 110:  * encoding scheme. Note that due to a deficiency in the Java language
 111:  * design, there is no way to determine which encodings are supported.
 112:  *
 113:  * @param out The <code>OutputStream</code> to write to
 114:  * @param encoding_scheme The name of the encoding scheme to use for 
 115:  * character to byte translation
 116:  *
 117:  * @exception UnsupportedEncodingException If the named encoding is 
 118:  * not available.
 119:  */
 120:  public OutputStreamWriter (OutputStream out, String encoding_scheme) 
 121:  throws UnsupportedEncodingException
 122:  {
 123:  this.out = out;
 124:  try 
 125:  {
 126:  // Don't use NIO if avoidable
 127:  if(EncodingHelper.isISOLatin1(encoding_scheme))
 128:  {
 129:  encodingName = "ISO8859_1";
 130:  encoder = null;
 131:  return;
 132:  }
 133: 
 134:  /*
 135:  * Workraround for encodings with a byte-order-mark.
 136:  * We only want to write it once per stream.
 137:  */
 138:  try 
 139:  {
 140:  if(encoding_scheme.equalsIgnoreCase("UnicodeBig") || 
 141:  encoding_scheme.equalsIgnoreCase("UTF-16") ||
 142:  encoding_scheme.equalsIgnoreCase("UTF16"))
 143:  {
 144:  encoding_scheme = "UTF-16BE"; 
 145:  out.write((byte)0xFE);
 146:  out.write((byte)0xFF);
 147:  } 
 148:  else if(encoding_scheme.equalsIgnoreCase("UnicodeLittle")){
 149:  encoding_scheme = "UTF-16LE";
 150:  out.write((byte)0xFF);
 151:  out.write((byte)0xFE);
 152:  }
 153:  }
 154:  catch(IOException ioe)
 155:  {
 156:  }
 157:  
 158:  outputBuffer = CharBuffer.allocate(BUFFER_SIZE);
 159: 
 160:  Charset cs = EncodingHelper.getCharset(encoding_scheme);
 161:  if(cs == null)
 162:  throw new UnsupportedEncodingException("Encoding "+encoding_scheme+
 163:  " unknown");
 164:  encoder = cs.newEncoder();
 165:  encodingName = EncodingHelper.getOldCanonical(cs.name());
 166: 
 167:  encoder.onMalformedInput(CodingErrorAction.REPLACE);
 168:  encoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
 169:  } 
 170:  catch(RuntimeException e) 
 171:  {
 172:  // Default to ISO Latin-1, will happen if this is called, for instance,
 173:  // before the NIO provider is loadable.
 174:  encoder = null; 
 175:  encodingName = "ISO8859_1";
 176:  }
 177:  }
 178: 
 179:  /**
 180:  * This method initializes a new instance of <code>OutputStreamWriter</code>
 181:  * to write to the specified stream using the default encoding.
 182:  *
 183:  * @param out The <code>OutputStream</code> to write to
 184:  */
 185:  public OutputStreamWriter (OutputStream out)
 186:  {
 187:  this.out = out;
 188:  outputBuffer = null;
 189:  try 
 190:  {
 191:  String encoding = System.getProperty("file.encoding");
 192:  Charset cs = Charset.forName(encoding);
 193:  encoder = cs.newEncoder();
 194:  encodingName = EncodingHelper.getOldCanonical(cs.name());
 195:  } 
 196:  catch(RuntimeException e) 
 197:  {
 198:  encoder = null; 
 199:  encodingName = "ISO8859_1";
 200:  }
 201: 
 202:  if(encoder != null)
 203:  {
 204:  encoder.onMalformedInput(CodingErrorAction.REPLACE);
 205:  encoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
 206:  outputBuffer = CharBuffer.allocate(BUFFER_SIZE);
 207:  }
 208:  }
 209: 
 210:  /**
 211:  * This method initializes a new instance of <code>OutputStreamWriter</code>
 212:  * to write to the specified stream using a given <code>Charset</code>.
 213:  *
 214:  * @param out The <code>OutputStream</code> to write to
 215:  * @param cs The <code>Charset</code> of the encoding to use
 216:  * 
 217:  * @since 1.5
 218:  */
 219:  public OutputStreamWriter(OutputStream out, Charset cs)
 220:  {
 221:  this.out = out;
 222:  encoder = cs.newEncoder();
 223:  encoder.onMalformedInput(CodingErrorAction.REPLACE);
 224:  encoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
 225:  outputBuffer = CharBuffer.allocate(BUFFER_SIZE);
 226:  encodingName = EncodingHelper.getOldCanonical(cs.name());
 227:  }
 228:  
 229:  /**
 230:  * This method initializes a new instance of <code>OutputStreamWriter</code>
 231:  * to write to the specified stream using a given
 232:  * <code>CharsetEncoder</code>.
 233:  *
 234:  * @param out The <code>OutputStream</code> to write to
 235:  * @param enc The <code>CharsetEncoder</code> to encode the output with
 236:  * 
 237:  * @since 1.5
 238:  */
 239:  public OutputStreamWriter(OutputStream out, CharsetEncoder enc)
 240:  {
 241:  this.out = out;
 242:  encoder = enc;
 243:  outputBuffer = CharBuffer.allocate(BUFFER_SIZE);
 244:  Charset cs = enc.charset();
 245:  if (cs == null)
 246:  encodingName = "US-ASCII";
 247:  else
 248:  encodingName = EncodingHelper.getOldCanonical(cs.name());
 249:  }
 250: 
 251:  /**
 252:  * This method closes this stream, and the underlying 
 253:  * <code>OutputStream</code>
 254:  *
 255:  * @exception IOException If an error occurs
 256:  */
 257:  public void close () throws IOException
 258:  {
 259:  if(out == null)
 260:  return;
 261:  flush();
 262:  out.close ();
 263:  out = null;
 264:  }
 265: 
 266:  /**
 267:  * This method returns the name of the character encoding scheme currently
 268:  * in use by this stream. If the stream has been closed, then this method
 269:  * may return <code>null</code>.
 270:  *
 271:  * @return The encoding scheme name
 272:  */
 273:  public String getEncoding ()
 274:  {
 275:  return out != null ? encodingName : null;
 276:  }
 277: 
 278:  /**
 279:  * This method flushes any buffered bytes to the underlying output sink.
 280:  *
 281:  * @exception IOException If an error occurs
 282:  */
 283:  public void flush () throws IOException
 284:  {
 285:  if(out != null){ 
 286:  if(outputBuffer != null){
 287:  char[] buf = new char[outputBuffer.position()];
 288:  if(buf.length > 0){
 289:  outputBuffer.flip();
 290:  outputBuffer.get(buf);
 291:  writeConvert(buf, 0, buf.length);
 292:  outputBuffer.clear();
 293:  }
 294:  }
 295:  out.flush ();
 296:  }
 297:  }
 298: 
 299:  /**
 300:  * This method writes <code>count</code> characters from the specified
 301:  * array to the output stream starting at position <code>offset</code>
 302:  * into the array.
 303:  *
 304:  * @param buf The array of character to write from
 305:  * @param offset The offset into the array to start writing chars from
 306:  * @param count The number of chars to write.
 307:  *
 308:  * @exception IOException If an error occurs
 309:  */
 310:  public void write (char[] buf, int offset, int count) throws IOException
 311:  {
 312:  if(out == null)
 313:  throw new IOException("Stream is closed.");
 314:  if(buf == null)
 315:  throw new IOException("Buffer is null.");
 316: 
 317:  if(outputBuffer != null)
 318:  {
 319:  if(count >= outputBuffer.remaining())
 320:  {
 321:  int r = outputBuffer.remaining();
 322:  outputBuffer.put(buf, offset, r);
 323:  writeConvert(outputBuffer.array(), 0, BUFFER_SIZE);
 324:  outputBuffer.clear();
 325:  offset += r;
 326:  count -= r;
 327:  // if the remaining bytes is larger than the whole buffer, 
 328:  // just don't buffer.
 329:  if(count >= outputBuffer.remaining()){
 330:  writeConvert(buf, offset, count);
 331:  return;
 332:  }
 333:  }
 334:  outputBuffer.put(buf, offset, count);
 335:  } else writeConvert(buf, offset, count);
 336:  }
 337: 
 338:  /**
 339:  * Converts and writes characters.
 340:  */
 341:  private void writeConvert (char[] buf, int offset, int count) 
 342:  throws IOException
 343:  {
 344:  if(encoder == null)
 345:  {
 346:  byte[] b = new byte[count];
 347:  for(int i=0;i<count;i++)
 348:  b[i] = (byte)((buf[offset+i] <= 0xFF)?buf[offset+i]:'?');
 349:  out.write(b);
 350:  } else {
 351:  try {
 352:  ByteBuffer output = encoder.encode(CharBuffer.wrap(buf,offset,count));
 353:  encoder.reset();
 354:  if(output.hasArray())
 355:  out.write(output.array());
 356:  else
 357:  {
 358:  byte[] outbytes = new byte[output.remaining()];
 359:  output.get(outbytes);
 360:  out.write(outbytes);
 361:  }
 362:  } catch(IllegalStateException e) {
 363:  throw new IOException("Internal error.");
 364:  } catch(MalformedInputException e) {
 365:  throw new IOException("Invalid character sequence.");
 366:  } catch(CharacterCodingException e) {
 367:  throw new IOException("Unmappable character.");
 368:  }
 369:  }
 370:  }
 371: 
 372:  /**
 373:  * This method writes <code>count</code> bytes from the specified 
 374:  * <code>String</code> starting at position <code>offset</code> into the
 375:  * <code>String</code>.
 376:  *
 377:  * @param str The <code>String</code> to write chars from
 378:  * @param offset The position in the <code>String</code> to start 
 379:  * writing chars from
 380:  * @param count The number of chars to write
 381:  *
 382:  * @exception IOException If an error occurs
 383:  */
 384:  public void write (String str, int offset, int count) throws IOException
 385:  {
 386:  if(str == null)
 387:  throw new IOException("String is null.");
 388: 
 389:  write(str.toCharArray(), offset, count);
 390:  }
 391: 
 392:  /**
 393:  * This method writes a single character to the output stream.
 394:  *
 395:  * @param ch The char to write, passed as an int.
 396:  *
 397:  * @exception IOException If an error occurs
 398:  */
 399:  public void write (int ch) throws IOException
 400:  {
 401:  write(new char[]{ (char)ch }, 0, 1);
 402:  }
 403: } // class OutputStreamWriter
Overview Package Class Use Source Tree Index Deprecated About
GNU Classpath (0.95)

AltStyle によって変換されたページ (->オリジナル) /