// Занимается парсингом и анализом файлов
import ExeHeader from "./headers/exeHeader";
import DataBlock from "./binary/dataBlock";
import ExportDirectory from "./dataDirectory/exportDirectory";
import DataDirectories from "./dataDirectory/dataDirectories";

// Ошибка App
class AppError extends Error {
  name = 'App'
}

export default class Pexe {
  // Заголовки файла
  headers = new ExeHeader()
  // Разделы данных
  directories = new DataDirectories()

  constructor(file: DataBlock) {
    this.headers.parse(file)

    // this.headers.to.nt.to.optional.to.dataDirectory.to.export.

    // console.log(this.headers.to.nt.to.optional.to.dataDirectory.to.export.fields.Size.toHex())
    //console.log(this.headers.to.nt.to.optional.to.dataDirectory.to.export.fields.Size.toHex())

    const exportRva = this.headers.to.nt.to.optional.to.dataDirectory.to.export.fields.VirtualAddress.toNumber()
    if (exportRva) {
      const exp = new ExportDirectory().parse(file, this.rvaToOffset(exportRva))
      const name = file.copyNT(this.rvaToOffset(exp.fields.Name.toNumber())).toString()
      console.log('>>>', name)
    }

    return this
  }

  // Высчитывает адрес смещения относительно файла из RVA адреса
  // RAW - Смещение относительно начала файла
  // VA = ImageBase + RVA
  rvaToOffset(rva: number) {
    // Выравнивание числа
    const alignUp = (n: number, align: number) => Math.ceil(n / align) * align
    // Определение индекса секции которой принадлежит RVA
    const getRvaSection = () => {
      const sections = this.headers.sections
      for (let i = 0; i < sections.length; i++) {
        const start = sections[i].fields.VirtualAddress.toNumber()
        const end = start + alignUp(
          sections[i].fields.VirtualSize.toNumber(),
          this.headers.to.nt.to.optional.fields.SectionAlignment.toNumber()
        )
        if (rva >= start && rva < end) return sections[i]
      }
      return null
    }
    // Конвертация адреса в смещение
    const section = getRvaSection()
    // Если не удалось найти секцию (возможно она не существует, например export для *.exe)
    if (!section) return undefined
    return rva - section.fields.VirtualAddress.toNumber() + section.fields.PointerToRawData.toNumber()
  }
}
