├── 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 |
--------------------------------------------------------------------------------