/*
 * Copyright (C) 2018 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.
 */

#ifndef ART_LIBDEXFILE_DEX_CLASS_ACCESSOR_INL_H_
#define ART_LIBDEXFILE_DEX_CLASS_ACCESSOR_INL_H_

#include "class_accessor.h"

#include "base/hiddenapi_flags.h"
#include "base/leb128.h"
#include "base/utils.h"
#include "class_iterator.h"
#include "code_item_accessors-inl.h"
#include "dex_file.h"
#include "method_reference.h"

namespace art {

inline ClassAccessor::ClassAccessor(const ClassIteratorData& data)
    : ClassAccessor(data.dex_file_, data.class_def_idx_) {}

inline ClassAccessor::ClassAccessor(const DexFile& dex_file,
                                    const dex::ClassDef& class_def,
                                    bool parse_hiddenapi_class_data)
    : ClassAccessor(dex_file,
                    dex_file.GetClassData(class_def),
                    dex_file.GetIndexForClassDef(class_def),
                    parse_hiddenapi_class_data) {}

inline ClassAccessor::ClassAccessor(const DexFile& dex_file, uint32_t class_def_index)
    : ClassAccessor(dex_file, dex_file.GetClassDef(class_def_index)) {}

inline ClassAccessor::ClassAccessor(const DexFile& dex_file,
                                    const uint8_t* class_data,
                                    uint32_t class_def_index,
                                    bool parse_hiddenapi_class_data)
    : dex_file_(dex_file),
      class_def_index_(class_def_index),
      ptr_pos_(class_data),
      hiddenapi_ptr_pos_(nullptr),
      num_static_fields_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u),
      num_instance_fields_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u),
      num_direct_methods_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u),
      num_virtual_methods_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u) {
  if (parse_hiddenapi_class_data && class_def_index != DexFile::kDexNoIndex32) {
    const dex::HiddenapiClassData* hiddenapi_class_data = dex_file.GetHiddenapiClassData();
    if (hiddenapi_class_data != nullptr) {
      hiddenapi_ptr_pos_ = hiddenapi_class_data->GetFlagsPointer(class_def_index);
    }
  }
}

inline void ClassAccessor::Method::Read() {
  index_ += DecodeUnsignedLeb128(&ptr_pos_);
  access_flags_ = DecodeUnsignedLeb128(&ptr_pos_);
  code_off_ = DecodeUnsignedLeb128(&ptr_pos_);
  if (hiddenapi_ptr_pos_ != nullptr) {
    hiddenapi_flags_ = DecodeUnsignedLeb128(&hiddenapi_ptr_pos_);
    DCHECK(hiddenapi::AreValidDexFlags(hiddenapi_flags_));
  }
}

inline MethodReference ClassAccessor::Method::GetReference() const {
  return MethodReference(&dex_file_, GetIndex());
}


inline void ClassAccessor::Field::Read() {
  index_ += DecodeUnsignedLeb128(&ptr_pos_);
  access_flags_ = DecodeUnsignedLeb128(&ptr_pos_);
  if (hiddenapi_ptr_pos_ != nullptr) {
    hiddenapi_flags_ = DecodeUnsignedLeb128(&hiddenapi_ptr_pos_);
    DCHECK(hiddenapi::AreValidDexFlags(hiddenapi_flags_));
  }
}

template <typename DataType, typename Visitor>
inline void ClassAccessor::VisitMembers(size_t count,
                                        const Visitor& visitor,
                                        DataType* data) const {
  DCHECK(data != nullptr);
  for ( ; count != 0; --count) {
    data->Read();
    visitor(*data);
  }
}

template <typename StaticFieldVisitor,
          typename InstanceFieldVisitor,
          typename DirectMethodVisitor,
          typename VirtualMethodVisitor>
inline void ClassAccessor::VisitFieldsAndMethods(
    const StaticFieldVisitor& static_field_visitor,
    const InstanceFieldVisitor& instance_field_visitor,
    const DirectMethodVisitor& direct_method_visitor,
    const VirtualMethodVisitor& virtual_method_visitor) const {
  Field field(dex_file_, ptr_pos_, hiddenapi_ptr_pos_);
  VisitMembers(num_static_fields_, static_field_visitor, &field);
  field.NextSection();
  VisitMembers(num_instance_fields_, instance_field_visitor, &field);

  Method method(dex_file_, field.ptr_pos_, field.hiddenapi_ptr_pos_, /*is_static_or_direct*/ true);
  VisitMembers(num_direct_methods_, direct_method_visitor, &method);
  method.NextSection();
  VisitMembers(num_virtual_methods_, virtual_method_visitor, &method);
}

template <typename DirectMethodVisitor,
          typename VirtualMethodVisitor>
inline void ClassAccessor::VisitMethods(const DirectMethodVisitor& direct_method_visitor,
                                        const VirtualMethodVisitor& virtual_method_visitor) const {
  VisitFieldsAndMethods(VoidFunctor(),
                        VoidFunctor(),
                        direct_method_visitor,
                        virtual_method_visitor);
}

template <typename StaticFieldVisitor,
          typename InstanceFieldVisitor>
inline void ClassAccessor::VisitFields(const StaticFieldVisitor& static_field_visitor,
                                       const InstanceFieldVisitor& instance_field_visitor) const {
  VisitFieldsAndMethods(static_field_visitor,
                        instance_field_visitor,
                        VoidFunctor(),
                        VoidFunctor());
}

inline const dex::CodeItem* ClassAccessor::GetCodeItem(const Method& method) const {
  return dex_file_.GetCodeItem(method.GetCodeItemOffset());
}

inline CodeItemInstructionAccessor ClassAccessor::Method::GetInstructions() const {
  return CodeItemInstructionAccessor(dex_file_, dex_file_.GetCodeItem(GetCodeItemOffset()));
}

inline CodeItemDataAccessor ClassAccessor::Method::GetInstructionsAndData() const {
  return CodeItemDataAccessor(dex_file_, dex_file_.GetCodeItem(GetCodeItemOffset()));
}

inline const char* ClassAccessor::GetDescriptor() const {
  return dex_file_.StringByTypeIdx(GetClassIdx());
}

inline const dex::CodeItem* ClassAccessor::Method::GetCodeItem() const {
  return dex_file_.GetCodeItem(code_off_);
}

inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Field>>
    ClassAccessor::GetFieldsInternal(size_t count) const {
  return {
      DataIterator<Field>(dex_file_,
                          0u,
                          num_static_fields_,
                          count,
                          ptr_pos_,
                          hiddenapi_ptr_pos_),
      DataIterator<Field>(dex_file_,
                          count,
                          num_static_fields_,
                          count,
                          // The following pointers are bogus but unused in the `end` iterator.
                          ptr_pos_,
                          hiddenapi_ptr_pos_) };
}

// Return an iteration range for the first <count> methods.
inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Method>>
    ClassAccessor::GetMethodsInternal(size_t count) const {
  // Skip over the fields.
  Field field(dex_file_, ptr_pos_, hiddenapi_ptr_pos_);
  VisitMembers(NumFields(), VoidFunctor(), &field);
  // Return the iterator pair.
  return {
      DataIterator<Method>(dex_file_,
                           0u,
                           num_direct_methods_,
                           count,
                           field.ptr_pos_,
                           field.hiddenapi_ptr_pos_),
      DataIterator<Method>(dex_file_,
                           count,
                           num_direct_methods_,
                           count,
                           // The following pointers are bogus but unused in the `end` iterator.
                           field.ptr_pos_,
                           field.hiddenapi_ptr_pos_) };
}

inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Field>> ClassAccessor::GetFields()
    const {
  return GetFieldsInternal(num_static_fields_ + num_instance_fields_);
}

inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Field>>
    ClassAccessor::GetStaticFields() const {
  return GetFieldsInternal(num_static_fields_);
}


inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Field>>
    ClassAccessor::GetInstanceFields() const {
  IterationRange<ClassAccessor::DataIterator<ClassAccessor::Field>> fields = GetFields();
  // Skip the static fields.
  return { std::next(fields.begin(), NumStaticFields()), fields.end() };
}

inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Method>>
    ClassAccessor::GetMethods() const {
  return GetMethodsInternal(NumMethods());
}

inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Method>>
    ClassAccessor::GetDirectMethods() const {
  return GetMethodsInternal(NumDirectMethods());
}

inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Method>>
    ClassAccessor::GetVirtualMethods() const {
  IterationRange<DataIterator<Method>> methods = GetMethods();
  // Skip the direct fields.
  return { std::next(methods.begin(), NumDirectMethods()), methods.end() };
}

inline dex::TypeIndex ClassAccessor::GetClassIdx() const {
  return dex_file_.GetClassDef(class_def_index_).class_idx_;
}

inline const dex::ClassDef& ClassAccessor::GetClassDef() const {
  return dex_file_.GetClassDef(GetClassDefIndex());
}

}  // namespace art

#endif  // ART_LIBDEXFILE_DEX_CLASS_ACCESSOR_INL_H_
