1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * you may not use this file except in compliance with the License.
6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * You may obtain a copy of the License at
7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * See the License for the specific language governing permissions and
14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * limitations under the License.
15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
1659a434629ba06d4decf7bc88a62ae370a1935f0eAndy McFadden
17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * UTF-8 and Unicode string manipulation, plus java/lang/String convenience
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * functions.
20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * In most cases we populate the fields in the String object directly,
22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * rather than going through an instance field lookup.
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "Dalvik.h"
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <stdlib.h>
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
28cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein * Allocate a new instance of the class String, performing first-use
29cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein * initialization of the class if necessary. Upon success, the
30cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein * returned value will have all its fields except hashCode already
31cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein * filled in, including a reference to a newly-allocated char[] for
32cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein * the contents, sized as given. Additionally, a reference to the
33cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein * chars array is stored to the pChars pointer. Callers must
34cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein * subsequently call dvmReleaseTrackedAlloc() on the result pointer.
35cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein * This function returns NULL on failure.
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
37cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornsteinstatic StringObject* makeStringObject(u4 charsLength, ArrayObject** pChars)
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
39cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein    /*
40cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein     * The String class should have already gotten found (but not
41cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein     * necessarily initialized) before making it here. We assert it
42cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein     * explicitly, since historically speaking, we have had bugs with
43cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein     * regard to when the class String gets set up. The assert helps
44cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein     * make any regressions easier to diagnose.
45cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein     */
46cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein    assert(gDvm.classJavaLangString != NULL);
47cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein
48cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein    if (!dvmIsClassInitialized(gDvm.classJavaLangString)) {
49cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein        /* Perform first-time use initialization of the class. */
50cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein        if (!dvmInitClass(gDvm.classJavaLangString)) {
51c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block            ALOGE("FATAL: Could not initialize class String");
52cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein            dvmAbort();
53cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein        }
54deeeeb264fc6f4ab7f5cb6e01b9dd76f487ff914Andy McFadden    }
55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
56cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein    Object* result = dvmAllocObject(gDvm.classJavaLangString, ALLOC_DEFAULT);
57cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein    if (result == NULL) {
58cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein        return NULL;
59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
61cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein    ArrayObject* chars = dvmAllocPrimitiveArray('C', charsLength, ALLOC_DEFAULT);
62cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein    if (chars == NULL) {
63cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein        dvmReleaseTrackedAlloc(result, NULL);
64cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein        return NULL;
6559a434629ba06d4decf7bc88a62ae370a1935f0eAndy McFadden    }
6659a434629ba06d4decf7bc88a62ae370a1935f0eAndy McFadden
67cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein    dvmSetFieldInt(result, STRING_FIELDOFF_COUNT, charsLength);
68cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein    dvmSetFieldObject(result, STRING_FIELDOFF_VALUE, (Object*) chars);
69cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein    dvmReleaseTrackedAlloc((Object*) chars, NULL);
70cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein    /* Leave offset and hashCode set to zero. */
71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
72cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein    *pChars = chars;
73cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein    return (StringObject*) result;
74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Compute a hash code on a UTF-8 string, for use with internal hash tables.
78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This may or may not yield the same results as the java/lang/String
80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * computeHashCode() function.  (To make sure this doesn't get abused,
81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * I'm initializing the hash code to 1 so they *don't* match up.)
82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * It would be more correct to invoke dexGetUtf16FromUtf8() here and compute
84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * the hash with the result.  That way, if something encoded the same
85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * character in two different ways, the hash value would be the same.  For
86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * our purposes that isn't necessary.
87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectu4 dvmComputeUtf8Hash(const char* utf8Str)
89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    u4 hash = 1;
91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    while (*utf8Str != '\0')
93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        hash = hash * 31 + *utf8Str++;
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return hash;
96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Like "strlen", but for strings encoded with "modified" UTF-8.
100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The value returned is the number of characters, which may or may not
102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * be the same as the number of bytes.
103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * (If this needs optimizing, try: mask against 0xa0, shift right 5,
105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * get increment {1-3} from table of 8 values.)
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
107d5c36b9040bd26a81219a7f399513526f9b46324Carl Shapirosize_t dvmUtf8Len(const char* utf8Str)
108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
109d5c36b9040bd26a81219a7f399513526f9b46324Carl Shapiro    size_t len = 0;
110d5c36b9040bd26a81219a7f399513526f9b46324Carl Shapiro    int ic;
111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    while ((ic = *utf8Str++) != '\0') {
113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        len++;
114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if ((ic & 0x80) != 0) {
115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /* two- or three-byte encoding */
116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            utf8Str++;
117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if ((ic & 0x20) != 0) {
118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                /* three-byte encoding */
119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                utf8Str++;
120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return len;
125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Convert a "modified" UTF-8 string to UTF-16.
129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmConvertUtf8ToUtf16(u2* utf16Str, const char* utf8Str)
131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    while (*utf8Str != '\0')
133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        *utf16Str++ = dexGetUtf16FromUtf8(&utf8Str);
134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Given a UTF-16 string, compute the length of the corresponding UTF-8
138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * string in bytes.
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic int utf16_utf8ByteLen(const u2* utf16Str, int len)
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int utf8Len = 0;
143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    while (len--) {
145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        unsigned int uic = *utf16Str++;
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * The most common case is (uic > 0 && uic <= 0x7f).
149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (uic == 0 || uic > 0x7f) {
151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (uic > 0x07ff)
152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                utf8Len += 3;
153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            else /*(uic > 0x7f || uic == 0) */
154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                utf8Len += 2;
155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else
156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            utf8Len++;
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return utf8Len;
159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Convert a UTF-16 string to UTF-8.
163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Make sure you allocate "utf8Str" with the result of utf16_utf8ByteLen(),
165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * not just "len".
166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void convertUtf16ToUtf8(char* utf8Str, const u2* utf16Str, int len)
168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(len >= 0);
170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    while (len--) {
172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        unsigned int uic = *utf16Str++;
173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * The most common case is (uic > 0 && uic <= 0x7f).
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (uic == 0 || uic > 0x7f) {
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (uic > 0x07ff) {
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                *utf8Str++ = (uic >> 12) | 0xe0;
180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                *utf8Str++ = ((uic >> 6) & 0x3f) | 0x80;
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                *utf8Str++ = (uic & 0x3f) | 0x80;
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else /*(uic > 0x7f || uic == 0)*/ {
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                *utf8Str++ = (uic >> 6) | 0xc0;
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                *utf8Str++ = (uic & 0x3f) | 0x80;
185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            *utf8Str++ = uic;
188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *utf8Str = '\0';
192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Use the java/lang/String.computeHashCode() algorithm.
196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
197d5c36b9040bd26a81219a7f399513526f9b46324Carl Shapirostatic inline u4 computeUtf16Hash(const u2* utf16Str, size_t len)
198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    u4 hash = 0;
200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    while (len--)
202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        hash = hash * 31 + *utf16Str++;
203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return hash;
205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
206d5c36b9040bd26a81219a7f399513526f9b46324Carl Shapiro
207dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapirou4 dvmComputeStringHash(StringObject* strObj) {
208dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapiro    int hashCode = dvmGetFieldInt(strObj, STRING_FIELDOFF_HASHCODE);
209dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapiro    if (hashCode != 0) {
210dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapiro      return hashCode;
211dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapiro    }
212dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapiro    int len = dvmGetFieldInt(strObj, STRING_FIELDOFF_COUNT);
213dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapiro    int offset = dvmGetFieldInt(strObj, STRING_FIELDOFF_OFFSET);
214fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes    ArrayObject* chars =
215fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes            (ArrayObject*) dvmGetFieldObject(strObj, STRING_FIELDOFF_VALUE);
216dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapiro    hashCode = computeUtf16Hash((u2*)(void*)chars->contents + offset, len);
217dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapiro    dvmSetFieldInt(strObj, STRING_FIELDOFF_HASHCODE, hashCode);
218dc9e44cc0af797679822484d88ef76bff15ffc98Carl Shapiro    return hashCode;
219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2210fbb7030fff58e25718291811394487d95d95a3eElliott HughesStringObject* dvmCreateStringFromCstr(const char* utf8Str) {
222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(utf8Str != NULL);
22381f3ebe03cd33c9003641084bece0604ee68bf88Barry Hayes    return dvmCreateStringFromCstrAndLength(utf8Str, dvmUtf8Len(utf8Str));
224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2260fbb7030fff58e25718291811394487d95d95a3eElliott HughesStringObject* dvmCreateStringFromCstr(const std::string& utf8Str) {
2270fbb7030fff58e25718291811394487d95d95a3eElliott Hughes    return dvmCreateStringFromCstr(utf8Str.c_str());
2280fbb7030fff58e25718291811394487d95d95a3eElliott Hughes}
2290fbb7030fff58e25718291811394487d95d95a3eElliott Hughes
230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Create a java/lang/String from a C string, given its UTF-16 length
232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * (number of UTF-16 code points).
233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
23481f3ebe03cd33c9003641084bece0604ee68bf88Barry Hayes * The caller must call dvmReleaseTrackedAlloc() on the return value.
235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Returns NULL and throws an exception on failure.
237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectStringObject* dvmCreateStringFromCstrAndLength(const char* utf8Str,
239d5c36b9040bd26a81219a7f399513526f9b46324Carl Shapiro    size_t utf16Length)
240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(utf8Str != NULL);
242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
243cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein    ArrayObject* chars;
244cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein    StringObject* newObj = makeStringObject(utf16Length, &chars);
245cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein    if (newObj == NULL) {
246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return NULL;
247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
248f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
249d5c36b9040bd26a81219a7f399513526f9b46324Carl Shapiro    dvmConvertUtf8ToUtf16((u2*)(void*)chars->contents, utf8Str);
250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
251d5c36b9040bd26a81219a7f399513526f9b46324Carl Shapiro    u4 hashCode = computeUtf16Hash((u2*)(void*)chars->contents, utf16Length);
252cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein    dvmSetFieldInt((Object*) newObj, STRING_FIELDOFF_HASHCODE, hashCode);
253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return newObj;
255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
258cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein * Create a new java/lang/String object, using the given Unicode data.
259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectStringObject* dvmCreateStringFromUnicode(const u2* unichars, int len)
261f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
262cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein    /* We allow a NULL pointer if the length is zero. */
263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(len == 0 || unichars != NULL);
264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
265cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein    ArrayObject* chars;
266cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein    StringObject* newObj = makeStringObject(len, &chars);
267cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein    if (newObj == NULL) {
268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return NULL;
269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
271cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein    if (len > 0) memcpy(chars->contents, unichars, len * sizeof(u2));
272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
273d5c36b9040bd26a81219a7f399513526f9b46324Carl Shapiro    u4 hashCode = computeUtf16Hash((u2*)(void*)chars->contents, len);
27459a434629ba06d4decf7bc88a62ae370a1935f0eAndy McFadden    dvmSetFieldInt((Object*)newObj, STRING_FIELDOFF_HASHCODE, hashCode);
275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return newObj;
277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
278f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
279f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
280f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Create a new C string from a java/lang/String object.
281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Returns NULL if the object is NULL.
283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
284fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hugheschar* dvmCreateCstrFromString(const StringObject* jstr)
285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
286cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein    assert(gDvm.classJavaLangString != NULL);
287fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes    if (jstr == NULL) {
288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return NULL;
289fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes    }
290f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
291fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes    int len = dvmGetFieldInt(jstr, STRING_FIELDOFF_COUNT);
292fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes    int offset = dvmGetFieldInt(jstr, STRING_FIELDOFF_OFFSET);
293fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes    ArrayObject* chars =
294fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes            (ArrayObject*) dvmGetFieldObject(jstr, STRING_FIELDOFF_VALUE);
295fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes    const u2* data = (const u2*)(void*)chars->contents + offset;
296f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(offset + len <= (int) chars->length);
297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
298fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes    int byteLen = utf16_utf8ByteLen(data, len);
299fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes    char* newStr = (char*) malloc(byteLen+1);
300fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes    if (newStr == NULL) {
301f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return NULL;
302fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes    }
303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    convertUtf16ToUtf8(newStr, data, len);
304f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
305f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return newStr;
306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
307f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
308d8a3f9fa1951e552f5f65c2914689083cc0c46c2Elliott Hughesvoid dvmGetStringUtfRegion(const StringObject* jstr,
309fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes        int start, int len, char* buf)
310f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
311d8a3f9fa1951e552f5f65c2914689083cc0c46c2Elliott Hughes    const u2* data = jstr->chars() + start;
312f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    convertUtf16ToUtf8(buf, data, len);
313f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
314f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
315d8a3f9fa1951e552f5f65c2914689083cc0c46c2Elliott Hughesint StringObject::utfLength() const
316f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
317cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein    assert(gDvm.classJavaLangString != NULL);
318f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
319d8a3f9fa1951e552f5f65c2914689083cc0c46c2Elliott Hughes    int len = dvmGetFieldInt(this, STRING_FIELDOFF_COUNT);
320d8a3f9fa1951e552f5f65c2914689083cc0c46c2Elliott Hughes    int offset = dvmGetFieldInt(this, STRING_FIELDOFF_OFFSET);
321fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes    ArrayObject* chars =
322d8a3f9fa1951e552f5f65c2914689083cc0c46c2Elliott Hughes            (ArrayObject*) dvmGetFieldObject(this, STRING_FIELDOFF_VALUE);
323fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes    const u2* data = (const u2*)(void*)chars->contents + offset;
324f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(offset + len <= (int) chars->length);
325f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
326f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return utf16_utf8ByteLen(data, len);
327f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
328f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
329d8a3f9fa1951e552f5f65c2914689083cc0c46c2Elliott Hughesint StringObject::length() const
330f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
331d8a3f9fa1951e552f5f65c2914689083cc0c46c2Elliott Hughes    return dvmGetFieldInt(this, STRING_FIELDOFF_COUNT);
332f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
333f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
334d8a3f9fa1951e552f5f65c2914689083cc0c46c2Elliott HughesArrayObject* StringObject::array() const
335ab00d455ea67fbf4090567bb09ead8017896ea61Andy McFadden{
336d8a3f9fa1951e552f5f65c2914689083cc0c46c2Elliott Hughes    return (ArrayObject*) dvmGetFieldObject(this, STRING_FIELDOFF_VALUE);
337ab00d455ea67fbf4090567bb09ead8017896ea61Andy McFadden}
338ab00d455ea67fbf4090567bb09ead8017896ea61Andy McFadden
339d8a3f9fa1951e552f5f65c2914689083cc0c46c2Elliott Hughesconst u2* StringObject::chars() const
340f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
341d8a3f9fa1951e552f5f65c2914689083cc0c46c2Elliott Hughes    int offset = dvmGetFieldInt(this, STRING_FIELDOFF_OFFSET);
342fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes    ArrayObject* chars =
343d8a3f9fa1951e552f5f65c2914689083cc0c46c2Elliott Hughes            (ArrayObject*) dvmGetFieldObject(this, STRING_FIELDOFF_VALUE);
344d5c36b9040bd26a81219a7f399513526f9b46324Carl Shapiro    return (const u2*)(void*)chars->contents + offset;
345f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
346f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
347f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
348f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
349f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Compare two String objects.
350f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
351f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This is a dvmHashTableLookup() callback.  The function has already
352f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * compared their hash values; we need to do a full compare to ensure
353f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * that the strings really match.
354f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
355f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectint dvmHashcmpStrings(const void* vstrObj1, const void* vstrObj2)
356f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
357f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const StringObject* strObj1 = (const StringObject*) vstrObj1;
358f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const StringObject* strObj2 = (const StringObject*) vstrObj2;
359f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
360cd380420ec1b52c3d6f0c7cc54b46ec29bb27dc0Dan Bornstein    assert(gDvm.classJavaLangString != NULL);
361f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
362f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* get offset and length into char array; all values are in 16-bit units */
363fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes    int len1 = dvmGetFieldInt(strObj1, STRING_FIELDOFF_COUNT);
364fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes    int offset1 = dvmGetFieldInt(strObj1, STRING_FIELDOFF_OFFSET);
365fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes    int len2 = dvmGetFieldInt(strObj2, STRING_FIELDOFF_COUNT);
366fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes    int offset2 = dvmGetFieldInt(strObj2, STRING_FIELDOFF_OFFSET);
367fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes    if (len1 != len2) {
368f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return len1 - len2;
369fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes    }
370f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
371fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes    ArrayObject* chars1 =
372fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes            (ArrayObject*) dvmGetFieldObject(strObj1, STRING_FIELDOFF_VALUE);
373fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes    ArrayObject* chars2 =
374fe7f2b3920bf5d66eda262e643245b03df3e57c8Elliott Hughes            (ArrayObject*) dvmGetFieldObject(strObj2, STRING_FIELDOFF_VALUE);
375f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
376f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* damage here actually indicates a broken java/lang/String */
377f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(offset1 + len1 <= (int) chars1->length);
378f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(offset2 + len2 <= (int) chars2->length);
379f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
380d5c36b9040bd26a81219a7f399513526f9b46324Carl Shapiro    return memcmp((const u2*)(void*)chars1->contents + offset1,
381d5c36b9040bd26a81219a7f399513526f9b46324Carl Shapiro                  (const u2*)(void*)chars2->contents + offset2,
382f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                  len1 * sizeof(u2));
383f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
38449dc060d5ae9bbcc78e570ec0dd244973e920fb6Elliott Hughes
3850fbb7030fff58e25718291811394487d95d95a3eElliott HughesArrayObject* dvmCreateStringArray(const std::vector<std::string>& strings) {
38649dc060d5ae9bbcc78e570ec0dd244973e920fb6Elliott Hughes    Thread* self = dvmThreadSelf();
38749dc060d5ae9bbcc78e570ec0dd244973e920fb6Elliott Hughes
3880fbb7030fff58e25718291811394487d95d95a3eElliott Hughes    // Allocate an array to hold the String objects.
3890fbb7030fff58e25718291811394487d95d95a3eElliott Hughes    ClassObject* elementClass = dvmFindArrayClassForElement(gDvm.classJavaLangString);
3900fbb7030fff58e25718291811394487d95d95a3eElliott Hughes    ArrayObject* stringArray = dvmAllocArrayByClass(elementClass, strings.size(), ALLOC_DEFAULT);
39149dc060d5ae9bbcc78e570ec0dd244973e920fb6Elliott Hughes    if (stringArray == NULL) {
3920fbb7030fff58e25718291811394487d95d95a3eElliott Hughes        // Probably OOM.
39349dc060d5ae9bbcc78e570ec0dd244973e920fb6Elliott Hughes        assert(dvmCheckException(self));
39449dc060d5ae9bbcc78e570ec0dd244973e920fb6Elliott Hughes        return NULL;
39549dc060d5ae9bbcc78e570ec0dd244973e920fb6Elliott Hughes    }
39649dc060d5ae9bbcc78e570ec0dd244973e920fb6Elliott Hughes
3970fbb7030fff58e25718291811394487d95d95a3eElliott Hughes    // Create the individual String objects and add them to the array.
3980fbb7030fff58e25718291811394487d95d95a3eElliott Hughes    for (size_t i = 0; i < strings.size(); i++) {
3990fbb7030fff58e25718291811394487d95d95a3eElliott Hughes        Object* str = (Object*) dvmCreateStringFromCstr(strings[i]);
40049dc060d5ae9bbcc78e570ec0dd244973e920fb6Elliott Hughes        if (str == NULL) {
4010fbb7030fff58e25718291811394487d95d95a3eElliott Hughes            // Probably OOM; drop out now.
40249dc060d5ae9bbcc78e570ec0dd244973e920fb6Elliott Hughes            assert(dvmCheckException(self));
40349dc060d5ae9bbcc78e570ec0dd244973e920fb6Elliott Hughes            dvmReleaseTrackedAlloc((Object*) stringArray, self);
40449dc060d5ae9bbcc78e570ec0dd244973e920fb6Elliott Hughes            return NULL;
40549dc060d5ae9bbcc78e570ec0dd244973e920fb6Elliott Hughes        }
40649dc060d5ae9bbcc78e570ec0dd244973e920fb6Elliott Hughes        dvmSetObjectArrayElement(stringArray, i, str);
40749dc060d5ae9bbcc78e570ec0dd244973e920fb6Elliott Hughes        /* stored in tracked array, okay to release */
40849dc060d5ae9bbcc78e570ec0dd244973e920fb6Elliott Hughes        dvmReleaseTrackedAlloc(str, self);
40949dc060d5ae9bbcc78e570ec0dd244973e920fb6Elliott Hughes    }
41049dc060d5ae9bbcc78e570ec0dd244973e920fb6Elliott Hughes
41149dc060d5ae9bbcc78e570ec0dd244973e920fb6Elliott Hughes    return stringArray;
41249dc060d5ae9bbcc78e570ec0dd244973e920fb6Elliott Hughes}
413