* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include "decompile_gen.h"
#include "file.h"
#include "logger.h"
#include <sstream>
using namespace OHOS::Hardware;
DecompileGen::DecompileGen(std::shared_ptr<Ast> ast, std::string outPutFileName) : ast_(ast)
{
outPutFileName_ = Util::File::StripSuffix(std::move(outPutFileName)).append(".d.hcs");
Logger().Debug() << "Decompile gen file: " << outPutFileName_;
}
bool DecompileGen::Init()
{
file_.open(outPutFileName_, std::ostream::out | std::ostream::binary);
if (!file_.is_open()) {
Logger().Error() << "Failed to open decompile output file: " << outPutFileName_;
return false;
}
return true;
}
void DecompileGen::WriteFile(const std::string &str)
{
file_ << str;
}
std::string DecompileGen::GetNodeRefPath(uint32_t value)
{
std::string refPath;
std::shared_ptr<AstObject> astObject = ast_->GetAstRoot();
if (astObject == nullptr) {
return refPath;
}
while (astObject->Child() != nullptr) {
refPath = astObject->Name() + ".";
auto child = astObject->Child();
bool deepIn = false;
while (child != nullptr) {
if (child->Type() != PARSEROP_CONFNODE) {
child = child->Next();
continue;
}
if (child->GetHash() == value) {
return (refPath + child->Name());
}
if (value > child->GetHash() && value < (child->GetHash() + child->GetSize())) {
astObject = child;
deepIn = true;
break;
}
child = child->Next();
}
if (!deepIn) {
Logger().Error() << "ref unknown node, hash = " << value;
break;
}
}
return std::string();
}
int32_t DecompileGen::PrintArrayType(const std::shared_ptr<AstObject> &astObj)
{
WriteFile("[");
auto arrayElement = astObj->Child();
if (arrayElement != nullptr) {
while (arrayElement->Next()) {
if (PrintBaseType(arrayElement) != NOERR) {
return EOUTPUT;
}
WriteFile(", ");
arrayElement = arrayElement->Next();
}
if (PrintBaseType(arrayElement) != NOERR) {
return EOUTPUT;
}
}
WriteFile("]");
return NOERR;
}
int32_t DecompileGen::PrintBaseType(const std::shared_ptr<AstObject> &astObj)
{
std::stringstream outStr;
std::string refPath;
switch (astObj->Type()) {
case PARSEROP_UINT8:
case PARSEROP_UINT16:
case PARSEROP_UINT32:
case PARSEROP_UINT64:
outStr << "0x" << std::uppercase << std::hex << astObj->IntegerValue();
WriteFile(outStr.str());
break;
case PARSEROP_STRING:
outStr << "\"" << astObj->StringValue() << "\"";
WriteFile(outStr.str());
break;
case PARSEROP_NODEREF:
refPath = GetNodeRefPath(astObj->IntegerValue());
if (refPath.empty()) {
return EOUTPUT;
}
WriteFile("&" + refPath);
break;
case PARSEROP_ARRAY:
return PrintArrayType(astObj);
default:
Logger().Error() << "unknown opcode = " << astObj->Type();
return EFAIL;
}
return NOERR;
}
int32_t DecompileGen::OutPutWalk(const std::shared_ptr<AstObject> &astObj, int32_t walkDepth)
{
if (astObj->Type() != PARSEROP_CONFNODE && astObj->Type() != PARSEROP_CONFTERM) {
return NOERR;
}
int ret;
std::string tabStr = std::string(TAB_SIZE * walkDepth, ' ');
if (walkDepth != 0) {
WriteFile(tabStr);
}
std::string str;
switch (astObj->Type()) {
case PARSEROP_CONFNODE:
str = astObj->Name() + " {\n";
WriteFile(str);
if (astObj->Child() == nullptr) {
tabStr += "}\n";
WriteFile(tabStr);
}
break;
case PARSEROP_CONFTERM:
str = astObj->Name() + " = ";
WriteFile(str);
ret = PrintBaseType(astObj->Child());
if (ret != NOERR) {
return ret;
}
WriteFile(";\n");
break;
default:
return EOUTPUT;
}
return 0;
}
int32_t DecompileGen::CloseBrace(const std::shared_ptr<AstObject> &astObj, int32_t walkDepth)
{
if (astObj->Type() != PARSEROP_CONFNODE) {
return NOERR;
}
std::string tabStr = std::string(TAB_SIZE * walkDepth, ' ');
if (astObj != ast_->GetAstRoot()) {
WriteFile(tabStr + "}\n");
} else {
WriteFile("}\n");
}
return file_.good() ? NOERR : EOUTPUT;
}
bool DecompileGen::OutPut()
{
if (!Init()) {
return false;
}
WriteFile(fileHeader_);
if (!ast_->WalkRound(
[this](std::shared_ptr<AstObject> ¤t, int32_t walkDepth) -> int32_t {
return OutPutWalk(current, walkDepth);
},
[this](std::shared_ptr<AstObject> ¤t, int32_t walkDepth) -> int32_t {
return CloseBrace(current, walkDepth);
})) {
return false;
}
return file_.good();
}