* Copyright (c) 2026 Huawei Device Co., Ltd.
* 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 "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)
: fileHeader_("/*\n * HDF decompile hcs file\n */\n\n"),
outPutFileName_(Util::File::StripSuffix(std::move(outPutFileName)).append(".d.hcs")),
file_(),
ast_(ast)
{
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;
}
uint32_t DecompileGen::OutPutWalk(const std::shared_ptr<AstObject> &astObj, int32_t walkDepth)
{
if (astObj->Type() != PARSEROP_CONFNODE && astObj->Type() != PARSEROP_CONFTERM) {
return NOERR;
}
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);
int32_t ret = PrintBaseType(astObj->Child());
if (ret != NOERR) {
return ret;
}
WriteFile(";\n");
break;
}
default:
return EOUTPUT;
}
return 0;
}
uint32_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();
}