├── readme.md ├── wgeo.c ├── .clang-format ├── dmx.h ├── Source2ResourceDecompiler.sdf ├── .gitattributes ├── Source2ResourceDecompiler.v12.suo ├── dmx ├── dmxbraw.h ├── dmxinternal.h ├── dmxb.h ├── dmxb.c ├── dmx.h ├── dmx.c └── dmxbraw.c ├── s2rd.h ├── dmx.c ├── crc32.h ├── decompilers ├── SVF1.h ├── decompilers.h └── SVF1.c ├── .gitignore ├── fileinfo.h ├── index.html ├── wgeo.h ├── PanoramaCompilerMSVC ├── PanoramaCompiler.vcxproj.filters ├── ReadMe.txt └── PanoramaCompiler.vcxproj ├── panorepack.c ├── Source2ResourceDecompiler.vcxproj.filters ├── Makefile ├── fileinfo.c ├── s2rd.c ├── Source2ResourceDecompiler.sln ├── vcs.h ├── Source2ResourceDecompiler.vcxproj ├── crc32.c ├── panoramacompiler.c ├── vcs.c ├── stupidvalve.h └── stupidvalve.c /readme.md: -------------------------------------------------------------------------------- 1 | A decompiler for Source 2 file formats. 2 | -------------------------------------------------------------------------------- /wgeo.c: -------------------------------------------------------------------------------- 1 | // Stio what are you doing this isn't a source2 file format... 2 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM 2 | IndentWidth: 8 3 | UseTab: ForIndentation 4 | -------------------------------------------------------------------------------- /dmx.h: -------------------------------------------------------------------------------- 1 | #ifndef DMX_H 2 | #define DMX_H 3 | #include "fileinfo.h" 4 | void parse_dmx(filedata *fd); 5 | #endif 6 | -------------------------------------------------------------------------------- /Source2ResourceDecompiler.sdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Penguinwizzard/Source2ResourceDecompiler/HEAD/Source2ResourceDecompiler.sdf -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | 3 | # VS 4 | *.sln text eol=crlf 5 | *.vcxproj text eol=crlf 6 | *.vcxproj.filters text eol=crlf 7 | -------------------------------------------------------------------------------- /Source2ResourceDecompiler.v12.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Penguinwizzard/Source2ResourceDecompiler/HEAD/Source2ResourceDecompiler.v12.suo -------------------------------------------------------------------------------- /dmx/dmxbraw.h: -------------------------------------------------------------------------------- 1 | // Note that we've skipped the silly ", 29)) { 55 | fprintf(stderr, "Error: The legacy dmx version binary_v2 is " 56 | "not supported\n"); 57 | return NULL; 58 | } 59 | if (strncmp(buffer, "\n%n", 75 | &encodingversion, filetype, &fileencodingversion, 76 | &lengthparsed); 77 | printf("%i %i\n", matched, lengthparsed); 78 | if (matched == EOF) { 79 | fprintf(stderr, "Error parsing dmx header - it seems " 80 | "to be misformatted?\n"); 81 | return NULL; 82 | } 83 | switch (encodingversion) { 84 | case 1: 85 | return dmx_from_buffer_1(buffer + lengthparsed + 1, 86 | length); 87 | case 2: 88 | return dmx_from_buffer_2(buffer + lengthparsed + 1, 89 | length); 90 | case 3: 91 | return dmx_from_buffer_3(buffer + lengthparsed + 1, 92 | length); 93 | case 4: 94 | return dmx_from_buffer_4(buffer + lengthparsed + 1, 95 | length); 96 | case 5: 97 | return dmx_from_buffer_5(buffer + lengthparsed + 1, 98 | length); 99 | case 6: 100 | return dmx_from_buffer_6(buffer + lengthparsed + 1, 101 | length); 102 | case 7: 103 | return dmx_from_buffer_7(buffer + lengthparsed + 1, 104 | length); 105 | case 8: 106 | return dmx_from_buffer_8(buffer + lengthparsed + 1, 107 | length); 108 | case 9: 109 | return dmx_from_buffer_9(buffer + lengthparsed + 1, 110 | length); 111 | default: 112 | fprintf(stderr, "Unknown variant of binary dmx - %i\n", 113 | encodingversion); 114 | return NULL; 115 | } 116 | } else if (!strncmp(current, "keyvalues", 8)) { 117 | fprintf(stderr, "keyvalues2/3 not yet handled!\n"); 118 | return NULL; 119 | } 120 | fprintf(stderr, "Unknown dmx variant\n"); 121 | return NULL; 122 | } 123 | -------------------------------------------------------------------------------- /Source2ResourceDecompiler.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {8EA29BB9-2393-4E50-BF00-87BC7D4C4F17} 15 | Win32Proj 16 | 17 | 18 | 19 | Application 20 | true 21 | v120 22 | 23 | 24 | Application 25 | false 26 | v120 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | true 40 | 41 | 42 | true 43 | 44 | 45 | 46 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 47 | MultiThreadedDebugDLL 48 | Level3 49 | ProgramDatabase 50 | Disabled 51 | 52 | 53 | MachineX86 54 | true 55 | Console 56 | 57 | 58 | 59 | 60 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 61 | MultiThreadedDLL 62 | Level3 63 | ProgramDatabase 64 | 65 | 66 | MachineX86 67 | true 68 | Console 69 | true 70 | true 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /PanoramaCompilerMSVC/PanoramaCompiler.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {6172C829-0FC4-43F0-8615-695866FCF679} 15 | Win32Proj 16 | PanoramaCompiler 17 | 18 | 19 | 20 | Application 21 | true 22 | v120 23 | Unicode 24 | 25 | 26 | Application 27 | false 28 | v120 29 | true 30 | Unicode 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | true 44 | 45 | 46 | false 47 | 48 | 49 | 50 | 51 | 52 | Level3 53 | Disabled 54 | WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 55 | 56 | 57 | Console 58 | true 59 | 60 | 61 | 62 | 63 | Level3 64 | 65 | 66 | MaxSpeed 67 | true 68 | true 69 | WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 70 | 71 | 72 | Console 73 | true 74 | true 75 | true 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /crc32.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or 3 | * code or tables extracted from it, as desired without restriction. 4 | * 5 | * First, the polynomial itself and its table of feedback terms. The 6 | * polynomial is 7 | * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 8 | * 9 | * Note that we take it "backwards" and put the highest-order term in 10 | * the lowest-order bit. The X^32 term is "implied"; the LSB is the 11 | * X^31 term, etc. The X^0 term (usually shown as "+1") results in 12 | * the MSB being 1 13 | * 14 | * Note that the usual hardware shift register implementation, which 15 | * is what we're using (we're merely optimizing it by doing eight-bit 16 | * chunks at a time) shifts bits into the lowest-order term. In our 17 | * implementation, that means shifting towards the right. Why do we 18 | * do it this way? Because the calculated CRC must be transmitted in 19 | * order from highest-order term to lowest-order term. UARTs transmit 20 | * characters in order from LSB to MSB. By storing the CRC this way 21 | * we hand it to the UART in the order low-byte to high-byte; the UART 22 | * sends each low-bit to hight-bit; and the result is transmission bit 23 | * by bit from highest- to lowest-order term without requiring any bit 24 | * shuffling on our part. Reception works similarly 25 | * 26 | * The feedback terms table consists of 256, 32-bit entries. Notes 27 | * 28 | * The table can be generated at runtime if desired; code to do so 29 | * is shown later. It might not be obvious, but the feedback 30 | * terms simply represent the results of eight shift/xor opera 31 | * tions for all combinations of data and CRC register values 32 | * 33 | * The values must be right-shifted by eight bits by the "updcrc 34 | * logic; the shift must be unsigned (bring in zeroes). On some 35 | * hardware you could probably optimize the shift in assembler by 36 | * using byte-swap instructions 37 | * polynomial $edb88320 38 | * 39 | * 40 | * CRC32 code derived from work by Gary S. Brown. 41 | */ 42 | 43 | #include 44 | #include 45 | 46 | static uint32_t crc32_tab[] = { 47 | 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 48 | 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 49 | 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 50 | 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 51 | 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 52 | 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 53 | 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 54 | 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 55 | 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 56 | 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 57 | 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 58 | 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 59 | 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 60 | 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 61 | 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 62 | 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 63 | 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 64 | 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 65 | 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 66 | 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 67 | 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 68 | 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 69 | 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 70 | 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 71 | 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 72 | 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 73 | 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 74 | 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 75 | 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 76 | 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 77 | 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 78 | 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 79 | 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 80 | 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 81 | 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 82 | 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 83 | 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 84 | 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 85 | 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 86 | 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 87 | 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 88 | 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 89 | 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d}; 90 | 91 | uint32_t crc32(uint32_t crc, const void *buf, size_t size) { 92 | const uint8_t *p; 93 | 94 | p = buf; 95 | crc = crc ^ ~0U; 96 | 97 | while (size--) 98 | crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); 99 | 100 | return crc ^ ~0U; 101 | } 102 | -------------------------------------------------------------------------------- /panoramacompiler.c: -------------------------------------------------------------------------------- 1 | #include "crc32.h" 2 | #include "stupidvalve.h" 3 | 4 | #define SETOFFS(x, y) x = ((char *)(y)) - ((char *)&(x)); 5 | #define setOffsetString(a, b) \ 6 | strncpy(pointer, (b), 64); \ 7 | (a) = pointer - ((char *)&(a)); \ 8 | pointer += strlen(b) + 1; 9 | 10 | char *construct_file(char *sourcefilename, char *sourcefilename2, 11 | char *contentdirname, char *contents) { 12 | uint32_t length = strlen(sourcefilename) + strlen(contents) + 13 | strlen(contentdirname) + 400; 14 | svf_header *output = calloc(length, 1); 15 | char *pointer = (char *)output; 16 | pointer += sizeof(svf_header); 17 | output->always_twelve = 12; 18 | output->version = 2; 19 | output->lumps.offset = 8; 20 | output->lumps.count = 2; // REDI and DATA 21 | svflump_header *headers = (svflump_header *)(pointer); 22 | pointer += output->lumps.count * sizeof(svflump_header); 23 | headers[0].tag[0] = 'R'; 24 | headers[0].tag[1] = 'E'; 25 | headers[0].tag[2] = 'D'; 26 | headers[0].tag[3] = 'I'; 27 | headers[1].tag[0] = 'D'; 28 | headers[1].tag[1] = 'A'; 29 | headers[1].tag[2] = 'T'; 30 | headers[1].tag[3] = 'A'; 31 | svfl_redi_header_datafile *srhd = 32 | (svfl_redi_header_datafile *)(pointer); 33 | pointer += sizeof(svfl_redi_header_datafile); 34 | // we need this 35 | srhd->sourceresource.count = 2; 36 | srhd->sourceresourceadd.offset = 0; 37 | srhd->sourceresourceadd.count = 0; 38 | // we need this 39 | srhd->arguments.count = 1; 40 | // we need this 41 | srhd->namemap.count = 1; 42 | srhd->customdeps.offset = 0; 43 | srhd->customdeps.count = 0; 44 | srhd->additional_related.offset = 0; 45 | srhd->additional_related.count = 0; 46 | srhd->child_ref.offset = 0; 47 | srhd->child_ref.count = 0; 48 | // we need this 49 | srhd->extradata_int.count = 1; 50 | srhd->extradata_float.offset = 0; 51 | srhd->extradata_float.count = 0; 52 | srhd->extradata_string.offset = 0; 53 | srhd->extradata_string.count = 0; 54 | 55 | // Information about source files 56 | svfl_redi_sourceresource_datafile *sourceref = 57 | (svfl_redi_sourceresource_datafile *)pointer; 58 | pointer += srhd->sourceresource.count * 59 | sizeof(svfl_redi_sourceresource_datafile); 60 | sourceref[0].CRC = 0; // Valve generally doesn't compile a vxml, and 61 | // this is just an alias, therefore the crc is 0 62 | sourceref[0].flags = 1; 63 | sourceref[1].CRC = 64 | 0; // This is generally non-zero, but it seems to be only 65 | // used for checking when things need recompilation, 66 | // which we're not bothering with (yet, anyway). 67 | sourceref[1].flags = 2; 68 | SETOFFS(srhd->sourceresource.offset, sourceref); 69 | setOffsetString(sourceref[0].offset_filename, sourcefilename); 70 | setOffsetString(sourceref[0].offset_modname, contentdirname); 71 | setOffsetString(sourceref[1].offset_filename, sourcefilename2); 72 | setOffsetString(sourceref[1].offset_modname, contentdirname); 73 | 74 | if ((pointer - (char *)srhd) % 4 != 0) { 75 | pointer += 4 - ((pointer - (char *)srhd) % 4); 76 | } 77 | 78 | // Creation arguments 79 | svfl_redi_argument_datafile *tdentry = 80 | (svfl_redi_argument_datafile *)(pointer); 81 | pointer += srhd->arguments.count * sizeof(svfl_redi_argument_datafile); 82 | tdentry->fingerprint = 0; 83 | tdentry->fingerprint_default = 0; 84 | SETOFFS(srhd->arguments.offset, tdentry); 85 | setOffsetString(tdentry->offset_name, "___OverrideInputData___"); 86 | setOffsetString(tdentry->offset_type, "BinaryBlobArg"); 87 | 88 | if ((pointer - (char *)srhd) % 4 != 0) { 89 | pointer += 4 - ((pointer - (char *)srhd) % 4); 90 | } 91 | 92 | // Named data map 93 | svfl_redi_namemap_datafile *ndentry = 94 | (svfl_redi_namemap_datafile *)pointer; 95 | pointer += srhd->namemap.count * sizeof(svfl_redi_namemap_datafile); 96 | ndentry->fingerprint = 5; 97 | ndentry->userdata = 0; 98 | SETOFFS(srhd->namemap.offset, ndentry); 99 | setOffsetString(ndentry->offset_key, "CompilePanorama"); 100 | setOffsetString(ndentry->offset_expanded, "Panorama Compiler Version"); 101 | 102 | if ((pointer - (char *)srhd) % 8 != 0) { 103 | pointer += 8 - ((pointer - (char *)srhd) % 8); 104 | } 105 | 106 | // Extra int data 107 | svfl_redi_extradata_int_datafile *sdentry = 108 | (svfl_redi_extradata_int_datafile *)pointer; 109 | pointer += srhd->extradata_int.count * 110 | sizeof(svfl_redi_extradata_int_datafile); 111 | sdentry->value = 0; 112 | SETOFFS(srhd->extradata_int.offset, sdentry); 113 | setOffsetString(sdentry->offset_key, "IsChildResource"); 114 | 115 | // ok, that's it for REDI 116 | SETOFFS(headers[0].offset, srhd); 117 | headers[0].length = pointer - ((char *)srhd); 118 | if ((pointer - (char *)output) % 16 != 0) { 119 | pointer += 16 - ((pointer - (char *)output) % 16); 120 | } 121 | // The 16-byte alignment for DATA isn't factored into block space 122 | SETOFFS(headers[1].offset, pointer); 123 | headers[1].length = strlen(contents) + 6; 124 | // The 4-byte header from hell, and two bytes of 0 125 | *((uint32_t *)pointer) = crc32(0, contents, strlen(contents)); 126 | pointer += 4; 127 | *((uint16_t *)pointer) = 0; 128 | pointer += 2; 129 | strcpy(pointer, contents); 130 | length = pointer + strlen(contents) - (char *)output; 131 | output->filelength = length; 132 | return (char *)output; 133 | } 134 | 135 | int main(int argc, char **argv) { 136 | if (argc < 6) { 137 | printf("Penguinwizzard Panorama Compiler v0.1\nUsage: " 138 | "./panoramacompiler " 139 | " " 140 | " \nThe last two " 141 | "are used " 142 | "inside the file for reference info.\n"); 143 | return 1; 144 | } 145 | FILE *f = fopen(argv[1], "r"); 146 | if (f == NULL) { 147 | printf("File read error; error code is %i\n", errno); 148 | return 1; 149 | } 150 | fseek(f, 0, SEEK_END); 151 | long size = ftell(f); 152 | fseek(f, 0, SEEK_SET); 153 | 154 | char *buffer = malloc(size + 1); 155 | long num_ret = fread(buffer, size, 1, f); 156 | if (num_ret != 1) { 157 | printf("Warning: File size is being wonky; expected 1 but got " 158 | "%li\n", 159 | num_ret); 160 | } 161 | fclose(f); 162 | buffer[size] = '\0'; 163 | char *output = construct_file(argv[3], argv[4], argv[5], buffer); 164 | FILE *out = fopen(argv[2], "w"); 165 | if (out == NULL) { 166 | printf("File open error; could not open output file; error " 167 | "code is %i\n", 168 | errno); 169 | return 1; 170 | } 171 | fwrite(output, *((uint32_t *)output), 1, out); 172 | fclose(out); 173 | printf("finished!\n"); 174 | return 0; 175 | } 176 | -------------------------------------------------------------------------------- /vcs.c: -------------------------------------------------------------------------------- 1 | #include "vcs.h" 2 | 3 | void parse_vcs(filedata *fd) { 4 | vcsfile *ret = (vcsfile *)malloc(sizeof(vcsfile)); 5 | vcs_header *vh = (vcs_header *)(fd->contents); 6 | uint32_t cur = 0; 7 | uint32_t type = 0; 8 | printf("ID %.8X\n", vh->file_identifier); 9 | if (vh->file_identifier == 0) { 10 | // This means we're in the features file. 11 | // This file contains information that identifies the shader. 12 | ret->namelen = vh->namelen; 13 | ret->name = fd->contents + 16; 14 | memcpy(ret->counts, fd->contents + 16 + ret->namelen + 1, 15 | sizeof(ret->counts)); 16 | cur = 16 + ret->namelen + 1 + sizeof(ret->counts); 17 | printf("Parsing as features file...\n"); 18 | printf("COUNTS: %d %d %d %d %d %d %d %d\n", ret->counts[0], 19 | ret->counts[1], ret->counts[2], ret->counts[3], 20 | ret->counts[4], ret->counts[5], ret->counts[6], 21 | ret->counts[7]); 22 | } else { 23 | ret->namelen = 0; 24 | // Skip a bunch of stuff I don't recognize 25 | cur = 44; 26 | type = 1; 27 | } 28 | // Read type 1 lumps 29 | if (type == 0) { 30 | uint32_t count1 = *(uint32_t *)(fd->contents + cur); 31 | cur += 4; 32 | if (count1 == 4) 33 | count1 = 2; 34 | printf("Type 1 count: %u\n", count1); 35 | uint32_t i; 36 | for (i = 0; i < count1; i++) { 37 | vcsl_1 *thisone = (vcsl_1 *)(fd->contents + cur); 38 | printf("\t%s\n", thisone->name); 39 | cur += sizeof(vcsl_1); 40 | } 41 | } 42 | // Read type 2 lumps 43 | { 44 | uint32_t count2 = *(uint32_t *)(fd->contents + cur); 45 | cur += 4; 46 | printf("Type 2 count: %u\n", count2); 47 | uint32_t i; 48 | for (i = 0; i < count2; i++) { 49 | vcsl_2 *thisone = (vcsl_2 *)(fd->contents + cur); 50 | printf("\t%s\n", thisone->name); 51 | printf("\t\t(unknowns are %.8X %.8X %.8X %.8X %.8X " 52 | "%.8X)\n", 53 | thisone->unknown1, thisone->unknown2, 54 | thisone->unknown3, thisone->unknown4, 55 | thisone->unknown5, thisone->unknown6); 56 | cur += sizeof(vcsl_2); 57 | } 58 | } 59 | // Read type 3 lumps 60 | { 61 | uint32_t count3 = *(uint32_t *)(fd->contents + cur); 62 | cur += 4; 63 | printf("Type 3 count: %u\n", count3); 64 | uint32_t i; 65 | for (i = 0; i < count3; i++) { 66 | cur += 8; 67 | } 68 | for (i = 0; i < count3; i++) { 69 | // vcsl_3* thisone = (vcsl_3*)(fd->contents + cur); 70 | printf("\tcontents unknown\n"); 71 | cur += sizeof(vcsl_3); 72 | } 73 | } 74 | // Read type 4 lumps 75 | { 76 | uint32_t count4 = *(uint32_t *)(fd->contents + cur); 77 | cur += 4; 78 | printf("Type 4 count: %u\n", count4); 79 | uint32_t i; 80 | for (i = 0; i < count4; i++) { 81 | vcsl_4 *thisone = (vcsl_4 *)(fd->contents + cur); 82 | printf("\t%s\n", thisone->name); 83 | printf("\t\t(unknowns are %.8X %.8X %.8X %.8X %.8X " 84 | "%.8X)\n", 85 | thisone->unknown1, thisone->unknown2, 86 | thisone->unknown3, thisone->unknown4, 87 | thisone->unknown5, thisone->unknown6); 88 | cur += sizeof(vcsl_4); 89 | } 90 | } 91 | // Read type 5 lumps 92 | { 93 | uint32_t count5 = *(uint32_t *)(fd->contents + cur); 94 | cur += 4; 95 | printf("Type 5 count: %u\n", count5); 96 | uint32_t i; 97 | for (i = 0; i < count5; i++) { 98 | // vcsl_5* thisone = (vcsl_5*)(fd->contents + cur); 99 | printf("\tformat unknown\n"); 100 | cur += sizeof(vcsl_5); 101 | } 102 | } 103 | // Read type 6 lumps 104 | { 105 | uint32_t count6 = *(uint32_t *)(fd->contents + cur); 106 | cur += 4; 107 | printf("Type 6 count: %u\n", count6); 108 | uint32_t i; 109 | vcsl_6 *lastone = NULL; 110 | for (i = 0; i < count6; i++) { 111 | vcsl_6 *thisone = (vcsl_6 *)(fd->contents + cur); 112 | printf("\t%s :", thisone->name); 113 | switch (thisone->type) { 114 | case VCSL_6_TYPE_T: 115 | case VCSL_6_TYPE_VECTOR: 116 | printf(" %s\n", thisone->string_value); 117 | break; 118 | case VCSL_6_TYPE_FLOAT: 119 | printf(" %f\n", thisone->float_value); 120 | break; 121 | default: 122 | printf("\n"); 123 | break; 124 | } 125 | printf("\t\t(type: %u, unknown: %u)\n", thisone->type, 126 | thisone->unknown2); 127 | printf("\t\tunknowns:\n"); 128 | uint32_t j; 129 | for (j = 0; j < 70; j++) { 130 | if (lastone != NULL && 131 | lastone->unknown[j] != 132 | thisone->unknown[j]) { 133 | printf("\x1b[31m%u:%.8X\x1b[0m\t", j, 134 | thisone->unknown[j]); 135 | } else { 136 | printf("%u:%.8X\t", j, 137 | thisone->unknown[j]); 138 | } 139 | } 140 | lastone = thisone; 141 | printf("\n"); 142 | cur += sizeof(vcsl_6); 143 | } 144 | } 145 | // Read type 7 lumps 146 | { 147 | uint32_t count7 = *(uint32_t *)(fd->contents + cur); 148 | cur += 4; 149 | printf("Type 7 count: %u\n", count7); 150 | uint32_t i; 151 | for (i = 0; i < count7; i++) { 152 | vcsl_7 *thisone = (vcsl_7 *)(fd->contents + cur); 153 | printf("\t%s\n", thisone->name); 154 | cur += sizeof(vcsl_7); 155 | } 156 | } 157 | // Read type 8 lumps 158 | { 159 | uint32_t count8 = *(uint32_t *)(fd->contents + cur); 160 | cur += 4; 161 | printf("Type 8 count: %u\n", count8); 162 | uint32_t i; 163 | for (i = 0; i < count8; i++) { 164 | vcsl_8 *current = (vcsl_8 *)(fd->contents + cur); 165 | cur += sizeof(vcsl_8); 166 | printf("\t%s:\n", current->name); 167 | uint32_t j; 168 | for (j = 0; j < current->num_keys; j++) { 169 | vcsl_8_kv *kv = 170 | (vcsl_8_kv *)(fd->contents + cur); 171 | printf("\t\t%s\n", kv->name); 172 | cur += sizeof(vcsl_8_kv); 173 | } 174 | // I think there's a CRC checksum or something at the 175 | // end... 176 | cur += 4; 177 | } 178 | } 179 | // Read type 9 lumps 180 | { 181 | uint32_t count9 = *(uint32_t *)(fd->contents + cur); 182 | cur += 4; 183 | printf("Type 9 count: %u\n", count9); 184 | // There is an optional set of strings here... 185 | /*uint32_t flag = *(uint32_t*)(fd->contents + cur); 186 | if(flag == 1) { 187 | printf("\tLump leading strings:\n"); 188 | while(*(fd->contents+cur)) { 189 | printf("\t\t%s\n",fd->contents + cur); 190 | cur += strlen(fd->contents + cur)+1; 191 | } 192 | }*/ 193 | { 194 | uint32_t j; 195 | for (j = 0; j < count9; j++) { 196 | printf("skipping %u\n", 197 | *(uint32_t *)(fd->contents + cur)); 198 | cur += 4; 199 | printf(" skipping %u\n", 200 | *(uint32_t *)(fd->contents + cur)); 201 | cur += 4; 202 | } 203 | for (j = 0; j < count9; j++) { 204 | printf("type 2 skip %u\n", 205 | *(uint32_t *)(fd->contents + cur)); 206 | cur += 4; 207 | } 208 | } 209 | { 210 | printf("\timportant value I don't know the purpose of " 211 | "yet: %u\n", 212 | *(uint32_t *)(fd->contents + cur)); 213 | cur += 4; 214 | printf("\tlength of first compressed block (with " 215 | "header): %u\n", 216 | *(uint32_t *)(fd->contents + cur)); 217 | cur += 4; 218 | } 219 | uint32_t i; 220 | for (i = 0; i < count9; i++) { 221 | vcsl_9_l *lump = (vcsl_9_l *)(fd->contents + cur); 222 | cur += sizeof(vcsl_9_l); 223 | printf("\tCompressed data (compressed with %.4s, " 224 | "compressed length " 225 | "%u, uncompressed length %u\n", 226 | lump->encoding_aschars, lump->compressed_length, 227 | lump->uncompressed_length); 228 | printf("\t\t(flags are %.8X %.8X)\n", lump->unknown1, 229 | lump->unknown2); 230 | cur += lump->compressed_length + 231 | 1; // +1 for null terminator 232 | } 233 | } 234 | print_vcs(ret); 235 | fd->filetype = VCS; 236 | fd->parsed = ret; 237 | } 238 | 239 | void print_vcs(vcsfile *vcs) { 240 | printf("VCS2 File\n"); 241 | printf("Shader Description: %.*s\n", vcs->namelen, vcs->name); 242 | } 243 | void free_vcs(filedata *fd) { 244 | if (fd->filetype != VCS) { 245 | fprintf(stderr, 246 | "Error: tried to use VCS free on non-VCS data.\n"); 247 | return; 248 | } 249 | free(fd->parsed); 250 | fd->parsed = NULL; 251 | } 252 | -------------------------------------------------------------------------------- /stupidvalve.h: -------------------------------------------------------------------------------- 1 | #ifndef stupidvalve_h 2 | #define stupidvalve_h 3 | #include "fileinfo.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | // Pretty common 11 | typedef struct { 12 | uint32_t offset; 13 | uint32_t count; 14 | } offsetcount; 15 | 16 | // SVF = Stupid Valve Format 17 | 18 | #ifndef WIN32 19 | typedef struct __attribute__((__packed__)) { 20 | #else 21 | #pragma pack(push, 1) 22 | typedef struct { 23 | #endif 24 | uint32_t 25 | filelength; // Why this is specified in a modern format is beyond me 26 | // The whole format would be so much better if this was 27 | // a type-specific magic number instead We'd actually be 28 | // able to add a `file` rule for them, we'd be able to 29 | // do exention-agnostic code, and a ton of other stuff 30 | // But no, Valve is stuck in the 90s. Also, note that 31 | // this number is often wrong, so don't use it for 32 | // allocation or anything terribly important. In fact, 33 | // it's probably better if you ignore this altogether, 34 | // and just go on with your life and ignore the format 35 | // details. 36 | uint16_t always_twelve; // 12 - Length of lump header? 37 | uint16_t version; // Type information 38 | offsetcount lumps; 39 | } svf_header; 40 | #ifdef WIN32 41 | #pragma pack(pop) 42 | #endif 43 | 44 | typedef struct { 45 | union { 46 | char tag[4]; // A magic number type identifier. AREN'T THEY NICE 47 | // VALVE? 48 | uint32_t type_asint; 49 | }; 50 | uint32_t offset; // Offset in the source file that the body of the lump 51 | // starts at 52 | uint32_t 53 | length; // Note that length includes the 12 bytes for the header 54 | } svflump_header; 55 | 56 | typedef struct { 57 | union { 58 | uint32_t type; // uint32 representation of tag, e.g. RERL 59 | char type_aschar[4]; 60 | }; 61 | char *content; 62 | uint32_t filler[10]; 63 | } svfl_header; 64 | 65 | typedef struct { 66 | svf_header *hdr; 67 | svflump_header *lumpheaders; 68 | svfl_header *lumps; 69 | } svffile_generic; 70 | 71 | /* 72 | * RERL 73 | */ 74 | 75 | typedef struct { 76 | offsetcount entries; 77 | } svfl_rerl_header_datafile; 78 | 79 | typedef struct { 80 | uint64_t objecttag; // The tag of the target resource - calculation 81 | // method unknown 82 | uint32_t offset; // Measured from this entry ... volvo plz 83 | uint32_t unknown; // Always 0? 84 | } svfl_rerl_entry_datafile; 85 | 86 | typedef struct { 87 | svfl_rerl_entry_datafile *df; 88 | char *content; 89 | } svfl_rerl_entry; 90 | 91 | typedef struct { 92 | uint32_t type; 93 | char *content; 94 | svfl_rerl_header_datafile *df; 95 | svfl_rerl_entry *entries; 96 | } svfl_rerl_header; 97 | 98 | /* 99 | * REDI 100 | */ 101 | 102 | #ifndef WIN32 103 | typedef struct __attribute__((__packed__)) { 104 | #else 105 | #pragma pack(push, 1) 106 | typedef struct { 107 | #endif 108 | offsetcount sourceresource; 109 | offsetcount sourceresourceadd; 110 | offsetcount arguments; 111 | offsetcount namemap; 112 | offsetcount customdeps; 113 | offsetcount additional_related; 114 | offsetcount child_ref; 115 | offsetcount extradata_int; 116 | offsetcount extradata_float; 117 | offsetcount extradata_string; 118 | } svfl_redi_header_datafile; 119 | #ifdef WIN32 120 | #pragma pack(pop) 121 | #endif 122 | 123 | // Sourceresourceref sub 124 | // Sourceresourcerefadd sub 125 | typedef struct { 126 | uint32_t offset_filename; 127 | uint32_t offset_modname; 128 | uint32_t CRC; // CRC of the input file 129 | uint32_t flags; // often 2 130 | } svfl_redi_sourceresource_datafile; 131 | 132 | typedef struct { 133 | svfl_redi_sourceresource_datafile *df; 134 | char *filename; 135 | char *contentsearchpath; 136 | } svfl_redi_sourceresource; 137 | 138 | // Typeddata sub 139 | typedef struct { 140 | uint32_t offset_name; 141 | uint32_t offset_type; 142 | uint32_t 143 | fingerprint; // The two flag fields are generally the same value. 144 | uint32_t fingerprint_default; // observed are 0x00000001 and 0x00002000 145 | } svfl_redi_argument_datafile; 146 | 147 | typedef struct { 148 | svfl_redi_argument_datafile *df; 149 | char *name; 150 | char *type; 151 | } svfl_redi_argument; 152 | 153 | // Namemap sub 154 | typedef struct { 155 | uint32_t offset_expanded; // the longer one, occurs second later :/ 156 | uint32_t offset_key; // the shorter one, occurs first later 157 | uint32_t fingerprint; // Various values 158 | uint32_t userdata; // Always 0? 159 | } svfl_redi_namemap_datafile; 160 | 161 | typedef struct { 162 | svfl_redi_namemap_datafile *df; 163 | char *key; 164 | char *expanded; 165 | } svfl_redi_namemap; 166 | 167 | // Deferredref sub 168 | typedef struct { 169 | uint64_t objecttag; // The tag of the target resource - calculation 170 | // method unknown 171 | uint32_t offset; // Measured from this entry ... volvo plz 172 | uint32_t unknown; // Always 0? - padding? 173 | } svfl_redi_childref_datafile; 174 | 175 | typedef struct { 176 | svfl_redi_childref_datafile *df; 177 | char *content; 178 | } svfl_redi_childref; 179 | 180 | // SpecialData sub 181 | typedef struct { 182 | uint32_t offset_key; 183 | uint32_t value; 184 | } svfl_redi_extradata_int_datafile; 185 | 186 | typedef struct { 187 | svfl_redi_extradata_int_datafile *df; 188 | char *key; 189 | } svfl_redi_extradata_int; 190 | 191 | // SpecialData sub 192 | typedef struct { 193 | uint32_t offset_key; 194 | float value; 195 | } svfl_redi_extradata_float_datafile; 196 | 197 | typedef struct { 198 | svfl_redi_extradata_float_datafile *df; 199 | char *key; 200 | } svfl_redi_extradata_float; 201 | 202 | // SpecialData sub 203 | typedef struct { 204 | uint32_t offset_key; 205 | uint32_t value; 206 | } svfl_redi_extradata_string_datafile; 207 | 208 | typedef struct { 209 | svfl_redi_extradata_string_datafile *df; 210 | char *key; 211 | } svfl_redi_extradata_string; 212 | 213 | typedef struct { 214 | uint32_t type; 215 | char *content; 216 | svfl_redi_header_datafile *df; 217 | svfl_redi_sourceresource *srentries; 218 | svfl_redi_sourceresource *sraentries; 219 | svfl_redi_argument *tdentries; 220 | svfl_redi_namemap *nmentries; 221 | void *unknown2; 222 | void *unknown3; 223 | svfl_redi_childref *crentries; 224 | svfl_redi_extradata_int *edientries; 225 | svfl_redi_extradata_float *edfentries; 226 | svfl_redi_extradata_string *edsentries; 227 | char *resourcename; 228 | char *modname; 229 | } svfl_redi_header; 230 | 231 | /* 232 | * NTRO 233 | */ 234 | #ifndef WIN32 235 | typedef struct __attribute__((__packed__)) { 236 | #else 237 | #pragma pack(push, 1) 238 | typedef struct { 239 | #endif 240 | uint32_t version; // Always 4? (thanks hmfd for tag) 241 | uint32_t typetag; // Used for structs in structs and the like 242 | uint32_t offset_classname; 243 | uint32_t crc; // crc (thanks hmfd for tag) 244 | int32_t user_version; // Always 0? (thanks hmfd for tag) 245 | uint16_t length; // length in data lump 246 | uint16_t alignment; // Always 4? (thanks hmfd for tag) 247 | uint32_t base_struct_id; // Always 0? (thanks hmfd for tag) 248 | offsetcount tags; // Where to find the tags 249 | uint8_t struct_flags; 250 | uint8_t padding[3]; // padding? 251 | } svfl_ntro_entry_header_datafile; 252 | #ifdef WIN32 253 | #pragma pack(pop) 254 | #endif 255 | 256 | #define SVFL_DATATYPE_SUBSTRUCT 1 257 | #define SVFL_DATATYPE_ENUM 2 258 | #define SVFL_DATATYPE_EXTREF 3 259 | #define SVFL_DATATYPE_STRING4 4 260 | #define SVFL_DATATYPE_INT8 10 261 | #define SVFL_DATATYPE_UINT8 11 262 | #define SVFL_DATATYPE_SINT 12 // INT16 263 | #define SVFL_DATATYPE_UINT16 13 264 | #define SVFL_DATATYPE_INT32 14 265 | #define SVFL_DATATYPE_UINT32 15 266 | #define SVFL_DATATYPE_INT64 16 // TENTATIVE - NOT ENCOUNTERED 267 | #define SVFL_DATATYPE_UINT64 17 268 | #define SVFL_DATATYPE_FLOAT 18 269 | #define SVFL_DATATYPE_VEC3 22 270 | #define SVFL_DATATYPE_VECTOR4D 23 271 | #define SVFL_DATATYPE_QUATERNION 25 272 | #define SVFL_DATATYPE_FLTX4 27 273 | #define SVFL_DATATYPE_VEC4 28 // tentative - likely incorrect, may be _COLOR 274 | #define SVFL_DATATYPE_BOOLEAN 30 275 | #define SVFL_DATATYPE_STRING 31 276 | #define SVFL_DATATYPE_MATRIX3X4 33 277 | #define SVFL_DATATYPE_MATRIX3X4A 36 278 | #define SVFL_DATATYPE_CTRANSFORM 40 279 | 280 | #ifndef WIN32 281 | typedef struct __attribute__((__packed__)) { 282 | #else 283 | #pragma pack(push, 1) 284 | typedef struct { 285 | #endif 286 | uint32_t offset_tagname; 287 | int16_t count; // if 0, treat as 1; if more, treat as is 288 | int16_t offset_in_struct; // increases based on size of entry 289 | offsetcount indirections; // Indirect data 290 | uint32_t ref_typetag; // Type tag referenced 291 | int16_t 292 | datatype; // 1 - array reference - 8 bytes - offset 4b, count 4b 293 | // 2/n - enum? 294 | // 3 - other resource reference - 8 bytes, holds 295 | // resource key 4 - also string? (hmfd) 11/p - 12/n 296 | // - signed number? - 4 bytes 14/n - number - 4 bytes 297 | // 15/n - flags - 4 bytes 298 | // 17/h - buffer? - 8 bytes 299 | // 18/fl - float - 4 bytes 300 | // 22/v - vector - 12 bytes 301 | // 23/v - vector - 64 bytes! 302 | // 25/q - quaternion? - 16 bytes 303 | // 30/b - boolean - 1 byte 304 | // 31 - worldNodePrefix/ResoureFileNameList? 305 | uint16_t padding; 306 | } svfl_ntro_entry_tag_datafile; 307 | #ifdef WIN32 308 | #pragma pack(pop) 309 | #endif 310 | 311 | typedef struct { 312 | svfl_ntro_entry_tag_datafile *df; 313 | char *name; 314 | int refindex; // Index into the refs table 315 | } svfl_ntro_entry_tag; 316 | 317 | typedef struct { 318 | svfl_ntro_entry_header_datafile *hdf; 319 | svfl_ntro_entry_tag *tags; 320 | char *classname; 321 | int numrefs; // Number of references to internal stuffs 322 | } svfl_ntro_entry; 323 | 324 | typedef struct { 325 | uint32_t offset_fieldname; 326 | uint32_t value; 327 | } svfl_ntro_enum_field_datafile; 328 | 329 | typedef struct { 330 | svfl_ntro_enum_field_datafile *df; 331 | char *fieldname; 332 | } svfl_ntro_enum_field; 333 | 334 | typedef struct { 335 | uint32_t version; 336 | uint32_t id; 337 | uint32_t offset_enumname; 338 | uint32_t crc; 339 | int32_t user_version; 340 | offsetcount fields; 341 | } svfl_ntro_enum_datafile; 342 | 343 | typedef struct { 344 | svfl_ntro_enum_datafile *df; 345 | char *name; 346 | svfl_ntro_enum_field *fields; 347 | } svfl_ntro_enum; 348 | 349 | typedef struct { 350 | uint32_t version; 351 | offsetcount entries; 352 | offsetcount enums; 353 | } svfl_ntro_header_datafile; 354 | 355 | typedef struct { 356 | uint32_t type; 357 | char *content; 358 | svfl_ntro_header_datafile *df; 359 | svfl_ntro_entry *entries; 360 | svfl_ntro_enum *enums; 361 | } svfl_ntro_header; 362 | 363 | /* 364 | * VBIB sub 365 | */ 366 | // This structure shows up in mesh data for models. 367 | typedef struct { 368 | offsetcount vertexheaders; 369 | offsetcount indexheaders; 370 | } svfl_vbib_header_datafile; 371 | 372 | typedef struct { 373 | uint32_t vertex_count; //? 374 | uint32_t vertex_size; //? 375 | offsetcount fra; // format-related array ? 376 | 377 | } svfl_vbib_vertex_header; 378 | 379 | /* 380 | * DATA sub 381 | */ 382 | // Since this is where actual data is handled, we change form a bit 383 | // The data is just an instance of the first described struct (from the NTRO 384 | // sub) which has been encoded as specified. We just need to decode it, and then 385 | // provide means by which we can access the constituent values. 386 | typedef struct svfl_struct_t { 387 | svfl_ntro_header *NTRO; 388 | svfl_ntro_entry *type; 389 | char *data; 390 | } svfl_struct; 391 | 392 | /* 393 | * Function stubs 394 | */ 395 | 396 | void parse_svf(filedata *fd); 397 | void parse_object(svfl_struct *object, svfl_ntro_header *ntro, char *data); 398 | void print_object_recursive(svfl_struct *object); 399 | svfl_ntro_entry *do_type_lookup(svfl_ntro_header *ntro, uint32_t typetag); 400 | svfl_ntro_enum *do_enum_lookup(svfl_ntro_header *ntro, uint32_t enumtag); 401 | void free_svf(filedata *fd); 402 | #endif 403 | -------------------------------------------------------------------------------- /dmx/dmxbraw.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | // NOTE THAT DMXB is set before this file is loaded! 4 | 5 | /* 6 | * DMX is a fairly straightforward stream-based file format. The main 7 | * issue with handling it properly is that it's poorly documented, and 8 | * the documentation that exists can be inconsistent. Additionally, 9 | * there have been several versions released over the years; they do 10 | * some things differently, which I try to handle in a (fairly) clear 11 | * manner below. 12 | */ 13 | #ifdef STRING_INDEX_SIZE 14 | #undef STRING_INDEX_SIZE 15 | #undef STRING_INDEX_UNSET 16 | #undef STRING_DICT_SIZE_TYPE 17 | #endif 18 | #if DMXB < 5 19 | #define STRING_INDEX_SIZE uint16_t 20 | #define STRING_INDEX_UNSET 0xFFFF 21 | #else 22 | #define STRING_INDEX_SIZE uint32_t 23 | #define STRING_INDEX_UNSET 0xFFFFFFFF 24 | #endif 25 | #if DMXB < 4 26 | #define STRING_DICT_SIZE_TYPE uint16_t 27 | #else 28 | #define STRING_DICT_SIZE_TYPE uint32_t 29 | #endif 30 | 31 | // one-line definition for a variable-type indirect stream-based read 32 | #define READI(x) \ 33 | *(x *)(*bufferptrptr); \ 34 | *bufferptrptr += sizeof(x); 35 | // string handling 36 | #define READISTRING() \ 37 | (char *)(*bufferptrptr); \ 38 | *bufferptrptr += strlen(*bufferptrptr) + 1; 39 | // object pointer handling 40 | #define READIP(x) \ 41 | (x *)(*bufferptrptr); \ 42 | *bufferptrptr += sizeof(x); 43 | // buffer for reading in dmxattributes 44 | dmxattribute *V(readattribute)(dmx *dmx, char **bufferptrptr, bool stringsraw) { 45 | uint8_t type = READI(uint8_t); 46 | printf("\t\tparsing attribute with type %hhu\n", type); 47 | uint32_t typeindex = type - 1; 48 | bool array = false; 49 | #ifdef TYPECOUNT 50 | #undef TYPECOUNT 51 | #endif 52 | #if DMXB < 9 53 | #define TYPECOUNT 15 54 | #else 55 | #define TYPECOUNT 16 56 | #endif 57 | #if DMXB >= 9 58 | if (typeindex > 2 * TYPECOUNT) { 59 | typeindex -= TYPECOUNT * 2; 60 | array = true; 61 | } 62 | #endif 63 | if (typeindex > TYPECOUNT) { 64 | typeindex -= TYPECOUNT; 65 | array = true; 66 | } 67 | 68 | uint32_t count = 1; 69 | if (array) { 70 | count = READI(uint32_t); 71 | } 72 | switch (typeindex) { 73 | case 0x1:; // int32 74 | case 0x2:; // float 75 | case 0x3:; // bool 76 | case 0x6:; // TimeSpan 77 | case 0x7:; // Color 78 | case 0xE:; // uint64 79 | case 0xF:; // byte 80 | // these are natively handled! just keep on doing your thing... 81 | if (array) { 82 | dmxattribute *ret = allocindirectdmxattribute(dmx); 83 | ret->type = type; 84 | ret->val.array = (dmxcontentval *)(*bufferptrptr); 85 | ret->val.count = count; 86 | *bufferptrptr += lengths[typeindex] * count; 87 | } else { 88 | dmxattribute *ret = 89 | (dmxattribute *)((*bufferptrptr) - sizeof(uint8_t)); 90 | *bufferptrptr += lengths[typeindex]; 91 | return ret; 92 | } 93 | case 0x0:; // Element 94 | case 0x4:; // string 95 | case 0x5:; // byte[] 96 | case 0x8:; // vector of 2 floats 97 | case 0x9:; // vector of 3 floats 98 | case 0xA:; // vector of 4 floats 99 | case 0xB:; // angle 100 | case 0xC:; // quaternion 101 | case 0xD:; // matrix 102 | // these are indirectly handled - we allocate space specially 103 | // for these. 104 | dmxattribute *ret = allocindirectdmxattribute(dmx); 105 | ret->type = type; 106 | dmxcontentval *value = &(ret->val); 107 | dmxcontentval *writeto; 108 | if (array) { 109 | value->array = malloc(count * sizeof(dmxcontentval)); 110 | value->count = count; 111 | writeto = value->array; 112 | } else { 113 | writeto = value; 114 | } 115 | for (uint32_t i = 0; i < count; i++, writeto += 1) { 116 | switch (typeindex) { 117 | case 0x0: // Element 118 | writeto->index = READI(uint32_t); 119 | if (writeto->index == -1) { 120 | // null element 121 | } else if (writeto->index == -2) { 122 | // guid is here, as ascii string 123 | writeto->guid_AsString = READISTRING(); 124 | } else { 125 | // it's just read based off the index 126 | } 127 | break; 128 | case 0x4: // string 129 | if (stringsraw) { 130 | writeto->indirect = false; 131 | writeto->strval = READISTRING(); 132 | printf("read raw string %s\n", 133 | writeto->strval); 134 | } else { 135 | writeto->indirect = true; 136 | writeto->strindex = 137 | READI(STRING_INDEX_SIZE); 138 | } 139 | break; 140 | case 0x5: // byte[] 141 | writeto->barr_length = READI(uint32_t); 142 | writeto->barr_contents = 143 | (uint8_t *)*bufferptrptr; 144 | // FILE* fp = fopen("dump.jpg","w"); 145 | // fwrite(writeto->barr_contents, 146 | // sizeof(uint8_t), writeto->barr_length,fp); 147 | // fclose(fp); 148 | *bufferptrptr += writeto->barr_length; 149 | break; 150 | case 0x8: // vector of 2 floats 151 | writeto->vec2val = READIP(dmx_vector2); 152 | break; 153 | case 0x9: 154 | writeto->vec3val = READIP(dmx_vector3); 155 | break; 156 | case 0xA: 157 | writeto->vec4val = READIP(dmx_vector4); 158 | break; 159 | case 0xB: 160 | writeto->angleval = READIP(dmx_vector3); 161 | break; 162 | case 0xC: 163 | writeto->quatval = READIP(dmx_vector4); 164 | break; 165 | case 0xD: 166 | writeto->matval = READIP(dmx_matrix); 167 | break; 168 | } 169 | } 170 | return ret; 171 | default:; 172 | fprintf(stderr, "Error: unknown type %hhu!\n", type); 173 | return NULL; 174 | } 175 | } 176 | #undef READI 177 | #undef READIP 178 | #undef READISTRING 179 | 180 | void V(printattribute)(const dmxattribute *attr) { 181 | if (attr == NULL) { 182 | fprintf( 183 | stderr, 184 | "Error: tried printing null pointer as dmx attribute\n"); 185 | return; 186 | } 187 | } 188 | 189 | char *V(dictsearch)(char *const *const dict, const STRING_INDEX_SIZE index, 190 | const STRING_DICT_SIZE_TYPE count) { 191 | if (index == STRING_INDEX_UNSET) { 192 | fprintf(stderr, "was null\n"); 193 | return ""; 194 | } 195 | if (index >= count) { 196 | fprintf(stderr, "string index out of range!\n"); 197 | return ""; 198 | } 199 | char *ret = dict[index]; 200 | return ret; 201 | } 202 | 203 | // The main function to parse a dmx file from a buffer. Note that this 204 | // could probably be re-written to handle streams, and get a little bit 205 | // of a performance boost from that. 206 | 207 | // one-line definition for a variable-type stream-based read 208 | #define READ(x) \ 209 | *(x *)curindex; \ 210 | curindex += sizeof(x) 211 | // string handling 212 | #define READSTRING() \ 213 | (char *)curindex; \ 214 | curindex += strlen(curindex) + 1; 215 | // object pointer handling 216 | #define READP(x) \ 217 | (x *)(curindex); \ 218 | curindex += sizeof(x); 219 | dmx *V(dmx_from_buffer)(char *buffer, const unsigned int length) { 220 | char *curindex = buffer; 221 | dmx *ret = (dmx *)malloc(sizeof(dmx)); 222 | dmx_init(ret); 223 | #if DMXB >= 7 224 | // In version 7, the prefix data structure got introduced. 225 | // This is (I believe) how to properly parse it: 226 | { 227 | printf("reading prefix data...\n"); 228 | if (curindex - buffer + sizeof(uint32_t) > length) { 229 | fprintf( 230 | stderr, 231 | "Error in dmx parse: insufficient data (type 0)\n"); 232 | return NULL; 233 | } 234 | uint32_t numelements = READ(uint32_t); 235 | printf("reading %i elements...\n", numelements); 236 | for (uint32_t i = 0; i < numelements; i++) { 237 | uint32_t numattributes = READ(uint32_t); 238 | if (i == 0) { 239 | ret->prefixdata = (dmxattribute **)malloc( 240 | numattributes * sizeof(dmxattribute *)); 241 | } 242 | printf("\treading %i attributes...\n", numattributes); 243 | for (uint32_t j = 0; j < numattributes; j++) { 244 | char *name = READSTRING(); 245 | printf("%s\n", name); 246 | V(readattribute)(ret, &curindex, true); 247 | } 248 | } 249 | } 250 | #endif 251 | if (length < sizeof(STRING_DICT_SIZE_TYPE)) { 252 | fprintf(stderr, 253 | "Error in dmx parse: insufficient data (type 1)\n"); 254 | return NULL; 255 | } 256 | // Check that we're able to parse it 257 | STRING_DICT_SIZE_TYPE numstrings = READ(STRING_DICT_SIZE_TYPE); 258 | printf("dmx_from_buffer_%d: Parsing %d strings into string " 259 | "dicitonary...\n", 260 | DMXB, (uint32_t)numstrings); 261 | char **strings = (char **)malloc(sizeof(char *) * numstrings); 262 | for (uint32_t i = 0; i < (uint32_t)(numstrings); i++) { 263 | strings[i] = READSTRING(); 264 | printf("dmx_from_buffer_%d: \t\t%s\n", DMXB, strings[i]); 265 | } 266 | for (uint32_t i = 0; i < (uint32_t)(numstrings); i++) { 267 | printf("dictionary contains %s at %u\n", 268 | V(dictsearch)(strings, i, numstrings), i); 269 | } 270 | // Read it into the data structure 271 | // Take a look at the elements 272 | uint32_t numelements = READ(uint32_t); 273 | printf("dmx_from_buffer_%d: Parsing %u elements...\n", DMXB, 274 | numelements); 275 | for (uint32_t i = 0; i < numelements; i++) { 276 | STRING_INDEX_SIZE typeindex = READ(STRING_INDEX_SIZE); 277 | char *type = V(dictsearch)(strings, typeindex, numstrings); 278 | #if DMXB >= 4 279 | STRING_INDEX_SIZE nameindex = READ(STRING_INDEX_SIZE); 280 | char *name = V(dictsearch)(strings, nameindex, numstrings); 281 | #else 282 | char *name = READSTRING(); 283 | #endif 284 | STRING_INDEX_SIZE unknownindex = READ(STRING_INDEX_SIZE); 285 | char *unknown = 286 | V(dictsearch)(strings, unknownindex, numstrings); 287 | GUID *guid = READP(GUID); 288 | printf("ELEMENT_PARSE_TEST: %s: %s (%s) %hhx\n", type, name, 289 | unknown, guid->bytes[0]); 290 | printf("CORRUPTION CHECK: %p\n", (void *)strings[6]); 291 | fflush(stdout); 292 | } 293 | for (uint32_t i = 0; i < (uint32_t)(numstrings); i++) { 294 | printf("dictionary contains %s at %u\n", 295 | V(dictsearch)(strings, i, numstrings), i); 296 | } 297 | for (uint32_t elem = 0; elem < numelements; elem++) { 298 | uint32_t numattributes = READ(uint32_t); 299 | printf("dmx_from_buffer_%d: Parsing %u attributes...(%u/%u)\n", 300 | DMXB, numattributes, elem + 1, numelements); 301 | fflush(stdout); 302 | for (uint32_t i = 0; i < numattributes; i++) { 303 | printf("strings[6] is %p\n", (void *)strings[6]); 304 | fflush(stdout); 305 | STRING_INDEX_SIZE attrnameindex = 306 | READ(STRING_INDEX_SIZE); 307 | printf("got index, it's %u\n", (uint32_t)attrnameindex); 308 | fflush(stdout); 309 | char *attrname = 310 | V(dictsearch)(strings, attrnameindex, numstrings); 311 | printf("2: strings[6] is %p\n", (void *)strings[6]); 312 | fflush(stdout); 313 | printf("got string!\n"); 314 | fflush(stdout); 315 | printf("%s:\n", attrname); 316 | fflush(stdout); 317 | V(readattribute)(ret, &curindex, true); 318 | printf("test\n"); 319 | fflush(stdout); 320 | } 321 | } 322 | fflush(stdout); 323 | printf("finished parse!\n"); 324 | // cleanup 325 | free(strings); 326 | return ret; 327 | } 328 | 329 | #undef READ 330 | #undef READP 331 | #undef READSTRING 332 | 333 | // take a memory dmx, and put it in a data file appropriately 334 | /* TODO 335 | char* V(dmx_to_buffer) (dmx* in, long* length) { 336 | if(in==NULL) { 337 | fprintf(stderr, "Error: Tried writing dmx to null buffer!\n"); 338 | *length = 0; 339 | return NULL; 340 | } 341 | if(length == NULL) { 342 | fprintf(stderr, "Error: length return for dmx_to_buffer_%u was 343 | null!\n",DMXB); *length = 0; return NULL; 344 | } 345 | int size = 1000; 346 | char* ret = (char*)malloc(size*sizeof(char)); 347 | char* cur = ret; 348 | // go through the dmx, and build a dictionary for it. 349 | uint32_t count = 0; 350 | uint32_t charcount = 0; 351 | for(uint32_t i=0;inumelements;i++) { 352 | } 353 | // emit the header 354 | // emit the prefix element 355 | // emit the element table 356 | // emit the attribute table 357 | // return successfully! 358 | *length = 0; 359 | return NULL; 360 | } 361 | */ 362 | -------------------------------------------------------------------------------- /stupidvalve.c: -------------------------------------------------------------------------------- 1 | #include "stupidvalve.h" 2 | 3 | const char downconvert[16] = {'0', '1', '2', '3', '4', '5', '6', '7', 4 | '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; 5 | 6 | #define RLHI ret->lumpheaders[i] 7 | // Take an offset field, and compute the target address 8 | #define OFFS(x) (((char *)&(x)) + (x)) 9 | /* 10 | * This new valve file format doesn't have type specifiers, so it's awful to 11 | * handle. 12 | */ 13 | void parse_svf(filedata *fd) { 14 | svffile_generic *ret = 15 | (svffile_generic *)malloc(sizeof(svffile_generic)); 16 | ret->hdr = (svf_header *)(fd->contents); 17 | if (ret->hdr->filelength != fd->length) { 18 | fprintf( 19 | stderr, 20 | "Warning: SVF header length does not match file length.\n"); 21 | } 22 | ret->lumpheaders = 23 | (svflump_header *)(fd->contents + sizeof(svf_header)); 24 | ret->lumps = 25 | (svfl_header *)malloc(sizeof(svfl_header) * ret->hdr->lumps.count); 26 | uint32_t i; 27 | for (i = 0; i < ret->hdr->lumps.count; i++) { 28 | printf("[%c%c%c%c]: offset %X | length: %X\n", RLHI.tag[0], 29 | RLHI.tag[1], RLHI.tag[2], RLHI.tag[3], RLHI.offset, 30 | RLHI.length); 31 | ret->lumps[i].content = OFFS(RLHI.offset); 32 | // because dealing with these is a lot faster than doing string 33 | // checks all the time 34 | ret->lumps[i].type = RLHI.type_asint; 35 | if (strncmp(RLHI.tag, "RERL", 4) == 0) { 36 | // Parse as a Resource External Reference block 37 | svfl_rerl_header *rh = 38 | (svfl_rerl_header *)&(ret->lumps[i]); 39 | rh->df = (svfl_rerl_header_datafile *)rh->content; 40 | rh->entries = (svfl_rerl_entry *)malloc( 41 | rh->df->entries.count * sizeof(svfl_rerl_entry)); 42 | svfl_rerl_entry_datafile *dfs = 43 | (svfl_rerl_entry_datafile *)OFFS( 44 | rh->df->entries.offset); 45 | uint32_t j; 46 | for (j = 0; j < rh->df->entries.count; j++) { 47 | rh->entries[j].df = &(dfs[j]); 48 | rh->entries[j].content = 49 | OFFS(rh->entries[j].df->offset); 50 | printf("%.16" PRIx64 ": %s\n", 51 | rh->entries[j].df->objecttag, 52 | rh->entries[j].content); 53 | } 54 | } else if (strncmp(RLHI.tag, "REDI", 4) == 0) { 55 | // Parse as a Resource Deferred Reference block 56 | svfl_redi_header *rh = 57 | (svfl_redi_header *)&(ret->lumps[i]); 58 | rh->df = (svfl_redi_header_datafile *)rh->content; 59 | uint32_t j; 60 | // Sourceresource multisub 61 | { 62 | printf("\t[SubBlock] sourceresource (%u " 63 | "entries)\n", 64 | rh->df->sourceresource.count); 65 | rh->srentries = 66 | (svfl_redi_sourceresource *)malloc( 67 | rh->df->sourceresource.count * 68 | sizeof(svfl_redi_sourceresource)); 69 | svfl_redi_sourceresource_datafile *srsd = 70 | (svfl_redi_sourceresource_datafile *)OFFS( 71 | rh->df->sourceresource.offset); 72 | for (j = 0; j < rh->df->sourceresource.count; 73 | j++) { 74 | rh->srentries[j].filename = 75 | OFFS(srsd[j].offset_filename); 76 | rh->srentries[j].contentsearchpath = 77 | OFFS(srsd[j].offset_modname); 78 | printf( 79 | "\t\t[File] '%s' in " 80 | "contentsearchpath: '%s'\n", 81 | rh->srentries[j].filename, 82 | rh->srentries[j].contentsearchpath); 83 | } 84 | } 85 | // Sourceresourceadd multisub 86 | { 87 | printf("\t[SubBlock] sourceresourceadd (%u " 88 | "entries)\n", 89 | rh->df->sourceresourceadd.count); 90 | rh->sraentries = 91 | (svfl_redi_sourceresource *)malloc( 92 | rh->df->sourceresourceadd.count * 93 | sizeof(svfl_redi_sourceresource)); 94 | svfl_redi_sourceresource_datafile *srsd = 95 | (svfl_redi_sourceresource_datafile *)OFFS( 96 | rh->df->sourceresource.offset); 97 | for (j = 0; j < rh->df->sourceresourceadd.count; 98 | j++) { 99 | rh->sraentries[j].filename = 100 | OFFS(srsd[j].offset_filename); 101 | rh->sraentries[j].contentsearchpath = 102 | OFFS(srsd[j].offset_modname); 103 | printf("\t\t[File] '%s' in " 104 | "contentsearchpath: '%s'\n", 105 | rh->sraentries[j].filename, 106 | rh->sraentries[j] 107 | .contentsearchpath); 108 | } 109 | } 110 | // Typeddata multisub 111 | { 112 | printf("\t[SubBlock]argumentss (%u entries)\n", 113 | rh->df->arguments.count); 114 | rh->tdentries = (svfl_redi_argument *)malloc( 115 | rh->df->arguments.count * 116 | sizeof(svfl_redi_argument)); 117 | svfl_redi_argument_datafile *srtd = 118 | (svfl_redi_argument_datafile *)OFFS( 119 | rh->df->arguments.offset); 120 | for (j = 0; j < rh->df->arguments.count; j++) { 121 | rh->tdentries[j].df = &(srtd[j]); 122 | rh->tdentries[j].name = 123 | OFFS(srtd[j].offset_name); 124 | rh->tdentries[j].type = 125 | OFFS(srtd[j].offset_type); 126 | printf("\t\t%s %s", 127 | rh->tdentries[j].type, 128 | rh->tdentries[j].name); 129 | if (srtd[j].fingerprint != 0) 130 | printf(" (fingerprint = %.8X)", 131 | srtd[j].fingerprint); 132 | if (srtd[j].fingerprint != 0) 133 | printf( 134 | " (fingerprint_default = " 135 | "%.8X)", 136 | srtd[j] 137 | .fingerprint_default); 138 | printf("\n"); 139 | } 140 | } 141 | // Namemap multisub 142 | { 143 | printf("\t[SubBlock] namemap (%u entries)\n", 144 | rh->df->namemap.count); 145 | rh->nmentries = (svfl_redi_namemap *)malloc( 146 | rh->df->namemap.count * 147 | sizeof(svfl_redi_namemap)); 148 | svfl_redi_namemap_datafile *srnd = 149 | (svfl_redi_namemap_datafile *)OFFS( 150 | rh->df->namemap.offset); 151 | for (j = 0; j < rh->df->namemap.count; j++) { 152 | rh->nmentries[j].df = &(srnd[j]); 153 | rh->nmentries[j].key = 154 | OFFS(srnd[j].offset_key); 155 | rh->nmentries[j].expanded = 156 | OFFS(srnd[j].offset_expanded); 157 | printf("\t\t%s -> %s (fingerprint:%x, " 158 | "userdata:%x)\n", 159 | rh->nmentries[j].key, 160 | rh->nmentries[j].expanded, 161 | rh->nmentries[j].df->fingerprint, 162 | rh->nmentries[j].df->userdata); 163 | } 164 | } 165 | // Custom dependencies multisub 166 | { 167 | printf("\t[SubBlock] customdeps (%u entries)\n", 168 | rh->df->customdeps.count); 169 | } 170 | // Additional related resources multisub 171 | { 172 | printf("\t[SubBlock] additional_related (%u " 173 | "entries)\n", 174 | rh->df->additional_related.count); 175 | } 176 | // ChildRef multisub 177 | { 178 | printf("\t[SubBlock] childref (%u entries)\n", 179 | rh->df->child_ref.count); 180 | rh->crentries = (svfl_redi_childref *)malloc( 181 | rh->df->child_ref.count * 182 | sizeof(svfl_redi_childref)); 183 | svfl_redi_childref_datafile *srdd = 184 | (svfl_redi_childref_datafile *)OFFS( 185 | rh->df->child_ref.offset); 186 | for (j = 0; j < rh->df->child_ref.count; j++) { 187 | rh->crentries[j].df = &(srdd[j]); 188 | rh->crentries[j].content = 189 | OFFS(srdd[j].offset); 190 | printf("\t\t%.16" PRIx64 ": %s\n", 191 | rh->crentries[j].df->objecttag, 192 | rh->crentries[j].content); 193 | } 194 | } 195 | // Extra Integer-Valued Data multisub 196 | { 197 | printf("\t[SubBlock] extradatadata_int (%u " 198 | "entries)\n", 199 | rh->df->extradata_int.count); 200 | rh->edientries = 201 | (svfl_redi_extradata_int *)malloc( 202 | rh->df->extradata_int.count * 203 | sizeof(svfl_redi_extradata_int)); 204 | svfl_redi_extradata_int_datafile *srsd = 205 | (svfl_redi_extradata_int_datafile *)OFFS( 206 | rh->df->extradata_int.offset); 207 | for (j = 0; j < rh->df->extradata_int.count; 208 | j++) { 209 | rh->edientries[j].df = &(srsd[j]); 210 | rh->edientries[j].key = 211 | OFFS(srsd[j].offset_key); 212 | printf("\t\t%s: %i\n", 213 | rh->edientries[j].key, 214 | rh->edientries[j].df->value); 215 | } 216 | } 217 | // Extra Float-Valued Data multisub 218 | { 219 | printf("\t[SubBlock] extradatadata_float (%u " 220 | "entries)\n", 221 | rh->df->extradata_float.count); 222 | rh->edfentries = 223 | (svfl_redi_extradata_float *)malloc( 224 | rh->df->extradata_float.count * 225 | sizeof(svfl_redi_extradata_float)); 226 | svfl_redi_extradata_float_datafile *srsd = 227 | (svfl_redi_extradata_float_datafile *)OFFS( 228 | rh->df->extradata_float.offset); 229 | for (j = 0; j < rh->df->extradata_float.count; 230 | j++) { 231 | rh->edfentries[j].df = &(srsd[j]); 232 | rh->edfentries[j].key = 233 | OFFS(srsd[j].offset_key); 234 | printf("\t\t%s: %f\n", 235 | rh->edfentries[j].key, 236 | rh->edfentries[j].df->value); 237 | } 238 | } 239 | // Extra String-Valued Data multisub 240 | { 241 | printf("\t[SubBlock] extradata_string (%u " 242 | "entries)\n", 243 | rh->df->extradata_string.count); 244 | } 245 | } else if (strncmp(RLHI.tag, "NTRO", 4) == 0) { 246 | svfl_ntro_header *nh = 247 | (svfl_ntro_header *)&(ret->lumps[i]); 248 | nh->df = (svfl_ntro_header_datafile *)nh->content; 249 | printf("\tVersion: %i\n", nh->df->version); 250 | printf("\tContents: %u structs, %u enums\n", 251 | nh->df->entries.count, nh->df->enums.count); 252 | nh->entries = (svfl_ntro_entry *)malloc( 253 | nh->df->entries.count * sizeof(svfl_ntro_entry)); 254 | uint32_t j; 255 | printf("\tStructs:\n"); 256 | for (j = 0; j < nh->df->entries.count; j++) { 257 | nh->entries[j].hdf = 258 | (svfl_ntro_entry_header_datafile 259 | *)(OFFS(nh->df->entries.offset) + 260 | j * sizeof( 261 | svfl_ntro_entry_header_datafile)); 262 | nh->entries[j].classname = 263 | OFFS(nh->entries[j].hdf->offset_classname); 264 | printf( 265 | "\t%i: %-30s (length %u, type tag %.8X)\n", 266 | j, nh->entries[j].classname, 267 | nh->entries[j].hdf->length, 268 | nh->entries[j].hdf->typetag); 269 | printf("\t Version:%u | CRC:%.8X | " 270 | "uVersion:%i L:%X A:%X " 271 | "Parent:%X flags:%hhX\n", 272 | nh->entries[j].hdf->version, 273 | nh->entries[j].hdf->crc, 274 | nh->entries[j].hdf->user_version, 275 | nh->entries[j].hdf->length, 276 | nh->entries[j].hdf->alignment, 277 | nh->entries[j].hdf->base_struct_id, 278 | nh->entries[j].hdf->struct_flags); 279 | nh->entries[j].tags = 280 | (svfl_ntro_entry_tag *)malloc( 281 | nh->entries[j].hdf->tags.count * 282 | sizeof(svfl_ntro_entry_tag)); 283 | svfl_ntro_entry_tag_datafile *ths = 284 | (svfl_ntro_entry_tag_datafile *)OFFS( 285 | nh->entries[j].hdf->tags.offset); 286 | int numrefs = 0; 287 | uint32_t k; 288 | for (k = 0; k < nh->entries[j].hdf->tags.count; 289 | k++) { 290 | nh->entries[j].tags[k].df = &(ths[k]); 291 | nh->entries[j].tags[k].name = 292 | OFFS(nh->entries[j] 293 | .tags[k] 294 | .df->offset_tagname); 295 | printf( 296 | "\t\t%-30s: (count: %.4hX offset: " 297 | "%.4hX " 298 | "indirections.offset: %u " 299 | "indirections.count: %u " 300 | "datatype: %u), ref_typetag:%.8X\n", 301 | nh->entries[j].tags[k].name, 302 | nh->entries[j].tags[k].df->count, 303 | nh->entries[j] 304 | .tags[k] 305 | .df->offset_in_struct, 306 | nh->entries[j] 307 | .tags[k] 308 | .df->indirections.offset, 309 | nh->entries[j] 310 | .tags[k] 311 | .df->indirections.count, 312 | nh->entries[j].tags[k].df->datatype, 313 | nh->entries[j] 314 | .tags[k] 315 | .df->ref_typetag); 316 | if (nh->entries[j] 317 | .tags[k] 318 | .df->indirections.count > 0) { 319 | uint32_t inds; 320 | char *baseaddr = 321 | OFFS(nh->entries[j] 322 | .tags[k] 323 | .df->indirections 324 | .offset); 325 | printf("\t\t\tindirections:\n"); 326 | for (inds = 0; 327 | inds < 328 | nh->entries[j] 329 | .tags[k] 330 | .df->indirections 331 | .count; 332 | inds++) { 333 | printf( 334 | "\t\t\t\t%hhu\n", 335 | *(uint8_t 336 | *)(baseaddr + 337 | inds)); 338 | } 339 | } 340 | if (nh->entries[j] 341 | .tags[k] 342 | .df->datatype == 1) { 343 | nh->entries[j] 344 | .tags[k] 345 | .refindex = numrefs; 346 | numrefs++; 347 | } else { 348 | nh->entries[j] 349 | .tags[k] 350 | .refindex = -1; 351 | } 352 | } 353 | nh->entries[j].numrefs = numrefs; 354 | } 355 | // Let's go expand all the enum data. 356 | nh->enums = (svfl_ntro_enum *)malloc( 357 | nh->df->enums.count * sizeof(svfl_ntro_enum)); 358 | printf("\tEnums:\n"); 359 | for (j = 0; j < nh->df->enums.count; j++) { 360 | nh->enums[j].df = 361 | (svfl_ntro_enum_datafile 362 | *)(OFFS(nh->df->enums.offset) + 363 | j * sizeof( 364 | svfl_ntro_enum_datafile)); 365 | nh->enums[j].name = 366 | OFFS(nh->enums[j].df->offset_enumname); 367 | printf("\t%i: %-30s (%u values, id %.8X)\n", j, 368 | nh->enums[j].name, 369 | nh->enums[j].df->fields.count, 370 | nh->enums[j].df->id); 371 | printf( 372 | "\t Version:%u | CRC:%.8X | uVersion:%i\n", 373 | nh->enums[j].df->version, 374 | nh->enums[j].df->crc, 375 | nh->enums[j].df->user_version); 376 | svfl_ntro_enum_field_datafile *efs = 377 | (svfl_ntro_enum_field_datafile *)OFFS( 378 | nh->enums[j].df->fields.offset); 379 | uint32_t k; 380 | nh->enums[j].fields = 381 | (svfl_ntro_enum_field *)malloc( 382 | nh->enums[j].df->fields.count * 383 | sizeof(svfl_ntro_enum_field)); 384 | for (k = 0; k < nh->enums[j].df->fields.count; 385 | k++) { 386 | nh->enums[j].fields[k].df = &(efs[k]); 387 | nh->enums[j].fields[k].fieldname = 388 | OFFS(nh->enums[j] 389 | .fields[k] 390 | .df->offset_fieldname); 391 | printf( 392 | "\t\t%-30s = %u\n", 393 | nh->enums[j].fields[k].fieldname, 394 | nh->enums[j].fields[k].df->value); 395 | } 396 | } 397 | } else if (strncmp(RLHI.tag, "DATA", 4) == 0) { 398 | printf("\tDATA Lump Length: %u\n", RLHI.length); 399 | // We don't parse it until later 400 | } else if (strncmp(RLHI.tag, "VBIB", 4) == 0) { 401 | printf("\tVBIB LUMP, POKE PWIZ\n"); 402 | char *output = 403 | (char *)malloc(2 * RLHI.length * sizeof(char)); 404 | uint32_t j; 405 | for (j = 0; j < RLHI.length; j++) { 406 | output[2 * j] = (char)downconvert 407 | [*((uint8_t *)(OFFS(RLHI.offset) + j)) / 408 | 16]; 409 | output[2 * j + 1] = (char)downconvert 410 | [*((uint8_t *)(OFFS(RLHI.offset) + j)) % 411 | 16]; 412 | } 413 | printf("%.*s\n", 2 * RLHI.length, output); 414 | } else { 415 | printf("\tUNHANDLED LUMP TYPE, POKE PWIZ\n"); 416 | char *output = 417 | (char *)malloc(2 * RLHI.length * sizeof(char)); 418 | uint32_t j; 419 | for (j = 0; j < RLHI.length; j++) { 420 | output[2 * j] = (char)downconvert 421 | [*((uint8_t *)(OFFS(RLHI.offset) + j)) / 422 | 16]; 423 | output[2 * j + 1] = (char)downconvert 424 | [*((uint8_t *)(OFFS(RLHI.offset) + j)) % 425 | 16]; 426 | } 427 | printf("%.*s\n", 2 * RLHI.length, output); 428 | } 429 | printf("\n"); 430 | } 431 | 432 | // Parse head object 433 | svfl_rerl_header *rerl = NULL; 434 | svfl_ntro_header *ntro = NULL; 435 | char *data = NULL; 436 | for (i = 0; i < ret->hdr->lumps.count; i++) { 437 | printf("[Lump] Tag: %.4s | Type: %u\n", RLHI.tag, 438 | ret->lumps[i].type); 439 | switch (ret->lumps[i].type) { 440 | case 1280460114: // RERL - external reference data 441 | rerl = (svfl_rerl_header *)&(ret->lumps[i]); 442 | break; 443 | case 1229210962: // REDI - dunno what it's used for 444 | break; 445 | case 1330795598: // NTRO - type data 446 | ntro = (svfl_ntro_header *)&(ret->lumps[i]); 447 | break; 448 | case 1096040772: // DATA 449 | data = ret->lumps[i].content; 450 | break; 451 | } 452 | } 453 | if (rerl == NULL) { 454 | printf("[Lump] No RERL lump...\n"); 455 | } 456 | printf("\n"); 457 | 458 | if (data != NULL && ntro != NULL) { 459 | svfl_struct *rootobject = 460 | (svfl_struct *)malloc(sizeof(svfl_struct)); 461 | rootobject->NTRO = ntro; 462 | rootobject->type = &(ntro->entries[0]); 463 | rootobject->data = data; 464 | 465 | // parse_object(rootobject,ntro,data); 466 | // fd->parsed_object = rootobject; 467 | printf("\n\n"); 468 | 469 | print_object_recursive(rootobject); 470 | } else if (ret->hdr->version == 1) { 471 | // Version 1 files are stuff like panorama non-xml, and sounds 472 | printf("DATA LUMP START:\n"); 473 | printf("%X\n", *(uint32_t *)data); 474 | } else { 475 | fd->parsed_object = NULL; 476 | } 477 | 478 | // Cleanup 479 | fd->filetype = SVF; 480 | fd->parsed = ret; 481 | } 482 | 483 | // STUB 484 | void print_object_recursive_internal(svfl_struct *obj, uint32_t depth, 485 | svfl_ntro_entry *curtype); 486 | 487 | int typesize(svfl_ntro_header *ntro, svfl_ntro_entry_tag *tag, 488 | uint32_t indirectionindex) { 489 | int levelsize = 0; 490 | if (tag->df->indirections.count > indirectionindex) { 491 | uint8_t type = *(uint8_t *)(indirectionindex + 492 | OFFS(tag->df->indirections.offset)); 493 | switch (type) { 494 | case 3: 495 | levelsize = 4; 496 | break; 497 | case 4: 498 | levelsize = 8; 499 | break; 500 | default: 501 | fprintf(stderr, "WARNING: tried to get size of unknown " 502 | "indirection type!\n"); 503 | levelsize = 4; 504 | break; 505 | } 506 | } else { 507 | switch (tag->df->datatype) { 508 | case SVFL_DATATYPE_SUBSTRUCT: 509 | levelsize = do_type_lookup(ntro, tag->df->ref_typetag) 510 | ->hdf->length; 511 | break; 512 | case SVFL_DATATYPE_INT8: 513 | case SVFL_DATATYPE_UINT8: 514 | case SVFL_DATATYPE_BOOLEAN: 515 | levelsize = 1; 516 | break; 517 | case SVFL_DATATYPE_SINT: 518 | case SVFL_DATATYPE_UINT16: 519 | levelsize = 2; 520 | break; 521 | case SVFL_DATATYPE_STRING4: 522 | case SVFL_DATATYPE_ENUM: 523 | case SVFL_DATATYPE_INT32: 524 | case SVFL_DATATYPE_UINT32: 525 | case SVFL_DATATYPE_FLOAT: 526 | case SVFL_DATATYPE_STRING: 527 | levelsize = 4; 528 | break; 529 | case SVFL_DATATYPE_EXTREF: 530 | case SVFL_DATATYPE_UINT64: 531 | levelsize = 8; 532 | break; 533 | case SVFL_DATATYPE_VEC3: 534 | levelsize = 12; 535 | break; 536 | case SVFL_DATATYPE_VECTOR4D: 537 | case SVFL_DATATYPE_QUATERNION: 538 | case SVFL_DATATYPE_FLTX4: 539 | case SVFL_DATATYPE_VEC4: 540 | levelsize = 16; 541 | break; 542 | case SVFL_DATATYPE_CTRANSFORM: 543 | levelsize = 32; 544 | break; 545 | case SVFL_DATATYPE_MATRIX3X4: 546 | case SVFL_DATATYPE_MATRIX3X4A: 547 | levelsize = 48; 548 | break; 549 | default: 550 | levelsize = 1; 551 | fprintf(stderr, "WARNING: tried to get size of unknown " 552 | "data type!\n"); 553 | } 554 | } 555 | return levelsize; 556 | } 557 | 558 | char *gettypestring(uint32_t datatype) { 559 | switch (datatype) { 560 | case SVFL_DATATYPE_SUBSTRUCT: 561 | return "substruct"; 562 | case SVFL_DATATYPE_ENUM: 563 | return "enum"; 564 | case SVFL_DATATYPE_EXTREF: 565 | return "ext ref"; 566 | case SVFL_DATATYPE_INT8: 567 | return "int8"; 568 | case SVFL_DATATYPE_UINT8: 569 | return "byte"; 570 | case SVFL_DATATYPE_SINT: 571 | return "int16"; 572 | case SVFL_DATATYPE_UINT16: 573 | return "uint16"; 574 | case SVFL_DATATYPE_INT32: 575 | return "int32"; 576 | case SVFL_DATATYPE_UINT32: 577 | return "uint32"; 578 | case SVFL_DATATYPE_UINT64: 579 | return "uint64"; 580 | case SVFL_DATATYPE_FLOAT: 581 | return "float"; 582 | case SVFL_DATATYPE_VEC3: 583 | return "vec3"; 584 | case SVFL_DATATYPE_FLTX4: 585 | return "fltx4"; 586 | case SVFL_DATATYPE_VEC4: 587 | return "vec4"; 588 | case SVFL_DATATYPE_QUATERNION: 589 | return "quaternion"; 590 | case SVFL_DATATYPE_BOOLEAN: 591 | return "bool"; 592 | case SVFL_DATATYPE_STRING4: 593 | return "string4"; 594 | case SVFL_DATATYPE_STRING: 595 | return "string"; 596 | case SVFL_DATATYPE_VECTOR4D: 597 | return "vector4d"; 598 | case SVFL_DATATYPE_MATRIX3X4: 599 | return "matrix3x4"; 600 | case SVFL_DATATYPE_MATRIX3X4A: 601 | return "matrix3x4a"; 602 | case SVFL_DATATYPE_CTRANSFORM: 603 | return "CTransform"; 604 | default: 605 | return "unhandled type"; 606 | } 607 | } 608 | 609 | /* 610 | * Print a single tagged item 611 | */ 612 | void print_thing_at_location(svfl_struct *obj, uint32_t depth, 613 | svfl_ntro_entry_tag *curtag, char *location, 614 | uint32_t indirectionindex, bool ignorecount) { 615 | char *tabs = 616 | &("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t" 617 | "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"[(50 - depth)]); 618 | printf("%s %s (%s) ", tabs, curtag->name, 619 | gettypestring(curtag->df->datatype)); 620 | if (curtag->df->count != 0 && !ignorecount) { 621 | int numentries = curtag->df->count; 622 | printf("[%d] ˅\n", numentries); 623 | int i; 624 | int eachsize = typesize(obj->NTRO, curtag, indirectionindex); 625 | for (i = 0; i < numentries; i++) { 626 | print_thing_at_location(obj, depth + 1, curtag, 627 | location + i * eachsize, 628 | indirectionindex, true); 629 | } 630 | return; 631 | } 632 | if (indirectionindex < curtag->df->indirections.count) { 633 | // follow the level of indirection to determine what to do 634 | char *baseaddr = OFFS(curtag->df->indirections.offset); 635 | uint32_t indirectiontype = 636 | *(uint8_t *)(indirectionindex + baseaddr); 637 | if (indirectiontype == 3) { 638 | printf("(ptr) ˅\n"); 639 | if ((*(uint32_t *)location) == 0) { 640 | // Null pointer 641 | printf("%s\t -> NULL\n", tabs - 1); 642 | } else { 643 | // single-object pointer derefernce 644 | print_thing_at_location( 645 | obj, depth + 1, curtag, 646 | location + *(uint32_t *)(location), 647 | indirectionindex + 1, true); 648 | } 649 | } 650 | if (indirectiontype == 4) { 651 | uint32_t j; 652 | uint32_t count = *(uint32_t *)(location + 4); 653 | printf("*[%u]: ˅\n", count); 654 | uint32_t levelsize = 655 | typesize(obj->NTRO, curtag, indirectionindex + 1); 656 | for (j = 0; j < count; j++) { 657 | // printf("location will be %p\n",location + 658 | // *(uint32_t*)(location) + j * levelsize); 659 | print_thing_at_location( 660 | obj, depth + 1, curtag, 661 | location + *(uint32_t *)(location) + 662 | j * levelsize, 663 | indirectionindex + 1, true); 664 | } 665 | } 666 | } else { 667 | // Just print the thing at the specified address by type 668 | switch (curtag->df->datatype) { 669 | svfl_struct *child; 670 | svfl_ntro_enum *thisenum; 671 | case SVFL_DATATYPE_SUBSTRUCT: 672 | printf("\n"); 673 | // curref = curtag->refindex; 674 | child = (svfl_struct *)malloc(sizeof(svfl_struct)); 675 | child->NTRO = obj->NTRO; 676 | child->type = 677 | do_type_lookup(obj->NTRO, curtag->df->ref_typetag); 678 | child->data = location; 679 | print_object_recursive_internal( 680 | child, depth + 1, 681 | do_type_lookup(obj->NTRO, curtag->df->ref_typetag)); 682 | break; 683 | case SVFL_DATATYPE_ENUM: 684 | thisenum = 685 | do_enum_lookup(obj->NTRO, curtag->df->ref_typetag); 686 | if (thisenum != NULL) { 687 | uint32_t index; 688 | for (index = 0; 689 | index < thisenum->df->fields.count; 690 | index++) { 691 | if ((*(uint32_t *)location) == 692 | thisenum->fields[index].df->value) { 693 | break; 694 | } 695 | } 696 | if (index != thisenum->df->fields.count) { 697 | printf( 698 | "(enum %s) [%u] (%s)\n", 699 | thisenum->name, 700 | *(uint32_t *)(location), 701 | thisenum->fields[index].fieldname); 702 | } else { 703 | // OK - it's likely a composite value (a 704 | // | b), so let's try that 705 | bool foundone = false; 706 | for (index = 0; 707 | index < thisenum->df->fields.count; 708 | index++) { 709 | if (((*(uint32_t *)location) & 710 | thisenum->fields[index] 711 | .df->value) != 0) { 712 | if (!foundone) { 713 | foundone = true; 714 | printf( 715 | "(enum %s) " 716 | "[%u](%s", 717 | thisenum 718 | ->name, 719 | *(uint32_t 720 | *)(location), 721 | thisenum 722 | ->fields 723 | [index] 724 | .fieldname); 725 | } else { 726 | printf( 727 | " | %s", 728 | thisenum 729 | ->fields 730 | [index] 731 | .fieldname); 732 | } 733 | } 734 | } 735 | if (!foundone) { 736 | if ((*(uint32_t *)location) == 737 | 0) { 738 | printf( 739 | "(enum %s) [%u] " 740 | "(unflagged)\n", 741 | thisenum->name, 742 | *(uint32_t 743 | *)(location)); 744 | } else { 745 | // We really don't knwo 746 | // what to do with the 747 | // value now, so just 748 | // print it 749 | printf( 750 | "(enum %s) " 751 | "(unknown enum " 752 | "field) %u\n", 753 | thisenum->name, 754 | *(uint32_t 755 | *)(location)); 756 | } 757 | } else { 758 | // if we did find one, terminate 759 | // the line 760 | printf(")\n"); 761 | } 762 | } 763 | } else { 764 | printf("(unknown enum) %u\n", 765 | *(uint32_t *)(location)); 766 | } 767 | break; 768 | case SVFL_DATATYPE_EXTREF: 769 | printf("%.16" PRIx64 "\n", *(uint64_t *)(location)); 770 | break; 771 | case SVFL_DATATYPE_INT8: 772 | printf("%hhx\n", *(char *)(location)); 773 | break; 774 | case SVFL_DATATYPE_UINT8: 775 | printf("%hhx\n", *(char *)(location)); 776 | break; 777 | case SVFL_DATATYPE_SINT: 778 | printf("%u\n", *(int16_t *)(location)); 779 | break; 780 | case SVFL_DATATYPE_UINT16: 781 | printf("%hu\n", *(uint16_t *)(location)); 782 | break; 783 | case SVFL_DATATYPE_INT32: 784 | printf("%i\n", *(int32_t *)(location)); 785 | break; 786 | case SVFL_DATATYPE_UINT32: 787 | printf("%08x\n", *(int32_t *)(location)); 788 | break; 789 | case SVFL_DATATYPE_UINT64: 790 | printf("%lu\n", *(uint64_t *)(location)); 791 | break; 792 | case SVFL_DATATYPE_FLOAT: 793 | printf("%f\n", *(float *)(location)); 794 | break; 795 | case SVFL_DATATYPE_VEC3: 796 | printf("[%f %f %f]\n", *(float *)(location), 797 | *(float *)(location + 4), 798 | *(float *)(location + 8)); 799 | break; 800 | case SVFL_DATATYPE_FLTX4: 801 | printf("[%f %f %f %f]\n", *(float *)(location), 802 | *(float *)(location + 4), 803 | *(float *)(location + 8), 804 | *(float *)(location + 12)); 805 | break; 806 | case SVFL_DATATYPE_VEC4: 807 | printf("[%f %f %f %f]\n", *(float *)(location), 808 | *(float *)(location + 4), 809 | *(float *)(location + 8), 810 | *(float *)(location + 12)); 811 | break; 812 | case SVFL_DATATYPE_QUATERNION: 813 | printf("[x: %f y: %f z: %f w: %f]\n", 814 | *(float *)(location), *(float *)(location + 4), 815 | *(float *)(location + 8), 816 | *(float *)(location + 12)); 817 | break; 818 | case SVFL_DATATYPE_BOOLEAN: 819 | printf("%hhu\n", *(char *)(location)); 820 | break; 821 | case SVFL_DATATYPE_STRING4: 822 | case SVFL_DATATYPE_STRING: 823 | printf("'%s'\n", ((char *)(location) + 824 | *((uint32_t *)(location)))); 825 | break; 826 | case SVFL_DATATYPE_VECTOR4D: 827 | printf("[%f %f %f %f]\n", *(float *)(location), 828 | *(float *)(location + 4), 829 | *(float *)(location + 8), 830 | *(float *)(location + 12)); 831 | break; 832 | case SVFL_DATATYPE_MATRIX3X4: 833 | case SVFL_DATATYPE_MATRIX3X4A: 834 | printf("[ %f %f %f %f\n%s\t\t\t\t %f %f %f " 835 | "%f\n%s\t\t\t\t %f %f %f " 836 | "%f]\n", 837 | *(float *)(location), *(float *)(location + 4), 838 | *(float *)(location + 8), 839 | *(float *)(location + 12), tabs, 840 | *(float *)(location + 16), 841 | *(float *)(location + 20), 842 | *(float *)(location + 24), 843 | *(float *)(location + 28), tabs, 844 | *(float *)(location + 32), 845 | *(float *)(location + 36), 846 | *(float *)(location + 40), 847 | *(float *)(location + 44)); 848 | break; 849 | case SVFL_DATATYPE_CTRANSFORM: 850 | printf("[q={%f %f %f %f}, p={%f %f %f}]\n", 851 | *(float *)(location + 16), 852 | *(float *)(location + 20), 853 | *(float *)(location + 24), 854 | *(float *)(location + 28), *(float *)(location), 855 | *(float *)(location + 4), 856 | *(float *)(location + 8)); 857 | // Note that we do skip 4 bytes in here, for alignment 858 | // purposes 859 | break; 860 | default: 861 | printf("(unhandled type %u)\n", curtag->df->datatype); 862 | break; 863 | } 864 | } 865 | } 866 | 867 | /* 868 | * The internal version, with specifyable depth. 869 | */ 870 | void print_object_recursive_internal(svfl_struct *obj, uint32_t depth, 871 | svfl_ntro_entry *curtype) { 872 | char *tabs = 873 | &("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t" 874 | "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"[(50 - depth)]); 875 | // only print type name of the childmost class 876 | if (obj->type == curtype) 877 | printf("%s%s:\n", tabs, obj->type->classname); 878 | // We now do a stack of types 879 | if (curtype->hdf->base_struct_id != 0) { 880 | svfl_ntro_entry *parent = 881 | do_type_lookup(obj->NTRO, curtype->hdf->base_struct_id); 882 | if (parent == NULL) 883 | fprintf(stderr, "ERROR PRINTING DATA, INHERITANCE FROM " 884 | "UNDEFINED TYPE!\n"); 885 | print_object_recursive_internal(obj, depth, parent); 886 | } 887 | uint32_t i; 888 | for (i = 0; i < curtype->hdf->tags.count; i++) { 889 | print_thing_at_location(obj, depth, &(curtype->tags[i]), 890 | curtype->tags[i].df->offset_in_struct + 891 | obj->data, 892 | 0, false); 893 | } 894 | } 895 | 896 | /* 897 | * The external version (tab reasons) 898 | */ 899 | void print_object_recursive(svfl_struct *obj) { 900 | // Set rounding mode 901 | fesetround(FE_TOWARDZERO); 902 | print_object_recursive_internal(obj, 0, obj->type); 903 | } 904 | 905 | /* 906 | * Look up a type entry in the ntro table by typetag. 907 | */ 908 | svfl_ntro_entry *do_type_lookup(svfl_ntro_header *ntro, uint32_t typetag) { 909 | uint32_t i; 910 | for (i = 0; i < ntro->df->entries.count; i++) { 911 | if (ntro->entries[i].hdf->typetag == typetag) 912 | return &(ntro->entries[i]); 913 | } 914 | printf("FAILED CLASS LOOKUP (%.8X)\n", typetag); 915 | return NULL; 916 | } 917 | 918 | /* 919 | * Look up an enum entry in the ntro table by enumtag. 920 | */ 921 | svfl_ntro_enum *do_enum_lookup(svfl_ntro_header *ntro, uint32_t enumtag) { 922 | uint32_t i; 923 | for (i = 0; i < ntro->df->enums.count; i++) { 924 | if (ntro->enums[i].df->id == enumtag) 925 | return &(ntro->enums[i]); 926 | } 927 | printf("FAILED ENUM LOOKUP (%.8X)\n", enumtag); 928 | return NULL; 929 | } 930 | 931 | /* 932 | * Cleanup 933 | */ 934 | void free_svf(filedata *fd) { 935 | if (fd->filetype != SVF) { 936 | fprintf(stderr, 937 | "Error: tried to use SVF free on non-SVF data.\n"); 938 | return; 939 | } 940 | free(((svffile_generic *)fd->parsed)->lumps); 941 | free(fd->parsed); 942 | fd->parsed = NULL; 943 | } 944 | --------------------------------------------------------------------------------