/* * Copyright (c) 2008 Hypertriton, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include const struct { enum ag_data_source_type type; const char *name; } types[] = { { AG_SOURCE_UINT8, "Uint8" }, { AG_SOURCE_SINT8, "Sint8" }, { AG_SOURCE_UINT16, "Uint16" }, { AG_SOURCE_SINT16, "Sint16" }, { AG_SOURCE_UINT32, "Uint32" }, { AG_SOURCE_SINT32, "Sint32" }, { AG_SOURCE_UINT64, "Uint64" }, { AG_SOURCE_SINT64, "Sint64" }, { AG_SOURCE_FLOAT, "Float" }, { AG_SOURCE_DOUBLE, "Double" }, { AG_SOURCE_STRING, "String" }, { AG_SOURCE_COLOR_RGBA, "ColorRGBA" }, { AG_SOURCE_STRING_PAD, "StringPad" }, }; const int nTypes = sizeof(types) / sizeof(types[0]); static void printusage(void) { fprintf(stderr, "Usage: agar-disasm [filename]\n"); } #define FORWARD(n) \ if (p+(n) > &buf[len]) { \ goto out; \ } \ p += (n) int main(int argc, char *argv[]) { char *file, *s; extern char *optarg; extern int optind; int i, c; AG_DataSource *ds = NULL; AG_ObjectHeader oh; Uint32 pos, sLen; size_t len; Uint8 *buf, *p; int asis = 0; if (AG_InitCore("agar-disasm", 0) == -1) { return (0); } while ((c = getopt(argc, argv, "?")) != -1) { switch (c) { case '?': default: printusage(); return (1); } } if (argc < 2) { printusage(); return (1); } file = argv[1]; if ((ds = AG_OpenFile(file, "r")) == NULL) { goto fail; } if (AG_ObjectReadHeader(ds, &oh) == -1) { goto fail; } printf("Class:\t\t%s\n", oh.cs.hier); if (oh.cs.libs[0] != '\0') { printf("Modules:\t%s\n", oh.cs.libs); } printf("Dataset at:\t%lx\n", (unsigned long)oh.dataOffs); printf("Version:\t%u.%u\n", oh.ver.major, oh.ver.minor); printf("Flags:\t\t0x%x\n", oh.flags); printf("\n"); if (AG_Seek(ds, 0, AG_SEEK_END) == -1) { goto fail; } len = AG_Tell(ds) - oh.dataOffs; if (AG_Seek(ds, (off_t)oh.dataOffs, AG_SEEK_SET) == -1) { goto fail; } pos = 0; if ((buf = malloc(len)) == NULL) { AG_SetError("Out of memory for dataset (%lu)", (unsigned long)len); goto fail; } if (AG_Read(ds, buf, len) == -1) goto fail; for (p = buf; ;) { for (i = 0; i < nTypes; i++) { if (AG_SwapBE32(*(Uint32 *)p) == types[i].type) { if (asis) { printf("\n"); } asis = 0; break; } } if (i == nTypes) { if (!asis) { printf("[%8s] ", "???"); asis = 1; } if (isprint(*(Uint8 *)p)) { fputc(*(Uint8 *)p, stdout); } else { printf("\\%x", *(Uint8 *)p); } FORWARD(1); continue; } FORWARD(4); printf("[%8s] ", types[i].name); switch (types[i].type) { case AG_SOURCE_UINT8: printf("%u\n", *(Uint8 *)p); FORWARD(1); break; case AG_SOURCE_SINT8: printf("%d\n", *(Sint8 *)p); FORWARD(1); break; case AG_SOURCE_UINT16: printf("%u\n", AG_SwapBE16(*(Uint16 *)p)); FORWARD(2); break; case AG_SOURCE_SINT16: printf("%d\n", (Sint16)AG_SwapBE16(*(Uint16 *)p)); FORWARD(2); break; case AG_SOURCE_UINT32: printf("%u\n", AG_SwapBE32(*(Uint32 *)p)); FORWARD(2); break; case AG_SOURCE_SINT32: printf("%u\n", AG_SwapBE32(*(Sint32 *)p)); FORWARD(2); break; #ifdef HAVE_64BIT case AG_SOURCE_UINT64: printf("%llu\n", (unsigned long long)AG_SwapBE64(*(Uint64 *)p)); FORWARD(8); break; case AG_SOURCE_SINT64: printf("%lld\n", (long long)AG_SwapBE64(*(Uint64 *)p)); FORWARD(8); break; #endif #ifdef HAVE_FLOAT case AG_SOURCE_FLOAT: printf("%f\n", *(float *)p); FORWARD(4); break; case AG_SOURCE_DOUBLE: printf("%f\n", *(double *)p); FORWARD(8); break; #endif case AG_SOURCE_STRING: if (AG_SwapBE32(*(Uint32 *)p) != AG_SOURCE_UINT32) { printf("Bad string length!\n"); break; } FORWARD(4); sLen = AG_SwapBE32(*(Uint32 *)p); FORWARD(4); if ((s = malloc(sLen+1)) == NULL) { printf("Out of memory for string!\n"); break; } memcpy(s, p, sLen); s[sLen] = '\0'; printf("\"%s\"\n", s); free(s); FORWARD(sLen); break; case AG_SOURCE_STRING_PAD: /* TODO */ break; default: printf("(skipping)\n"); break; } } out: AG_CloseFile(ds); return (0); fail: fprintf(stderr, "%s\n", AG_GetError()); if (ds != NULL) { AG_CloseFile(ds); } AG_Destroy(); return (1); }