All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javolution.io.UTF8ByteBufferWriter Maven / Gradle / Ivy

/*
 * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
 * Copyright (C) 2012 - Javolution (http://javolution.org/)
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software is
 * freely granted, provided that this notice is preserved.
 */
package javolution.io;

import java.io.CharConversionException;
import java.io.IOException;
import java.io.Writer;
import java.nio.ByteBuffer;

/**
 * 

A UTF-8 java.nio.ByteBuffer writer.

* *

This writer supports surrogate char pairs (representing * characters in the range [U+10000 .. U+10FFFF]). It can also be used * to write characters from their unicodes (31 bits) directly * (ref. {@link #write(int)}).

* *

Instances of this class can be reused for different output streams * and can be part of a higher level component (e.g. serializer) in order * to avoid dynamic buffer allocation when the destination output changes. * Also wrapping using a java.io.BufferedWriter is unnescessary * as instances of this class embed their own data buffers.

* *

Note: This writer is unsynchronized and always produces well-formed * UTF-8 sequences.

* * @author Jean-Marie Dautelle * @version 2.0, December 9, 2004 * @see UTF8ByteBufferReader */ public final class UTF8ByteBufferWriter extends Writer { /** * Holds the byte buffer destination. */ private ByteBuffer _byteBuffer; /** * Default constructor. */ public UTF8ByteBufferWriter() {} /** * Constructor to Provide a Byte Buffer on Initialization * * @param byteBuffer Byte Buffer to use for Writing */ public UTF8ByteBufferWriter(final ByteBuffer byteBuffer) { _byteBuffer = byteBuffer; } protected ByteBuffer getOutput(){ return _byteBuffer; } /** * Sets the byte buffer to use for writing until this writer is closed. * * @param byteBuffer the destination byte buffer. * @return this UTF-8 writer. * @throws IllegalStateException if this writer is being reused and * it has not been {@link #close closed} or {@link #reset reset}. */ public UTF8ByteBufferWriter setOutput(ByteBuffer byteBuffer) { if (_byteBuffer != null) throw new IllegalStateException("Writer not closed or reset"); _byteBuffer = byteBuffer; return this; } /** * Writes a single character. This method supports 16-bits * character surrogates. * * @param c char the character to be written (possibly * a surrogate). * @throws IOException if an I/O error occurs. */ public void write(char c) throws IOException { if(_byteBuffer == null) throw new IOException("Writer closed"); if ((c < 0xd800) || (c > 0xdfff)) { write((int) c); } else if (c < 0xdc00) { // High surrogate. _highSurrogate = c; } else { // Low surrogate. int code = ((_highSurrogate - 0xd800) << 10) + (c - 0xdc00) + 0x10000; write(code); } } private char _highSurrogate; /** * Writes a character given its 31-bits Unicode. * * @param code the 31 bits Unicode of the character to be written. * @throws IOException if an I/O error occurs. */ public void write(int code) throws IOException { if(_byteBuffer == null) throw new IOException("Writer closed"); if ((code & 0xffffff80) == 0) { _byteBuffer.put((byte) code); } else { // Writes more than one byte. write2(code); } } private void write2(int c) throws IOException { if ((c & 0xfffff800) == 0) { // 2 bytes. _byteBuffer.put((byte) (0xc0 | (c >> 6))); _byteBuffer.put((byte) (0x80 | (c & 0x3f))); } else if ((c & 0xffff0000) == 0) { // 3 bytes. _byteBuffer.put((byte) (0xe0 | (c >> 12))); _byteBuffer.put((byte) (0x80 | ((c >> 6) & 0x3f))); _byteBuffer.put((byte) (0x80 | (c & 0x3f))); } else if ((c & 0xff200000) == 0) { // 4 bytes. _byteBuffer.put((byte) (0xf0 | (c >> 18))); _byteBuffer.put((byte) (0x80 | ((c >> 12) & 0x3f))); _byteBuffer.put((byte) (0x80 | ((c >> 6) & 0x3f))); _byteBuffer.put((byte) (0x80 | (c & 0x3f))); } else if ((c & 0xf4000000) == 0) { // 5 bytes. _byteBuffer.put((byte) (0xf8 | (c >> 24))); _byteBuffer.put((byte) (0x80 | ((c >> 18) & 0x3f))); _byteBuffer.put((byte) (0x80 | ((c >> 12) & 0x3f))); _byteBuffer.put((byte) (0x80 | ((c >> 6) & 0x3f))); _byteBuffer.put((byte) (0x80 | (c & 0x3f))); } else if ((c & 0x80000000) == 0) { // 6 bytes. _byteBuffer.put((byte) (0xfc | (c >> 30))); _byteBuffer.put((byte) (0x80 | ((c >> 24) & 0x3f))); _byteBuffer.put((byte) (0x80 | ((c >> 18) & 0x3f))); _byteBuffer.put((byte) (0x80 | ((c >> 12) & 0x3F))); _byteBuffer.put((byte) (0x80 | ((c >> 6) & 0x3F))); _byteBuffer.put((byte) (0x80 | (c & 0x3F))); } else { throw new CharConversionException("Illegal character U+" + Integer.toHexString(c)); } } /** * Writes a portion of an array of characters. * * @param cbuf the array of characters. * @param off the offset from which to start writing characters. * @param len the number of characters to write. * @throws IOException if an I/O error occurs. */ public void write(char cbuf[], int off, int len) throws IOException { if(_byteBuffer == null) throw new IOException("Writer closed"); final int off_plus_len = off + len; for (int i = off; i < off_plus_len;) { char c = cbuf[i++]; if (c < 0x80) { _byteBuffer.put((byte) c); } else { write(c); } } } /** * Writes a portion of a string. * * @param str a String. * @param off the offset from which to start writing characters. * @param len the number of characters to write. * @throws IOException if an I/O error occurs */ public void write(String str, int off, int len) throws IOException { if(_byteBuffer == null) throw new IOException("Writer closed"); final int off_plus_len = off + len; for (int i = off; i < off_plus_len;) { char c = str.charAt(i++); if (c < 0x80) { _byteBuffer.put((byte) c); } else { write(c); } } } /** * Writes the specified character sequence. * * @param csq the character sequence. * @throws IOException if an I/O error occurs */ public void write(CharSequence csq) throws IOException { if(_byteBuffer == null) throw new IOException("Writer closed"); final int length = csq.length(); for (int i = 0; i < length;) { char c = csq.charAt(i++); if (c < 0x80) { _byteBuffer.put((byte) c); } else { write(c); } } } /** * Flushes the stream (this method has no effect, the data is * always directly written to the ByteBuffer). * * @throws IOException if an I/O error occurs. */ public void flush() throws IOException { if (_byteBuffer == null) { throw new IOException("Writer closed"); } } /** * Closes and {@link #reset resets} this writer for reuse. * * @throws IOException if an I/O error occurs */ public void close() throws IOException { if (_byteBuffer != null) { reset(); } } // Implements Reusable. public void reset() { _byteBuffer = null; _highSurrogate = 0; } /** * @deprecated Replaced by {@link #setOutput(ByteBuffer)} */ public UTF8ByteBufferWriter setByteBuffer(ByteBuffer byteBuffer) { return this.setOutput(byteBuffer); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy