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 }