Mercurial > msvpvf
comparison src/main.c @ 79:8f90d5addda9 v2.0
*: refactor... basically everything!
The Win32 GUI version is now unicode-friendly. HOWEVER, ANSI still very
much works. you can configure which version to use through `-DUNICODE=0/1`
in CFLAGS.
the CLI is also friendlier and uses a more sane interface as well.
note: the command line flags (which were optional before) are now required.
Unicode filenames will not work on Windows because Windows sucks.
| author | Paper <paper@paper.us.eu.org> |
|---|---|
| date | Wed, 20 Mar 2024 17:06:26 -0400 |
| parents | fcd4b9fe957b |
| children | c06dcab17923 |
comparison
equal
deleted
inserted
replaced
| 78:fae1d67d8cfd | 79:8f90d5addda9 |
|---|---|
| 1 #include <stdio.h> | 1 #include <stdio.h> |
| 2 #include <stdint.h> | |
| 2 #include <stdlib.h> | 3 #include <stdlib.h> |
| 3 #include <string.h> | 4 #include <string.h> |
| 4 #include <unistd.h> | 5 //#include <unistd.h> |
| 5 #include <getopt.h> | 6 #include <getopt.h> |
| 6 #include <libgen.h> | 7 #include <libgen.h> |
| 7 #include "../include/common.h" | 8 |
| 8 #ifdef _MSC_VER | 9 #include "common.h" |
| 9 #define strdup(p) _strdup(p) | 10 |
| 11 /* non-portable functions */ | |
| 12 static inline char* msvpvf_internal_strdup(const char* str) { | |
| 13 size_t len = strlen(str) + 1; | |
| 14 | |
| 15 char* copy = malloc(len); | |
| 16 if (!copy) | |
| 17 return NULL; | |
| 18 | |
| 19 memcpy(copy, str, len); | |
| 20 return copy; | |
| 21 } | |
| 22 | |
| 23 /* source needs read permissions, target needs write permissions, both must be in binary mode */ | |
| 24 static inline int copy_file(FILE* source, FILE* target) { | |
| 25 char ch[4096]; | |
| 26 | |
| 27 while (!feof(source)) { | |
| 28 size_t b = fread(ch, 1, sizeof(ch), source); | |
| 29 if (b) | |
| 30 fwrite(ch, 1, b, target); | |
| 31 } | |
| 32 | |
| 33 return 0; | |
| 34 } | |
| 35 | |
| 36 static inline const char* type_to_string(enum types type) { | |
| 37 switch (type) { | |
| 38 case TYPES_VF: return "Movie Studio"; | |
| 39 case TYPES_VEG: return "Vegas Pro"; | |
| 40 case TYPES_UNKNOWN: | |
| 41 default: return "Unknown"; | |
| 42 } | |
| 43 } | |
| 44 | |
| 45 static inline const char* type_to_extension(enum types type) { | |
| 46 switch (type) { | |
| 47 case TYPES_VF: return "vf"; | |
| 48 case TYPES_VEG: | |
| 49 case TYPES_UNKNOWN: | |
| 50 default: return "veg"; | |
| 51 } | |
| 52 } | |
| 53 | |
| 54 #ifndef ARRAYSIZE | |
| 55 #define ARRAYSIZE(x) (sizeof(x) / sizeof((x)[0])) | |
| 10 #endif | 56 #endif |
| 11 | 57 |
| 58 static const char* help_text = | |
| 59 "msvpvf by Paper\n" | |
| 60 "usage: %s <input>... (arguments)\n" | |
| 61 "\n" | |
| 62 "arguments:\n" | |
| 63 " -t, --type one of [vf,veg] (required)\n" | |
| 64 " -v, --version version to convert to (required)\n" | |
| 65 " -h, --help show this screen (optional)\n"; | |
| 66 | |
| 12 static struct option options_long[] = { | 67 static struct option options_long[] = { |
| 13 {"input", required_argument, NULL, 'i'}, | |
| 14 {"output", required_argument, NULL, 'o'}, | |
| 15 {"version", required_argument, NULL, 'v'}, | 68 {"version", required_argument, NULL, 'v'}, |
| 16 {"type", required_argument, NULL, 't'}, | 69 {"type", required_argument, NULL, 't'}, |
| 17 {"help", 0, NULL, 'h'} | 70 {"help", 0, NULL, 'h'} |
| 18 }; | 71 }; |
| 19 | 72 |
| 20 char* strremove(char* str, const char* sub) { | 73 int main(int argc, char *argv[]) { |
| 21 size_t len = strlen(sub); | 74 uint8_t version = 0; |
| 22 if (len > 0) { | 75 enum types type = TYPES_UNKNOWN; |
| 23 char* p = str; | |
| 24 while ((p = strstr(p, sub)) != NULL) { | |
| 25 memmove(p, p + len, strlen(p + len) + 1); | |
| 26 } | |
| 27 } | |
| 28 return str; | |
| 29 } | |
| 30 | 76 |
| 31 int main(int argc, char *argv[]) { | 77 int c; |
| 32 int c, option_index = 0; | 78 int option_index = 0; |
| 33 unsigned char magic[16]; | 79 while ((c = getopt_long(argc, argv, "v:t:h", options_long, &option_index)) != -1) { |
| 34 FILE* outfile; | 80 /* option argument */ |
| 35 struct arguments { | 81 switch (c) { |
| 36 char input[256]; | |
| 37 char output[256]; | |
| 38 int version; | |
| 39 char type[4]; | |
| 40 } args; | |
| 41 strcpy(args.input, " "); | |
| 42 strcpy(args.output, " "); | |
| 43 args.version = -1; | |
| 44 strcpy(args.type, " "); | |
| 45 | |
| 46 while ((c = getopt_long(argc, argv, "i:o:v:t:h", options_long, &option_index)) != -1) | |
| 47 switch(c) { | |
| 48 case 'i': | |
| 49 strncpy(args.input, optarg, sizeof(args.input)-1); /* subtract 1 to make sure it's "null-safe" */ | |
| 50 break; | |
| 51 case 'o': | |
| 52 strncpy(args.output, optarg, sizeof(args.output)-1); | |
| 53 break; | |
| 54 case 'v': | 82 case 'v': |
| 55 args.version = abs(atoi(strdup(optarg))); /* abs() for possible negative inputs */ | 83 version = atoi(optarg); |
| 56 break; | 84 break; |
| 57 case 't': | 85 case 't': |
| 58 strncpy(args.type, optarg, sizeof(args.type)-1); | 86 if (!strcmp(optarg, "vf")) { |
| 87 type = TYPES_VF; | |
| 88 } else if (!strcmp(optarg, "veg")) { | |
| 89 type = TYPES_VEG; | |
| 90 } else { | |
| 91 fprintf(stderr, "[ERROR]: Received an invalid type parameter!\n"); | |
| 92 printf(help_text, argv[0]); | |
| 93 } | |
| 94 | |
| 59 break; | 95 break; |
| 60 case 'h': | 96 case 'h': |
| 61 default: | 97 default: |
| 62 printf("msvpvf by Paper\nusage: %s (-i/--input) infile [(-o/--output) outfile] (-v/--version) version (-t/--type) [vf, veg]\n", argv[0]); | 98 printf(help_text, argv[0]); |
| 63 return 0; | 99 break; |
| 64 } | 100 } |
| 65 if (argc == 1) { | |
| 66 printf("msvpvf by Paper\nusage: %s (-i/--input) infile [(-o/--output) outfile] (-v/--version) version (-t/--type) [vf, veg]\n", argv[0]); | |
| 67 return 0; | |
| 68 } | 101 } |
| 69 if (strcmp(args.input, " ") == 0) { | 102 |
| 70 printf("Input file name?\n"); | 103 if (argc <= optind) { |
| 71 fflush(stdout); | 104 fprintf(stderr, "[ERROR]: Missing input file!\n"); |
| 72 fgets(args.input, sizeof(args.input)-1, stdin); | 105 printf(help_text, argv[0]); |
| 73 args.input[strcspn(args.input, "\r\n")] = 0; | |
| 74 } | |
| 75 if (access(args.input, F_OK) != 0) { | |
| 76 fprintf(stderr, "Input file \"%s\" doesn't exist! Exiting.", args.input); | |
| 77 return 1; | 106 return 1; |
| 78 } | 107 } |
| 79 FILE* input_file = fopen(args.input, "r"); | 108 |
| 80 if (fgetc(input_file) == EOF) { | 109 if (!version || !type) { |
| 81 fprintf(stderr, "Input file \"%s\" is empty.", args.input); | 110 printf(help_text, (argc > 0) ? argv[0] : "msvpvf"); |
| 82 fclose(input_file); | |
| 83 return 1; | 111 return 1; |
| 84 } | 112 } |
| 85 fseek(input_file, 0x46, SEEK_SET); | 113 |
| 86 printf("Input file version: %d\n", fgetc(input_file)); | 114 /* this progressively */ |
| 87 fseek(input_file, 0x18, SEEK_SET); | 115 while (optind < argc) { |
| 88 int file_version = fgetc(input_file); | 116 const char* input = argv[optind++]; |
| 89 printf("Input file type: "); | 117 FILE* output_file = NULL; |
| 90 switch (file_version) { | 118 |
| 91 case 0xEF: | 119 { |
| 92 printf("VEGAS Pro\n\n"); | 120 uint8_t file_version = 0; |
| 93 break; | 121 enum types file_type = TYPES_UNKNOWN; |
| 94 case 0xF6: | 122 |
| 95 printf("Movie Studio\n\n"); | 123 printf("Input file name: %s\n", input); |
| 96 break; | 124 /* print information about the input file */ |
| 97 default: | 125 FILE* input_file = fopen(input, "rb"); |
| 98 printf("Unknown\n\n"); | 126 if (!input_file) { |
| 99 break; | 127 fprintf(stderr, "[ERROR]: Error opening input file %s!\n\n", input); |
| 128 continue; | |
| 129 } | |
| 130 | |
| 131 if (fgetc(input_file) == EOF) { | |
| 132 fprintf(stderr, "[ERROR]: Input file \"%s\" is empty.\n", input); | |
| 133 fclose(input_file); | |
| 134 continue; | |
| 135 } | |
| 136 | |
| 137 if (get_file_information(input_file, &file_version, &file_type)) { | |
| 138 fprintf(stderr, "[ERROR]: Failed to get file information for input file \"%s\"!\n", input); | |
| 139 fclose(input_file); | |
| 140 continue; | |
| 141 } | |
| 142 | |
| 143 printf("Input file version: %u\n", file_version); | |
| 144 printf("Input file type: %s\n\n", type_to_string(file_type)); | |
| 145 | |
| 146 { | |
| 147 /* open the output file... */ | |
| 148 char* basec = msvpvf_internal_strdup(input); | |
| 149 char* bname = basename(basec); | |
| 150 int ext = strrchr(bname, '.') - bname; | |
| 151 | |
| 152 /* create the output filename */ | |
| 153 int needed_size = snprintf(NULL, 0, "V%u_%.*s.%s", version, ext, bname, type_to_extension(type)); | |
| 154 char* output = malloc((needed_size + 1) * sizeof(char)); | |
| 155 if (!output) { | |
| 156 fprintf(stderr, "[ERROR]: Failed to allocate memory for output string!\n"); | |
| 157 free(basec); | |
| 158 return 1; | |
| 159 } | |
| 160 | |
| 161 snprintf(output, needed_size + 1, "V%u_%.*s.%s", version, ext, bname, type_to_extension(type)); | |
| 162 printf("Output filename: %s\n", output); | |
| 163 | |
| 164 output_file = fopen(output, "w+b"); | |
| 165 if (!output_file) { | |
| 166 fprintf(stderr, "[ERROR]: Failed to open output file %s! Do you have write permissions?\n", output); | |
| 167 free(basec); | |
| 168 free(output); | |
| 169 continue; | |
| 170 } | |
| 171 free(basec); | |
| 172 free(output); | |
| 173 } | |
| 174 | |
| 175 copy_file(input_file, output_file); | |
| 176 | |
| 177 fflush(stdout); | |
| 178 fclose(input_file); | |
| 179 } | |
| 180 | |
| 181 set_file_information(output_file, version, type); | |
| 182 fclose(output_file); | |
| 100 } | 183 } |
| 101 int* ptr = &args.version; | 184 |
| 102 if (args.version == -1) { | |
| 103 printf("What version of VEGAS would you like to spoof to?: "); | |
| 104 fflush(stdout); | |
| 105 scanf("%d", ptr); | |
| 106 } | |
| 107 if (strcmp(args.type, " ") == 0) { | |
| 108 printf("Would you like it to be VEGAS Pro or Movie Studio? [veg/vf]: "); | |
| 109 fflush(stdout); | |
| 110 scanf("%3s", args.type); | |
| 111 } | |
| 112 fflush(stdout); | |
| 113 if (strcmp(args.output, " ") == 0) { /* string manipulation hell */ | |
| 114 char* temp = (char*)calloc(256, sizeof(char)); | |
| 115 temp[0] = '\0'; | |
| 116 char str_version[4]; | |
| 117 sprintf(str_version, "V%d", args.version); | |
| 118 strncat(temp, str_version, 4); | |
| 119 strncat(temp, "_", 2); | |
| 120 strncat(temp, basename(args.input), 248); | |
| 121 strcpy(temp, strremove(temp, strrchr(basename(args.input), ('.')))); /* remove file extension */ | |
| 122 strncat(temp, ".", 2); | |
| 123 strncat(temp, args.type, 4); | |
| 124 strncpy(args.output, temp, 255); | |
| 125 free(temp); | |
| 126 } | |
| 127 if (strcmp(args.type, "veg") == 0) { | |
| 128 const unsigned char T[] = {0xEF, 0x29, 0xC4, 0x46, 0x4A, 0x90, 0xD2, 0x11, 0x87, 0x22, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A}; | |
| 129 for (option_index = 0; option_index <= 15; option_index++) { /* this line is repeated, but it's probably best to just leave it be. */ | |
| 130 magic[option_index] = T[option_index]; | |
| 131 } | |
| 132 } else if (strcmp(args.type, "vf") == 0) { | |
| 133 const unsigned char T[] = {0xF6, 0x1B, 0x3C, 0x53, 0x35, 0xD6, 0xF3, 0x43, 0x8A, 0x90, 0x64, 0xB8, 0x87, 0x23, 0x1F, 0x7F}; | |
| 134 for (option_index = 0; option_index <= 15; option_index++) { | |
| 135 magic[option_index] = T[option_index]; | |
| 136 } | |
| 137 } else { | |
| 138 fprintf(stderr, "Type %s is invalid!", args.type); | |
| 139 return 1; | |
| 140 } | |
| 141 copy_file(args.input, args.output); | |
| 142 #ifdef _WIN32 /* disallowed characters in filenames */ | |
| 143 if (strcspn(args.input, "<>:\"/\\|?*") == strlen(args.input)+1) { | |
| 144 #elif defined(__unix__) | |
| 145 if (strcspn(args.input, "/") == strlen(args.input)+1) { | |
| 146 #else | |
| 147 if (NULL) { | |
| 148 #endif | |
| 149 fprintf(stderr, "Invalid output filename detected! Exiting..."); | |
| 150 return 1; | |
| 151 } | |
| 152 outfile = fopen(args.output, "r+b"); | |
| 153 if (outfile == NULL) { | |
| 154 fprintf(stderr, "Failed to open file %s! Do you have write permissions?", args.output); | |
| 155 return 1; | |
| 156 } | |
| 157 set_data(&magic, args.version, outfile); | |
| 158 fclose(outfile); | |
| 159 return 0; | 185 return 0; |
| 160 } | 186 } |
