
// Microsoft OLE2 stream parser.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "logger.h"
#include "pldstr.h"
#include "ole.h"

#define ROLE_VERSION "0.0.3"

struct ripOLE_object {
	int debug;
	int verbose;
	int save_unknown_streams;

	char *inputfile;
	char *outputdir;
};


static char defaultdir[]=".";
static char version[]="0.0.3 - 2003-Jul-05 (C) PLDaniels http://www.pldaniels.com/ripole";
static char help[]="ripOLE -i <OLE2 file> [ -d <directory> ] [--save-unknown-streams] [--version|-V] [--verbose|-v] [--debug] [--help|-h]";

/*-----------------------------------------------------------------\
 Function Name	: set_defaults
 Returns Type	: int
 	----Parameter List
	1. struct ripOLE_object *role , 
 	------------------
 Exit Codes	: 
 Side Effects	: 
--------------------------------------------------------------------
 Comments:
 
--------------------------------------------------------------------
 Changes:
 
\------------------------------------------------------------------*/
int set_defaults( struct ripOLE_object *role )
{
	role->outputdir = defaultdir;
	role->debug = 0;
	role->verbose = 0;
	role->save_unknown_streams = 0;
	role->inputfile = NULL;

	return 0;
}

/*-----------------------------------------------------------------\
 Function Name	: parse_parameters
 Returns Type	: int
 	----Parameter List
	1. struct ripOLE_object *role, 
	2.  int argc, 
	3.  char **argv , 
 	------------------
 Exit Codes	: 
 Side Effects	: 
--------------------------------------------------------------------
 Comments:
 
--------------------------------------------------------------------
 Changes:
 
\------------------------------------------------------------------*/
int parse_parameters( struct ripOLE_object *role, int argc, char **argv )
{
	int i;
	int result = 0;

	role->outputdir = defaultdir;

	for (i = 1; i < argc; i++)
	{
		if (argv[i][0] == '-')
		{
			switch (argv[i][1])
			{
				case 'i':
					i++;
					role->inputfile = strdup(argv[i]);
					break;

				case 'd':
					i++;
					role->outputdir = strdup(argv[i]);
					break;

				case 'v':
					role->verbose = 1;
					break;

				case 'V':
					fprintf (stdout, "%s\n", version);
					exit (1);
					break;
				case 'h':
					fprintf (stdout, "%s\n", help);
					exit (1);
					break;

					// if we get ANOTHER - symbol, then we have an extended flag

				case '-':
						if (strncmp (&(argv[i][2]), "verbose", 7) == 0)
						{
							role->verbose=1;
							
						} else if (strncmp (&(argv[i][2]), "save-unknown-streams", 20) == 0) {
							role->save_unknown_streams = 1;
						
						} else if (strncmp (&(argv[i][2]), "debug", 5) == 0) {
							role->debug=1;
							
						} else if (strncmp (&(argv[i][2]), "version", 7) == 0) {
							fprintf (stdout, "%s\n", version);
							exit (1);
							
						} else if (strncmp(&(argv[i][2]),"help",4)==0) {
							fprintf(stdout,"%s\n",help);
							exit(1);

						} else {
							fprintf(stdout,"Cannot interpret option \"%s\"\n%s\n", argv[i], help);
							exit (1);
							break;
						}
					break;

					// else, just dump out the help message

				default:
					fprintf(stdout,"Cannot interpret option \"%s\"\n%s\n", argv[i], help);
					exit (1);
					break;

			}			// Switch argv[i][1]

		}			// if argv[i][0] == -

	}				// for

	return result;
}

/*-----------------------------------------------------------------\
 Function Name	: set_parameters
 Returns Type	: int
 	----Parameter List
	1. struct ripOLE_object *role, 
	2.  struct OLE_object *ole , 
 	------------------
 Exit Codes	: 
 Side Effects	: 
--------------------------------------------------------------------
 Comments:
 
--------------------------------------------------------------------
 Changes:
 
\------------------------------------------------------------------*/
int set_parameters( struct ripOLE_object *role, struct OLE_object *ole )
{
	if(role->debug == 1)
	{
		OLE_set_debug(ole, OLE_DEBUG_NORMAL);
	} else OLE_set_debug(ole, 0);

	if (role->verbose == 1)
	{
		OLE_set_verbose(ole, OLE_VERBOSE_NORMAL);
	} else OLE_set_verbose(ole, 0);

	if (role->save_unknown_streams == 1)
	{
		OLE_set_save_unknown_streams(ole, 1);
	} else OLE_set_save_unknown_streams(ole, 0);

	return 0;
}


/*-----------------------------------------------------------------\
 Function Name	: ripOLE_report_filename_decoded
 Returns Type	: int
 	----Parameter List
	1. char *filename, 
 	------------------
 Exit Codes	: 
 Side Effects	: 
--------------------------------------------------------------------
 Comments:
 
--------------------------------------------------------------------
 Changes:
 
\------------------------------------------------------------------*/
int ripOLE_report_filename_decoded(char *filename)
{
	LOGGER_log("Decoding filename=%s", filename);

	return 0;
}
	 


/*-----------------------------------------------------------------\
 Function Name	: ROLE_init
 Returns Type	: int
 	----Parameter List
	1. struct ripOLE_object *role, 
 	------------------
 Exit Codes	: 
 Side Effects	: 
--------------------------------------------------------------------
 Comments:
 
--------------------------------------------------------------------
 Changes:
 
\------------------------------------------------------------------*/
int ROLE_init(struct ripOLE_object *role)
{
	role->debug = 0;
	role->verbose = 0;
	role->save_unknown_streams = 0;

	role->inputfile = NULL;
	role->outputdir = NULL;

	return 0;
}


/*-----------------------------------------------------------------\
 Function Name	: ROLE_done
 Returns Type	: int
 	----Parameter List
	1. struct ripOLE_object *role, 
 	------------------
 Exit Codes	: 
 Side Effects	: 
--------------------------------------------------------------------
 Comments:
 
--------------------------------------------------------------------
 Changes:
 
\------------------------------------------------------------------*/
int ROLE_done(struct ripOLE_object *role)
{
	if (role->inputfile != NULL) free(role->inputfile);
	if (role->outputdir != NULL) free(role->outputdir);

	return 0;
}

/*-----------------------------------------------------------------\
 Function Name	: main
 Returns Type	: int
 	----Parameter List
	1. int argc, 
	2.  char **argv , 
 	------------------
 Exit Codes	: 
 Side Effects	: 
--------------------------------------------------------------------
 Comments:
 
--------------------------------------------------------------------
 Changes:
 
\------------------------------------------------------------------*/
int main( int argc, char **argv )
{
	struct ripOLE_object role;
	struct OLE_object *ole = NULL;
	int result = 0;

	ole = malloc(sizeof(struct OLE_object));
	if (ole == NULL)
	{
		LOGGER_log("ripOLE: Cannot allocate memory for OLE object");
		return 1;
	}

	LOGGER_set_output_mode(_LOGGER_STDOUT);
	OLE_init(ole);
	ROLE_init(&role);
	set_defaults( &role );
	parse_parameters(&role, argc, argv);
	set_parameters(&role, ole);
	OLE_set_filename_report_fn(ole, ripOLE_report_filename_decoded );
	result = OLE_decode_file( ole, role.inputfile, role.outputdir );
	if ((result != 0)&&(role.verbose)) LOGGER_log("ripOLE: decoding of %s resulted in error %d\n", role.inputfile, result );

	if (ole != NULL) free(ole);
	ROLE_done(&role);
	
	return result;
}
