Hard Light Productions Forums
Modding, Mission Design, and Coding => FS2 Open Tools => Topic started by: delt on November 25, 2014, 01:26:53 am
-
Hello everyone, it's been a while, years even, since i posted on this site... Freespace 1 and 2 have always been my all-time favourite games ever since they came out!
I've recently been playing Freespace 2 (and the excellent "fsport" of freespace 1) and i was reminded of how much the music in these games is just awesome. So, to extract it from the game data, i wrote a small command-line utility for manipulating .VP files - it should compile and run on any POSIX compliant operating system, i've tested it on a few linux systems (slackware, ubuntu) and on freebsd. Please keep in mind i haven't programmed in C for several years before writing this small project :D
Here it is: http://www.deimos.ca/vpfile-0.01a.tar.gz
It doesn't depend on anything else than a C compiler, the standard C libs, and basic knowledge of how to use a command line shell. To compile and install, just type:
make && sudo make install
If anyone gets this working on other systems, please let me know.
-
New version, 0.02alpha: fixed bug with timestamp on extracted files. Also tested on OpenBSD and NetBSD.
http://www.deimos.ca/vpfile-0.02a.tar.gz
-
whats wrong with vp viewer for extracting files?
-
Nothing. But it doesn't exactly work on non Windows PCs, and for some tasks, commandline utilities are simply faster; both the mediavps and blue planet have build scripts that we can just run and which use commandline tools to build vps.
-
Fair enough then
-
Hi delt,
Looks like a neat little tool.
Suggest considering the below patch, which I've written to address a few memory management issues within the commandline tool (buffer overruns, unfree'd heap blocks, resource leaks etc).
Confirmation was received from running your tool through the below cycle with Valgrind (http://valgrind.org/) and cppcheck (http://cppcheck.sourceforge.net/), and then confirming the hash of the README file was preserved:
$ valgrind --leak-check=full ./vpfile c test.vp README
$ valgrind --leak-check=full ./vpfile l test.vp
$ valgrind --leak-check=full ./vpfile x test.vp
$ cppcheck . 2> err.txt
Patch:
diff -u vpfile/vpfile.c vpfile-patch/vpfile.c
--- vpfile/vpfile.c 2014-11-25 18:51:10.000000000 +1100
+++ vpfile-patch/vpfile.c 2015-03-06 23:01:35.112886167 +1100
@@ -129,7 +129,7 @@
char buffer [32];
if (message) printf ("%s", message);
- scanf ("%35s", buffer);
+ scanf ("%31s", buffer);
if (buffer [0] == 'y' || buffer [0] == 'Y')
return 1;
else
@@ -370,24 +370,30 @@
buffer = safe_malloc (vp -> direntries [i].size);
if (fseek (vp -> f, vp -> direntries [i].offset, SEEK_SET)) {
sprintf (vp -> errormsg, "Couldn't seek into inputfile");
+ free (buffer);
return 0;
}
s = fread (buffer, 1, vp -> direntries [i].size, vp -> f);
if (s != vp -> direntries [i].size) {
sprintf (vp -> errormsg, "Error reading into buffer for file %s: expected %d, got %d",
vp -> fullpaths [i], (int) vp -> direntries [i].size, (int) s);
+ free (buffer);
return 0;
}
s = (fwrite (buffer, 1, vp -> direntries [i].size, outputfile));
if (s != vp -> direntries [i].size) {
sprintf (vp -> errormsg, "Error writing to file %s: expected %d, got %d",
vp -> fullpaths [i], (int) vp -> direntries [i].size, (int) s);
+ free (buffer);
return 0;
}
if (fclose (outputfile)) {
- sprintf (vp -> errormsg, "Error closing file %s", vp -> fullpaths [i]);
+ sprintf (vp -> errormsg, "Error closing file %s", vp -> fullpaths [i]);
+ free (buffer);
return 0;
}
+
+ free (buffer);
}
}
}
@@ -590,7 +596,6 @@
}
int dispose_of_vp_outputfile (t_vp_outputfile *vp, t_opts *opts) {
- int i = 0;
t_direntry_list *direntry_list = NULL, *last_direntry_list = NULL;
// let's take care of the filename list_vp_contents
@@ -676,6 +681,7 @@
// we can count and write all the data segments in the same pass
if (!vp -> direntry_list) {
printf ("write_vp_outputfile () -- vp contains no entries!!!\n");
+ fclose (f);
return 0;
}
@@ -697,16 +703,20 @@
if (!inputfile) {
printf ("\nError: Can't read from input file %s\n\n", direntry_list -> fullpath);
//printf ("direntry_list -> fullpath: %s\n", direntry_list -> fullpath);
+ fclose (f);
return 0;
}
if (fstat (fileno (inputfile), &statinfo)) {
printf ("Error stat'ing file %s\n", direntry_list -> fullpath);
+ fclose (f);
return 0;
}
opts -> v > 2 && printf ("Allocating memory for file buffer\n");
buffer = safe_malloc (statinfo.st_size);
if ((s = fread (buffer, 1, statinfo.st_size, inputfile) != statinfo.st_size)) {
printf ("Error reading %d bytes from %s (got %d bytes)\n", (int) statinfo.st_size, direntry_list -> fullpath, (int) s);
+ free (buffer);
+ fclose (f);
return 0;
}
opts -> v > 1 && printf ("Read %d bytes from file %s\n", (int) statinfo.st_size, direntry_list -> fullpath);
@@ -714,6 +724,8 @@
totalsize += statinfo.st_size;
if ((s = fwrite (buffer, 1, statinfo.st_size, f) != statinfo.st_size)) {
printf ("Error writing %d bytes to output file (%d bytes made it)\n", (int) statinfo.st_size, (int) s);
+ free (buffer);
+ fclose (f);
return 0;
}
if (inputfile)
@@ -749,6 +761,7 @@
}
fclose (f);
if (opts -> v > 2) inspect_vp_outputfile (vp, opts);
+ free (buffer);
return 1;
}
@@ -916,7 +929,7 @@
if (opts -> equal_sign) bitfield |= 2;
if (bitfield != 1) { // ...in which case we're at the compound to the last argument, so don't add
//printf ("Allocating memory for opts -> extra_args [%d]\n", opts -> extra_arg_count);
- opts -> extra_args [opts -> extra_arg_count] = safe_malloc (strlen (argv [i]));
+ opts -> extra_args [opts -> extra_arg_count] = safe_malloc (strlen (argv [i]) + 1);
strcpy (opts -> extra_args [opts -> extra_arg_count], argv [i]);
opts -> extra_arg_count++;
}
@@ -989,6 +1002,11 @@
print_usage (&opts);
}
+ for (i = 0; i < opts.extra_arg_count; ++i)
+ if (opts.extra_args [i] != NULL)
+ free (opts.extra_args [i]);
+ free (opts.extra_args);
+
// exit cleanly
return 0;
}