/* Copyright 2017 - 2026 R. Thomas
* Copyright 2017 - 2026 Quarkslab
*
* 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 "LIEF/DEX/Type.hpp"
#include "LIEF/DEX/hash.hpp"
#include "LIEF/DEX/Class.hpp"
#include "logging.hpp"
namespace LIEF::DEX {
Type::Type() = default;
Type::Type(const std::string& mangled) {
parse(mangled);
}
Type::Type(const Type& other) :
Object{other},
type_{other.type_} {
switch (type()) {
case TYPES::ARRAY:
{
array_ = new array_t{};
std::copy(other.array().begin(), other.array().end(),
std::back_inserter(*array_));
break;
}
case TYPES::CLASS:
{
cls_ = other.cls_;
break;
}
case TYPES::PRIMITIVE:
{
basic_ = new PRIMITIVES{other.primitive()};
break;
}
default:
{
}
}
}
Type::TYPES Type::type() const {
return type_;
}
const Class& Type::cls() const {
return *cls_;
}
const Type::array_t& Type::array() const {
return *array_;
}
const Type::PRIMITIVES& Type::primitive() const {
return *basic_;
}
Class& Type::cls() {
return const_cast<Class&>(static_cast<const Type*>(this)->cls());
}
Type::array_t& Type::array() {
return const_cast<Type::array_t&>(static_cast<const Type*>(this)->array());
}
Type::PRIMITIVES& Type::primitive() {
return const_cast<Type::PRIMITIVES&>(
static_cast<const Type*>(this)->primitive()
);
}
const Type& Type::underlying_array_type() const {
const Type* underlying_type = this;
while (underlying_type->type() == TYPES::ARRAY) {
underlying_type = &underlying_type->array().back();
}
return *underlying_type;
}
Type& Type::underlying_array_type() {
return const_cast<Type&>(
(static_cast<const Type*>(this)->underlying_array_type())
);
}
void Type::parse(const std::string& type) {
if (type.empty()) {
type_ = Type::TYPES::UNKNOWN;
return;
}
const char t = type[0];
switch (t) {
case 'V':
{
type_ = Type::TYPES::PRIMITIVE;
basic_ = new Type::PRIMITIVES{Type::PRIMITIVES::VOID_T};
break;
}
case 'Z':
{
type_ = Type::TYPES::PRIMITIVE;
basic_ = new Type::PRIMITIVES{Type::PRIMITIVES::BOOLEAN};
break;
}
case 'B':
{
type_ = Type::TYPES::PRIMITIVE;
basic_ = new Type::PRIMITIVES{Type::PRIMITIVES::BYTE};
break;
}
case 'S':
{
type_ = Type::TYPES::PRIMITIVE;
basic_ = new Type::PRIMITIVES{Type::PRIMITIVES::SHORT};
break;
}
case 'C':
{
type_ = Type::TYPES::PRIMITIVE;
basic_ = new Type::PRIMITIVES{Type::PRIMITIVES::CHAR};
break;
}
case 'I':
{
type_ = Type::TYPES::PRIMITIVE;
basic_ = new Type::PRIMITIVES{Type::PRIMITIVES::INT};
break;
}
case 'J':
{
type_ = Type::TYPES::PRIMITIVE;
basic_ = new Type::PRIMITIVES{Type::PRIMITIVES::LONG};
break;
}
case 'F':
{
type_ = Type::TYPES::PRIMITIVE;
basic_ = new Type::PRIMITIVES{Type::PRIMITIVES::FLOAT};
break;
}
case 'D':
{
type_ = Type::TYPES::PRIMITIVE;
basic_ = new Type::PRIMITIVES{Type::PRIMITIVES::DOUBLE};
break;
}
case 'L': // CLASS
{
type_ = Type::TYPES::CLASS;
break;
}
case '[': // ARRAY
{
if (array_ == nullptr) {
array_ = new array_t{};
}
type_ = Type::TYPES::ARRAY;
array_->emplace_back(type.substr(1));
break;
}
default:
{
LIEF_WARN("Unknown type: '{}'", t);
}
}
}
size_t Type::dim() const {
if (type() != TYPES::ARRAY) {
return 0;
}
const Type* t = this;
size_t d = 0;
while (t->type() == TYPES::ARRAY) {
++d;
t = &(t->array().back());
}
return d;
}
void Type::accept(Visitor& visitor) const {
visitor.visit(*this);
}
std::ostream& operator<<(std::ostream& os, const Type& type) {
switch (type.type()) {
case Type::TYPES::ARRAY:
{
os << type.underlying_array_type();
for (size_t i = 0; i < type.dim(); ++i) {
os << "[]";
}
return os;
}
case Type::TYPES::CLASS:
{
os << type.cls().fullname();
return os;
}
case Type::TYPES::PRIMITIVE:
{
os << Type::pretty_name(type.primitive());
return os;
}
default:
{
return os;
}
}
return os;
}
std::string Type::pretty_name(PRIMITIVES p) {
switch (p) {
case PRIMITIVES::BOOLEAN:
{
return "bool";
}
case PRIMITIVES::BYTE:
{
return "byte";
}
case PRIMITIVES::CHAR:
{
return "char";
}
case PRIMITIVES::DOUBLE:
{
return "double";
}
case PRIMITIVES::FLOAT:
{
return "float";
}
case PRIMITIVES::INT:
{
return "int";
}
case PRIMITIVES::LONG:
{
return "long";
}
case PRIMITIVES::SHORT:
{
return "short";
}
case PRIMITIVES::VOID_T:
{
return "void";
}
default:
{
return "";
}
}
}
Type::~Type() {
switch (type()) {
case Type::TYPES::ARRAY:
{
delete array_;
break;
}
case Type::TYPES::PRIMITIVE:
{
delete basic_;
break;
}
case Type::TYPES::CLASS:
case Type::TYPES::UNKNOWN:
default:
{
}
}
}
}