Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Android/art/art/libdexfile/dex/   (Android Betriebssystem Version 17©)  Datei vom 26.5.2026 mit Größe 14 kB image not shown  

Quelle  descriptors_names.cc

  Sprache: C
 

/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


#include "descriptors_names.h"

#include <algorithm>

#include "android-base/stringprintf.h"
#include "android-base/strings.h"

#include "base/macros.h"
#include "dex/utf-inl.h"

namespace art {

using android::base::StringAppendF;

void AppendPrettyDescriptor(const char* descriptor, std::string* result) {
  // Count the number of '['s to get the dimensionality.
  const char* c = descriptor;
  size_t dim = 0;
  while (*c == '[') {
    dim++;
    c++;
  }

  // Reference or primitive?
  if (*c == 'L') {
    // "[[La/b/C;" -> "a.b.C[][]".
    std::string_view stripped = std::string_view(c + 1);  // Skip the 'L'...
    if (stripped.ends_with(';')) {
      stripped.remove_suffix(1u);  // ...and remove the semicolon.
    }
    // At this point, `stripped` is of the form "fully/qualified/Type".
    // Append it to the `*result` and replace all '/'s with '.' in place.
    size_t old_size = result->size();
    *result += stripped;
    std::replace(result->begin() + old_size, result->end(), '/''.');
  } else {
    // "[[B" -> "byte[][]".
    std::string_view pretty_primitive;
    switch (*c) {
      case 'B':
        pretty_primitive = "byte";
        break;
      case 'C':
        pretty_primitive = "char";
        break;
      case 'D':
        pretty_primitive = "double";
        break;
      case 'F':
        pretty_primitive = "float";
        break;
      case 'I':
        pretty_primitive = "int";
        break;
      case 'J':
        pretty_primitive = "long";
        break;
      case 'S':
        pretty_primitive = "short";
        break;
      case 'Z':
        pretty_primitive = "boolean";
        break;
      case 'V':
        pretty_primitive = "void";
        break;  // Used when decoding return types.
      default: result->append(descriptor); return;
    }
    result->append(pretty_primitive);
  }

  // Finally, add 'dim' "[]" pairs:
  for (size_t i = 0; i < dim; ++i) {
    result->append("[]");
  }
}

std::string PrettyDescriptor(const char* descriptor) {
  std::string result;
  AppendPrettyDescriptor(descriptor, &result);
  return result;
}

std::string InversePrettyDescriptor(const std::string& pretty_descriptor) {
  std::string result;

  // Used to determine the length of the descriptor without trailing "[]"s.
  size_t l = pretty_descriptor.length();

  // Determine dimensionality, and append the necessary leading '['s.
  size_t dim = 0;
  size_t pos = 0;
  static const std::string array_indicator = "[]";
  while ((pos = pretty_descriptor.find(array_indicator, pos)) != std::string::npos) {
    if (dim == 0) {
      l = pos;
    }
    ++dim;
    pos += array_indicator.length();
  }
  for (size_t i = 0; i < dim; ++i) {
    result += '[';
  }

  // temp_descriptor is now in the form of "some.pretty.Type" or "primitive".
  std::string temp_descriptor(pretty_descriptor, 0, l);
  if (temp_descriptor == "byte") {
    result += 'B';
  } else if (temp_descriptor == "char") {
    result += 'C';
  } else if (temp_descriptor == "double") {
    result += 'D';
  } else if (temp_descriptor == "float") {
    result += 'F';
  } else if (temp_descriptor == "int") {
    result += 'I';
  } else if (temp_descriptor == "long") {
    result += 'J';
  } else if (temp_descriptor == "short") {
    result += 'S';
  } else if (temp_descriptor == "boolean") {
    result += 'Z';
  } else if (temp_descriptor == "void") {
    result += 'V';
  } else {
    result += 'L';
    std::replace(temp_descriptor.begin(), temp_descriptor.end(), '.''/');
    result += temp_descriptor;
    result += ';';
  }
  return result;
}

std::string GetJniShortName(const std::string& class_descriptor, const std::string& method) {
  // Remove the leading 'L' and trailing ';'...
  std::string class_name(class_descriptor);
  CHECK_EQ(class_name[0], 'L') << class_name;
  CHECK_EQ(class_name[class_name.size() - 1], ';') << class_name;
  class_name.erase(01);
  class_name.erase(class_name.size() - 11);

  std::string short_name;
  short_name += "Java_";
  short_name += MangleForJni(class_name);
  short_name += "_";
  short_name += MangleForJni(method);
  return short_name;
}

// See http://java.sun.com/j2se/1.5.0/docs/guide/jni/spec/design.html#wp615 for the full rules.
std::string MangleForJni(const std::string& s) {
  std::string result;
  size_t char_count = CountModifiedUtf8Chars(s.c_str());
  const char* cp = &s[0];
  for (size_t i = 0; i < char_count; ++i) {
    uint32_t ch = GetUtf16FromUtf8(&cp);
    if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')) {
      result.push_back(ch);
    } else if (ch == '.' || ch == '/') {
      result += "_";
    } else if (ch == '_') {
      result += "_1";
    } else if (ch == ';') {
      result += "_2";
    } else if (ch == '[') {
      result += "_3";
    } else {
      const uint16_t leading = GetLeadingUtf16Char(ch);
      const uint32_t trailing = GetTrailingUtf16Char(ch);

      StringAppendF(&result, "_0%04x", leading);
      if (trailing != 0) {
        StringAppendF(&result, "_0%04x", trailing);
      }
    }
  }
  return result;
}

std::string DotToDescriptor(std::string_view class_name) {
  std::string descriptor(class_name);
  std::replace(descriptor.begin(), descriptor.end(), '.''/');
  if (descriptor.length() > 0 && descriptor[0] != '[') {
    descriptor.insert(descriptor.begin(), 'L');
    descriptor.insert(descriptor.end(), ';');
  }
  return descriptor;
}

std::string DescriptorToDot(std::string_view descriptor) {
  size_t length = descriptor.length();
  if (length > 1) {
    if (descriptor[0] == 'L' && descriptor[length - 1] == ';') {
      // Descriptors have the leading 'L' and trailing ';' stripped.
      std::string result(descriptor.substr(1, length - 2));
      std::replace(result.begin(), result.end(), '/''.');
      return result;
    } else {
      // For arrays the 'L' and ';' remain intact.
      std::string result(descriptor);
      std::replace(result.begin(), result.end(), '/''.');
      return result;
    }
  }
  // Do nothing for non-class/array descriptors.
  return std::string(descriptor);
}

std::string DescriptorToName(std::string_view descriptor) {
  size_t length = descriptor.length();
  if (descriptor[0] == 'L' && descriptor[length - 1] == ';') {
    std::string result(descriptor.substr(1, length - 2));
    return result;
  }
  return std::string(descriptor);
}

// Helper for IsValidPartOfMemberNameUtf8(), a bit vector indicating valid low ascii.
static constexpr uint32_t DEX_MEMBER_VALID_LOW_ASCII[4] = {
  0x00000000,  // 00..1f low control characters; nothing valid
  0x03ff2011,  // 20..3f space, digits and symbols; valid: ' ', '0'..'9', '$', '-'
  0x87fffffe,  // 40..5f uppercase etc.; valid: 'A'..'Z', '_'
  0x07fffffe   // 60..7f lowercase etc.; valid: 'a'..'z'
};

// Helper for IsValidPartOfMemberNameUtf8(); do not call directly.
COLD_ATTR
static bool IsValidPartOfMemberNameUtf8Slow(const char** pUtf8Ptr) {
  /*
   * It's a multibyte encoded character. Decode it and analyze. We
   * accept anything that isn't:
   *   - an improperly encoded low value
   *   - an improper surrogate pair
   *   - an encoded '\0'
   *   - a C1 control character U+0080..U+009f
   *   - a format character U+200b..U+200f, U+2028..U+202e
   *   - a special character U+fff0..U+ffff
   * Prior to DEX format version 040, we also excluded some of the Unicode
   * space characters:
   *   - U+00a0, U+2000..U+200a, U+202f
   * This is all specified in the dex format document.
   */


  const uint32_t pair = GetUtf16FromUtf8(pUtf8Ptr);
  const uint16_t leading = GetLeadingUtf16Char(pair);

  // We have a surrogate pair resulting from a valid 4 byte UTF sequence.
  // No further checks are necessary because 4 byte sequences span code
  // points [U+10000, U+1FFFFF], which are valid codepoints in a dex
  // identifier. Furthermore, GetUtf16FromUtf8 guarantees that each of
  // the surrogate halves are valid and well formed in this instance.
  if (GetTrailingUtf16Char(pair) != 0) {
    return true;
  }


  // We've encountered a one, two or three byte UTF-8 sequence. The
  // three byte UTF-8 sequence could be one half of a surrogate pair.
  switch (leading >> 8) {
    case 0x00:
      // It's in the range that has C1 control characters.
      return (leading >= 0x00a0);
    case 0xd8:
    case 0xd9:
    case 0xda:
    case 0xdb:
      {
        // We found a three byte sequence encoding one half of a surrogate.
        // Look for the other half.
        const uint32_t pair2 = GetUtf16FromUtf8(pUtf8Ptr);
        const uint16_t trailing = GetLeadingUtf16Char(pair2);

        return (GetTrailingUtf16Char(pair2) == 0) && (0xdc00 <= trailing && trailing <= 0xdfff);
      }
    case 0xdc:
    case 0xdd:
    case 0xde:
    case 0xdf:
      // It's a trailing surrogate, which is not valid at this point.
      return false;
    case 0x20:
    case 0xff:
      // It's in the range that has format characters and specials.
      switch (leading & 0xfff8) {
        case 0x2008:
          return (leading <= 0x200a);
        case 0x2028:
          return (leading == 0x202f);
        case 0xfff0:
        case 0xfff8:
          return false;
      }
      return true;
    default:
      return true;
  }
}

/* Return whether the pointed-at modified-UTF-8 encoded character is
 * valid as part of a member name, updating the pointer to point past
 * the consumed character. This will consume two encoded UTF-16 code
 * points if the character is encoded as a surrogate pair. Also, if
 * this function returns false, then the given pointer may only have
 * been partially advanced.
 */

ALWAYS_INLINE
static bool IsValidPartOfMemberNameUtf8(const char** pUtf8Ptr) {
  uint8_t c = (uint8_t) **pUtf8Ptr;
  if (LIKELY(c <= 0x7f)) {
    // It's low-ascii, so check the table.
    uint32_t wordIdx = c >> 5;
    uint32_t bitIdx = c & 0x1f;
    (*pUtf8Ptr)++;
    return (DEX_MEMBER_VALID_LOW_ASCII[wordIdx] & (1 << bitIdx)) != 0;
  }

  // It's a multibyte encoded character. Call a non-inline function
  // for the heavy lifting.
  return IsValidPartOfMemberNameUtf8Slow(pUtf8Ptr);
}

bool IsValidMemberName(const char* s) {
  bool angle_name = false;

  switch (*s) {
    case '\0':
      // The empty string is not a valid name.
      return false;
    case '<':
      angle_name = true;
      s++;
      break;
  }

  while (true) {
    switch (*s) {
      case '\0':
        return !angle_name;
      case '>':
        return angle_name && s[1] == '\0';
    }

    if (!IsValidPartOfMemberNameUtf8(&s)) {
      return false;
    }
  }
}

enum ClassNameType { kName, kDescriptor };
template<ClassNameType kType, char kSeparator>
static bool IsValidClassName(const char* s) {
  int arrayCount = 0;
  while (*s == '[') {
    arrayCount++;
    s++;
  }

  if (arrayCount > 255) {
    // Arrays may have no more than 255 dimensions.
    return false;
  }

  ClassNameType type = kType;
  if (type != kDescriptor && arrayCount != 0) {
    /*
     * If we're looking at an array of some sort, then it doesn't
     * matter if what is being asked for is a class name; the
     * format looks the same as a type descriptor in that case, so
     * treat it as such.
     */

    type = kDescriptor;
  }

  if (type == kDescriptor) {
    /*
     * We are looking for a descriptor. Either validate it as a
     * single-character primitive type, or continue on to check the
     * embedded class name (bracketed by "L" and ";").
     */

    switch (*(s++)) {
    case 'B':
    case 'C':
    case 'D':
    case 'F':
    case 'I':
    case 'J':
    case 'S':
    case 'Z':
      // These are all single-character descriptors for primitive types.
      return (*s == '\0');
    case 'V':
      // Non-array void is valid, but you can't have an array of void.
      return (arrayCount == 0) && (*s == '\0');
    case 'L':
      // Class name: Break out and continue below.
      break;
    default:
      // Oddball descriptor character.
      return false;
    }
  }

  /*
   * We just consumed the 'L' that introduces a class name as part
   * of a type descriptor, or we are looking for an unadorned class
   * name.
   */


  bool sepOrFirst = true;  // first character or just encountered a separator.
  for (;;) {
    uint8_t c = (uint8_t) *s;
    switch (c) {
    case '\0':
      /*
       * Premature end for a type descriptor, but valid for
       * a class name as long as we haven't encountered an
       * empty component (including the degenerate case of
       * the empty string "").
       */

      return (type == kName) && !sepOrFirst;
    case ';':
      /*
       * Invalid character for a class name, but the
       * legitimate end of a type descriptor. In the latter
       * case, make sure that this is the end of the string
       * and that it doesn't end with an empty component
       * (including the degenerate case of "L;").
       */

      return (type == kDescriptor) && !sepOrFirst && (s[1] == '\0');
    case '/':
    case '.':
      if (c != kSeparator) {
        // The wrong separator character.
        return false;
      }
      if (sepOrFirst) {
        // Separator at start or two separators in a row.
        return false;
      }
      sepOrFirst = true;
      s++;
      break;
    default:
      if (!IsValidPartOfMemberNameUtf8(&s)) {
        return false;
      }
      sepOrFirst = false;
      break;
    }
  }
}

bool IsValidBinaryClassName(const char* s) {
  return IsValidClassName<kName, '.'>(s);
}

bool IsValidJniClassName(const char* s) {
  return IsValidClassName<kName, '/'>(s);
}

bool IsValidDescriptor(const char* s) {
  return IsValidClassName<kDescriptor, '/'>(s);
}

std::string PrettyDescriptor(Primitive::Type type) {
  return PrettyDescriptor(Primitive::Descriptor(type));
}

}  // namespace art

Messung V0.5 in Prozent
C=88 H=95 G=91

¤ Dauer der Verarbeitung: 0.13 Sekunden  (vorverarbeitet am  2026-06-29) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.