Hard Light Productions Forums

Modding, Mission Design, and Coding => FS2 Open Tools => Topic started by: delt on November 25, 2014, 01:26:53 am

Title: Simple command-line VP utility
Post 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.
Title: Re: Simple command-line VP utility
Post by: delt on December 02, 2014, 02:05:06 pm
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
Title: Re: Simple command-line VP utility
Post by: headdie on December 03, 2014, 04:58:26 am
whats wrong with vp viewer for extracting files?
Title: Re: Simple command-line VP utility
Post by: The E on December 03, 2014, 05:11:29 am
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.
Title: Re: Simple command-line VP utility
Post by: headdie on December 03, 2014, 05:38:53 am
Fair enough then
Title: Re: Simple command-line VP utility
Post by: Echelon9 on March 06, 2015, 06:10:40 am
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:
Code: [Select]
$ 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:
Code: [Select]
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;
 }