2 * Copyright (C) 2008 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * Functions for dealing with method prototypes
27 * ===========================================================================
29 * ===========================================================================
33 * Make sure that the given cache can hold a string of the given length,
34 * including the final '\0' byte.
36 void dexStringCacheAlloc(DexStringCache* pCache, size_t length) {
37 if (pCache->allocatedSize != 0) {
38 if (pCache->allocatedSize >= length) {
41 free((void*) pCache->value);
44 if (length <= sizeof(pCache->buffer)) {
45 pCache->value = pCache->buffer;
46 pCache->allocatedSize = 0;
48 pCache->value = (char*) malloc(length);
49 pCache->allocatedSize = length;
54 * Initialize the given DexStringCache. Use this function before passing
55 * one into any other function.
57 void dexStringCacheInit(DexStringCache* pCache) {
58 pCache->value = pCache->buffer;
59 pCache->allocatedSize = 0;
60 pCache->buffer[0] = '\0';
64 * Release the allocated contents of the given DexStringCache, if any.
65 * Use this function after your last use of a DexStringCache.
67 void dexStringCacheRelease(DexStringCache* pCache) {
68 if (pCache->allocatedSize != 0) {
69 free((void*) pCache->value);
70 pCache->value = pCache->buffer;
71 pCache->allocatedSize = 0;
76 * If the given DexStringCache doesn't already point at the given value,
77 * make a copy of it into the cache. This always returns a writable
78 * pointer to the contents (whether or not a copy had to be made). This
79 * function is intended to be used after making a call that at least
80 * sometimes doesn't populate a DexStringCache.
82 char* dexStringCacheEnsureCopy(DexStringCache* pCache, const char* value) {
83 if (value != pCache->value) {
84 size_t length = strlen(value) + 1;
85 dexStringCacheAlloc(pCache, length);
86 memcpy(pCache->value, value, length);
93 * Abandon the given DexStringCache, and return a writable copy of the
94 * given value (reusing the string cache's allocation if possible).
95 * The return value must be free()d by the caller. Use this instead of
96 * dexStringCacheRelease() if you want the buffer to survive past the
97 * scope of the DexStringCache.
99 char* dexStringCacheAbandon(DexStringCache* pCache, const char* value) {
100 if ((value == pCache->value) && (pCache->allocatedSize != 0)) {
101 char* result = pCache->value;
102 pCache->allocatedSize = 0;
103 pCache->value = pCache->buffer;
106 return strdup(value);
112 * ===========================================================================
114 * ===========================================================================
118 * Return the DexProtoId from the given DexProto. The DexProto must
119 * actually refer to a DexProtoId.
121 static inline const DexProtoId* getProtoId(const DexProto* pProto) {
122 return dexGetProtoId(pProto->dexFile, pProto->protoIdx);
125 /* (documented in header file) */
126 const char* dexProtoGetShorty(const DexProto* pProto) {
127 const DexProtoId* protoId = getProtoId(pProto);
129 return dexStringById(pProto->dexFile, protoId->shortyIdx);
132 /* (documented in header file) */
133 const char* dexProtoGetMethodDescriptor(const DexProto* pProto,
134 DexStringCache* pCache) {
135 const DexFile* dexFile = pProto->dexFile;
136 const DexProtoId* protoId = getProtoId(pProto);
137 const DexTypeList* typeList = dexGetProtoParameters(dexFile, protoId);
138 size_t length = 3; // parens and terminating '\0'
139 u4 paramCount = (typeList == NULL) ? 0 : typeList->size;
142 for (i = 0; i < paramCount; i++) {
143 u4 idx = dexTypeListGetIdx(typeList, i);
144 length += strlen(dexStringByTypeIdx(dexFile, idx));
147 length += strlen(dexStringByTypeIdx(dexFile, protoId->returnTypeIdx));
149 dexStringCacheAlloc(pCache, length);
151 char *at = (char*) pCache->value;
154 for (i = 0; i < paramCount; i++) {
155 u4 idx = dexTypeListGetIdx(typeList, i);
156 const char* desc = dexStringByTypeIdx(dexFile, idx);
163 strcpy(at, dexStringByTypeIdx(dexFile, protoId->returnTypeIdx));
164 return pCache->value;
167 /* (documented in header file) */
168 char* dexProtoCopyMethodDescriptor(const DexProto* pProto) {
169 DexStringCache cache;
171 dexStringCacheInit(&cache);
172 return dexStringCacheAbandon(&cache,
173 dexProtoGetMethodDescriptor(pProto, &cache));
176 /* (documented in header file) */
177 const char* dexProtoGetParameterDescriptors(const DexProto* pProto,
178 DexStringCache* pCache) {
179 DexParameterIterator iterator;
180 size_t length = 1; /* +1 for the terminating '\0' */
182 dexParameterIteratorInit(&iterator, pProto);
185 const char* descriptor = dexParameterIteratorNextDescriptor(&iterator);
186 if (descriptor == NULL) {
190 length += strlen(descriptor);
193 dexParameterIteratorInit(&iterator, pProto);
195 dexStringCacheAlloc(pCache, length);
196 char *at = (char*) pCache->value;
199 const char* descriptor = dexParameterIteratorNextDescriptor(&iterator);
200 if (descriptor == NULL) {
204 strcpy(at, descriptor);
205 at += strlen(descriptor);
208 return pCache->value;
211 /* (documented in header file) */
212 const char* dexProtoGetReturnType(const DexProto* pProto) {
213 const DexProtoId* protoId = getProtoId(pProto);
214 return dexStringByTypeIdx(pProto->dexFile, protoId->returnTypeIdx);
217 /* (documented in header file) */
218 size_t dexProtoGetParameterCount(const DexProto* pProto) {
219 const DexProtoId* protoId = getProtoId(pProto);
220 const DexTypeList* typeList =
221 dexGetProtoParameters(pProto->dexFile, protoId);
222 return (typeList == NULL) ? 0 : typeList->size;
225 /* (documented in header file) */
226 int dexProtoComputeArgsSize(const DexProto* pProto) {
227 const char* shorty = dexProtoGetShorty(pProto);
230 /* Skip the return type. */
234 switch (*(shorty++)) {
252 * Common implementation for dexProtoCompare() and dexProtoCompareParameters().
254 static int protoCompare(const DexProto* pProto1, const DexProto* pProto2,
255 bool compareReturnType) {
257 if (pProto1 == pProto2) {
261 const DexFile* dexFile1 = pProto1->dexFile;
262 const DexProtoId* protoId1 = getProtoId(pProto1);
263 const DexTypeList* typeList1 =
264 dexGetProtoParameters(dexFile1, protoId1);
265 int paramCount1 = (typeList1 == NULL) ? 0 : typeList1->size;
267 const DexFile* dexFile2 = pProto2->dexFile;
268 const DexProtoId* protoId2 = getProtoId(pProto2);
269 const DexTypeList* typeList2 =
270 dexGetProtoParameters(dexFile2, protoId2);
271 int paramCount2 = (typeList2 == NULL) ? 0 : typeList2->size;
273 if (protoId1 == protoId2) {
278 // Compare return types.
280 if (compareReturnType) {
282 strcmp(dexStringByTypeIdx(dexFile1, protoId1->returnTypeIdx),
283 dexStringByTypeIdx(dexFile2, protoId2->returnTypeIdx));
290 // Compare parameters.
292 int minParam = (paramCount1 > paramCount2) ? paramCount2 : paramCount1;
295 for (i = 0; i < minParam; i++) {
296 u4 idx1 = dexTypeListGetIdx(typeList1, i);
297 u4 idx2 = dexTypeListGetIdx(typeList2, i);
299 strcmp(dexStringByTypeIdx(dexFile1, idx1),
300 dexStringByTypeIdx(dexFile2, idx2));
307 if (paramCount1 < paramCount2) {
309 } else if (paramCount1 > paramCount2) {
317 /* (documented in header file) */
318 int dexProtoCompare(const DexProto* pProto1, const DexProto* pProto2) {
319 return protoCompare(pProto1, pProto2, true);
322 /* (documented in header file) */
323 int dexProtoCompareParameters(const DexProto* pProto1, const DexProto* pProto2){
324 return protoCompare(pProto1, pProto2, false);
329 * Helper for dexProtoCompareToDescriptor(), which gets the return type
330 * descriptor from a method descriptor string.
332 static const char* methodDescriptorReturnType(const char* descriptor) {
333 const char* result = strchr(descriptor, ')');
335 if (result == NULL) {
339 // The return type is the character just past the ')'.
344 * Helper for dexProtoCompareToDescriptor(), which indicates the end
345 * of an embedded argument type descriptor, which is also the
346 * beginning of the next argument type descriptor. Since this is for
347 * argument types, it doesn't accept 'V' as a valid type descriptor.
349 static const char* methodDescriptorNextType(const char* descriptor) {
350 // Skip any array references.
352 while (*descriptor == '[') {
356 switch (*descriptor) {
357 case 'B': case 'C': case 'D': case 'F':
358 case 'I': case 'J': case 'S': case 'Z': {
359 return descriptor + 1;
362 const char* result = strchr(descriptor + 1, ';');
363 if (result != NULL) {
364 // The type ends just past the ';'.
374 * Common implementation for dexProtoCompareToDescriptor() and
375 * dexProtoCompareToParameterDescriptors(). The descriptor argument
376 * can be either a full method descriptor (with parens and a return
377 * type) or an unadorned concatenation of types (e.g. a list of
380 static int protoCompareToParameterDescriptors(const DexProto* proto,
381 const char* descriptor, bool expectParens) {
382 char expectedEndChar = expectParens ? ')' : '\0';
383 DexParameterIterator iterator;
384 dexParameterIteratorInit(&iterator, proto);
388 assert (*descriptor == '(');
393 const char* protoDesc = dexParameterIteratorNextDescriptor(&iterator);
395 if (*descriptor == expectedEndChar) {
396 // It's the end of the descriptor string.
397 if (protoDesc == NULL) {
398 // It's also the end of the prototype's arguments.
401 // The prototype still has more arguments.
406 if (protoDesc == NULL) {
408 * The prototype doesn't have arguments left, but the
409 * descriptor string does.
414 // Both prototype and descriptor have arguments. Compare them.
416 const char* nextDesc = methodDescriptorNextType(descriptor);
417 assert(nextDesc != NULL);
420 char c1 = *(protoDesc++);
421 char c2 = (descriptor < nextDesc) ? *(descriptor++) : '\0';
424 // This includes the case where the proto is shorter.
426 } else if (c1 > c2) {
427 // This includes the case where the desc is shorter.
429 } else if (c1 == '\0') {
430 // The two types are equal in length. (c2 necessarily == '\0'.)
436 * If we made it here, the two arguments matched, and
437 * descriptor == nextDesc.
442 /* (documented in header file) */
443 int dexProtoCompareToDescriptor(const DexProto* proto,
444 const char* descriptor) {
445 // First compare the return types.
447 const char *returnType = methodDescriptorReturnType(descriptor);
448 assert(returnType != NULL);
450 int result = strcmp(dexProtoGetReturnType(proto), returnType);
456 // The return types match, so we have to check arguments.
457 return protoCompareToParameterDescriptors(proto, descriptor, true);
460 /* (documented in header file) */
461 int dexProtoCompareToParameterDescriptors(const DexProto* proto,
462 const char* descriptors) {
463 return protoCompareToParameterDescriptors(proto, descriptors, false);
472 * ===========================================================================
473 * Parameter Iterators
474 * ===========================================================================
478 * Initialize the given DexParameterIterator to be at the start of the
479 * parameters of the given prototype.
481 void dexParameterIteratorInit(DexParameterIterator* pIterator,
482 const DexProto* pProto) {
483 pIterator->proto = pProto;
484 pIterator->cursor = 0;
486 pIterator->parameters =
487 dexGetProtoParameters(pProto->dexFile, getProtoId(pProto));
488 pIterator->parameterCount = (pIterator->parameters == NULL) ? 0
489 : pIterator->parameters->size;
493 * Get the type_id index for the next parameter, if any. This returns
494 * kDexNoIndex if the last parameter has already been consumed.
496 u4 dexParameterIteratorNextIndex(DexParameterIterator* pIterator) {
497 int cursor = pIterator->cursor;
498 int parameterCount = pIterator->parameterCount;
500 if (cursor >= parameterCount) {
501 // The iteration is complete.
504 u4 idx = dexTypeListGetIdx(pIterator->parameters, cursor);
511 * Get the type descriptor for the next parameter, if any. This returns
512 * NULL if the last parameter has already been consumed.
514 const char* dexParameterIteratorNextDescriptor(
515 DexParameterIterator* pIterator) {
516 u4 idx = dexParameterIteratorNextIndex(pIterator);
518 if (idx == kDexNoIndex) {
522 return dexStringByTypeIdx(pIterator->proto->dexFile, idx);