Use C++ streams over C style IO

This commit is contained in:
Perceval Wajsbürt
2023-06-02 00:36:58 +02:00
committed by Perceval Wajsbürt
parent 409f175827
commit c4c35fc531
10 changed files with 488 additions and 460 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -4,8 +4,8 @@
#include "ASTNode.h" #include "ASTNode.h"
PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod); PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod);
void print_src(PycRef<ASTNode> node, PycModule* mod); void print_src(PycRef<ASTNode> node, PycModule* mod, std::ostream& pyc_output);
void decompyle(PycRef<PycCode> code, PycModule* mod); void decompyle(PycRef<PycCode> code, PycModule* mod, std::ostream& pyc_output);
#endif #endif

View File

@@ -160,10 +160,10 @@ bool Pyc::IsCompareArg(int opcode)
return (opcode == Pyc::COMPARE_OP_A); return (opcode == Pyc::COMPARE_OP_A);
} }
void print_const(PycRef<PycObject> obj, PycModule* mod, const char* parent_f_string_quote) void print_const(PycRef<PycObject> obj, PycModule* mod, const char* parent_f_string_quote, std::ostream& pyc_output)
{ {
if (obj == NULL) { if (obj == NULL) {
fputs("<NULL>", pyc_output); pyc_output << "<NULL>";
return; return;
} }
@@ -190,112 +190,112 @@ void print_const(PycRef<PycObject> obj, PycModule* mod, const char* parent_f_str
case PycObject::TYPE_TUPLE: case PycObject::TYPE_TUPLE:
case PycObject::TYPE_SMALL_TUPLE: case PycObject::TYPE_SMALL_TUPLE:
{ {
fputs("(", pyc_output); pyc_output << "(";
PycTuple::value_t values = obj.cast<PycTuple>()->values(); PycTuple::value_t values = obj.cast<PycTuple>()->values();
auto it = values.cbegin(); auto it = values.cbegin();
if (it != values.cend()) { if (it != values.cend()) {
print_const(*it, mod); print_const(*it, mod, nullptr, pyc_output);
while (++it != values.cend()) { while (++it != values.cend()) {
fputs(", ", pyc_output); pyc_output << ", ";
print_const(*it, mod); print_const(*it, mod, nullptr, pyc_output);
} }
} }
if (values.size() == 1) if (values.size() == 1)
fputs(",)", pyc_output); pyc_output << ",)";
else else
fputs(")", pyc_output); pyc_output << ")";
} }
break; break;
case PycObject::TYPE_LIST: case PycObject::TYPE_LIST:
{ {
fputs("[", pyc_output); pyc_output << "[";
PycList::value_t values = obj.cast<PycList>()->values(); PycList::value_t values = obj.cast<PycList>()->values();
auto it = values.cbegin(); auto it = values.cbegin();
if (it != values.cend()) { if (it != values.cend()) {
print_const(*it, mod); print_const(*it, mod, nullptr, pyc_output);
while (++it != values.cend()) { while (++it != values.cend()) {
fputs(", ", pyc_output); pyc_output << ", ";
print_const(*it, mod); print_const(*it, mod, nullptr, pyc_output);
} }
} }
fputs("]", pyc_output); pyc_output << "]";
} }
break; break;
case PycObject::TYPE_DICT: case PycObject::TYPE_DICT:
{ {
fputs("{", pyc_output); pyc_output << "{";
PycDict::key_t keys = obj.cast<PycDict>()->keys(); PycDict::key_t keys = obj.cast<PycDict>()->keys();
PycDict::value_t values = obj.cast<PycDict>()->values(); PycDict::value_t values = obj.cast<PycDict>()->values();
auto ki = keys.cbegin(); auto ki = keys.cbegin();
auto vi = values.cbegin(); auto vi = values.cbegin();
if (ki != keys.cend()) { if (ki != keys.cend()) {
print_const(*ki, mod); print_const(*ki, mod, nullptr, pyc_output);
fputs(": ", pyc_output); pyc_output << ": ";
print_const(*vi, mod); print_const(*vi, mod, nullptr, pyc_output);
while (++ki != keys.cend()) { while (++ki != keys.cend()) {
++vi; ++vi;
fputs(", ", pyc_output); pyc_output << ", ";
print_const(*ki, mod); print_const(*ki, mod, nullptr, pyc_output);
fputs(": ", pyc_output); pyc_output << ": ";
print_const(*vi, mod); print_const(*vi, mod, nullptr, pyc_output);
} }
} }
fputs("}", pyc_output); pyc_output << "}";
} }
break; break;
case PycObject::TYPE_SET: case PycObject::TYPE_SET:
{ {
fputs("{", pyc_output); pyc_output << "{";
PycSet::value_t values = obj.cast<PycSet>()->values(); PycSet::value_t values = obj.cast<PycSet>()->values();
auto it = values.cbegin(); auto it = values.cbegin();
if (it != values.cend()) { if (it != values.cend()) {
print_const(*it, mod); print_const(*it, mod, nullptr, pyc_output);
while (++it != values.cend()) { while (++it != values.cend()) {
fputs(", ", pyc_output); pyc_output << ", ";
print_const(*it, mod); print_const(*it, mod, nullptr, pyc_output);
} }
} }
fputs("}", pyc_output); pyc_output << "}";
} }
break; break;
case PycObject::TYPE_FROZENSET: case PycObject::TYPE_FROZENSET:
{ {
fputs("frozenset({", pyc_output); pyc_output << "frozenset({";
PycSet::value_t values = obj.cast<PycSet>()->values(); PycSet::value_t values = obj.cast<PycSet>()->values();
auto it = values.cbegin(); auto it = values.cbegin();
if (it != values.cend()) { if (it != values.cend()) {
print_const(*it, mod); print_const(*it, mod, nullptr, pyc_output);
while (++it != values.cend()) { while (++it != values.cend()) {
fputs(", ", pyc_output); pyc_output << ", ";
print_const(*it, mod); print_const(*it, mod, nullptr, pyc_output);
} }
} }
fputs("})", pyc_output); pyc_output << "})";
} }
break; break;
case PycObject::TYPE_NONE: case PycObject::TYPE_NONE:
fputs("None", pyc_output); pyc_output << "None";
break; break;
case PycObject::TYPE_TRUE: case PycObject::TYPE_TRUE:
fputs("True", pyc_output); pyc_output << "True";
break; break;
case PycObject::TYPE_FALSE: case PycObject::TYPE_FALSE:
fputs("False", pyc_output); pyc_output << "False";
break; break;
case PycObject::TYPE_ELLIPSIS: case PycObject::TYPE_ELLIPSIS:
fputs("...", pyc_output); pyc_output << "...";
break; break;
case PycObject::TYPE_INT: case PycObject::TYPE_INT:
fprintf(pyc_output, "%d", obj.cast<PycInt>()->value()); formatted_print(pyc_output, "%d", obj.cast<PycInt>()->value());
break; break;
case PycObject::TYPE_LONG: case PycObject::TYPE_LONG:
fprintf(pyc_output, "%s", obj.cast<PycLong>()->repr().c_str()); formatted_print(pyc_output, "%s", obj.cast<PycLong>()->repr().c_str());
break; break;
case PycObject::TYPE_FLOAT: case PycObject::TYPE_FLOAT:
fprintf(pyc_output, "%s", obj.cast<PycFloat>()->value()); formatted_print(pyc_output, "%s", obj.cast<PycFloat>()->value());
break; break;
case PycObject::TYPE_COMPLEX: case PycObject::TYPE_COMPLEX:
fprintf(pyc_output, "(%s+%sj)", obj.cast<PycComplex>()->value(), formatted_print(pyc_output, "(%s+%sj)", obj.cast<PycComplex>()->value(),
obj.cast<PycComplex>()->imag()); obj.cast<PycComplex>()->imag());
break; break;
case PycObject::TYPE_BINARY_FLOAT: case PycObject::TYPE_BINARY_FLOAT:
@@ -305,31 +305,31 @@ void print_const(PycRef<PycObject> obj, PycModule* mod, const char* parent_f_str
bool is_negative = std::signbit(value); bool is_negative = std::signbit(value);
if (std::isnan(value)) { if (std::isnan(value)) {
if (is_negative) { if (is_negative) {
fprintf(pyc_output, "float('-nan')"); pyc_output << "float('-nan')";
} else { } else {
fprintf(pyc_output, "float('nan')"); pyc_output << "float('nan')";
} }
} else if (std::isinf(value)) { } else if (std::isinf(value)) {
if (is_negative) { if (is_negative) {
fprintf(pyc_output, "float('-inf')"); pyc_output << "float('-inf')";
} else { } else {
fprintf(pyc_output, "float('inf')"); pyc_output << "float('inf')";
} }
} else { } else {
fprintf(pyc_output, "%g", value); formatted_print(pyc_output, "%g", value);
} }
} }
break; break;
case PycObject::TYPE_BINARY_COMPLEX: case PycObject::TYPE_BINARY_COMPLEX:
fprintf(pyc_output, "(%g+%gj)", obj.cast<PycCComplex>()->value(), formatted_print(pyc_output, "(%g+%gj)", obj.cast<PycCComplex>()->value(),
obj.cast<PycCComplex>()->imag()); obj.cast<PycCComplex>()->imag());
break; break;
case PycObject::TYPE_CODE: case PycObject::TYPE_CODE:
case PycObject::TYPE_CODE2: case PycObject::TYPE_CODE2:
fprintf(pyc_output, "<CODE> %s", obj.cast<PycCode>()->name()->value()); formatted_print(pyc_output, "<CODE> %s", obj.cast<PycCode>()->name()->value());
break; break;
default: default:
fprintf(pyc_output, "<TYPE: %d>\n", obj->type()); formatted_print(pyc_output, "<TYPE: %d>\n", obj->type());
} }
} }
@@ -363,7 +363,7 @@ void bc_next(PycBuffer& source, PycModule* mod, int& opcode, int& operand, int&
} }
} }
void bc_disasm(PycRef<PycCode> code, PycModule* mod, int indent, unsigned flags) void bc_disasm(PycRef<PycCode> code, PycModule* mod, int indent, unsigned flags, std::ostream &pyc_output)
{ {
static const char *cmp_strings[] = { static const char *cmp_strings[] = {
"<", "<=", "==", "!=", ">", ">=", "in", "not in", "is", "is not", "<", "<=", "==", "!=", ">", ">=", "in", "not in", "is", "is not",
@@ -388,78 +388,78 @@ void bc_disasm(PycRef<PycCode> code, PycModule* mod, int indent, unsigned flags)
continue; continue;
for (int i=0; i<indent; i++) for (int i=0; i<indent; i++)
fputs(" ", pyc_output); pyc_output << " ";
fprintf(pyc_output, "%-7d %-30s", start_pos, Pyc::OpcodeName(opcode)); formatted_print(pyc_output, "%-7d %-30s", start_pos, Pyc::OpcodeName(opcode));
if (opcode >= Pyc::PYC_HAVE_ARG) { if (opcode >= Pyc::PYC_HAVE_ARG) {
if (Pyc::IsConstArg(opcode)) { if (Pyc::IsConstArg(opcode)) {
try { try {
auto constParam = code->getConst(operand); auto constParam = code->getConst(operand);
fprintf(pyc_output, "%d: ", operand); formatted_print(pyc_output, "%d: ", operand);
print_const(constParam, mod); print_const(constParam, mod, nullptr, pyc_output);
} catch (const std::out_of_range &) { } catch (const std::out_of_range &) {
fprintf(pyc_output, "%d <INVALID>", operand); formatted_print(pyc_output, "%d <INVALID>", operand);
} }
} else if (opcode == Pyc::LOAD_GLOBAL_A) { } else if (opcode == Pyc::LOAD_GLOBAL_A) {
// Special case for Python 3.11+ // Special case for Python 3.11+
try { try {
if (operand & 1) 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 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 &) { } catch (const std::out_of_range &) {
fprintf(pyc_output, "%d <INVALID>", operand); formatted_print(pyc_output, "%d <INVALID>", operand);
} }
} else if (Pyc::IsNameArg(opcode)) { } else if (Pyc::IsNameArg(opcode)) {
try { 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 &) { } catch (const std::out_of_range &) {
fprintf(pyc_output, "%d <INVALID>", operand); formatted_print(pyc_output, "%d <INVALID>", operand);
} }
} else if (Pyc::IsVarNameArg(opcode)) { } else if (Pyc::IsVarNameArg(opcode)) {
try { 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 &) { } catch (const std::out_of_range &) {
fprintf(pyc_output, "%d <INVALID>", operand); formatted_print(pyc_output, "%d <INVALID>", operand);
} }
} else if (Pyc::IsCellArg(opcode)) { } else if (Pyc::IsCellArg(opcode)) {
try { 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 &) { } catch (const std::out_of_range &) {
fprintf(pyc_output, "%d <INVALID>", operand); formatted_print(pyc_output, "%d <INVALID>", operand);
} }
} else if (Pyc::IsJumpOffsetArg(opcode)) { } else if (Pyc::IsJumpOffsetArg(opcode)) {
int offs = operand; int offs = operand;
if (mod->verCompare(3, 10) >= 0) if (mod->verCompare(3, 10) >= 0)
offs *= sizeof(uint16_t); // BPO-27129 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)) { } else if (Pyc::IsJumpArg(opcode)) {
if (mod->verCompare(3, 10) >= 0) // BPO-27129 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 else
fprintf(pyc_output, "%d", operand); formatted_print(pyc_output, "%d", operand);
} else if (Pyc::IsCompareArg(opcode)) { } else if (Pyc::IsCompareArg(opcode)) {
if (static_cast<size_t>(operand) < cmp_strings_len) if (static_cast<size_t>(operand) < cmp_strings_len)
fprintf(pyc_output, "%d (%s)", operand, cmp_strings[operand]); formatted_print(pyc_output, "%d (%s)", operand, cmp_strings[operand]);
else else
fprintf(pyc_output, "%d (UNKNOWN)", operand); formatted_print(pyc_output, "%d (UNKNOWN)", operand);
} else if (opcode == Pyc::BINARY_OP_A) { } else if (opcode == Pyc::BINARY_OP_A) {
if (static_cast<size_t>(operand) < binop_strings_len) if (static_cast<size_t>(operand) < binop_strings_len)
fprintf(pyc_output, "%d (%s)", operand, binop_strings[operand]); formatted_print(pyc_output, "%d (%s)", operand, binop_strings[operand]);
else else
fprintf(pyc_output, "%d (UNKNOWN)", operand); formatted_print(pyc_output, "%d (UNKNOWN)", operand);
} else if (opcode == Pyc::IS_OP_A) { } 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" : (operand == 1) ? "is not"
: "UNKNOWN"); : "UNKNOWN");
} else if (opcode == Pyc::CONTAINS_OP_A) { } 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" : (operand == 1) ? "not in"
: "UNKNOWN"); : "UNKNOWN");
} else { } else {
fprintf(pyc_output, "%d", operand); formatted_print(pyc_output, "%d", operand);
} }
} }
fputs("\n", pyc_output); pyc_output << "\n";
} }
} }

View File

@@ -35,6 +35,6 @@ bool IsCompareArg(int opcode);
} }
void print_const(PycRef<PycObject> obj, PycModule* mod, const char* parent_f_string_quote = nullptr); void print_const(PycRef<PycObject> 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_next(PycBuffer& source, PycModule* mod, int& opcode, int& operand, int& pos);
void bc_disasm(PycRef<PycCode> code, PycModule* mod, int indent, unsigned flags); void bc_disasm(PycRef<PycCode> code, PycModule* mod, int indent, unsigned flags, std::ostream& pyc_output);

View File

@@ -1,7 +1,7 @@
#include "data.h" #include "data.h"
#include <cstring> #include <cstring>
#include <ostream>
FILE* pyc_output = stdout; #include <vector>
/* PycData */ /* PycData */
int PycData::get16() int PycData::get16()
@@ -82,3 +82,21 @@ int PycBuffer::getBuffer(int bytes, void* buffer)
memcpy(buffer, (m_buffer + m_pos), bytes); memcpy(buffer, (m_buffer + m_pos), bytes);
return 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<char> 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

3
data.h
View File

@@ -2,6 +2,7 @@
#define _PYC_FILE_H #define _PYC_FILE_H
#include <cstdio> #include <cstdio>
#include <ostream>
#ifdef WIN32 #ifdef WIN32
typedef __int64 Pyc_INT64; typedef __int64 Pyc_INT64;
@@ -56,6 +57,6 @@ private:
int m_size, m_pos; int m_size, m_pos;
}; };
extern FILE* pyc_output; int formatted_print(std::ostream& stream, const std::string& format, ...);
#endif #endif

View File

@@ -2,6 +2,7 @@
#include "pyc_module.h" #include "pyc_module.h"
#include "data.h" #include "data.h"
#include <stdexcept> #include <stdexcept>
#include <ostream>
static bool check_ascii(const std::string& data) static bool check_ascii(const std::string& data)
{ {
@@ -56,15 +57,15 @@ bool PycString::isEqual(PycRef<PycObject> obj) const
return isEqual(strObj->m_value); return isEqual(strObj->m_value);
} }
void OutputString(PycRef<PycString> str, char prefix, bool triple, FILE* F, const char* parent_f_string_quote) void OutputString(PycRef<PycString> str, char prefix, bool triple, std::ostream &pyc_output, const char* parent_f_string_quote)
{ {
if (prefix != 0) if (prefix != 0)
fputc(prefix, F); pyc_output << prefix;
const char* ch = str->value(); const char* ch = str->value();
int len = str->length(); int len = str->length();
if (ch == 0) { if (ch == 0) {
fputs("''", F); pyc_output << "''";
return; return;
} }
@@ -89,51 +90,51 @@ void OutputString(PycRef<PycString> str, char prefix, bool triple, FILE* F, cons
// Output the string // Output the string
if (!parent_f_string_quote) { if (!parent_f_string_quote) {
if (triple) if (triple)
fputs(useQuotes ? "\"\"\"" : "'''", F); pyc_output << (useQuotes ? "\"\"\"" : "'''");
else else
fputc(useQuotes ? '"' : '\'', F); pyc_output << (useQuotes ? '"' : '\'');
} }
while (len--) { while (len--) {
if ((unsigned char)(*ch) < 0x20 || *ch == 0x7F) { if ((unsigned char)(*ch) < 0x20 || *ch == 0x7F) {
if (*ch == '\r') { if (*ch == '\r') {
fputs("\\r", F); pyc_output << "\\r";
} else if (*ch == '\n') { } else if (*ch == '\n') {
if (triple) if (triple)
fputc('\n', F); pyc_output << '\n';
else else
fputs("\\n", F); pyc_output << "\\n";
} else if (*ch == '\t') { } else if (*ch == '\t') {
fputs("\\t", F); pyc_output << "\\t";
} else { } else {
fprintf(F, "\\x%02x", (*ch & 0xFF)); formatted_print(pyc_output, "\\x%02x", (*ch & 0xFF));
} }
} else if ((unsigned char)(*ch) >= 0x80) { } else if ((unsigned char)(*ch) >= 0x80) {
if (str->type() == PycObject::TYPE_UNICODE) { if (str->type() == PycObject::TYPE_UNICODE) {
// Unicode stored as UTF-8... Let the stream interpret it // Unicode stored as UTF-8... Let the stream interpret it
fputc(*ch, F); pyc_output << *ch;
} else { } else {
fprintf(F, "\\x%x", (*ch & 0xFF)); formatted_print(pyc_output, "\\x%x", (*ch & 0xFF));
} }
} else { } else {
if (!useQuotes && *ch == '\'') if (!useQuotes && *ch == '\'')
fputs("\\'", F); pyc_output << "\\'";
else if (useQuotes && *ch == '"') else if (useQuotes && *ch == '"')
fputs("\\\"", F); pyc_output << "\\\"";
else if (*ch == '\\') else if (*ch == '\\')
fputs("\\\\", F); pyc_output << "\\\\";
else if (parent_f_string_quote && *ch == '{') else if (parent_f_string_quote && *ch == '{')
fputs("{{", F); pyc_output << "{{";
else if (parent_f_string_quote && *ch == '}') else if (parent_f_string_quote && *ch == '}')
fputs("}}", F); pyc_output << "}}";
else else
fputc(*ch, F); pyc_output << *ch;
} }
ch++; ch++;
} }
if (!parent_f_string_quote) { if (!parent_f_string_quote) {
if (triple) if (triple)
fputs(useQuotes ? "\"\"\"" : "'''", F); pyc_output << (useQuotes ? "\"\"\"" : "'''");
else else
fputc(useQuotes ? '"' : '\'', F); pyc_output << (useQuotes ? '"' : '\'');
} }
} }

View File

@@ -31,7 +31,7 @@ private:
std::string m_value; std::string m_value;
}; };
void OutputString(PycRef<PycString> str, char prefix = 0, bool triple = false, void OutputString(PycRef<PycString> str, char prefix, bool triple,
FILE* F = pyc_output, const char* parent_f_string_quote = nullptr); std::ostream& stream, const char* parent_f_string_quote = nullptr);
#endif #endif

View File

@@ -2,9 +2,11 @@
#include <cstring> #include <cstring>
#include <cstdarg> #include <cstdarg>
#include <string> #include <string>
#include <iostream>
#include "pyc_module.h" #include "pyc_module.h"
#include "pyc_numeric.h" #include "pyc_numeric.h"
#include "bytecode.h" #include "bytecode.h"
#include <fstream>
#ifdef WIN32 #ifdef WIN32
# define PATHSEP '\\' # define PATHSEP '\\'
@@ -25,57 +27,57 @@ static const char* flag_names[] = {
"<0x10000000>", "<0x20000000>", "<0x40000000>", "<0x80000000>" "<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) { if (flags == 0) {
fputs("\n", pyc_output); pyc_output << "\n";
return; return;
} }
fputs(" (", pyc_output); pyc_output << " (";
unsigned long f = 1; unsigned long f = 1;
int k = 0; int k = 0;
while (k < 32) { while (k < 32) {
if ((flags & f) != 0) { if ((flags & f) != 0) {
flags &= ~f; flags &= ~f;
if (flags == 0) if (flags == 0)
fputs(flag_names[k], pyc_output); pyc_output << flag_names[k];
else else
fprintf(pyc_output, "%s | ", flag_names[k]); pyc_output << flag_names[k] << " | ";
} }
++k; ++k;
f <<= 1; 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<indent; i++) for (int i=0; i<indent; i++)
fputs(" ", pyc_output); pyc_output << " ";
fputs(text, pyc_output); pyc_output << text;
} }
static void ivprintf(int indent, const char* fmt, va_list varargs) static void ivprintf(std::ostream& pyc_output, int indent, const char* fmt, va_list varargs)
{ {
for (int i=0; i<indent; i++) for (int i=0; i<indent; i++)
fputs(" ", pyc_output); pyc_output << " ";
vfprintf(pyc_output, fmt, varargs); formatted_print(pyc_output, fmt, varargs);
} }
static void iprintf(int indent, const char* fmt, ...) static void iprintf(std::ostream& pyc_output, int indent, const char* fmt, ...)
{ {
va_list varargs; va_list varargs;
va_start(varargs, fmt); va_start(varargs, fmt);
ivprintf(indent, fmt, varargs); ivprintf(pyc_output, indent, fmt, varargs);
va_end(varargs); va_end(varargs);
} }
void output_object(PycRef<PycObject> obj, PycModule* mod, int indent, void output_object(PycRef<PycObject> obj, PycModule* mod, int indent,
unsigned flags) unsigned flags, std::ostream& pyc_output)
{ {
if (obj == NULL) { if (obj == NULL) {
iputs(indent, "<NULL>"); iputs(pyc_output, indent, "<NULL>");
return; return;
} }
@@ -84,175 +86,175 @@ void output_object(PycRef<PycObject> obj, PycModule* mod, int indent,
case PycObject::TYPE_CODE2: case PycObject::TYPE_CODE2:
{ {
PycRef<PycCode> codeObj = obj.cast<PycCode>(); PycRef<PycCode> codeObj = obj.cast<PycCode>();
iputs(indent, "[Code]\n"); iputs(pyc_output, indent, "[Code]\n");
iprintf(indent + 1, "File Name: %s\n", codeObj->fileName()->value()); iprintf(pyc_output, indent + 1, "File Name: %s\n", codeObj->fileName()->value());
iprintf(indent + 1, "Object Name: %s\n", codeObj->name()->value()); iprintf(pyc_output, indent + 1, "Object Name: %s\n", codeObj->name()->value());
if (mod->verCompare(3, 11) >= 0) if (mod->verCompare(3, 11) >= 0)
iprintf(indent + 1, "Qualified Name: %s\n", codeObj->qualName()->value()); iprintf(pyc_output, indent + 1, "Qualified Name: %s\n", codeObj->qualName()->value());
iprintf(indent + 1, "Arg Count: %d\n", codeObj->argCount()); iprintf(pyc_output, indent + 1, "Arg Count: %d\n", codeObj->argCount());
if (mod->verCompare(3, 8) >= 0) 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) 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) 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) 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) { if (mod->verCompare(1, 3) >= 0) {
iprintf(indent + 1, "Flags: 0x%08X", codeObj->flags()); iprintf(pyc_output, indent + 1, "Flags: 0x%08X", codeObj->flags());
print_coflags(codeObj->flags()); print_coflags(codeObj->flags(), pyc_output);
} }
iputs(indent + 1, "[Names]\n"); iputs(pyc_output, indent + 1, "[Names]\n");
for (int i=0; i<codeObj->names()->size(); i++) for (int i=0; i<codeObj->names()->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(1, 3) >= 0 && mod->verCompare(3, 11) < 0) {
if (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 else
iputs(indent + 1, "[Var Names]\n"); iputs(pyc_output, indent + 1, "[Var Names]\n");
for (int i=0; i<codeObj->localNames()->size(); i++) for (int i=0; i<codeObj->localNames()->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) { if (mod->verCompare(3, 11) >= 0 && (flags & Pyc::DISASM_PYCODE_VERBOSE) != 0) {
iputs(indent + 1, "[Locals+Kinds]\n"); iputs(pyc_output, indent + 1, "[Locals+Kinds]\n");
output_object(codeObj->localKinds().cast<PycObject>(), mod, indent + 2, flags); output_object(codeObj->localKinds().cast<PycObject>(), mod, indent + 2, flags, pyc_output);
} }
if (mod->verCompare(2, 1) >= 0 && mod->verCompare(3, 11) < 0) { 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; i<codeObj->freeVars()->size(); i++) for (int i=0; i<codeObj->freeVars()->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; i<codeObj->cellVars()->size(); i++) for (int i=0; i<codeObj->cellVars()->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; i<codeObj->consts()->size(); i++) for (int i=0; i<codeObj->consts()->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"); iputs(pyc_output, indent + 1, "[Disassembly]\n");
bc_disasm(codeObj, mod, indent + 2, flags); bc_disasm(codeObj, mod, indent + 2, flags, pyc_output);
if (mod->verCompare(1, 5) >= 0 && (flags & Pyc::DISASM_PYCODE_VERBOSE) != 0) { if (mod->verCompare(1, 5) >= 0 && (flags & Pyc::DISASM_PYCODE_VERBOSE) != 0) {
iputs(indent + 1, "[Line Number Table]\n"); iputs(pyc_output, indent + 1, "[Line Number Table]\n");
output_object(codeObj->lnTable().cast<PycObject>(), mod, indent + 2, flags); output_object(codeObj->lnTable().cast<PycObject>(), mod, indent + 2, flags, pyc_output);
} }
if (mod->verCompare(3, 11) >= 0 && (flags & Pyc::DISASM_PYCODE_VERBOSE) != 0) { if (mod->verCompare(3, 11) >= 0 && (flags & Pyc::DISASM_PYCODE_VERBOSE) != 0) {
iputs(indent + 1, "[Exception Table]\n"); iputs(pyc_output, indent + 1, "[Exception Table]\n");
output_object(codeObj->exceptTable().cast<PycObject>(), mod, indent + 2, flags); output_object(codeObj->exceptTable().cast<PycObject>(), mod, indent + 2, flags, pyc_output);
} }
} }
break; break;
case PycObject::TYPE_STRING: case PycObject::TYPE_STRING:
iputs(indent, ""); iputs(pyc_output, indent, "");
OutputString(obj.cast<PycString>(), mod->strIsUnicode() ? 'b' : 0); OutputString(obj.cast<PycString>(), mod->strIsUnicode() ? 'b' : 0, false, pyc_output);
fputs("\n", pyc_output); pyc_output << "\n";
break; break;
case PycObject::TYPE_UNICODE: case PycObject::TYPE_UNICODE:
iputs(indent, ""); iputs(pyc_output, indent, "");
OutputString(obj.cast<PycString>(), mod->strIsUnicode() ? 0 : 'u'); OutputString(obj.cast<PycString>(), mod->strIsUnicode() ? 0 : 'u', false, pyc_output);
fputs("\n", pyc_output); pyc_output << "\n";
break; break;
case PycObject::TYPE_INTERNED: case PycObject::TYPE_INTERNED:
case PycObject::TYPE_ASCII: case PycObject::TYPE_ASCII:
case PycObject::TYPE_ASCII_INTERNED: case PycObject::TYPE_ASCII_INTERNED:
case PycObject::TYPE_SHORT_ASCII: case PycObject::TYPE_SHORT_ASCII:
case PycObject::TYPE_SHORT_ASCII_INTERNED: case PycObject::TYPE_SHORT_ASCII_INTERNED:
iputs(indent, ""); iputs(pyc_output, indent, "");
if (mod->majorVer() >= 3) if (mod->majorVer() >= 3)
OutputString(obj.cast<PycString>(), 0); OutputString(obj.cast<PycString>(), 0, false, pyc_output);
else else
OutputString(obj.cast<PycString>(), mod->strIsUnicode() ? 'b' : 0); OutputString(obj.cast<PycString>(), mod->strIsUnicode() ? 'b' : 0, false, pyc_output);
fputs("\n", pyc_output); pyc_output << "\n";
break; break;
case PycObject::TYPE_TUPLE: case PycObject::TYPE_TUPLE:
case PycObject::TYPE_SMALL_TUPLE: case PycObject::TYPE_SMALL_TUPLE:
{ {
iputs(indent, "(\n"); iputs(pyc_output, indent, "(\n");
for (const auto& val : obj.cast<PycTuple>()->values()) for (const auto& val : obj.cast<PycTuple>()->values())
output_object(val, mod, indent + 1, flags); output_object(val, mod, indent + 1, flags, pyc_output);
iputs(indent, ")\n"); iputs(pyc_output, indent, ")\n");
} }
break; break;
case PycObject::TYPE_LIST: case PycObject::TYPE_LIST:
{ {
iputs(indent, "[\n"); iputs(pyc_output, indent, "[\n");
for (const auto& val : obj.cast<PycList>()->values()) for (const auto& val : obj.cast<PycList>()->values())
output_object(val, mod, indent + 1, flags); output_object(val, mod, indent + 1, flags, pyc_output);
iputs(indent, "]\n"); iputs(pyc_output, indent, "]\n");
} }
break; break;
case PycObject::TYPE_DICT: case PycObject::TYPE_DICT:
{ {
iputs(indent, "{\n"); iputs(pyc_output, indent, "{\n");
PycDict::key_t keys = obj.cast<PycDict>()->keys(); PycDict::key_t keys = obj.cast<PycDict>()->keys();
PycDict::value_t values = obj.cast<PycDict>()->values(); PycDict::value_t values = obj.cast<PycDict>()->values();
PycDict::key_t::const_iterator ki = keys.begin(); PycDict::key_t::const_iterator ki = keys.begin();
PycDict::value_t::const_iterator vi = values.begin(); PycDict::value_t::const_iterator vi = values.begin();
while (ki != keys.end()) { while (ki != keys.end()) {
output_object(*ki, mod, indent + 1, flags); output_object(*ki, mod, indent + 1, flags, pyc_output);
output_object(*vi, mod, indent + 2, flags); output_object(*vi, mod, indent + 2, flags, pyc_output);
++ki, ++vi; ++ki, ++vi;
} }
iputs(indent, "}\n"); iputs(pyc_output, indent, "}\n");
} }
break; break;
case PycObject::TYPE_SET: case PycObject::TYPE_SET:
{ {
iputs(indent, "{\n"); iputs(pyc_output, indent, "{\n");
for (const auto& val : obj.cast<PycSet>()->values()) for (const auto& val : obj.cast<PycSet>()->values())
output_object(val, mod, indent + 1, flags); output_object(val, mod, indent + 1, flags, pyc_output);
iputs(indent, "}\n"); iputs(pyc_output, indent, "}\n");
} }
break; break;
case PycObject::TYPE_FROZENSET: case PycObject::TYPE_FROZENSET:
{ {
iputs(indent, "frozenset({\n"); iputs(pyc_output, indent, "frozenset({\n");
for (const auto& val : obj.cast<PycSet>()->values()) for (const auto& val : obj.cast<PycSet>()->values())
output_object(val, mod, indent + 1, flags); output_object(val, mod, indent + 1, flags, pyc_output);
iputs(indent, "})\n"); iputs(pyc_output, indent, "})\n");
} }
break; break;
case PycObject::TYPE_NONE: case PycObject::TYPE_NONE:
iputs(indent, "None\n"); iputs(pyc_output, indent, "None\n");
break; break;
case PycObject::TYPE_FALSE: case PycObject::TYPE_FALSE:
iputs(indent, "False\n"); iputs(pyc_output, indent, "False\n");
break; break;
case PycObject::TYPE_TRUE: case PycObject::TYPE_TRUE:
iputs(indent, "True\n"); iputs(pyc_output, indent, "True\n");
break; break;
case PycObject::TYPE_ELLIPSIS: case PycObject::TYPE_ELLIPSIS:
iputs(indent, "...\n"); iputs(pyc_output, indent, "...\n");
break; break;
case PycObject::TYPE_INT: case PycObject::TYPE_INT:
iprintf(indent, "%d\n", obj.cast<PycInt>()->value()); iprintf(pyc_output, indent, "%d\n", obj.cast<PycInt>()->value());
break; break;
case PycObject::TYPE_LONG: case PycObject::TYPE_LONG:
iprintf(indent, "%s\n", obj.cast<PycLong>()->repr().c_str()); iprintf(pyc_output, indent, "%s\n", obj.cast<PycLong>()->repr().c_str());
break; break;
case PycObject::TYPE_FLOAT: case PycObject::TYPE_FLOAT:
iprintf(indent, "%s\n", obj.cast<PycFloat>()->value()); iprintf(pyc_output, indent, "%s\n", obj.cast<PycFloat>()->value());
break; break;
case PycObject::TYPE_COMPLEX: case PycObject::TYPE_COMPLEX:
iprintf(indent, "(%s+%sj)\n", obj.cast<PycComplex>()->value(), iprintf(pyc_output, indent, "(%s+%sj)\n", obj.cast<PycComplex>()->value(),
obj.cast<PycComplex>()->imag()); obj.cast<PycComplex>()->imag());
break; break;
case PycObject::TYPE_BINARY_FLOAT: case PycObject::TYPE_BINARY_FLOAT:
iprintf(indent, "%g\n", obj.cast<PycCFloat>()->value()); iprintf(pyc_output, indent, "%g\n", obj.cast<PycCFloat>()->value());
break; break;
case PycObject::TYPE_BINARY_COMPLEX: case PycObject::TYPE_BINARY_COMPLEX:
iprintf(indent, "(%g+%gj)\n", obj.cast<PycCComplex>()->value(), iprintf(pyc_output, indent, "(%g+%gj)\n", obj.cast<PycCComplex>()->value(),
obj.cast<PycCComplex>()->imag()); obj.cast<PycCComplex>()->imag());
break; break;
default: default:
iprintf(indent, "<TYPE: %d>\n", obj->type()); iprintf(pyc_output, indent, "<TYPE: %d>\n", obj->type());
} }
} }
@@ -262,18 +264,20 @@ int main(int argc, char* argv[])
bool marshalled = false; bool marshalled = false;
const char* version = nullptr; const char* version = nullptr;
unsigned disasm_flags = 0; unsigned disasm_flags = 0;
std::ostream &pyc_output = std::cout;
for (int arg = 1; arg < argc; ++arg) { for (int arg = 1; arg < argc; ++arg) {
if (strcmp(argv[arg], "-o") == 0) { if (strcmp(argv[arg], "-o") == 0) {
if (arg + 1 < argc) { if (arg + 1 < argc) {
const char* filename = argv[++arg]; 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", fprintf(stderr, "Error opening file '%s' for writing\n",
argv[arg]); argv[arg]);
return 1; return 1;
} }
pyc_output = outfile; pyc_output.rdbuf(outfile);
} else { } else {
fputs("Option '-o' requires a filename\n", stderr); fputs("Option '-o' requires a filename\n", stderr);
return 1; return 1;
@@ -339,10 +343,10 @@ int main(int argc, char* argv[])
} }
const char* dispname = strrchr(infile, PATHSEP); const char* dispname = strrchr(infile, PATHSEP);
dispname = (dispname == NULL) ? infile : dispname + 1; 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" : ""); (mod.majorVer() < 3 && mod.isUnicode()) ? " -U" : "");
try { try {
output_object(mod.code().try_cast<PycObject>(), &mod, 0, disasm_flags); output_object(mod.code().try_cast<PycObject>(), &mod, 0, disasm_flags, pyc_output);
} catch (std::exception& ex) { } catch (std::exception& ex) {
fprintf(stderr, "Error disassembling %s: %s\n", infile, ex.what()); fprintf(stderr, "Error disassembling %s: %s\n", infile, ex.what());
return 1; return 1;

View File

@@ -1,4 +1,6 @@
#include <cstring> #include <cstring>
#include <fstream>
#include <iostream>
#include "ASTree.h" #include "ASTree.h"
#ifdef WIN32 #ifdef WIN32
@@ -12,17 +14,19 @@ int main(int argc, char* argv[])
const char* infile = nullptr; const char* infile = nullptr;
bool marshalled = false; bool marshalled = false;
const char* version = nullptr; const char* version = nullptr;
std::ostream &pyc_output = std::cout;
for (int arg = 1; arg < argc; ++arg) { for (int arg = 1; arg < argc; ++arg) {
if (strcmp(argv[arg], "-o") == 0) { if (strcmp(argv[arg], "-o") == 0) {
if (arg + 1 < argc) { if (arg + 1 < argc) {
const char* filename = argv[++arg]; const char* filename = argv[++arg];
FILE* outfile = fopen(filename, "w"); auto* outfile = new std::filebuf;
if (!outfile) { if(! outfile->open(filename, std::ios::out)) {
fprintf(stderr, "Error opening file '%s' for writing\n", fprintf(stderr, "Error opening file '%s' for writing\n",
argv[arg]); argv[arg]);
return 1; return 1;
} }
pyc_output = outfile; pyc_output.rdbuf(outfile);
} else { } else {
fputs("Option '-o' requires a filename\n", stderr); fputs("Option '-o' requires a filename\n", stderr);
return 1; return 1;
@@ -84,11 +88,11 @@ int main(int argc, char* argv[])
} }
const char* dispname = strrchr(infile, PATHSEP); const char* dispname = strrchr(infile, PATHSEP);
dispname = (dispname == NULL) ? infile : dispname + 1; dispname = (dispname == NULL) ? infile : dispname + 1;
fputs("# Source Generated with Decompyle++\n", pyc_output); std::cout << "# Source Generated with Decompyle++\n";
fprintf(pyc_output, "# File: %s (Python %d.%d%s)\n\n", dispname, mod.majorVer(), mod.minorVer(), formatted_print(pyc_output, "# File: %s (Python %d.%d%s)\n\n", dispname, mod.majorVer(), mod.minorVer(),
(mod.majorVer() < 3 && mod.isUnicode()) ? " Unicode" : ""); (mod.majorVer() < 3 && mod.isUnicode()) ? " Unicode" : "");
try { try {
decompyle(mod.code(), &mod); decompyle(mod.code(), &mod, pyc_output);
} catch (std::exception& ex) { } catch (std::exception& ex) {
fprintf(stderr, "Error decompyling %s: %s\n", infile, ex.what()); fprintf(stderr, "Error decompyling %s: %s\n", infile, ex.what());
return 1; return 1;