001    /* CharArrayWriter.java -- Write chars to a buffer
002       Copyright (C) 1998, 1999, 2001, 2002, 2005  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 java.io;
040    
041    /**
042      * This class allows data to be written to a char array buffer and
043      * and then retrieved by an application.   The internal char array
044      * buffer is dynamically resized to hold all the data written.  Please
045      * be aware that writing large amounts to data to this stream will
046      * cause large amounts of memory to be allocated.
047      * <p>
048      * The size of the internal buffer defaults to 32 and it is resized
049      * in increments of 1024 chars.  This behavior can be over-ridden by using the
050      * following two properties:
051      * <p>
052      * <ul>
053      * <li><xmp>gnu.java.io.CharArrayWriter.initialBufferSize</xmp></li>
054      * <li><xmp>gnu.java.io.CharArrayWriter.bufferIncrementSize</xmp></li>
055      * </ul>
056      * <p>
057      * There is a constructor that specified the initial buffer size and
058      * that is the preferred way to set that value because it it portable
059      * across all Java class library implementations.
060      * <p>
061      *
062      * @author Aaron M. Renn (arenn@urbanophile.com)
063      * @author Tom Tromey (tromey@cygnus.com)
064      */
065    public class CharArrayWriter extends Writer
066    {
067      /**
068       * The default initial buffer size
069       */
070      private static final int DEFAULT_INITIAL_BUFFER_SIZE = 32;
071    
072      /**
073       * This method initializes a new <code>CharArrayWriter</code> with
074       * the default buffer size of 32 chars.  If a different initial
075       * buffer size is desired, see the constructor
076       * <code>CharArrayWriter(int size)</code>.
077       */
078      public CharArrayWriter ()
079      {
080        this (DEFAULT_INITIAL_BUFFER_SIZE);
081      }
082    
083      /**
084       * This method initializes a new <code>CharArrayWriter</code> with
085       * a specified initial buffer size.
086       *
087       * @param size The initial buffer size in chars
088       */
089      public CharArrayWriter (int size)
090      {
091        super ();
092        buf = new char[size];
093      }
094    
095      /**
096       * Closes the stream.  This method is guaranteed not to free the contents
097       * of the internal buffer, which can still be retrieved.
098       */
099      public void close ()
100      {
101      }
102    
103      /**
104       * This method flushes all buffered chars to the stream.
105       */
106      public void flush ()
107      {
108      }
109    
110      /**
111       * This method discards all of the chars that have been written to the
112       * internal buffer so far by setting the <code>count</code> variable to
113       * 0.  The internal buffer remains at its currently allocated size.
114       */
115      public void reset ()
116      {
117        synchronized (lock)
118          {
119            count = 0;
120          }
121      }
122    
123      /**
124       * This method returns the number of chars that have been written to
125       * the buffer so far.  This is the same as the value of the protected
126       * <code>count</code> variable.  If the <code>reset</code> method is
127       * called, then this value is reset as well.  Note that this method does
128       * not return the length of the internal buffer, but only the number
129       * of chars that have been written to it.
130       *
131       * @return The number of chars in the internal buffer
132       *
133       * @see #reset()
134       */
135      public int size ()
136      {
137        return count;
138      }
139    
140      /**
141       * This method returns a char array containing the chars that have been
142       * written to this stream so far.  This array is a copy of the valid
143       * chars in the internal buffer and its length is equal to the number of
144       * valid chars, not necessarily to the the length of the current 
145       * internal buffer.  Note that since this method allocates a new array,
146       * it should be used with caution when the internal buffer is very large.
147       */
148      public char[] toCharArray ()
149      {
150        synchronized (lock)
151          {      
152            char[] nc = new char[count];
153            System.arraycopy(buf, 0, nc, 0, count);
154            return nc;
155          }
156      }
157    
158      /**
159       * Returns the chars in the internal array as a <code>String</code>.  The
160       * chars in the buffer are converted to characters using the system default
161       * encoding.  There is an overloaded <code>toString()</code> method that
162       * allows an application specified character encoding to be used.
163       *
164       * @return A <code>String</code> containing the data written to this
165       *         stream so far
166       */
167      public String toString ()
168      {
169        synchronized (lock)
170          {
171            return new String (buf, 0, count);
172          }
173      }
174    
175      /**
176       * This method writes the writes the specified char into the internal
177       * buffer.
178       *
179       * @param oneChar The char to be read passed as an int
180       */
181      public void write (int oneChar)
182      {
183        synchronized (lock)
184          {
185            resize (1);
186            buf[count++] = (char) oneChar;
187          }
188      }
189    
190      /**
191       * This method writes <code>len</code> chars from the passed in array 
192       * <code>buf</code> starting at index <code>offset</code> into that buffer
193       *
194       * @param buffer The char array to write data from
195       * @param offset The index into the buffer to start writing data from
196       * @param len The number of chars to write
197       */
198      public void write (char[] buffer, int offset, int len)
199      {
200        synchronized (lock)
201          {
202            if (len >= 0)
203              resize (len);
204            System.arraycopy(buffer, offset, buf, count, len);
205            count += len;
206          }
207      }
208    
209      /**
210       * This method writes <code>len</code> chars from the passed in
211       * <code>String</code> <code>buf</code> starting at index
212       * <code>offset</code> into the internal buffer.
213       *
214       * @param str The <code>String</code> to write data from
215       * @param offset The index into the string to start writing data from
216       * @param len The number of chars to write
217       */
218      public void write (String str, int offset, int len)
219      {
220        synchronized (lock)
221          {
222            if (len >= 0)
223              resize (len);
224            str.getChars(offset, offset + len, buf, count);
225            count += len;
226          }
227      }
228    
229      /**
230       * This method writes all the chars that have been written to this stream
231       * from the internal buffer to the specified <code>Writer</code>.
232       *
233       * @param out The <code>Writer</code> to write to
234       *
235       * @exception IOException If an error occurs
236       */
237      public void writeTo (Writer out) throws IOException
238      {
239        synchronized (lock)
240          {
241            out.write(buf, 0, count);
242          }
243      }
244    
245      /** 
246       * Appends the Unicode character, <code>c</code>, to the output stream
247       * underlying this writer.  This is equivalent to <code>write(c)</code>.
248       *
249       * @param c the character to append.
250       * @return a reference to this object.
251       * @since 1.5 
252       */
253      public CharArrayWriter append(char c)
254      {
255        write(c);
256        return this;
257      }
258    
259      /** 
260       * Appends the specified sequence of Unicode characters to the
261       * output stream underlying this writer.  This is equivalent to
262       * appending the results of calling <code>toString()</code> on the
263       * character sequence.  As a result, the entire sequence may not be
264       * appended, as it depends on the implementation of
265       * <code>toString()</code> provided by the
266       * <code>CharSequence</code>.  For example, if the character
267       * sequence is wrapped around an input buffer, the results will
268       * depend on the current position and length of that buffer.
269       *
270       * @param seq the character sequence to append.  If seq is null,
271       *        then the string "null" (the string representation of null)
272       *        is appended.
273       * @return a reference to this object.
274       * @since 1.5 
275       */
276      public CharArrayWriter append(CharSequence cs)
277      {
278        try
279          {
280            write(cs == null ? "null" : cs.toString());
281          }
282        catch (IOException _)
283          {
284            // Can't happen.
285          }
286        return this;
287      }
288    
289      /** 
290       * Appends the specified subsequence of Unicode characters to the
291       * output stream underlying this writer, starting and ending at the
292       * specified positions within the sequence.  The behaviour of this
293       * method matches the behaviour of writing the result of
294       * <code>append(seq.subSequence(start,end))</code> when the sequence
295       * is not null.
296       *
297       * @param seq the character sequence to append.  If seq is null,
298       *        then the string "null" (the string representation of null)
299       *        is appended.
300       * @param start the index of the first Unicode character to use from
301       *        the sequence.
302       * @param end the index of the last Unicode character to use from the
303       *        sequence.
304       * @return a reference to this object.
305       * @throws IndexOutOfBoundsException if either of the indices are negative,
306       *         the start index occurs after the end index, or the end index is
307       *         beyond the end of the sequence.
308       * @since 1.5
309       */
310      public CharArrayWriter append(CharSequence cs, int start, int end)
311      {
312        try
313          {
314            write(cs == null ? "null" : cs.subSequence(start, end).toString());
315          }
316        catch (IOException _)
317          {
318            // Can't happen.
319          }
320        return this;
321      }
322    
323      /**
324       * This private method makes the buffer bigger when we run out of room
325       * by allocating a larger buffer and copying the valid chars from the
326       * old array into it.  This is obviously slow and should be avoided by
327       * application programmers by setting their initial buffer size big
328       * enough to hold everything if possible.
329       */
330      private void resize (int len)
331      {
332        if (count + len >= buf.length)
333          {
334            int newlen = buf.length * 2;
335            if (count + len > newlen)
336              newlen = count + len;
337            char[] newbuf = new char[newlen];
338            System.arraycopy(buf, 0, newbuf, 0, count);
339            buf = newbuf;
340          }
341      }
342    
343      /**
344       * The internal buffer where the data written is stored
345       */
346      protected char[] buf;
347    
348      /**
349       * The number of chars that have been written to the buffer
350       */
351      protected int count;
352    }