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 } |