~ubuntu-branches/ubuntu/maverick/proguard/maverick

« back to all changes in this revision

Viewing changes to src/proguard/classfile/constant/Utf8Constant.java

  • Committer: Bazaar Package Importer
  • Author(s): Sam Clegg, Onkar Shinde, Sam Clegg
  • Date: 2009-10-09 16:17:49 UTC
  • mfrom: (1.2.3 upstream) (3.1.6 karmic)
  • Revision ID: james.westby@ubuntu.com-20091009161749-qjk059y5r792co7c
Tags: 4.4-1
[ Onkar Shinde ]
* Merge from Ubuntu. (Closes: #534029, #548810)

[ Sam Clegg ]
* Thanks Onkar for the above fixes!
* New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 * ProGuard -- shrinking, optimization, obfuscation, and preverification
3
3
 *             of Java bytecode.
4
4
 *
5
 
 * Copyright (c) 2002-2008 Eric Lafortune (eric@graphics.cornell.edu)
 
5
 * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
6
6
 *
7
7
 * This program is free software; you can redistribute it and/or modify it
8
8
 * under the terms of the GNU General Public License as published by the Free
32
32
 */
33
33
public class Utf8Constant extends Constant
34
34
{
35
 
    private static final String ENCODING = "UTF-8";
36
 
 
37
35
    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;
 
36
    private static final int  TWO_BYTE_CONSTANT1 = 0xc0;
 
37
    private static final int  TWO_BYTE_CONSTANT2 = 0x80;
40
38
    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;
 
39
    private static final int  TWO_BYTE_MASK1     = 0x1f;
 
40
    private static final int  TWO_BYTE_MASK2     = 0x3f;
43
41
 
44
42
    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;
 
43
    private static final int  THREE_BYTE_CONSTANT1 = 0xe0;
 
44
    private static final int  THREE_BYTE_CONSTANT2 = 0x80;
 
45
    private static final int  THREE_BYTE_CONSTANT3 = 0x80;
48
46
    private static final int  THREE_BYTE_SHIFT1    = 12;
49
47
    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;
 
48
    private static final int  THREE_BYTE_MASK1     = 0x0f;
 
49
    private static final int  THREE_BYTE_MASK2     = 0x3f;
 
50
    private static final int  THREE_BYTE_MASK3     = 0x3f;
53
51
 
54
52
 
55
53
    // There are a lot of Utf8Constant objects, so we're optimising their storage.
60
58
    //private int u2length;
61
59
    private byte[] bytes;
62
60
 
63
 
    private String utf8string;
 
61
    private String string;
64
62
 
65
63
 
66
64
    /**
75
73
    /**
76
74
     * Creates a Utf8Constant containing the given string.
77
75
     */
78
 
    public Utf8Constant(String utf8string)
 
76
    public Utf8Constant(String string)
79
77
    {
80
 
        this.bytes      = null;
81
 
        this.utf8string = utf8string;
 
78
        this.bytes  = null;
 
79
        this.string = string;
82
80
    }
83
81
 
84
82
 
87
85
     */
88
86
    public void setBytes(byte[] bytes)
89
87
    {
90
 
        this.bytes      = bytes;
91
 
        this.utf8string = null;
 
88
        this.bytes  = bytes;
 
89
        this.string = null;
92
90
    }
93
91
 
94
92
 
99
97
    {
100
98
        try
101
99
        {
102
 
            return getByteArrayRepresentation();
 
100
            switchToByteArrayRepresentation();
103
101
        }
104
102
        catch (UnsupportedEncodingException ex)
105
103
        {
106
104
            throw new RuntimeException(ex.getMessage());
107
105
        }
 
106
 
 
107
        return bytes;
108
108
    }
109
109
 
110
110
 
113
113
     */
114
114
    public void setString(String utf8String)
115
115
    {
116
 
        this.bytes      = null;
117
 
        this.utf8string = utf8String;
 
116
        this.bytes  = null;
 
117
        this.string = utf8String;
118
118
    }
119
119
 
120
120
 
132
132
            throw new RuntimeException(ex.getMessage());
133
133
        }
134
134
 
135
 
        return utf8string;
 
135
        return string;
136
136
    }
137
137
 
 
138
 
138
139
    // Implementations for Constant.
139
140
 
140
141
    public int getTag()
148
149
    }
149
150
 
150
151
 
 
152
    // Small utility methods.
 
153
 
 
154
    /**
 
155
     * Switches to a byte array representation of the UTF-8 data.
 
156
     */
 
157
    private void switchToByteArrayRepresentation() throws UnsupportedEncodingException
 
158
    {
 
159
        if (bytes == null)
 
160
        {
 
161
            bytes  = getByteArrayRepresentation(string);
 
162
            string = null;
 
163
        }
 
164
    }
 
165
 
 
166
 
151
167
    /**
152
168
     * Switches to a String representation of the UTF-8 data.
153
169
     */
154
170
    private void switchToStringRepresentation() throws UnsupportedEncodingException
155
171
    {
156
 
        if (utf8string == null)
 
172
        if (string == null)
157
173
        {
158
 
            utf8string = new String(bytes, ENCODING);
159
 
            bytes      = null;
 
174
            string = getStringRepresentation(bytes);
 
175
            bytes  = null;
160
176
        }
161
177
    }
162
178
 
163
179
 
164
180
    /**
165
 
     * Transforms UTF-8 bytes to the slightly modified UTF-8 representation that
166
 
     * is used by classes.
 
181
     * Returns the modified UTF-8 byte array representation of the given string.
167
182
     */
168
 
    private byte[] getByteArrayRepresentation() throws UnsupportedEncodingException
 
183
    private byte[] getByteArrayRepresentation(String string) throws UnsupportedEncodingException
169
184
    {
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
185
        // We're computing the byte array ourselves, because the implementation
178
186
        // of String.getBytes("UTF-8") has a bug, at least up to JRE 1.4.2.
179
187
        // Also note the special treatment of the 0 character.
180
188
 
181
189
        // Compute the byte array length.
182
190
        int byteLength   = 0;
183
 
        int stringLength = utf8string.length();
 
191
        int stringLength = string.length();
184
192
        for (int stringIndex = 0; stringIndex < stringLength; stringIndex++)
185
193
        {
186
 
            char c = utf8string.charAt(stringIndex);
 
194
            char c = string.charAt(stringIndex);
187
195
 
188
196
            // The character is represented by one, two, or three bytes.
189
197
            byteLength += c == 0                ? 2 :
199
207
        int byteIndex = 0;
200
208
        for (int stringIndex = 0; stringIndex < stringLength; stringIndex++)
201
209
        {
202
 
            char c = utf8string.charAt(stringIndex);
 
210
            char c = string.charAt(stringIndex);
203
211
            if (c == 0)
204
212
            {
205
213
                // The 0 character gets a two-byte representation in classes.
206
 
                bytes[byteIndex++] = TWO_BYTE_CONSTANT1;
207
 
                bytes[byteIndex++] = TWO_BYTE_CONSTANT2;
 
214
                bytes[byteIndex++] = (byte)TWO_BYTE_CONSTANT1;
 
215
                bytes[byteIndex++] = (byte)TWO_BYTE_CONSTANT2;
208
216
            }
209
217
            else if (c < TWO_BYTE_LIMIT)
210
218
            {
228
236
 
229
237
        return bytes;
230
238
    }
 
239
 
 
240
 
 
241
    /**
 
242
     * Returns the String representation of the given modified UTF-8 byte array.
 
243
     */
 
244
    private String getStringRepresentation(byte[] bytes) throws UnsupportedEncodingException
 
245
    {
 
246
        // We're computing the string ourselves, because the implementation
 
247
        // of "new String(bytes)" doesn't honor the special treatment of
 
248
        // the 0 character in JRE 1.6_u11.
 
249
 
 
250
        // Allocate the byte array with the computed length.
 
251
        char[] chars  = new char[bytes.length];
 
252
 
 
253
        // Fill out the array.
 
254
        int charIndex = 0;
 
255
        int byteIndex = 0;
 
256
        while (byteIndex < bytes.length)
 
257
        {
 
258
 
 
259
            int b = bytes[byteIndex++] & 0xff;
 
260
 
 
261
            // Depending on the flag bits in the first byte, the character
 
262
            // is represented by a single byte, by two bytes, or by three
 
263
            // bytes. We're not checking the redundant flag bits in the
 
264
            // second byte and the third byte.
 
265
            try
 
266
            {
 
267
                chars[charIndex++] =
 
268
                    (char)(b < TWO_BYTE_CONSTANT1   ? b                                                          :
 
269
 
 
270
                           b < THREE_BYTE_CONSTANT1 ? ((b                  & TWO_BYTE_MASK1) << TWO_BYTE_SHIFT1) |
 
271
                                                      ((bytes[byteIndex++] & TWO_BYTE_MASK2)                   ) :
 
272
 
 
273
                                                      ((b                  & THREE_BYTE_MASK1) << THREE_BYTE_SHIFT1) |
 
274
                                                      ((bytes[byteIndex++] & THREE_BYTE_MASK2) << THREE_BYTE_SHIFT2) |
 
275
                                                      ((bytes[byteIndex++] & THREE_BYTE_MASK3)                     ));
 
276
            }
 
277
            catch (ArrayIndexOutOfBoundsException e)
 
278
            {
 
279
                throw new UnsupportedEncodingException("Missing UTF-8 bytes after initial byte [0x"+Integer.toHexString(b)+"] in string ["+new String(chars, 0, charIndex)+"]");
 
280
            }
 
281
        }
 
282
 
 
283
        return new String(chars, 0, charIndex);
 
284
    }
231
285
}