1 /* Copyright (C) 2005, 2006  Free Software Foundation
2 
3 This file is part of libgcj.
4 
5 This software is copyrighted work licensed under the terms of the
6 Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
7 details.  */
8 
9 package gnu.gcj.convert;
10 
11 import java.nio.ByteBuffer;
12 import java.nio.CharBuffer;
13 import java.nio.charset.Charset;
14 import java.nio.charset.CharsetEncoder;
15 import java.nio.charset.CodingErrorAction;
16 import java.nio.charset.CoderResult;
17 import gnu.java.nio.charset.EncodingHelper;
18 
19 /**
20  * Adaptor class that allow any {@link Charset} to be used
21  * as a UnicodeToBytes converter.
22  */
23 public class CharsetToBytesAdaptor extends UnicodeToBytes
24 {
25   /**
26    * The CharsetEncoder that does all the work.
27    */
28   private final CharsetEncoder encoder;
29 
30   /**
31    * ByteBuffer wrapper for this.buf.
32    */
33   private ByteBuffer outBuf;
34 
35   /**
36    * True if we've told the CharsetEncoder that there are no more
37    * characters available.
38    */
39   private boolean closedEncoder;
40 
41   /**
42    * True if there are bytes pending in the encoder.
43    */
44   private boolean hasBytes;
45 
46   /**
47    * True if we're finished.
48    */
49   private boolean finished;
50 
51   /**
52    * Create a new CharsetToBytesAdaptor for the given Charset.
53    *
54    * @param cs The Charset.
55    */
CharsetToBytesAdaptor(Charset cs)56   public CharsetToBytesAdaptor(Charset cs)
57   {
58     this(cs.newEncoder());
59   }
60 
61   /**
62    * Create a new CharsetToBytesAdaptor for the given CharsetEncoder.
63    *
64    * @param enc The CharsetEncoder.
65    */
CharsetToBytesAdaptor(CharsetEncoder enc)66   public CharsetToBytesAdaptor(CharsetEncoder enc)
67   {
68     encoder = enc;
69     // Use default replacments on bad input so that we don't have to
70     // deal with errors.
71     encoder.onMalformedInput(CodingErrorAction.REPLACE);
72     encoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
73   }
74 
75   /**
76    * Return the encoder's name.  The backing Charset's name is
77    * returned.
78    *
79    * @return The name.
80    */
getName()81   public String getName()
82   {
83     return EncodingHelper.getOldCanonical(encoder.charset().name());
84   }
85 
write(char[] inbuffer, int inpos, int inlength)86   public int write (char[] inbuffer, int inpos, int inlength)
87   {
88     // Wrap the char array so it can be used by the encoder.
89     CharBuffer b = CharBuffer.wrap(inbuffer, inpos, inlength);
90     write(b);
91     return b.position() - inpos; // Number of chars consumed.
92   }
93 
write(String str, int inpos, int inlength, char work)94   public int write (String str, int inpos, int inlength, char work)
95   {
96     // Wrap the String so it can be used by the encoder.
97     CharBuffer b = CharBuffer.wrap(str, inpos, inlength);
98     write(b);
99     return b.position() - inpos; // Number of chars consumed.
100   }
101 
102   /**
103    * Encode as much of inBuf as will fit in buf.  The number of
104    * chars consumed is reflected by the new position of inBuf.  The
105    * output is put in buf and count is incremented by the number of
106    * bytes written.
107    *
108    * @param inBuf The input.
109    */
write(CharBuffer inBuf)110   private void write(CharBuffer inBuf)
111   {
112     // Reuse existing outBuf if it is still wrapping the same array
113     // it was created with.
114     if (outBuf == null || !outBuf.hasArray() || outBuf.array() != buf)
115       outBuf = ByteBuffer.wrap(buf);
116 
117     // Set the current position.
118     outBuf.position(count);
119 
120     // Do the conversion.
121     CoderResult result = encoder.encode(inBuf, outBuf, closedEncoder);
122     hasBytes = result == CoderResult.OVERFLOW;
123     if (closedEncoder)
124       {
125 	result = encoder.flush(outBuf);
126 	if (result == CoderResult.UNDERFLOW)
127 	  finished = true;
128 	else
129 	  hasBytes = true;
130       }
131 
132     // Mark the new end of buf.
133     count = outBuf.position();
134   }
135 
136   /**
137    * Check for cached output in the converter.
138    *
139    * @return true if there is cached output that has not been
140    * written to buf.
141    */
havePendingBytes()142   public boolean havePendingBytes()
143   {
144     return hasBytes;
145   }
146 
setFinished()147   public void setFinished()
148   {
149     closedEncoder = true;
150   }
151 
152   // These aren't cached.
done()153   public void done()
154   {
155   }
156 }
157