From c4c35fc5318b904d5141a7f3c4a70d80576c30da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Perceval=20Wajsb=C3=BCrt?= Date: Fri, 2 Jun 2023 00:36:58 +0200 Subject: [PATCH] Use C++ streams over C style IO --- ASTree.cpp | 526 ++++++++++++++++++++++++------------------------- ASTree.h | 4 +- bytecode.cpp | 148 +++++++------- bytecode.h | 4 +- data.cpp | 22 ++- data.h | 3 +- pyc_string.cpp | 41 ++-- pyc_string.h | 4 +- pycdas.cpp | 180 ++++++++--------- pycdc.cpp | 16 +- 10 files changed, 488 insertions(+), 460 deletions(-) diff --git a/ASTree.cpp b/ASTree.cpp index bcf7996..dfba04c 100644 --- a/ASTree.cpp +++ b/ASTree.cpp @@ -14,8 +14,8 @@ // NOTE: Nested f-strings not supported. #define F_STRING_QUOTE "'''" -static void append_to_chain_store(PycRef chainStore, PycRef item, - FastStack& stack, PycRef curblock); +static void append_to_chain_store(PycRef &chainStore, PycRef item, + FastStack& stack, PycRef &curblock); /* Use this to determine if an error occurred (and therefore, if we should * avoid cleaning the output tree) */ @@ -2398,8 +2398,8 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) return new ASTNodeList(defblock->nodes()); } -static void append_to_chain_store(PycRef chainStore, PycRef item, - FastStack& stack, PycRef curblock) +static void append_to_chain_store(PycRef &chainStore, PycRef item, + FastStack& stack, PycRef &curblock) { stack.pop(); // ignore identical source object. chainStore.cast()->append(item); @@ -2462,96 +2462,96 @@ static int cmp_prec(PycRef parent, PycRef child) } static void print_ordered(PycRef parent, PycRef child, - PycModule* mod) + PycModule* mod, std::ostream& pyc_output) { if (child.type() == ASTNode::NODE_BINARY || child.type() == ASTNode::NODE_COMPARE) { if (cmp_prec(parent, child) > 0) { - fputs("(", pyc_output); - print_src(child, mod); - fputs(")", pyc_output); + pyc_output << "("; + print_src(child, mod, pyc_output); + pyc_output << ")"; } else { - print_src(child, mod); + print_src(child, mod, pyc_output); } } else if (child.type() == ASTNode::NODE_UNARY) { if (cmp_prec(parent, child) > 0) { - fputs("(", pyc_output); - print_src(child, mod); - fputs(")", pyc_output); + pyc_output << "("; + print_src(child, mod, pyc_output); + pyc_output << ")"; } else { - print_src(child, mod); + print_src(child, mod, pyc_output); } } else { - print_src(child, mod); + print_src(child, mod, pyc_output); } } -static void start_line(int indent) +static void start_line(int indent, std::ostream& pyc_output) { if (inLambda) return; for (int i=0; i blk, PycModule* mod) { +static void print_block(PycRef blk, PycModule* mod, std::ostream& pyc_output) { ASTBlock::list_t lines = blk->nodes(); if (lines.size() == 0) { PycRef pass = new ASTKeyword(ASTKeyword::KW_PASS); - start_line(cur_indent); - print_src(pass, mod); + start_line(cur_indent, pyc_output); + print_src(pass, mod, pyc_output); } for (auto ln = lines.cbegin(); ln != lines.cend();) { if ((*ln).cast().type() != ASTNode::NODE_NODELIST) { - start_line(cur_indent); + start_line(cur_indent, pyc_output); } - print_src(*ln, mod); + print_src(*ln, mod, pyc_output); if (++ln != lines.end()) { - end_line(); + end_line(pyc_output); } } } -void print_formatted_value(PycRef formatted_value, PycModule* mod) +void print_formatted_value(PycRef formatted_value, PycModule* mod, std::ostream& pyc_output) { - fputs("{", pyc_output); - print_src(formatted_value->val(), mod); + pyc_output << "{"; + print_src(formatted_value->val(), mod, pyc_output); switch (formatted_value->conversion()) { case ASTFormattedValue::ConversionFlag::NONE: break; case ASTFormattedValue::ConversionFlag::STR: - fputs("!s", pyc_output); + pyc_output << "!s"; break; case ASTFormattedValue::ConversionFlag::REPR: - fputs("!r", pyc_output); + pyc_output << "!r"; break; case ASTFormattedValue::ConversionFlag::ASCII: - fputs("!a", pyc_output); + pyc_output << "!a"; break; case ASTFormattedValue::ConversionFlag::FMTSPEC: - fprintf(pyc_output, ":%s", formatted_value->format_spec().cast()->object().cast()->value()); + pyc_output << ":" << formatted_value->format_spec().cast()->object().cast()->value(); break; default: fprintf(stderr, "Unsupported NODE_FORMATTEDVALUE conversion flag: %d\n", formatted_value->conversion()); } - fputs("}", pyc_output); + pyc_output << "}"; } -void print_src(PycRef node, PycModule* mod) +void print_src(PycRef node, PycModule* mod, std::ostream &pyc_output) { if (node == NULL) { - fputs("None", pyc_output); + pyc_output << "None"; cleanBuild = true; return; } @@ -2561,183 +2561,183 @@ void print_src(PycRef node, PycModule* mod) case ASTNode::NODE_COMPARE: { PycRef bin = node.cast(); - print_ordered(node, bin->left(), mod); - fprintf(pyc_output, "%s", bin->op_str()); - print_ordered(node, bin->right(), mod); + print_ordered(node, bin->left(), mod, pyc_output); + pyc_output << bin->op_str(); + print_ordered(node, bin->right(), mod, pyc_output); } break; case ASTNode::NODE_UNARY: { PycRef un = node.cast(); - fprintf(pyc_output, "%s", un->op_str()); - print_ordered(node, un->operand(), mod); + pyc_output << un->op_str(); + print_ordered(node, un->operand(), mod, pyc_output); } break; case ASTNode::NODE_CALL: { PycRef call = node.cast(); - print_src(call->func(), mod); - fputs("(", pyc_output); + print_src(call->func(), mod, pyc_output); + pyc_output << "("; bool first = true; for (const auto& param : call->pparams()) { if (!first) - fputs(", ", pyc_output); - print_src(param, mod); + pyc_output << ", "; + print_src(param, mod, pyc_output); first = false; } for (const auto& param : call->kwparams()) { if (!first) - fputs(", ", pyc_output); + pyc_output << ", "; if (param.first.type() == ASTNode::NODE_NAME) { - fprintf(pyc_output, "%s = ", param.first.cast()->name()->value()); + pyc_output << param.first.cast()->name()->value() << " = "; } else { PycRef str_name = param.first.cast()->object().cast(); - fprintf(pyc_output, "%s = ", str_name->value()); + pyc_output << str_name->value() << " = "; } - print_src(param.second, mod); + print_src(param.second, mod, pyc_output); first = false; } if (call->hasVar()) { if (!first) - fputs(", ", pyc_output); - fputs("*", pyc_output); - print_src(call->var(), mod); + pyc_output << ", "; + pyc_output << "*"; + print_src(call->var(), mod, pyc_output); first = false; } if (call->hasKW()) { if (!first) - fputs(", ", pyc_output); - fputs("**", pyc_output); - print_src(call->kw(), mod); + pyc_output << ", "; + pyc_output << "**"; + print_src(call->kw(), mod, pyc_output); first = false; } - fputs(")", pyc_output); + pyc_output << ")"; } break; case ASTNode::NODE_DELETE: { - fputs("del ", pyc_output); - print_src(node.cast()->value(), mod); + pyc_output << "del "; + print_src(node.cast()->value(), mod, pyc_output); } break; case ASTNode::NODE_EXEC: { PycRef exec = node.cast(); - fputs("exec ", pyc_output); - print_src(exec->statement(), mod); + pyc_output << "exec "; + print_src(exec->statement(), mod, pyc_output); if (exec->globals() != NULL) { - fputs(" in ", pyc_output); - print_src(exec->globals(), mod); + pyc_output << " in "; + print_src(exec->globals(), mod, pyc_output); if (exec->locals() != NULL && exec->globals() != exec->locals()) { - fputs(", ", pyc_output); - print_src(exec->locals(), mod); + pyc_output << ", "; + print_src(exec->locals(), mod, pyc_output); } } } break; case ASTNode::NODE_FORMATTEDVALUE: - fputs("f" F_STRING_QUOTE, pyc_output); - print_formatted_value(node.cast(), mod); - fputs(F_STRING_QUOTE, pyc_output); + pyc_output << "f" F_STRING_QUOTE; + print_formatted_value(node.cast(), mod, pyc_output); + pyc_output << F_STRING_QUOTE; break; case ASTNode::NODE_JOINEDSTR: - fputs("f" F_STRING_QUOTE, pyc_output); + pyc_output << "f" F_STRING_QUOTE; for (const auto& val : node.cast()->values()) { switch (val.type()) { case ASTNode::NODE_FORMATTEDVALUE: - print_formatted_value(val.cast(), mod); + print_formatted_value(val.cast(), mod, pyc_output); break; case ASTNode::NODE_OBJECT: // When printing a piece of the f-string, keep the quote style consistent. // This avoids problems when ''' or """ is part of the string. - print_const(val.cast()->object(), mod, F_STRING_QUOTE); + print_const(val.cast()->object(), mod, F_STRING_QUOTE, pyc_output); break; default: fprintf(stderr, "Unsupported node type %d in NODE_JOINEDSTR\n", val.type()); } } - fputs(F_STRING_QUOTE, pyc_output); + pyc_output << F_STRING_QUOTE; break; case ASTNode::NODE_KEYWORD: - fprintf(pyc_output, "%s", node.cast()->word_str()); + pyc_output << node.cast()->word_str(); break; case ASTNode::NODE_LIST: { - fputs("[", pyc_output); + pyc_output << "["; bool first = true; cur_indent++; for (const auto& val : node.cast()->values()) { if (first) - fputs("\n", pyc_output); + pyc_output << "\n"; else - fputs(",\n", pyc_output); - start_line(cur_indent); - print_src(val, mod); + pyc_output << ",\n"; + start_line(cur_indent, pyc_output); + print_src(val, mod, pyc_output); first = false; } cur_indent--; - fputs("]", pyc_output); + pyc_output << "]"; } break; case ASTNode::NODE_SET: { - fputs("{", pyc_output); + pyc_output << "{"; bool first = true; cur_indent++; for (const auto& val : node.cast()->values()) { if (first) - fputs("\n", pyc_output); + pyc_output << "\n"; else - fputs(",\n", pyc_output); - start_line(cur_indent); - print_src(val, mod); + pyc_output << ",\n"; + start_line(cur_indent, pyc_output); + print_src(val, mod, pyc_output); first = false; } cur_indent--; - fputs("}", pyc_output); + pyc_output << "}"; } break; case ASTNode::NODE_COMPREHENSION: { PycRef comp = node.cast(); - fputs("[ ", pyc_output); - print_src(comp->result(), mod); + pyc_output << "[ "; + print_src(comp->result(), mod, pyc_output); for (const auto& gen : comp->generators()) { - fputs(" for ", pyc_output); - print_src(gen->index(), mod); - fputs(" in ", pyc_output); - print_src(gen->iter(), mod); + pyc_output << " for "; + print_src(gen->index(), mod, pyc_output); + pyc_output << " in "; + print_src(gen->iter(), mod, pyc_output); if (gen->condition()) { - fprintf(pyc_output, " if "); - print_src(gen->condition(), mod); + pyc_output << " if "; + print_src(gen->condition(), mod, pyc_output); } } - fputs(" ]", pyc_output); + pyc_output << " ]"; } break; case ASTNode::NODE_MAP: { - fputs("{", pyc_output); + pyc_output << "{"; bool first = true; cur_indent++; for (const auto& val : node.cast()->values()) { if (first) - fputs("\n", pyc_output); + pyc_output << "\n"; else - fputs(",\n", pyc_output); - start_line(cur_indent); - print_src(val.first, mod); - fputs(": ", pyc_output); - print_src(val.second, mod); + pyc_output << ",\n"; + start_line(cur_indent, pyc_output); + print_src(val.first, mod, pyc_output); + pyc_output << ": "; + print_src(val.second, mod, pyc_output); first = false; } cur_indent--; - fputs(" }", pyc_output); + pyc_output << " }"; } break; case ASTNode::NODE_CONST_MAP: @@ -2755,21 +2755,21 @@ void print_src(PycRef node, PycModule* mod) map->add(new ASTObject(key), value); } - print_src(map, mod); + print_src(map, mod, pyc_output); } break; case ASTNode::NODE_NAME: - fprintf(pyc_output, "%s", node.cast()->name()->value()); + pyc_output << node.cast()->name()->value(); break; case ASTNode::NODE_NODELIST: { cur_indent++; for (const auto& ln : node.cast()->nodes()) { if (ln.cast().type() != ASTNode::NODE_NODELIST) { - start_line(cur_indent); + start_line(cur_indent, pyc_output); } - print_src(ln, mod); - end_line(); + print_src(ln, mod, pyc_output); + end_line(pyc_output); } cur_indent--; } @@ -2781,44 +2781,44 @@ void print_src(PycRef node, PycModule* mod) break; if (blk->blktype() == ASTBlock::BLK_CONTAINER) { - end_line(); - print_block(blk, mod); - end_line(); + end_line(pyc_output); + print_block(blk, mod, pyc_output); + end_line(pyc_output); break; } - fprintf(pyc_output, "%s", blk->type_str()); + pyc_output << blk->type_str(); if (blk->blktype() == ASTBlock::BLK_IF || blk->blktype() == ASTBlock::BLK_ELIF || blk->blktype() == ASTBlock::BLK_WHILE) { if (blk.cast()->negative()) - fputs(" not ", pyc_output); + pyc_output << " not "; else - fputs(" ", pyc_output); + pyc_output << " "; - print_src(blk.cast()->cond(), mod); + print_src(blk.cast()->cond(), mod, pyc_output); } else if (blk->blktype() == ASTBlock::BLK_FOR || blk->blktype() == ASTBlock::BLK_ASYNCFOR) { - fputs(" ", pyc_output); - print_src(blk.cast()->index(), mod); - fputs(" in ", pyc_output); - print_src(blk.cast()->iter(), mod); + pyc_output << " "; + print_src(blk.cast()->index(), mod, pyc_output); + pyc_output << " in "; + print_src(blk.cast()->iter(), mod, pyc_output); } else if (blk->blktype() == ASTBlock::BLK_EXCEPT && blk.cast()->cond() != NULL) { - fputs(" ", pyc_output); - print_src(blk.cast()->cond(), mod); + pyc_output << " "; + print_src(blk.cast()->cond(), mod, pyc_output); } else if (blk->blktype() == ASTBlock::BLK_WITH) { - fputs(" ", pyc_output); - print_src(blk.cast()->expr(), mod); + pyc_output << " "; + print_src(blk.cast()->expr(), mod, pyc_output); PycRef var = blk.try_cast()->var(); if (var != NULL) { - fputs(" as ", pyc_output); - print_src(var, mod); + pyc_output << " as "; + print_src(var, mod, pyc_output); } } - fputs(":\n", pyc_output); + pyc_output << ":\n"; cur_indent++; - print_block(blk, mod); + print_block(blk, mod, pyc_output); cur_indent--; } break; @@ -2827,41 +2827,41 @@ void print_src(PycRef node, PycModule* mod) PycRef obj = node.cast()->object(); if (obj.type() == PycObject::TYPE_CODE) { PycRef code = obj.cast(); - decompyle(code, mod); + decompyle(code, mod, pyc_output); } else { - print_const(obj, mod); + print_const(obj, mod, nullptr, pyc_output); } } break; case ASTNode::NODE_PRINT: { - fputs("print ", pyc_output); + pyc_output << "print "; bool first = true; if (node.cast()->stream() != nullptr) { - fputs(">>", pyc_output); - print_src(node.cast()->stream(), mod); + pyc_output << ">>"; + print_src(node.cast()->stream(), mod, pyc_output); first = false; } for (const auto& val : node.cast()->values()) { if (!first) - fputs(", ", pyc_output); - print_src(val, mod); + pyc_output << ", "; + print_src(val, mod, pyc_output); first = false; } if (!node.cast()->eol()) - fputs(",", pyc_output); + pyc_output << ","; } break; case ASTNode::NODE_RAISE: { PycRef raise = node.cast(); - fputs("raise ", pyc_output); + pyc_output << "raise "; bool first = true; for (const auto& param : raise->params()) { if (!first) - fputs(", ", pyc_output); - print_src(param, mod); + pyc_output << ", "; + print_src(param, mod, pyc_output); first = false; } } @@ -2873,22 +2873,22 @@ void print_src(PycRef node, PycModule* mod) if (!inLambda) { switch (ret->rettype()) { case ASTReturn::RETURN: - fputs("return ", pyc_output); + pyc_output << "return "; break; case ASTReturn::YIELD: - fputs("yield ", pyc_output); + pyc_output << "yield "; break; case ASTReturn::YIELD_FROM: if (value.type() == ASTNode::NODE_AWAITABLE) { - fputs("await ", pyc_output); + pyc_output << "await "; value = value.cast()->expression(); } else { - fputs("yield from ", pyc_output); + pyc_output << "yield from "; } break; } } - print_src(value, mod); + print_src(value, mod, pyc_output); } break; case ASTNode::NODE_SLICE: @@ -2896,11 +2896,11 @@ void print_src(PycRef node, PycModule* mod) PycRef slice = node.cast(); if (slice->op() & ASTSlice::SLICE1) { - print_src(slice->left(), mod); + print_src(slice->left(), mod, pyc_output); } - fputs(":", pyc_output); + pyc_output << ":"; if (slice->op() & ASTSlice::SLICE2) { - print_src(slice->right(), mod); + print_src(slice->right(), mod, pyc_output); } } break; @@ -2910,46 +2910,46 @@ void print_src(PycRef node, PycModule* mod) if (import->stores().size()) { ASTImport::list_t stores = import->stores(); - fputs("from ", pyc_output); + pyc_output << "from "; if (import->name().type() == ASTNode::NODE_IMPORT) - print_src(import->name().cast()->name(), mod); + print_src(import->name().cast()->name(), mod, pyc_output); else - print_src(import->name(), mod); - fputs(" import ", pyc_output); + print_src(import->name(), mod, pyc_output); + pyc_output << " import "; if (stores.size() == 1) { auto src = stores.front()->src(); auto dest = stores.front()->dest(); - print_src(src, mod); + print_src(src, mod, pyc_output); if (src.cast()->name()->value() != dest.cast()->name()->value()) { - fputs(" as ", pyc_output); - print_src(dest, mod); + pyc_output << " as "; + print_src(dest, mod, pyc_output); } } else { bool first = true; for (const auto& st : stores) { if (!first) - fputs(", ", pyc_output); - print_src(st->src(), mod); + pyc_output << ", "; + print_src(st->src(), mod, pyc_output); first = false; if (st->src().cast()->name()->value() != st->dest().cast()->name()->value()) { - fputs(" as ", pyc_output); - print_src(st->dest(), mod); + pyc_output << " as "; + print_src(st->dest(), mod, pyc_output); } } } } else { - fputs("import ", pyc_output); - print_src(import->name(), mod); + pyc_output << "import "; + print_src(import->name(), mod, pyc_output); } } break; case ASTNode::NODE_FUNCTION: { /* Actual named functions are NODE_STORE with a name */ - fputs("(lambda ", pyc_output); + pyc_output << "(lambda "; PycRef code = node.cast()->code(); PycRef code_src = code.cast()->object().cast(); ASTFunction::defarg_t defargs = node.cast()->defargs(); @@ -2958,32 +2958,32 @@ void print_src(PycRef node, PycModule* mod) int narg = 0; for (int i=0; iargCount(); i++) { if (narg) - fputs(", ", pyc_output); - fprintf(pyc_output, "%s", code_src->getLocal(narg++)->value()); + pyc_output << ", "; + pyc_output << code_src->getLocal(narg++)->value(); if ((code_src->argCount() - i) <= (int)defargs.size()) { - fputs(" = ", pyc_output); - print_src(*da++, mod); + pyc_output << " = "; + print_src(*da++, mod, pyc_output); } } da = kwdefargs.cbegin(); if (code_src->kwOnlyArgCount() != 0) { - fputs(narg == 0 ? "*" : ", *", pyc_output); + pyc_output << (narg == 0 ? "*" : ", *"); for (int i = 0; i < code_src->argCount(); i++) { - fputs(", ", pyc_output); - fprintf(pyc_output, "%s", code_src->getLocal(narg++)->value()); + pyc_output << ", "; + pyc_output << code_src->getLocal(narg++)->value(); if ((code_src->kwOnlyArgCount() - i) <= (int)kwdefargs.size()) { - fputs(" = ", pyc_output); - print_src(*da++, mod); + pyc_output << " = "; + print_src(*da++, mod, pyc_output); } } } - fputs(": ", pyc_output); + pyc_output << ": "; inLambda = true; - print_src(code, mod); + print_src(code, mod, pyc_output); inLambda = false; - fputs(")", pyc_output); + pyc_output << ")"; } break; case ASTNode::NODE_STORE: @@ -2996,19 +2996,19 @@ void print_src(PycRef node, PycModule* mod) bool isLambda = false; if (strcmp(code_src->name()->value(), "") == 0) { - fputs("\n", pyc_output); - start_line(cur_indent); - print_src(dest, mod); - fputs(" = lambda ", pyc_output); + pyc_output << "\n"; + start_line(cur_indent, pyc_output); + print_src(dest, mod, pyc_output); + pyc_output << " = lambda "; isLambda = true; } else { - fputs("\n", pyc_output); - start_line(cur_indent); + pyc_output << "\n"; + start_line(cur_indent, pyc_output); if (code_src->flags() & PycCode::CO_COROUTINE) - fputs("async ", pyc_output); - fputs("def ", pyc_output); - print_src(dest, mod); - fputs("(", pyc_output); + pyc_output << "async "; + pyc_output << "def "; + print_src(dest, mod, pyc_output); + pyc_output << "("; } ASTFunction::defarg_t defargs = src.cast()->defargs(); @@ -3017,141 +3017,141 @@ void print_src(PycRef node, PycModule* mod) int narg = 0; for (int i = 0; i < code_src->argCount(); ++i) { if (narg) - fputs(", ", pyc_output); - fprintf(pyc_output, "%s", code_src->getLocal(narg++)->value()); + pyc_output << ", "; + pyc_output << code_src->getLocal(narg++)->value(); if ((code_src->argCount() - i) <= (int)defargs.size()) { - fputs(" = ", pyc_output); - print_src(*da++, mod); + pyc_output << " = "; + print_src(*da++, mod, pyc_output); } } da = kwdefargs.cbegin(); if (code_src->kwOnlyArgCount() != 0) { - fputs(narg == 0 ? "*" : ", *", pyc_output); + pyc_output << (narg == 0 ? "*" : ", *"); for (int i = 0; i < code_src->kwOnlyArgCount(); ++i) { - fputs(", ", pyc_output); - fprintf(pyc_output, "%s", code_src->getLocal(narg++)->value()); + pyc_output << ", "; + pyc_output << code_src->getLocal(narg++)->value(); if ((code_src->kwOnlyArgCount() - i) <= (int)kwdefargs.size()) { - fputs(" = ", pyc_output); - print_src(*da++, mod); + pyc_output << " = "; + print_src(*da++, mod, pyc_output); } } } if (code_src->flags() & PycCode::CO_VARARGS) { if (narg) - fputs(", ", pyc_output); - fprintf(pyc_output, "*%s", code_src->getLocal(narg++)->value()); + pyc_output << ", "; + pyc_output << "*" << code_src->getLocal(narg++)->value(); } if (code_src->flags() & PycCode::CO_VARKEYWORDS) { if (narg) - fputs(", ", pyc_output); - fprintf(pyc_output, "**%s", code_src->getLocal(narg++)->value()); + pyc_output << ", "; + pyc_output << "**" << code_src->getLocal(narg++)->value(); } if (isLambda) { - fputs(": ", pyc_output); + pyc_output << ": "; } else { - fputs("):\n", pyc_output); + pyc_output << "):\n"; printDocstringAndGlobals = true; } bool preLambda = inLambda; inLambda |= isLambda; - print_src(code, mod); + print_src(code, mod, pyc_output); inLambda = preLambda; } else if (src.type() == ASTNode::NODE_CLASS) { - fputs("\n", pyc_output); - start_line(cur_indent); - fputs("class ", pyc_output); - print_src(dest, mod); + pyc_output << "\n"; + start_line(cur_indent, pyc_output); + pyc_output << "class "; + print_src(dest, mod, pyc_output); PycRef bases = src.cast()->bases().cast(); if (bases->values().size() > 0) { - fputs("(", pyc_output); + pyc_output << "("; bool first = true; for (const auto& val : bases->values()) { if (!first) - fputs(", ", pyc_output); - print_src(val, mod); + pyc_output << ", "; + print_src(val, mod, pyc_output); first = false; } - fputs("):\n", pyc_output); + pyc_output << "):\n"; } else { // Don't put parens if there are no base classes - fputs(":\n", pyc_output); + pyc_output << ":\n"; } printClassDocstring = true; PycRef code = src.cast()->code().cast() ->func().cast()->code(); - print_src(code, mod); + print_src(code, mod, pyc_output); } else if (src.type() == ASTNode::NODE_IMPORT) { PycRef import = src.cast(); if (import->fromlist() != NULL) { PycRef fromlist = import->fromlist().cast()->object(); if (fromlist != Pyc_None) { - fputs("from ", pyc_output); + pyc_output << "from "; if (import->name().type() == ASTNode::NODE_IMPORT) - print_src(import->name().cast()->name(), mod); + print_src(import->name().cast()->name(), mod, pyc_output); else - print_src(import->name(), mod); - fputs(" import ", pyc_output); + print_src(import->name(), mod, pyc_output); + pyc_output << " import "; if (fromlist.type() == PycObject::TYPE_TUPLE || fromlist.type() == PycObject::TYPE_SMALL_TUPLE) { bool first = true; for (const auto& val : fromlist.cast()->values()) { if (!first) - fputs(", ", pyc_output); - fprintf(pyc_output, "%s", val.cast()->value()); + pyc_output << ", "; + pyc_output << val.cast()->value(); first = false; } } else { - fprintf(pyc_output, "%s", fromlist.cast()->value()); + pyc_output << fromlist.cast()->value(); } } else { - fputs("import ", pyc_output); - print_src(import->name(), mod); + pyc_output << "import "; + print_src(import->name(), mod, pyc_output); } } else { - fputs("import ", pyc_output); + pyc_output << "import "; PycRef import_name = import->name(); - print_src(import_name, mod); + print_src(import_name, mod, pyc_output); if (!dest.cast()->name()->isEqual(import_name.cast()->name().cast())) { - fputs(" as ", pyc_output); - print_src(dest, mod); + pyc_output << " as "; + print_src(dest, mod, pyc_output); } } } else if (src.type() == ASTNode::NODE_BINARY && src.cast()->is_inplace()) { - print_src(src, mod); + print_src(src, mod, pyc_output); } else { - print_src(dest, mod); - fputs(" = ", pyc_output); - print_src(src, mod); + print_src(dest, mod, pyc_output); + pyc_output << " = "; + print_src(src, mod, pyc_output); } } break; case ASTNode::NODE_CHAINSTORE: { for (auto& dest : node.cast()->nodes()) { - print_src(dest, mod); - fputs(" = ", pyc_output); + print_src(dest, mod, pyc_output); + pyc_output << " = "; } - print_src(node.cast()->src(), mod); + print_src(node.cast()->src(), mod, pyc_output); } break; case ASTNode::NODE_SUBSCR: { - print_src(node.cast()->name(), mod); - fputs("[", pyc_output); - print_src(node.cast()->key(), mod); - fputs("]", pyc_output); + print_src(node.cast()->name(), mod, pyc_output); + pyc_output << "["; + print_src(node.cast()->key(), mod, pyc_output); + pyc_output << "]"; } break; case ASTNode::NODE_CONVERT: { - fputs("`", pyc_output); - print_src(node.cast()->name(), mod); - fputs("`", pyc_output); + pyc_output << "`"; + print_src(node.cast()->name(), mod, pyc_output); + pyc_output << "`"; } break; case ASTNode::NODE_TUPLE: @@ -3159,18 +3159,18 @@ void print_src(PycRef node, PycModule* mod) PycRef tuple = node.cast(); ASTTuple::value_t values = tuple->values(); if (tuple->requireParens()) - fputc('(', pyc_output); + pyc_output << "("; bool first = true; for (const auto& val : values) { if (!first) - fputs(", ", pyc_output); - print_src(val, mod); + pyc_output << ", "; + print_src(val, mod, pyc_output); first = false; } if (values.size() == 1) - fputc(',', pyc_output); + pyc_output << ','; if (tuple->requireParens()) - fputc(')', pyc_output); + pyc_output << ')'; } break; case ASTNode::NODE_ANNOTATED_VAR: @@ -3179,9 +3179,9 @@ void print_src(PycRef node, PycModule* mod) PycRef name = annotated_var->name().cast(); PycRef annotation = annotated_var->annotation(); - fputs(name->object().cast()->value(), pyc_output); - fputs(": ", pyc_output); - print_src(annotation, mod); + pyc_output << name->object().cast()->value(); + pyc_output << ": "; + print_src(annotation, mod, pyc_output); } break; case ASTNode::NODE_TERNARY: @@ -3195,20 +3195,20 @@ void print_src(PycRef node, PycModule* mod) * but, let's not add parenthesis - to keep the source as close to original as possible in most cases */ PycRef ternary = node.cast(); - //fputs("(", pyc_output); - print_src(ternary->if_expr(), mod); + //pyc_output << "("; + print_src(ternary->if_expr(), mod, pyc_output); const auto if_block = ternary->if_block().cast(); - fputs(" if ", pyc_output); + pyc_output << " if "; if (if_block->negative()) - fputs("not ", pyc_output); - print_src(if_block->cond(), mod); - fputs(" else ", pyc_output); - print_src(ternary->else_expr(), mod); - //fputs(")", pyc_output); + pyc_output << "not "; + print_src(if_block->cond(), mod, pyc_output); + pyc_output << " else "; + print_src(ternary->else_expr(), mod, pyc_output); + //pyc_output << ")"; } break; default: - fprintf(pyc_output, "", node->type()); + pyc_output << "type() << ">"; fprintf(stderr, "Unsupported Node type: %d\n", node->type()); cleanBuild = false; return; @@ -3217,7 +3217,7 @@ void print_src(PycRef node, PycModule* mod) cleanBuild = true; } -bool print_docstring(PycRef obj, int indent, PycModule* mod) +bool print_docstring(PycRef obj, int indent, PycModule* mod, std::ostream& pyc_output) { // docstrings are translated from the bytecode __doc__ = 'string' to simply '''string''' signed char prefix = -1; @@ -3240,15 +3240,15 @@ bool print_docstring(PycRef obj, int indent, PycModule* mod) break; } if (prefix != -1) { - start_line(indent); - OutputString(obj.cast(), prefix, true); - fputs("\n", pyc_output); + start_line(indent, pyc_output); + OutputString(obj.cast(), prefix, true, pyc_output); + pyc_output << "\n"; return true; } else return false; } -void decompyle(PycRef code, PycModule* mod) +void decompyle(PycRef code, PycModule* mod, std::ostream& pyc_output) { PycRef source = BuildFromCode(code, mod); @@ -3295,7 +3295,7 @@ void decompyle(PycRef code, PycModule* mod) store->dest().cast()->name()->isEqual("__doc__") && store->src().type() == ASTNode::NODE_OBJECT) { if (print_docstring(store->src().cast()->object(), - cur_indent + (code->name()->isEqual("") ? 0 : 1), mod)) + cur_indent + (code->name()->isEqual("") ? 0 : 1), mod, pyc_output)) clean->removeFirst(); } } @@ -3318,28 +3318,28 @@ void decompyle(PycRef code, PycModule* mod) if (printDocstringAndGlobals) { if (code->consts()->size()) - print_docstring(code->getConst(0), cur_indent + 1, mod); + print_docstring(code->getConst(0), cur_indent + 1, mod, pyc_output); PycCode::globals_t globs = code->getGlobals(); if (globs.size()) { - start_line(cur_indent + 1); - fputs("global ", pyc_output); + start_line(cur_indent + 1, pyc_output); + pyc_output << "global "; bool first = true; for (const auto& glob : globs) { if (!first) - fputs(", ", pyc_output); - fprintf(pyc_output, "%s", glob->value()); + pyc_output << ", "; + pyc_output << glob->value(); first = false; } - fputs("\n", pyc_output); + pyc_output << "\n"; } printDocstringAndGlobals = false; } - print_src(source, mod); + print_src(source, mod, pyc_output); if (!cleanBuild || !part1clean) { - start_line(cur_indent); - fputs("# WARNING: Decompyle incomplete\n", pyc_output); + start_line(cur_indent, pyc_output); + pyc_output << "# WARNING: Decompyle incomplete\n"; } } diff --git a/ASTree.h b/ASTree.h index 9082f33..75ed7a1 100644 --- a/ASTree.h +++ b/ASTree.h @@ -4,8 +4,8 @@ #include "ASTNode.h" PycRef BuildFromCode(PycRef code, PycModule* mod); -void print_src(PycRef node, PycModule* mod); +void print_src(PycRef node, PycModule* mod, std::ostream& pyc_output); -void decompyle(PycRef code, PycModule* mod); +void decompyle(PycRef code, PycModule* mod, std::ostream& pyc_output); #endif diff --git a/bytecode.cpp b/bytecode.cpp index 75927ce..d663350 100644 --- a/bytecode.cpp +++ b/bytecode.cpp @@ -160,10 +160,10 @@ bool Pyc::IsCompareArg(int opcode) return (opcode == Pyc::COMPARE_OP_A); } -void print_const(PycRef obj, PycModule* mod, const char* parent_f_string_quote) +void print_const(PycRef obj, PycModule* mod, const char* parent_f_string_quote, std::ostream& pyc_output) { if (obj == NULL) { - fputs("", pyc_output); + pyc_output << ""; return; } @@ -190,112 +190,112 @@ void print_const(PycRef obj, PycModule* mod, const char* parent_f_str case PycObject::TYPE_TUPLE: case PycObject::TYPE_SMALL_TUPLE: { - fputs("(", pyc_output); + pyc_output << "("; PycTuple::value_t values = obj.cast()->values(); auto it = values.cbegin(); if (it != values.cend()) { - print_const(*it, mod); + print_const(*it, mod, nullptr, pyc_output); while (++it != values.cend()) { - fputs(", ", pyc_output); - print_const(*it, mod); + pyc_output << ", "; + print_const(*it, mod, nullptr, pyc_output); } } if (values.size() == 1) - fputs(",)", pyc_output); + pyc_output << ",)"; else - fputs(")", pyc_output); + pyc_output << ")"; } break; case PycObject::TYPE_LIST: { - fputs("[", pyc_output); + pyc_output << "["; PycList::value_t values = obj.cast()->values(); auto it = values.cbegin(); if (it != values.cend()) { - print_const(*it, mod); + print_const(*it, mod, nullptr, pyc_output); while (++it != values.cend()) { - fputs(", ", pyc_output); - print_const(*it, mod); + pyc_output << ", "; + print_const(*it, mod, nullptr, pyc_output); } } - fputs("]", pyc_output); + pyc_output << "]"; } break; case PycObject::TYPE_DICT: { - fputs("{", pyc_output); + pyc_output << "{"; PycDict::key_t keys = obj.cast()->keys(); PycDict::value_t values = obj.cast()->values(); auto ki = keys.cbegin(); auto vi = values.cbegin(); if (ki != keys.cend()) { - print_const(*ki, mod); - fputs(": ", pyc_output); - print_const(*vi, mod); + print_const(*ki, mod, nullptr, pyc_output); + pyc_output << ": "; + print_const(*vi, mod, nullptr, pyc_output); while (++ki != keys.cend()) { ++vi; - fputs(", ", pyc_output); - print_const(*ki, mod); - fputs(": ", pyc_output); - print_const(*vi, mod); + pyc_output << ", "; + print_const(*ki, mod, nullptr, pyc_output); + pyc_output << ": "; + print_const(*vi, mod, nullptr, pyc_output); } } - fputs("}", pyc_output); + pyc_output << "}"; } break; case PycObject::TYPE_SET: { - fputs("{", pyc_output); + pyc_output << "{"; PycSet::value_t values = obj.cast()->values(); auto it = values.cbegin(); if (it != values.cend()) { - print_const(*it, mod); + print_const(*it, mod, nullptr, pyc_output); while (++it != values.cend()) { - fputs(", ", pyc_output); - print_const(*it, mod); + pyc_output << ", "; + print_const(*it, mod, nullptr, pyc_output); } } - fputs("}", pyc_output); + pyc_output << "}"; } break; case PycObject::TYPE_FROZENSET: { - fputs("frozenset({", pyc_output); + pyc_output << "frozenset({"; PycSet::value_t values = obj.cast()->values(); auto it = values.cbegin(); if (it != values.cend()) { - print_const(*it, mod); + print_const(*it, mod, nullptr, pyc_output); while (++it != values.cend()) { - fputs(", ", pyc_output); - print_const(*it, mod); + pyc_output << ", "; + print_const(*it, mod, nullptr, pyc_output); } } - fputs("})", pyc_output); + pyc_output << "})"; } break; case PycObject::TYPE_NONE: - fputs("None", pyc_output); + pyc_output << "None"; break; case PycObject::TYPE_TRUE: - fputs("True", pyc_output); + pyc_output << "True"; break; case PycObject::TYPE_FALSE: - fputs("False", pyc_output); + pyc_output << "False"; break; case PycObject::TYPE_ELLIPSIS: - fputs("...", pyc_output); + pyc_output << "..."; break; case PycObject::TYPE_INT: - fprintf(pyc_output, "%d", obj.cast()->value()); + formatted_print(pyc_output, "%d", obj.cast()->value()); break; case PycObject::TYPE_LONG: - fprintf(pyc_output, "%s", obj.cast()->repr().c_str()); + formatted_print(pyc_output, "%s", obj.cast()->repr().c_str()); break; case PycObject::TYPE_FLOAT: - fprintf(pyc_output, "%s", obj.cast()->value()); + formatted_print(pyc_output, "%s", obj.cast()->value()); break; case PycObject::TYPE_COMPLEX: - fprintf(pyc_output, "(%s+%sj)", obj.cast()->value(), + formatted_print(pyc_output, "(%s+%sj)", obj.cast()->value(), obj.cast()->imag()); break; case PycObject::TYPE_BINARY_FLOAT: @@ -305,31 +305,31 @@ void print_const(PycRef obj, PycModule* mod, const char* parent_f_str bool is_negative = std::signbit(value); if (std::isnan(value)) { if (is_negative) { - fprintf(pyc_output, "float('-nan')"); + pyc_output << "float('-nan')"; } else { - fprintf(pyc_output, "float('nan')"); + pyc_output << "float('nan')"; } } else if (std::isinf(value)) { if (is_negative) { - fprintf(pyc_output, "float('-inf')"); + pyc_output << "float('-inf')"; } else { - fprintf(pyc_output, "float('inf')"); + pyc_output << "float('inf')"; } } else { - fprintf(pyc_output, "%g", value); + formatted_print(pyc_output, "%g", value); } } break; case PycObject::TYPE_BINARY_COMPLEX: - fprintf(pyc_output, "(%g+%gj)", obj.cast()->value(), + formatted_print(pyc_output, "(%g+%gj)", obj.cast()->value(), obj.cast()->imag()); break; case PycObject::TYPE_CODE: case PycObject::TYPE_CODE2: - fprintf(pyc_output, " %s", obj.cast()->name()->value()); + formatted_print(pyc_output, " %s", obj.cast()->name()->value()); break; default: - fprintf(pyc_output, "\n", obj->type()); + formatted_print(pyc_output, "\n", obj->type()); } } @@ -363,7 +363,7 @@ void bc_next(PycBuffer& source, PycModule* mod, int& opcode, int& operand, int& } } -void bc_disasm(PycRef code, PycModule* mod, int indent, unsigned flags) +void bc_disasm(PycRef code, PycModule* mod, int indent, unsigned flags, std::ostream &pyc_output) { static const char *cmp_strings[] = { "<", "<=", "==", "!=", ">", ">=", "in", "not in", "is", "is not", @@ -388,78 +388,78 @@ void bc_disasm(PycRef code, PycModule* mod, int indent, unsigned flags) continue; for (int i=0; i= Pyc::PYC_HAVE_ARG) { if (Pyc::IsConstArg(opcode)) { try { auto constParam = code->getConst(operand); - fprintf(pyc_output, "%d: ", operand); - print_const(constParam, mod); + formatted_print(pyc_output, "%d: ", operand); + print_const(constParam, mod, nullptr, pyc_output); } catch (const std::out_of_range &) { - fprintf(pyc_output, "%d ", operand); + formatted_print(pyc_output, "%d ", operand); } } else if (opcode == Pyc::LOAD_GLOBAL_A) { // Special case for Python 3.11+ try { if (operand & 1) - fprintf(pyc_output, "%d: NULL + %s", operand, code->getName(operand >> 1)->value()); + formatted_print(pyc_output, "%d: NULL + %s", operand, code->getName(operand >> 1)->value()); else - fprintf(pyc_output, "%d: %s", operand, code->getName(operand >> 1)->value()); + formatted_print(pyc_output, "%d: %s", operand, code->getName(operand >> 1)->value()); } catch (const std::out_of_range &) { - fprintf(pyc_output, "%d ", operand); + formatted_print(pyc_output, "%d ", operand); } } else if (Pyc::IsNameArg(opcode)) { try { - fprintf(pyc_output, "%d: %s", operand, code->getName(operand)->value()); + formatted_print(pyc_output, "%d: %s", operand, code->getName(operand)->value()); } catch (const std::out_of_range &) { - fprintf(pyc_output, "%d ", operand); + formatted_print(pyc_output, "%d ", operand); } } else if (Pyc::IsVarNameArg(opcode)) { try { - fprintf(pyc_output, "%d: %s", operand, code->getLocal(operand)->value()); + formatted_print(pyc_output, "%d: %s", operand, code->getLocal(operand)->value()); } catch (const std::out_of_range &) { - fprintf(pyc_output, "%d ", operand); + formatted_print(pyc_output, "%d ", operand); } } else if (Pyc::IsCellArg(opcode)) { try { - fprintf(pyc_output, "%d: %s", operand, code->getCellVar(mod, operand)->value()); + formatted_print(pyc_output, "%d: %s", operand, code->getCellVar(mod, operand)->value()); } catch (const std::out_of_range &) { - fprintf(pyc_output, "%d ", operand); + formatted_print(pyc_output, "%d ", operand); } } else if (Pyc::IsJumpOffsetArg(opcode)) { int offs = operand; if (mod->verCompare(3, 10) >= 0) offs *= sizeof(uint16_t); // BPO-27129 - fprintf(pyc_output, "%d (to %d)", operand, pos+offs); + formatted_print(pyc_output, "%d (to %d)", operand, pos+offs); } else if (Pyc::IsJumpArg(opcode)) { if (mod->verCompare(3, 10) >= 0) // BPO-27129 - fprintf(pyc_output, "%d (to %d)", operand, int(operand * sizeof(uint16_t))); + formatted_print(pyc_output, "%d (to %d)", operand, int(operand * sizeof(uint16_t))); else - fprintf(pyc_output, "%d", operand); + formatted_print(pyc_output, "%d", operand); } else if (Pyc::IsCompareArg(opcode)) { if (static_cast(operand) < cmp_strings_len) - fprintf(pyc_output, "%d (%s)", operand, cmp_strings[operand]); + formatted_print(pyc_output, "%d (%s)", operand, cmp_strings[operand]); else - fprintf(pyc_output, "%d (UNKNOWN)", operand); + formatted_print(pyc_output, "%d (UNKNOWN)", operand); } else if (opcode == Pyc::BINARY_OP_A) { if (static_cast(operand) < binop_strings_len) - fprintf(pyc_output, "%d (%s)", operand, binop_strings[operand]); + formatted_print(pyc_output, "%d (%s)", operand, binop_strings[operand]); else - fprintf(pyc_output, "%d (UNKNOWN)", operand); + formatted_print(pyc_output, "%d (UNKNOWN)", operand); } else if (opcode == Pyc::IS_OP_A) { - fprintf(pyc_output, "%d (%s)", operand, (operand == 0) ? "is" + formatted_print(pyc_output, "%d (%s)", operand, (operand == 0) ? "is" : (operand == 1) ? "is not" : "UNKNOWN"); } else if (opcode == Pyc::CONTAINS_OP_A) { - fprintf(pyc_output, "%d (%s)", operand, (operand == 0) ? "in" + formatted_print(pyc_output, "%d (%s)", operand, (operand == 0) ? "in" : (operand == 1) ? "not in" : "UNKNOWN"); } else { - fprintf(pyc_output, "%d", operand); + formatted_print(pyc_output, "%d", operand); } } - fputs("\n", pyc_output); + pyc_output << "\n"; } } diff --git a/bytecode.h b/bytecode.h index 06313bc..09fb19e 100644 --- a/bytecode.h +++ b/bytecode.h @@ -35,6 +35,6 @@ bool IsCompareArg(int opcode); } -void print_const(PycRef obj, PycModule* mod, const char* parent_f_string_quote = nullptr); +void print_const(PycRef obj, PycModule* mod, const char* parent_f_string_quote, std::ostream& pyc_output); void bc_next(PycBuffer& source, PycModule* mod, int& opcode, int& operand, int& pos); -void bc_disasm(PycRef code, PycModule* mod, int indent, unsigned flags); +void bc_disasm(PycRef code, PycModule* mod, int indent, unsigned flags, std::ostream& pyc_output); diff --git a/data.cpp b/data.cpp index 3f6ba06..011ef5d 100644 --- a/data.cpp +++ b/data.cpp @@ -1,7 +1,7 @@ #include "data.h" #include - -FILE* pyc_output = stdout; +#include +#include /* PycData */ int PycData::get16() @@ -82,3 +82,21 @@ int PycBuffer::getBuffer(int bytes, void* buffer) memcpy(buffer, (m_buffer + m_pos), bytes); return bytes; } + + + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wvarargs" +int formatted_print(std::ostream& stream, const std::string& format, ...) { + va_list args; + va_start(args, format); + size_t len = std::vsnprintf(NULL, 0, format.c_str(), args); + va_end(args); + std::vector vec(len + 1); + va_start(args, format); + std::vsnprintf(&vec[0], len + 1, format.c_str(), args); + va_end(args); + stream << &vec[0]; + return 0; +} +#pragma clang diagnostic pop \ No newline at end of file diff --git a/data.h b/data.h index 5534388..3951c91 100644 --- a/data.h +++ b/data.h @@ -2,6 +2,7 @@ #define _PYC_FILE_H #include +#include #ifdef WIN32 typedef __int64 Pyc_INT64; @@ -56,6 +57,6 @@ private: int m_size, m_pos; }; -extern FILE* pyc_output; +int formatted_print(std::ostream& stream, const std::string& format, ...); #endif diff --git a/pyc_string.cpp b/pyc_string.cpp index 8c4bcbd..f22adf4 100644 --- a/pyc_string.cpp +++ b/pyc_string.cpp @@ -2,6 +2,7 @@ #include "pyc_module.h" #include "data.h" #include +#include static bool check_ascii(const std::string& data) { @@ -56,15 +57,15 @@ bool PycString::isEqual(PycRef obj) const return isEqual(strObj->m_value); } -void OutputString(PycRef str, char prefix, bool triple, FILE* F, const char* parent_f_string_quote) +void OutputString(PycRef str, char prefix, bool triple, std::ostream &pyc_output, const char* parent_f_string_quote) { if (prefix != 0) - fputc(prefix, F); + pyc_output << prefix; const char* ch = str->value(); int len = str->length(); if (ch == 0) { - fputs("''", F); + pyc_output << "''"; return; } @@ -89,51 +90,51 @@ void OutputString(PycRef str, char prefix, bool triple, FILE* F, cons // Output the string if (!parent_f_string_quote) { if (triple) - fputs(useQuotes ? "\"\"\"" : "'''", F); + pyc_output << (useQuotes ? "\"\"\"" : "'''"); else - fputc(useQuotes ? '"' : '\'', F); + pyc_output << (useQuotes ? '"' : '\''); } while (len--) { if ((unsigned char)(*ch) < 0x20 || *ch == 0x7F) { if (*ch == '\r') { - fputs("\\r", F); + pyc_output << "\\r"; } else if (*ch == '\n') { if (triple) - fputc('\n', F); + pyc_output << '\n'; else - fputs("\\n", F); + pyc_output << "\\n"; } else if (*ch == '\t') { - fputs("\\t", F); + pyc_output << "\\t"; } else { - fprintf(F, "\\x%02x", (*ch & 0xFF)); + formatted_print(pyc_output, "\\x%02x", (*ch & 0xFF)); } } else if ((unsigned char)(*ch) >= 0x80) { if (str->type() == PycObject::TYPE_UNICODE) { // Unicode stored as UTF-8... Let the stream interpret it - fputc(*ch, F); + pyc_output << *ch; } else { - fprintf(F, "\\x%x", (*ch & 0xFF)); + formatted_print(pyc_output, "\\x%x", (*ch & 0xFF)); } } else { if (!useQuotes && *ch == '\'') - fputs("\\'", F); + pyc_output << "\\'"; else if (useQuotes && *ch == '"') - fputs("\\\"", F); + pyc_output << "\\\""; else if (*ch == '\\') - fputs("\\\\", F); + pyc_output << "\\\\"; else if (parent_f_string_quote && *ch == '{') - fputs("{{", F); + pyc_output << "{{"; else if (parent_f_string_quote && *ch == '}') - fputs("}}", F); + pyc_output << "}}"; else - fputc(*ch, F); + pyc_output << *ch; } ch++; } if (!parent_f_string_quote) { if (triple) - fputs(useQuotes ? "\"\"\"" : "'''", F); + pyc_output << (useQuotes ? "\"\"\"" : "'''"); else - fputc(useQuotes ? '"' : '\'', F); + pyc_output << (useQuotes ? '"' : '\''); } } diff --git a/pyc_string.h b/pyc_string.h index 0ad17d6..886cce2 100644 --- a/pyc_string.h +++ b/pyc_string.h @@ -31,7 +31,7 @@ private: std::string m_value; }; -void OutputString(PycRef str, char prefix = 0, bool triple = false, - FILE* F = pyc_output, const char* parent_f_string_quote = nullptr); +void OutputString(PycRef str, char prefix, bool triple, + std::ostream& stream, const char* parent_f_string_quote = nullptr); #endif diff --git a/pycdas.cpp b/pycdas.cpp index cdb6bf0..1c2e0c5 100644 --- a/pycdas.cpp +++ b/pycdas.cpp @@ -2,9 +2,11 @@ #include #include #include +#include #include "pyc_module.h" #include "pyc_numeric.h" #include "bytecode.h" +#include #ifdef WIN32 # define PATHSEP '\\' @@ -25,57 +27,57 @@ static const char* flag_names[] = { "<0x10000000>", "<0x20000000>", "<0x40000000>", "<0x80000000>" }; -static void print_coflags(unsigned long flags) +static void print_coflags(unsigned long flags, std::ostream& pyc_output) { if (flags == 0) { - fputs("\n", pyc_output); + pyc_output << "\n"; return; } - fputs(" (", pyc_output); + pyc_output << " ("; unsigned long f = 1; int k = 0; while (k < 32) { if ((flags & f) != 0) { flags &= ~f; if (flags == 0) - fputs(flag_names[k], pyc_output); + pyc_output << flag_names[k]; else - fprintf(pyc_output, "%s | ", flag_names[k]); + pyc_output << flag_names[k] << " | "; } ++k; f <<= 1; } - fputs(")\n", pyc_output); + pyc_output << ")\n"; } -static void iputs(int indent, const char* text) +static void iputs(std::ostream& pyc_output, int indent, const char* text) { for (int i=0; i obj, PycModule* mod, int indent, - unsigned flags) + unsigned flags, std::ostream& pyc_output) { if (obj == NULL) { - iputs(indent, ""); + iputs(pyc_output, indent, ""); return; } @@ -84,175 +86,175 @@ void output_object(PycRef obj, PycModule* mod, int indent, case PycObject::TYPE_CODE2: { PycRef codeObj = obj.cast(); - iputs(indent, "[Code]\n"); - iprintf(indent + 1, "File Name: %s\n", codeObj->fileName()->value()); - iprintf(indent + 1, "Object Name: %s\n", codeObj->name()->value()); + iputs(pyc_output, indent, "[Code]\n"); + iprintf(pyc_output, indent + 1, "File Name: %s\n", codeObj->fileName()->value()); + iprintf(pyc_output, indent + 1, "Object Name: %s\n", codeObj->name()->value()); if (mod->verCompare(3, 11) >= 0) - iprintf(indent + 1, "Qualified Name: %s\n", codeObj->qualName()->value()); - iprintf(indent + 1, "Arg Count: %d\n", codeObj->argCount()); + iprintf(pyc_output, indent + 1, "Qualified Name: %s\n", codeObj->qualName()->value()); + iprintf(pyc_output, indent + 1, "Arg Count: %d\n", codeObj->argCount()); if (mod->verCompare(3, 8) >= 0) - iprintf(indent + 1, "Pos Only Arg Count: %d\n", codeObj->posOnlyArgCount()); + iprintf(pyc_output, indent + 1, "Pos Only Arg Count: %d\n", codeObj->posOnlyArgCount()); if (mod->majorVer() >= 3) - iprintf(indent + 1, "KW Only Arg Count: %d\n", codeObj->kwOnlyArgCount()); + iprintf(pyc_output, indent + 1, "KW Only Arg Count: %d\n", codeObj->kwOnlyArgCount()); if (mod->verCompare(3, 11) < 0) - iprintf(indent + 1, "Locals: %d\n", codeObj->numLocals()); + iprintf(pyc_output, indent + 1, "Locals: %d\n", codeObj->numLocals()); if (mod->verCompare(1, 5) >= 0) - iprintf(indent + 1, "Stack Size: %d\n", codeObj->stackSize()); + iprintf(pyc_output, indent + 1, "Stack Size: %d\n", codeObj->stackSize()); if (mod->verCompare(1, 3) >= 0) { - iprintf(indent + 1, "Flags: 0x%08X", codeObj->flags()); - print_coflags(codeObj->flags()); + iprintf(pyc_output, indent + 1, "Flags: 0x%08X", codeObj->flags()); + print_coflags(codeObj->flags(), pyc_output); } - iputs(indent + 1, "[Names]\n"); + iputs(pyc_output, indent + 1, "[Names]\n"); for (int i=0; inames()->size(); i++) - output_object(codeObj->names()->get(i), mod, indent + 2, flags); + output_object(codeObj->names()->get(i), mod, indent + 2, flags, pyc_output); if (mod->verCompare(1, 3) >= 0 && mod->verCompare(3, 11) < 0) { if (mod->verCompare(3, 11) >= 0) - iputs(indent + 1, "[Locals+Names]\n"); + iputs(pyc_output, indent + 1, "[Locals+Names]\n"); else - iputs(indent + 1, "[Var Names]\n"); + iputs(pyc_output, indent + 1, "[Var Names]\n"); for (int i=0; ilocalNames()->size(); i++) - output_object(codeObj->localNames()->get(i), mod, indent + 2, flags); + output_object(codeObj->localNames()->get(i), mod, indent + 2, flags, pyc_output); } if (mod->verCompare(3, 11) >= 0 && (flags & Pyc::DISASM_PYCODE_VERBOSE) != 0) { - iputs(indent + 1, "[Locals+Kinds]\n"); - output_object(codeObj->localKinds().cast(), mod, indent + 2, flags); + iputs(pyc_output, indent + 1, "[Locals+Kinds]\n"); + output_object(codeObj->localKinds().cast(), mod, indent + 2, flags, pyc_output); } if (mod->verCompare(2, 1) >= 0 && mod->verCompare(3, 11) < 0) { - iputs(indent + 1, "[Free Vars]\n"); + iputs(pyc_output, indent + 1, "[Free Vars]\n"); for (int i=0; ifreeVars()->size(); i++) - output_object(codeObj->freeVars()->get(i), mod, indent + 2, flags); + output_object(codeObj->freeVars()->get(i), mod, indent + 2, flags, pyc_output); - iputs(indent + 1, "[Cell Vars]\n"); + iputs(pyc_output, indent + 1, "[Cell Vars]\n"); for (int i=0; icellVars()->size(); i++) - output_object(codeObj->cellVars()->get(i), mod, indent + 2, flags); + output_object(codeObj->cellVars()->get(i), mod, indent + 2, flags, pyc_output); } - iputs(indent + 1, "[Constants]\n"); + iputs(pyc_output, indent + 1, "[Constants]\n"); for (int i=0; iconsts()->size(); i++) - output_object(codeObj->consts()->get(i), mod, indent + 2, flags); + output_object(codeObj->consts()->get(i), mod, indent + 2, flags, pyc_output); - iputs(indent + 1, "[Disassembly]\n"); - bc_disasm(codeObj, mod, indent + 2, flags); + iputs(pyc_output, indent + 1, "[Disassembly]\n"); + bc_disasm(codeObj, mod, indent + 2, flags, pyc_output); if (mod->verCompare(1, 5) >= 0 && (flags & Pyc::DISASM_PYCODE_VERBOSE) != 0) { - iputs(indent + 1, "[Line Number Table]\n"); - output_object(codeObj->lnTable().cast(), mod, indent + 2, flags); + iputs(pyc_output, indent + 1, "[Line Number Table]\n"); + output_object(codeObj->lnTable().cast(), mod, indent + 2, flags, pyc_output); } if (mod->verCompare(3, 11) >= 0 && (flags & Pyc::DISASM_PYCODE_VERBOSE) != 0) { - iputs(indent + 1, "[Exception Table]\n"); - output_object(codeObj->exceptTable().cast(), mod, indent + 2, flags); + iputs(pyc_output, indent + 1, "[Exception Table]\n"); + output_object(codeObj->exceptTable().cast(), mod, indent + 2, flags, pyc_output); } } break; case PycObject::TYPE_STRING: - iputs(indent, ""); - OutputString(obj.cast(), mod->strIsUnicode() ? 'b' : 0); - fputs("\n", pyc_output); + iputs(pyc_output, indent, ""); + OutputString(obj.cast(), mod->strIsUnicode() ? 'b' : 0, false, pyc_output); + pyc_output << "\n"; break; case PycObject::TYPE_UNICODE: - iputs(indent, ""); - OutputString(obj.cast(), mod->strIsUnicode() ? 0 : 'u'); - fputs("\n", pyc_output); + iputs(pyc_output, indent, ""); + OutputString(obj.cast(), mod->strIsUnicode() ? 0 : 'u', false, pyc_output); + pyc_output << "\n"; break; case PycObject::TYPE_INTERNED: case PycObject::TYPE_ASCII: case PycObject::TYPE_ASCII_INTERNED: case PycObject::TYPE_SHORT_ASCII: case PycObject::TYPE_SHORT_ASCII_INTERNED: - iputs(indent, ""); + iputs(pyc_output, indent, ""); if (mod->majorVer() >= 3) - OutputString(obj.cast(), 0); + OutputString(obj.cast(), 0, false, pyc_output); else - OutputString(obj.cast(), mod->strIsUnicode() ? 'b' : 0); - fputs("\n", pyc_output); + OutputString(obj.cast(), mod->strIsUnicode() ? 'b' : 0, false, pyc_output); + pyc_output << "\n"; break; case PycObject::TYPE_TUPLE: case PycObject::TYPE_SMALL_TUPLE: { - iputs(indent, "(\n"); + iputs(pyc_output, indent, "(\n"); for (const auto& val : obj.cast()->values()) - output_object(val, mod, indent + 1, flags); - iputs(indent, ")\n"); + output_object(val, mod, indent + 1, flags, pyc_output); + iputs(pyc_output, indent, ")\n"); } break; case PycObject::TYPE_LIST: { - iputs(indent, "[\n"); + iputs(pyc_output, indent, "[\n"); for (const auto& val : obj.cast()->values()) - output_object(val, mod, indent + 1, flags); - iputs(indent, "]\n"); + output_object(val, mod, indent + 1, flags, pyc_output); + iputs(pyc_output, indent, "]\n"); } break; case PycObject::TYPE_DICT: { - iputs(indent, "{\n"); + iputs(pyc_output, indent, "{\n"); PycDict::key_t keys = obj.cast()->keys(); PycDict::value_t values = obj.cast()->values(); PycDict::key_t::const_iterator ki = keys.begin(); PycDict::value_t::const_iterator vi = values.begin(); while (ki != keys.end()) { - output_object(*ki, mod, indent + 1, flags); - output_object(*vi, mod, indent + 2, flags); + output_object(*ki, mod, indent + 1, flags, pyc_output); + output_object(*vi, mod, indent + 2, flags, pyc_output); ++ki, ++vi; } - iputs(indent, "}\n"); + iputs(pyc_output, indent, "}\n"); } break; case PycObject::TYPE_SET: { - iputs(indent, "{\n"); + iputs(pyc_output, indent, "{\n"); for (const auto& val : obj.cast()->values()) - output_object(val, mod, indent + 1, flags); - iputs(indent, "}\n"); + output_object(val, mod, indent + 1, flags, pyc_output); + iputs(pyc_output, indent, "}\n"); } break; case PycObject::TYPE_FROZENSET: { - iputs(indent, "frozenset({\n"); + iputs(pyc_output, indent, "frozenset({\n"); for (const auto& val : obj.cast()->values()) - output_object(val, mod, indent + 1, flags); - iputs(indent, "})\n"); + output_object(val, mod, indent + 1, flags, pyc_output); + iputs(pyc_output, indent, "})\n"); } break; case PycObject::TYPE_NONE: - iputs(indent, "None\n"); + iputs(pyc_output, indent, "None\n"); break; case PycObject::TYPE_FALSE: - iputs(indent, "False\n"); + iputs(pyc_output, indent, "False\n"); break; case PycObject::TYPE_TRUE: - iputs(indent, "True\n"); + iputs(pyc_output, indent, "True\n"); break; case PycObject::TYPE_ELLIPSIS: - iputs(indent, "...\n"); + iputs(pyc_output, indent, "...\n"); break; case PycObject::TYPE_INT: - iprintf(indent, "%d\n", obj.cast()->value()); + iprintf(pyc_output, indent, "%d\n", obj.cast()->value()); break; case PycObject::TYPE_LONG: - iprintf(indent, "%s\n", obj.cast()->repr().c_str()); + iprintf(pyc_output, indent, "%s\n", obj.cast()->repr().c_str()); break; case PycObject::TYPE_FLOAT: - iprintf(indent, "%s\n", obj.cast()->value()); + iprintf(pyc_output, indent, "%s\n", obj.cast()->value()); break; case PycObject::TYPE_COMPLEX: - iprintf(indent, "(%s+%sj)\n", obj.cast()->value(), + iprintf(pyc_output, indent, "(%s+%sj)\n", obj.cast()->value(), obj.cast()->imag()); break; case PycObject::TYPE_BINARY_FLOAT: - iprintf(indent, "%g\n", obj.cast()->value()); + iprintf(pyc_output, indent, "%g\n", obj.cast()->value()); break; case PycObject::TYPE_BINARY_COMPLEX: - iprintf(indent, "(%g+%gj)\n", obj.cast()->value(), + iprintf(pyc_output, indent, "(%g+%gj)\n", obj.cast()->value(), obj.cast()->imag()); break; default: - iprintf(indent, "\n", obj->type()); + iprintf(pyc_output, indent, "\n", obj->type()); } } @@ -262,18 +264,20 @@ int main(int argc, char* argv[]) bool marshalled = false; const char* version = nullptr; unsigned disasm_flags = 0; + std::ostream &pyc_output = std::cout; for (int arg = 1; arg < argc; ++arg) { if (strcmp(argv[arg], "-o") == 0) { if (arg + 1 < argc) { const char* filename = argv[++arg]; - FILE* outfile = fopen(filename, "w"); - if (!outfile) { + + auto* outfile = new std::filebuf; + if(! outfile->open(filename, std::ios::out)) { fprintf(stderr, "Error opening file '%s' for writing\n", argv[arg]); return 1; } - pyc_output = outfile; + pyc_output.rdbuf(outfile); } else { fputs("Option '-o' requires a filename\n", stderr); return 1; @@ -339,10 +343,10 @@ int main(int argc, char* argv[]) } const char* dispname = strrchr(infile, PATHSEP); dispname = (dispname == NULL) ? infile : dispname + 1; - fprintf(pyc_output, "%s (Python %d.%d%s)\n", dispname, mod.majorVer(), mod.minorVer(), + formatted_print(pyc_output, "%s (Python %d.%d%s)\n", dispname, mod.majorVer(), mod.minorVer(), (mod.majorVer() < 3 && mod.isUnicode()) ? " -U" : ""); try { - output_object(mod.code().try_cast(), &mod, 0, disasm_flags); + output_object(mod.code().try_cast(), &mod, 0, disasm_flags, pyc_output); } catch (std::exception& ex) { fprintf(stderr, "Error disassembling %s: %s\n", infile, ex.what()); return 1; diff --git a/pycdc.cpp b/pycdc.cpp index a114a3f..61fe342 100644 --- a/pycdc.cpp +++ b/pycdc.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include "ASTree.h" #ifdef WIN32 @@ -12,17 +14,19 @@ int main(int argc, char* argv[]) const char* infile = nullptr; bool marshalled = false; const char* version = nullptr; + std::ostream &pyc_output = std::cout; + for (int arg = 1; arg < argc; ++arg) { if (strcmp(argv[arg], "-o") == 0) { if (arg + 1 < argc) { const char* filename = argv[++arg]; - FILE* outfile = fopen(filename, "w"); - if (!outfile) { + auto* outfile = new std::filebuf; + if(! outfile->open(filename, std::ios::out)) { fprintf(stderr, "Error opening file '%s' for writing\n", argv[arg]); return 1; } - pyc_output = outfile; + pyc_output.rdbuf(outfile); } else { fputs("Option '-o' requires a filename\n", stderr); return 1; @@ -84,11 +88,11 @@ int main(int argc, char* argv[]) } const char* dispname = strrchr(infile, PATHSEP); dispname = (dispname == NULL) ? infile : dispname + 1; - fputs("# Source Generated with Decompyle++\n", pyc_output); - fprintf(pyc_output, "# File: %s (Python %d.%d%s)\n\n", dispname, mod.majorVer(), mod.minorVer(), + std::cout << "# Source Generated with Decompyle++\n"; + formatted_print(pyc_output, "# File: %s (Python %d.%d%s)\n\n", dispname, mod.majorVer(), mod.minorVer(), (mod.majorVer() < 3 && mod.isUnicode()) ? " Unicode" : ""); try { - decompyle(mod.code(), &mod); + decompyle(mod.code(), &mod, pyc_output); } catch (std::exception& ex) { fprintf(stderr, "Error decompyling %s: %s\n", infile, ex.what()); return 1;