KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > proguard > classfile > constant > Utf8Constant


1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  * of Java bytecode.
4  *
5  * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu)
6  *
7  * This library is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the Free
9  * Software Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * This library is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
15  * for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this library; if not, write to the Free Software Foundation,
19  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */

21 package proguard.classfile.constant;
22
23 import proguard.classfile.*;
24 import proguard.classfile.constant.visitor.ConstantVisitor;
25
26 import java.io.*;
27
28 /**
29  * This Constant represents a UTF-8 constant in the constant pool.
30  *
31  * @author Eric Lafortune
32  */

33 public class Utf8Constant extends Constant
34 {
35     private static final String JavaDoc ENCODING = "UTF-8";
36
37     private static final char TWO_BYTE_LIMIT = 0x80;
38     private static final byte TWO_BYTE_CONSTANT1 = (byte)0xc0;
39     private static final byte TWO_BYTE_CONSTANT2 = (byte)0x80;
40     private static final int TWO_BYTE_SHIFT1 = 6;
41     private static final byte TWO_BYTE_MASK1 = (byte)0x1f;
42     private static final byte TWO_BYTE_MASK2 = (byte)0x3f;
43
44     private static final char THREE_BYTE_LIMIT = 0x800;
45     private static final byte THREE_BYTE_CONSTANT1 = (byte)0xe0;
46     private static final byte THREE_BYTE_CONSTANT2 = (byte)0x80;
47     private static final byte THREE_BYTE_CONSTANT3 = (byte)0x80;
48     private static final int THREE_BYTE_SHIFT1 = 12;
49     private static final int THREE_BYTE_SHIFT2 = 6;
50     private static final byte THREE_BYTE_MASK1 = (byte)0x0f;
51     private static final byte THREE_BYTE_MASK2 = (byte)0x3f;
52     private static final byte THREE_BYTE_MASK3 = (byte)0x3f;
53
54
55     // There are a lot of Utf8Constant objects, so we're optimising their storage.
56
// Initially, we're storing the UTF-8 bytes in a byte array.
57
// When the corresponding String is requested, we ditch the array and just
58
// store the String.
59

60     //private int u2length;
61
private byte[] bytes;
62
63     private String JavaDoc utf8string;
64
65
66     /**
67      * Creates an uninitialized Utf8Constant.
68      *
69      */

70     public Utf8Constant()
71     {
72     }
73
74
75     /**
76      * Creates a Utf8Constant containing the given string.
77      */

78     public Utf8Constant(String JavaDoc utf8string)
79     {
80         this.bytes = null;
81         this.utf8string = utf8string;
82     }
83
84
85     /**
86      * Initializes the UTF-8 data with an array of bytes.
87      */

88     public void setBytes(byte[] bytes)
89     {
90         this.bytes = bytes;
91         this.utf8string = null;
92     }
93
94
95     /**
96      * Returns the UTF-8 data as an array of bytes.
97      */

98     public byte[] getBytes()
99     {
100         try
101         {
102             return getByteArrayRepresentation();
103         }
104         catch (UnsupportedEncodingException ex)
105         {
106             throw new RuntimeException JavaDoc(ex.getMessage());
107         }
108     }
109
110
111     /**
112      * Initializes the UTF-8 data with a String.
113      */

114     public void setString(String JavaDoc utf8String)
115     {
116         this.bytes = null;
117         this.utf8string = utf8String;
118     }
119
120
121     /**
122      * Returns the UTF-8 data as a String.
123      */

124     public String JavaDoc getString()
125     {
126         try
127         {
128             switchToStringRepresentation();
129         }
130         catch (UnsupportedEncodingException ex)
131         {
132             throw new RuntimeException JavaDoc(ex.getMessage());
133         }
134
135         return utf8string;
136     }
137
138     // Implementations for Constant.
139

140     public int getTag()
141     {
142         return ClassConstants.CONSTANT_Utf8;
143     }
144
145     public void accept(Clazz clazz, ConstantVisitor constantVisitor)
146     {
147         constantVisitor.visitUtf8Constant(clazz, this);
148     }
149
150
151     /**
152      * Switches to a String representation of the UTF-8 data.
153      */

154     private void switchToStringRepresentation() throws UnsupportedEncodingException
155     {
156         if (utf8string == null)
157         {
158             utf8string = new String JavaDoc(bytes, ENCODING);
159             bytes = null;
160         }
161     }
162
163
164     /**
165      * Transforms UTF-8 bytes to the slightly modified UTF-8 representation that
166      * is used by classes.
167      */

168     private byte[] getByteArrayRepresentation() throws UnsupportedEncodingException
169     {
170         // Do we still have the byte array representation?
171
if (bytes != null)
172         {
173             // Then return that one.
174
return bytes;
175         }
176
177         // We're computing the byte array ourselves, because the implementation
178
// of String.getBytes("UTF-8") has a bug, at least up to JRE 1.4.2.
179
// Also note the special treatment of the 0 character.
180

181         // Compute the byte array length.
182
int byteLength = 0;
183         int stringLength = utf8string.length();
184         for (int stringIndex = 0; stringIndex < stringLength; stringIndex++)
185         {
186             char c = utf8string.charAt(stringIndex);
187
188             // The character is represented by one, two, or three bytes.
189
byteLength += c == 0 ? 2 :
190                           c < TWO_BYTE_LIMIT ? 1 :
191                           c < THREE_BYTE_LIMIT ? 2 :
192                                                   3;
193         }
194
195         // Allocate the byte array with the computed length.
196
byte[] bytes = new byte[byteLength];
197
198         // Fill out the array.
199
int byteIndex = 0;
200         for (int stringIndex = 0; stringIndex < stringLength; stringIndex++)
201         {
202             char c = utf8string.charAt(stringIndex);
203             if (c == 0)
204             {
205                 // The 0 character gets a two-byte representation in classes.
206
bytes[byteIndex++] = TWO_BYTE_CONSTANT1;
207                 bytes[byteIndex++] = TWO_BYTE_CONSTANT2;
208             }
209             else if (c < TWO_BYTE_LIMIT)
210             {
211                 // The character is represented by a single byte.
212
bytes[byteIndex++] = (byte)c;
213             }
214             else if (c < THREE_BYTE_LIMIT)
215             {
216                 // The character is represented by two bytes.
217
bytes[byteIndex++] = (byte)(TWO_BYTE_CONSTANT1 | ((c >>> TWO_BYTE_SHIFT1) & TWO_BYTE_MASK1));
218                 bytes[byteIndex++] = (byte)(TWO_BYTE_CONSTANT2 | ( c & TWO_BYTE_MASK2));
219             }
220             else
221             {
222                 // The character is represented by three bytes.
223
bytes[byteIndex++] = (byte)(THREE_BYTE_CONSTANT1 | ((c >>> THREE_BYTE_SHIFT1) & THREE_BYTE_MASK1));
224                 bytes[byteIndex++] = (byte)(THREE_BYTE_CONSTANT2 | ((c >>> THREE_BYTE_SHIFT2) & THREE_BYTE_MASK2));
225                 bytes[byteIndex++] = (byte)(THREE_BYTE_CONSTANT3 | ( c & THREE_BYTE_MASK3));
226             }
227         }
228
229         return bytes;
230     }
231 }
232
Popular Tags