Mercurial > veg
comparison veg.c @ 0:b4d1a6e4bbde default tip
*: initial commit and research on the .veg file format
| author | Paper <paper@tflc.us> |
|---|---|
| date | Fri, 17 Oct 2025 19:01:34 -0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:b4d1a6e4bbde |
|---|---|
| 1 /* Sony Vegas RIFF parser | |
| 2 * | |
| 3 * Ok, here's a bit of what's going on here. | |
| 4 * Sony Vegas uses Wave64 chunks; these are sort-of-RIFF-but-not-really. | |
| 5 * Most notably, they use GUIDs (aka UUIDs) instead of chunk identifiers, | |
| 6 * and have 64-bit chunk sizes instead of 32-bit. */ | |
| 7 | |
| 8 #include <stdio.h> | |
| 9 #include <string.h> | |
| 10 #include <stdint.h> | |
| 11 | |
| 12 /* The first chunk is the "riff_chunk" in this file. | |
| 13 * This is basically equivalent to a LIST chunk. */ | |
| 14 | |
| 15 /* 5A 2D 8F B2 0F 23 D2 11 86 AF 00 C0 4F 8E DB 8A -- header chunk; always at the start | |
| 16 * I'm going to completely ignore this chunk, as it's not PARTICULARLY useful for me. | |
| 17 * also for some reason this includes the full path to the veg?? (no wonder people | |
| 18 * kept getting doxxed from this, hurr durr) | |
| 19 * 6C 69 73 74 2F 91 CF 11 A5 D6 28 DB 04 C1 00 00 -- seems to be equivalent to RIFF LIST | |
| 20 * in fact, the beginning is "list" in ASCII | |
| 21 * D8 B9 CC 2C DD DE AC 46 85 3D 19 16 A9 9A 9A 02 -- LIST chunk ID (like LIST-INFO) | |
| 22 * but I don't know what it's used for | |
| 23 * 39 8C 8A 5E 6B DA 99 44 B0 B2 36 63 70 9E 1C E4 -- chunk ID; part of the previous chunk | |
| 24 * 5B 2D 8F B2 0F 23 D2 11 86 AF 00 C0 4F 8E DB 8A -- another LIST chunk ID; this is also used as the containing identifier | |
| 25 * so like LIST-INFO-ISFT if it was LIST-INFO-INFO, which is odd */ | |
| 26 | |
| 27 static const unsigned char riff_chunk[16] = "\x72\x69\x66\x66\x2E\x91\xCF\x11\xA5\xD6\x28\xDB\x04\xC1\x00\x00"; | |
| 28 static const unsigned char list_chunk[16] = "\x6C\x69\x73\x74\x2F\x91\xCF\x11\xA5\xD6\x28\xDB\x04\xC1\x00\x00"; | |
| 29 /* this is the GUID used to identify the list of sources */ | |
| 30 static const unsigned char list_sources_chunk[16] = "\x5B\x2D\x8F\xB2\x0F\x23\xD2\x11\x86\xAF\x00\xC0\x4F\x8E\xDB\x8A"; | |
| 31 | |
| 32 /* fread() but it doesn't suck */ | |
| 33 #define freadb(fp, data, size) (fread(data, 1, size, fp)) | |
| 34 | |
| 35 struct w64_chunk { | |
| 36 unsigned char id[16]; | |
| 37 uint64_t size; | |
| 38 int64_t offset; /* into the file */ | |
| 39 }; | |
| 40 | |
| 41 /* endianness-independent little endian byteswap | |
| 42 * (works regardless of endianness) */ | |
| 43 static uint64_t bswapLE64(uint64_t n) | |
| 44 { | |
| 45 unsigned char *np = (unsigned char *)&n; | |
| 46 | |
| 47 return ((uint64_t)np[7] << 56) | | |
| 48 ((uint64_t)np[6] << 48) | | |
| 49 ((uint64_t)np[5] << 40) | | |
| 50 ((uint64_t)np[4] << 32) | | |
| 51 ((uint64_t)np[3] << 24) | | |
| 52 ((uint64_t)np[2] << 16) | | |
| 53 ((uint64_t)np[1] << 8) | | |
| 54 ((uint64_t)np[0]); | |
| 55 } | |
| 56 | |
| 57 static int w64_chunk_peek(struct w64_chunk *chunk, FILE *fp, int64_t off) | |
| 58 { | |
| 59 if (freadb(fp, chunk->id, sizeof(chunk->id)) != sizeof(chunk->id)) | |
| 60 return 0; | |
| 61 | |
| 62 if (freadb(fp, &chunk->size, sizeof(chunk->size)) != sizeof(chunk->size)) | |
| 63 return 0; | |
| 64 | |
| 65 chunk->size = bswapLE64(chunk->size); | |
| 66 | |
| 67 /* Size includes the size of the header, for whatever reason. */ | |
| 68 if (chunk->size < 24) | |
| 69 return 0; | |
| 70 | |
| 71 chunk->size -= 24; | |
| 72 | |
| 73 chunk->offset = ftell(fp); | |
| 74 if (chunk->offset < 0) | |
| 75 return 0; | |
| 76 | |
| 77 /* w64 sizes are aligned to 64-bit boundaries */ | |
| 78 fseek(fp, (chunk->size + 7) & ~7, SEEK_CUR); | |
| 79 | |
| 80 /* ehhh, okay */ | |
| 81 return ftell(fp) <= off; | |
| 82 } | |
| 83 | |
| 84 //#define C_STRING_UUIDS 1 | |
| 85 | |
| 86 static void print_uuid(unsigned char id[16]) | |
| 87 { | |
| 88 #ifdef C_STRING_UUIDS | |
| 89 uint32_t i; | |
| 90 printf("\""); | |
| 91 for (i = 0; i < 16; i++) | |
| 92 printf("\\x%02X", (unsigned int)id[i]); | |
| 93 printf("\"\n"); | |
| 94 #else | |
| 95 printf("{%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n", | |
| 96 id[3], id[2], id[1], id[0], id[5], id[4], id[7], id[6], | |
| 97 id[8], id[9], id[10], id[11], id[12], id[13], id[14], id[15]); | |
| 98 #endif | |
| 99 } | |
| 100 | |
| 101 static void print_tabs(uint32_t tabs) | |
| 102 { | |
| 103 uint32_t i; | |
| 104 for (i = 0; i < tabs; i++) putc('\t', stdout); | |
| 105 } | |
| 106 | |
| 107 static void parse_list(FILE *fp, int64_t size, uint32_t tabs) | |
| 108 { | |
| 109 struct w64_chunk w64; | |
| 110 int64_t off = ftell(fp) + size; | |
| 111 | |
| 112 /* we're now inside the chunk, so start printing out which | |
| 113 * ones we have */ | |
| 114 while (w64_chunk_peek(&w64, fp, off)) { | |
| 115 int64_t pos; | |
| 116 | |
| 117 pos = ftell(fp); | |
| 118 | |
| 119 print_tabs(tabs); | |
| 120 print_uuid(w64.id); | |
| 121 | |
| 122 fseek(fp, w64.offset, SEEK_SET); | |
| 123 | |
| 124 if (!memcmp(list_chunk, w64.id, 16) || !memcmp(riff_chunk, w64.id, 16)) { | |
| 125 unsigned char id[16]; | |
| 126 freadb(fp, id, 16); | |
| 127 | |
| 128 print_tabs(tabs); | |
| 129 printf("LIST UUID: "); | |
| 130 print_uuid(id); | |
| 131 | |
| 132 if (!memcmp(list_sources_chunk, id, 16)) { | |
| 133 print_tabs(tabs); | |
| 134 printf("### This is the sources chunk!\n"); | |
| 135 } | |
| 136 | |
| 137 /* jump into the list */ | |
| 138 parse_list(fp, w64.size, tabs + 1); | |
| 139 } else { | |
| 140 print_tabs(tabs); | |
| 141 printf("chunk data: { "); | |
| 142 for (uint64_t i = 0; i < w64.size; i++) | |
| 143 printf("%02x ", fgetc(fp)); | |
| 144 printf("}\n"); | |
| 145 } | |
| 146 | |
| 147 fseek(fp, pos, SEEK_SET); | |
| 148 } | |
| 149 } | |
| 150 | |
| 151 static int parse_veg(FILE *fp) | |
| 152 { | |
| 153 /* eh, alright */ | |
| 154 parse_list(fp, INT64_MAX, 0); | |
| 155 | |
| 156 return 0; | |
| 157 } | |
| 158 | |
| 159 int main(int argc, char *argv[]) | |
| 160 { | |
| 161 FILE *fp = NULL; | |
| 162 char riff[4]; | |
| 163 uint32_t x; | |
| 164 | |
| 165 if (argc < 2) | |
| 166 return 255; | |
| 167 | |
| 168 fp = fopen(argv[1], "rb"); | |
| 169 if (!fp) | |
| 170 return 1; | |
| 171 | |
| 172 parse_veg(fp); | |
| 173 | |
| 174 fclose(fp); | |
| 175 return 0; | |
| 176 } |
