#include "compiler/Unmangle.h" typedef struct UnmangleBuffer { char *buf; size_t remaining; } UnmangleBuffer; // forward decls static const char *Unmangle_Type(jmp_buf errorbuf, UnmangleBuffer *ub, const char *p); static void Unmangle_Error(jmp_buf errorbuf) { longjmp(errorbuf, 1); } static void Unmangle_BufferInit(UnmangleBuffer *ub, char *buf, size_t size) { ub->buf = buf; ub->remaining = size - 1; } static void Unmangle_BufferAppendChar(UnmangleBuffer *ub, char ch) { if (ub && ub->remaining) { *(ub->buf++) = ch; ub->remaining--; } } static void Unmangle_BufferAppendString(UnmangleBuffer *ub, const char *str) { size_t len; if (ub) { len = strlen(str); if (ub->remaining < len) len = ub->remaining; memcpy(ub->buf, str, len); ub->buf += len; ub->remaining -= len; } } static void Unmangle_BufferTerminate(UnmangleBuffer *ub) { ub->buf[0] = 0; ub->remaining = 0; } static const char *Unmangle_TemplateParams(jmp_buf errorbuf, UnmangleBuffer *ub, const char *p) { const char *p2; Unmangle_BufferAppendChar(ub, '<'); while (1) { switch (*p) { case '&': case '=': if (*(p++) == '&') Unmangle_BufferAppendChar(ub, '&'); while (1) { switch (*p) { case ',': case '>': break; case 0: Unmangle_Error(errorbuf); break; default: Unmangle_BufferAppendChar(ub, *(p++)); continue; } break; } break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': p2 = p + 1; while (1) { if (*p2 == 0) Unmangle_Error(errorbuf); if (*p2 == ',' || *p2 == '>') { do { Unmangle_BufferAppendChar(ub, *(p++)); } while (*p != '>' && *p != ','); break; } else if (!(*p2 >= '0' && *p2 <= '9')) { p = Unmangle_Type(errorbuf, ub, p); break; } p2++; } break; default: p = Unmangle_Type(errorbuf, ub, p); } if (*p == '>') break; if (*(p++) != ',') Unmangle_Error(errorbuf); Unmangle_BufferAppendString(ub, ", "); } Unmangle_BufferAppendChar(ub, '>'); return p + 1; } static const char *Unmangle_SpecialName(jmp_buf errorbuf, UnmangleBuffer *ub, const char *p) { const char *what; Boolean flag = 0; switch (*(p++)) { case 'a': switch (*(p++)) { case 'a': switch (*(p++)) { case '_': what = "operator &&"; p--; break; case 'd': what = "operator &="; break; default: return NULL; } break; case 'd': switch (*(p++)) { case '_': what = "operator &"; p--; break; case 'v': what = "operator /="; break; default: return NULL; } break; case 'e': switch (*(p++)) { case 'r': what = "operator ^="; break; default: return NULL; } break; case 'l': switch (*(p++)) { case 's': what = "operator <<="; break; default: return NULL; } break; case 'm': switch (*(p++)) { case 'd': what = "operator %="; break; case 'i': what = "operator -="; break; case 'u': what = "operator *="; break; default: return NULL; } break; case 'o': switch (*(p++)) { case 'r': what = "operator |="; break; default: return NULL; } break; case 'p': switch (*(p++)) { case 'l': what = "operator +="; break; default: return NULL; } break; case 'r': switch (*(p++)) { case 's': what = "operator >>="; break; default: return NULL; } break; case 's': what = "operator ="; break; default: return NULL; } break; case 'c': switch (*(p++)) { case 'l': what = "operator ()"; break; case 'm': what = "operator ,"; break; case 'o': what = "operator ~"; break; case 't': what = "!"; break; default: return NULL; } break; case 'd': switch (*(p++)) { case 'l': if (*p == 'a') { what = "operator delete[]"; p++; } else { what = "operator delete"; } break; case 't': what = "~"; break; case 'v': what = "operator /"; break; default: return NULL; } break; case 'e': switch (*(p++)) { case 'q': what = "operator =="; break; case 'r': what = "operator ^"; break; default: return NULL; } break; case 'g': switch (*(p++)) { case 'e': what = "operator >="; break; case 't': what = "operator >"; break; default: return NULL; } break; case 'l': switch (*(p++)) { case 'e': what = "operator <="; break; case 's': what = "operator <<"; break; case 't': what = "operator <"; break; default: return NULL; } break; case 'm': switch (*(p++)) { case 'd': what = "operator %"; break; case 'i': what = "operator -"; break; case 'l': what = "operator *"; break; case 'm': what = "operator --"; break; default: return NULL; } break; case 'n': switch (*(p++)) { case 'e': what = "operator !="; break; case 't': what = "operator !"; break; case 'w': if (*p == 'a') { what = "operator new[]"; p++; } else { what = "operator new"; } break; default: return NULL; } break; case 'o': switch (*(p++)) { case 'r': what = "operator |"; break; case 'o': what = "operator ||"; break; case 'p': Unmangle_BufferAppendString(ub, "operator "); p = Unmangle_Type(errorbuf, ub, p); flag = 1; break; default: return NULL; } break; case 'p': switch (*(p++)) { case 'l': what = "operator +"; break; case 'p': what = "operator ++"; break; default: return NULL; } break; case 'r': switch (*(p++)) { case 'f': what = "operator ->"; break; case 's': what = "operator >>"; break; case 'm': what = "operator ->*"; break; default: return NULL; } break; case 'v': switch (*(p++)) { case 'c': what = "operator []"; break; default: return NULL; } break; default: return NULL; } if (!flag) { if (*p) { Unmangle_BufferAppendString(ub, what); if (*p == '<') p = Unmangle_TemplateParams(errorbuf, ub, p + 1); if (!(*(p++) == '_' && *(p++) == '_')) return NULL; } } else { if (!(*(p++) == '_' && *(p++) == '_')) return NULL; } Unmangle_BufferTerminate(ub); return p; } static const char *Unmangle_ClassName(jmp_buf errorbuf, UnmangleBuffer *ub, const char *p, size_t len, Boolean flag) { int ch; const char *p2; while (len--) { ch = *(p++); if (!ch) Unmangle_Error(errorbuf); if (ch == '<') { p2 = Unmangle_TemplateParams(errorbuf, flag ? ub : NULL, p); len -= (p2 - p); if (len == 0) return p2; Unmangle_Error(errorbuf); } else { Unmangle_BufferAppendChar(ub, ch); } } return p; } static const char *Unmangle_QClassName(jmp_buf errorbuf, UnmangleBuffer *ub, const char *p, Boolean flag1, Boolean flag2) { const char *lastPiece; size_t len; int i; int ch; int count; if (*p == 'Q') { p++; count = *(p++) - '0'; if (count < 1 || count > 9) Unmangle_Error(errorbuf); } else { count = 1; } for (i = 0; i < count; i++) { if (i && ub) Unmangle_BufferAppendString(ub, "::"); if (*p < '0' || *p > '9') Unmangle_Error(errorbuf); len = 0; while ((ch = *p) >= '0' && ch <= '9') { len = len * 10 + ch - '0'; p++; } if (len == 0) Unmangle_Error(errorbuf); lastPiece = p; p = Unmangle_ClassName(errorbuf, ub, p, len, 1); } if (flag1 && ub) { if (flag2) Unmangle_BufferAppendString(ub, "::~"); else Unmangle_BufferAppendString(ub, "::"); Unmangle_ClassName(errorbuf, ub, lastPiece, len, 0); } return p; } static const char *Unmangle_Modifiers(UnmangleBuffer *ub, const char *p) { const char *what; Boolean isFirst = 1; while (1) { switch (*p) { case 'U': what = "unsigned"; break; case 'C': what = "const"; break; case 'V': what = "volatile"; break; case 'S': what = "signed"; break; default: return p; } if (!isFirst) Unmangle_BufferAppendChar(ub, ' '); Unmangle_BufferAppendString(ub, what); isFirst = 0; p++; } } static const char *Unmangle_PointerType(jmp_buf errorbuf, UnmangleBuffer *ub, const char *p) { const char *modifiers; modifiers = p; p = Unmangle_Modifiers(NULL, p); if (modifiers == p) modifiers = NULL; switch (*p) { case 'P': p = Unmangle_PointerType(errorbuf, ub, p + 1); if (ub) { Unmangle_BufferAppendChar(ub, '*'); if (modifiers) Unmangle_Modifiers(ub, modifiers); } return p; case 'R': p = Unmangle_PointerType(errorbuf, ub, p + 1); if (ub) { Unmangle_BufferAppendChar(ub, '&'); if (modifiers) Unmangle_Modifiers(ub, modifiers); } return p; case 'M': p = Unmangle_QClassName(errorbuf, ub, p + 1, 0, 0); if (ub) { Unmangle_BufferAppendString(ub, "::*"); if (modifiers) Unmangle_Modifiers(ub, modifiers); } return p; default: return p; } } static const char *Unmangle_ArrayType(jmp_buf errorbuf, UnmangleBuffer *ub, const char *p, const char *pointer) { const char *digits; digits = ++p; while (1) { switch (*(p++)) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': continue; case '_': if (*p == 'A') { p++; continue; } break; default: Unmangle_Error(errorbuf); } break; } p = Unmangle_Type(errorbuf, ub, p); if (ub) { if (pointer) { Unmangle_BufferAppendString(ub, " ("); Unmangle_PointerType(errorbuf, ub, pointer); Unmangle_BufferAppendChar(ub, ')'); } Unmangle_BufferAppendChar(ub, '['); while (1) { switch (*digits) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': Unmangle_BufferAppendChar(ub, *(digits++)); continue; case '_': if (digits[1] == 'A') { Unmangle_BufferAppendString(ub, "]["); digits += 2; continue; } break; default: Unmangle_Error(errorbuf); } break; } Unmangle_BufferAppendChar(ub, ']'); } return p; } static const char *Unmangle_FunctionType(jmp_buf errorbuf, UnmangleBuffer *ub, const char *p, const char *pointer) { const char *returnType; returnType = ++p; while (*p != '_') p = Unmangle_Type(errorbuf, NULL, p); p = Unmangle_Type(errorbuf, ub, p + 1); if (ub) { if (pointer) { Unmangle_BufferAppendString(ub, " ("); Unmangle_PointerType(errorbuf, ub, pointer); Unmangle_BufferAppendChar(ub, ')'); } Unmangle_BufferAppendChar(ub, '('); if (*returnType != '_') { while (1) { returnType = Unmangle_Type(errorbuf, ub, returnType); if (*returnType == '_') break; Unmangle_BufferAppendString(ub, ", "); } } Unmangle_BufferAppendChar(ub, ')'); } return p; } static const char *Unmangle_Pointer(jmp_buf errorbuf, UnmangleBuffer *ub, const char *p, const char *modifiers, char c) { const char *pointer; const char *tmp; pointer = p; tmp = Unmangle_PointerType(errorbuf, NULL, p); switch (*tmp) { case 'A': if (modifiers) pointer = modifiers; return Unmangle_ArrayType(errorbuf, ub, tmp, pointer); case 'F': if (modifiers) pointer = modifiers; return Unmangle_FunctionType(errorbuf, ub, tmp, pointer); default: if (c == 'M') { p = Unmangle_QClassName(errorbuf, NULL, p + 1, 0, 0); p = Unmangle_Type(errorbuf, ub, p); if (ub) { Unmangle_BufferAppendChar(ub, ' '); Unmangle_QClassName(errorbuf, ub, pointer + 1, 0, 0); Unmangle_BufferAppendString(ub, "::*"); if (modifiers) Unmangle_Modifiers(ub, modifiers); } } else { p = Unmangle_Type(errorbuf, ub, p + 1); if (ub) { Unmangle_BufferAppendChar(ub, c); if (modifiers) Unmangle_Modifiers(ub, modifiers); } } return p; } } static const char *Unmangle_Vector(jmp_buf errorbuf, UnmangleBuffer *ub, const char *p, const char *modifiers) { const char *p2 = p + 2; switch (p[1]) { case 'U': switch (p[2]) { case 'c': p2++; Unmangle_BufferAppendString(ub, "vector unsigned char"); break; case 's': p2++; Unmangle_BufferAppendString(ub, "vector unsigned short"); break; case 'i': p2++; Unmangle_BufferAppendString(ub, "vector unsigned int"); break; } break; case 'c': Unmangle_BufferAppendString(ub, "vector signed char"); break; case 'C': Unmangle_BufferAppendString(ub, "vector bool char"); break; case 's': Unmangle_BufferAppendString(ub, "vector signed short"); break; case 'S': Unmangle_BufferAppendString(ub, "vector bool short"); break; case 'i': Unmangle_BufferAppendString(ub, "vector signed int"); break; case 'I': Unmangle_BufferAppendString(ub, "vector bool int"); break; case 'f': Unmangle_BufferAppendString(ub, "vector float"); break; case 'p': Unmangle_BufferAppendString(ub, "vector pixel"); break; default: p2 = p + 1; } return p2; } static const char *Unmangle_Type(jmp_buf errorbuf, UnmangleBuffer *ub, const char *p) { const char *modifiers; const char *what; modifiers = p; p = Unmangle_Modifiers(NULL, p); if (modifiers == p) modifiers = NULL; switch (*p) { case 'b': what = "bool"; break; case 'v': what = "void"; break; case 'c': what = "char"; break; case 'w': what = "wchar_t"; break; case 's': what = "short"; break; case 'i': what = "int"; break; case 'l': what = "long"; break; case 'x': what = "long long"; break; case 'f': what = "float"; break; case 'D': what = "short double"; break; case 'd': what = "double"; break; case 'r': what = "long double"; break; case 'X': return Unmangle_Vector(errorbuf, ub, p, modifiers); case 'P': return Unmangle_Pointer(errorbuf, ub, p, modifiers, '*'); case 'R': return Unmangle_Pointer(errorbuf, ub, p, modifiers, '&'); case 'M': return Unmangle_Pointer(errorbuf, ub, p, modifiers, 'M'); case 'A': return Unmangle_ArrayType(errorbuf, ub, p, NULL); case 'F': return Unmangle_FunctionType(errorbuf, ub, p, NULL); case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'Q': if (modifiers) { Unmangle_Modifiers(ub, modifiers); Unmangle_BufferAppendChar(ub, ' '); } return Unmangle_QClassName(errorbuf, ub, p, 0, 0); default: Unmangle_Error(errorbuf); } if (modifiers) { Unmangle_Modifiers(ub, modifiers); Unmangle_BufferAppendChar(ub, ' '); } Unmangle_BufferAppendString(ub, what); return p + 1; } static void Unmangle_FuncArgList(jmp_buf errorbuf, UnmangleBuffer *ub, const char *p) { Boolean is_volatile; Boolean is_const; is_volatile = is_const = 0; if (*p == 'C') { is_const = 1; p++; } if (*p == 'V') { is_volatile = 1; p++; } if (*(p++) != 'F') Unmangle_Error(errorbuf); Unmangle_BufferAppendChar(ub, '('); if (!(p[0] == 'v' && p[1] == 0)) { while (1) { if (*p == 'e') { if (p[1]) Unmangle_Error(errorbuf); Unmangle_BufferAppendString(ub, "..."); break; } if (*p == '_') { p = Unmangle_Type(errorbuf, NULL, p + 1); if (p[0]) Unmangle_Error(errorbuf); break; } p = Unmangle_Type(errorbuf, ub, p); if (!*p) break; if (*p != '_') Unmangle_BufferAppendChar(ub, ','); } } Unmangle_BufferAppendChar(ub, ')'); if (is_const) Unmangle_BufferAppendString(ub, " const"); if (is_volatile) Unmangle_BufferAppendString(ub, " volatile"); Unmangle_BufferTerminate(ub); } void MWUnmangleClassName(const char *input, char *output, size_t maxLen) { UnmangleBuffer ub; jmp_buf errorbuf; const char *p; Boolean flag; if (input[0] == 'Q' && (input[1] >= '1' && input[1] <= '9')) { if (setjmp(errorbuf) == 0) { Unmangle_BufferInit(&ub, output, maxLen); Unmangle_QClassName(errorbuf, &ub, input, 0, 0); Unmangle_BufferTerminate(&ub); return; } } p = input; flag = 0; while (1) { switch (*p) { case 0: break; case '<': flag = 1; default: p++; continue; } break; } if (flag) { if (setjmp(errorbuf) == 0) { Unmangle_BufferInit(&ub, output, maxLen); Unmangle_ClassName(errorbuf, &ub, input, p - input, 1); Unmangle_BufferTerminate(&ub); return; } } strncpy(output, input, maxLen); output[maxLen - 1] = 0; } void MWUnmangle(const char *input, char *output, size_t maxLen) { UnmangleBuffer ub_internal; UnmangleBuffer ub; jmp_buf errorbuf; char mybuf[256]; const char *p; Boolean flag; int ch; switch (*input) { case '.': if ("_"[0] == '.') input++; break; case '_': if ("_"[0] == '_') input++; switch (input[1]) { case '%': case '#': case '@': input += 2; break; } break; } if (setjmp(errorbuf) == 0) { Unmangle_BufferInit(&ub_internal, mybuf, sizeof(mybuf)); Unmangle_BufferInit(&ub, output, maxLen); if (!(input[0] == '_' && input[1] == '_' && (p = Unmangle_SpecialName(errorbuf, &ub_internal, input + 2)))) { flag = 0; Unmangle_BufferInit(&ub_internal, mybuf, sizeof(mybuf)); for (p = input; *p == '_'; p++) Unmangle_BufferAppendChar(&ub_internal, '_'); while ((ch = *(p++))) { if (ch == '_' && *p == '_') { while (*(++p) == '_') Unmangle_BufferAppendChar(&ub_internal, '_'); flag = 1; break; } Unmangle_BufferAppendChar(&ub_internal, ch); } Unmangle_BufferTerminate(&ub_internal); if (!flag) { Unmangle_BufferAppendString(&ub, mybuf); Unmangle_BufferTerminate(&ub); return; } } switch (*p) { case 'F': if (mybuf[1] != 0 || (mybuf[0] != '!' && mybuf[0] != '~')) { Unmangle_BufferAppendString(&ub, mybuf); Unmangle_FuncArgList(errorbuf, &ub, p); return; } break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'Q': if (mybuf[1] == 0 && (mybuf[0] == '!' || mybuf[0] == '~')) { p = Unmangle_QClassName(errorbuf, &ub, p, 1, mybuf[0] == '~'); } else { p = Unmangle_QClassName(errorbuf, &ub, p, 0, 0); Unmangle_BufferAppendString(&ub, "::"); Unmangle_BufferAppendString(&ub, mybuf); if (*p == 0) { Unmangle_BufferTerminate(&ub); return; } } Unmangle_FuncArgList(errorbuf, &ub, p); return; } } strncpy(output, input, maxLen); output[maxLen - 1] = 0; }