/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
 * vsdump: test program to dump and parse content of vsd file
 *
 * Copyright (C) 2006-2007	Valek Filippov (frob@df.ru)
 * Copyright (C) 2002-2006	Jody Goldberg (jody@gnome.org)
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of version 3 or later of the GNU General Public
 * License as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
 * USA
 *
 * Parts of this code are taken from libgsf library
 */
#include <gsf/gsf-infile-msole.h>
#include <gsf/gsf-infile-zip.h>
#include <gsf/gsf-infile.h>
#include <gsf/gsf-input-stdio.h>
#include <gsf/gsf-utils.h>
#include <gsf/gsf-input.h>
#include <gsf/gsf-input-proxy.h>
#include <glib.h>
#include <glib/gstdio.h>
#include <ctype.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <locale.h>
#include "vsdump.h"
#include "vsd_utils.h"
#include "vsd_fonts_colors_parse.h"
#include "vsd_pointers.h"
#include "vsd_inflate.h"
#include "vsd_dump_stream_15.h"
#include "vsd_dump_stream_c.h"
#include "vsd_dump_stream_23.h"
#include "vsd_parse_cmds.h"
#include "vsd_parse_chunks.h"

#define DEBUG


/* ------------------------------------------------------------------------- */

static int
vsd_help (G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv)
{
	g_print ("Available subcommands are...\n");
	g_print ("* help\t\t\t\tlist subcommands\n");
	g_print ("* dump <file> [dir]\tdump pointers and inflated streams\n");
	g_print ("* test \ttest command table\n");
	return 0;
}

/* ------------------------------------------------------------------------- */

static int
vsd_dump (int argc, char **argv)
{
	FILE 			*fptr=NULL, *fstrm=NULL, *ftmp=NULL, *fdraw=NULL;
	char const 	*filename;
	char const	*ptr_file="/pointers";
	char const	*strm_file="/streams";
	char const	*draw_file="/drawing";
	char 			*dirname="vsdmp";

#ifdef DEBUG
	char			*tmpstr;
	FILE			*fdebug=NULL;
#endif /* DEBUG */	
	
	GsfInput 	*member, *input_pointers = NULL;
	GByteArray	*decomp;
	GArray		*pointers;
	int			version, fsize;
	strm_ptr		strmp, *sp;	
	
	int			fdindex = 0, numfrgn=1, numdump=1, numico = 1;
	guint 		j, ind_pntr, printhex=0;
	const guint8  *data = {0};
	GHashTable	*vaetbls;
	
	sp = &strmp;
	if(NULL == (vaetbls = vsd_parse_cmd_file())) return 1; /* problem with cmd tbl file */
	
	if (argc >= 2) dirname = argv[1];
	g_mkdir(dirname, 0755);
	fptr = vsd_openfd(dirname, ptr_file);
	fstrm = vsd_openfd(dirname, strm_file);
	fdraw = vsd_openfd(dirname, draw_file);
	
	filename = argv[0];
	member = vsd_get_input (filename);
	if (NULL == member)
		return 1;
	
	gsf_input_seek(member, VER_OFFSET, G_SEEK_SET);
	data = gsf_input_read(member, 1, NULL);
	version = GSF_LE_GET_GUINT8(data);
	g_print("Version: %x\t", version);
	gsf_input_seek(member, SIZE_OFFSET, G_SEEK_SET);
	data = gsf_input_read(member, 4, NULL);
	fsize = GSF_LE_GET_GUINT32(data);
	g_print("Size: %x\n", fsize);
		
	pointers = vsd_pointers_collect (member, version);
	vsd_pointers_print(pointers, fptr);
	
	for (ind_pntr = 0; ind_pntr < pointers->len; ind_pntr++) {
		sp = &g_array_index(pointers, strm_ptr, ind_pntr);
			
		if(5 == (sp->frmt>>4)){ /* 0x50, 0x52, 0x53, 0x54, 0x56, 0x57 streams */
		 fprintf  (fptr,"\n=== Pointer T/O/L/F/P: %x\t%x\t%x\t%x\t%x ===\n", sp->type, sp->offset, sp->len, sp->frmt, sp->prnt);
		}
		 fprintf (fstrm,"\n=== Pointer T/O/L/F/P: %x\t%x\t%x\t%x\t%x ===\n", sp->type, sp->offset, sp->len, sp->frmt, sp->prnt);
									
		if(sp->frmt & 2){ /* content is compressed, decompress to decomp */
				input_pointers = gsf_input_proxy_new_section(member, (gsf_off_t) sp->offset, (gsf_off_t) sp->len);
				decomp = vsd_inflate(input_pointers, 0);
													
		} else { /* content is non-compressed, copy it to decomp */
			gsf_input_seek(member, (gsf_off_t) sp->offset, G_SEEK_SET);
			decomp = g_byte_array_new ();
			g_byte_array_append(decomp, gsf_input_read(member, sp->len, NULL), sp->len);
		}
		/* replace bogus 'decoded length' in pointers */
		
#ifdef DEBUG
			/* Change here to dump something */
			if(0xc == (sp->type>>4) || 0xd == (sp->frmt>>4) || 0xc == (sp->frmt>>4)){
			tmpstr = g_strdup_printf ("debug%05d", numdump++);
			fdebug = vsd_openfd (dirname, tmpstr);
			fprintf(fdebug,"Type %x. Offset: %x\n", sp->type, sp->offset);
					for(j = 0; j < decomp->len; j++)
					{
						fputc(decomp->data[j],fdebug);
					}
					fclose(fdebug);
			}
#endif /* DEBUG */
					
			switch (sp->type)
			{
			case 0x0c:
					g_print("Dumping stream %d. T/O/L/F/P: %x  %x  %x  %x  %x\n", numdump, sp->type, sp->offset, sp->len, sp->frmt, sp->prnt);
					vsd_dump_stream_c(decomp, dirname, &numfrgn);
				  	break;
			case 0x15:		/* would be better to use sp->frmt>>4 == d here */
			case 0x18:					
			case 0x1a:
			case 0x31:
			case 0x46:	
			case 0x47:
			case 0x48: 
					g_print("Dumping stream %d. T/O/L/F/P: %x  %x  %x  %x  %x\n", numdump, sp->type, sp->offset, sp->len, sp->frmt, sp->prnt);
 					if(vsd_dump_stream15(decomp, version, fdraw, dirname, vaetbls)) {
 						g_warning("There is a problem with T/O/L/F/P: %x  %x  %x  %x  %x\n", sp->type, sp->offset, sp->len, sp->frmt, sp->prnt);
					}
					break;
			case 0x16:
					vsd_dump_colorentries (decomp, fstrm);
					break;
			case 0x23: /* icon for master */
					vsd_dump_stream_23(decomp, dirname, &numico);
				 	break;
 			case 0x33: /* text srings */
					if(0x45 == sp->frmt){
					 printhex=0;
					}else{
					 printhex=4;
					}
						fprintf(fstrm, "%d\t", decomp->data[printhex]);
					/* FALL THROUGH!!! */
			case 0xa:
					printhex+= 4;			   
					for (j = printhex; j < decomp->len; j++) {
						if((31 < decomp->data[j]) && (128 > decomp->data[j]))
						fputc(decomp->data[j],fstrm);
		     		}
		     		printhex=0;
					break;
			case 0xd7:
					/* Visio2k3 */
				  	vsd_dump_fontdescriptor (decomp, fstrm, &fdindex);
				 	break;
     		default:	
					ftmp = fstrm;
  					if (5 == (sp->frmt>>4))	ftmp = fptr;  	/* to where to dump? */
  					for (j = 0; j < decomp->len; j++) {
		     			fprintf(ftmp, "%02x ", decomp->data[j]);
		     			printhex++;
		     			if(0x10 == printhex){
		     				fprintf(ftmp, "\n");
		     				printhex = 0;
		     			}
		    		}
  					printhex = 0;
			 }
		   if(decomp->len) g_byte_array_free(decomp, TRUE);
			
	} /* end 'for' loop through the pointers */
	g_array_free(pointers, TRUE);
	g_object_unref(member);
	if(input_pointers) 	g_object_unref(input_pointers);
	
	fclose(fptr);
	fclose(fstrm);
	fclose(fdraw);

	return 0;
}

/* ------------------------------------------------------------------------- */

int
main (int argc, char **argv)
{
	GOptionContext *ocontext;
	GError *error = NULL;	
	char const *usage;
	char const *cmd;

	g_set_prgname (argv[0]);
	gsf_init ();

#if 0
	bindtextdomain (GETTEXT_PACKAGE, gnm_locale_dir ());
	textdomain (GETTEXT_PACKAGE);
#endif
	setlocale (LC_ALL, "");

	usage = "SUBCOMMAND ARCHIVE...";
	ocontext = g_option_context_new (usage);
	g_option_context_parse (ocontext, &argc, &argv, &error);
	g_option_context_free (ocontext);

	if (error) {
		g_printerr ("%s\nRun '%s --help' to see a full list of available command line options.\n",
			    error->message, argv[0]);
		g_error_free (error);
		return 1;
	}

	if (argc <= 1) {
		g_printerr ("Usage: %s %s\n", (argv[0] ? argv[0] : "vsdump"), usage);
		return 1;
	}

	cmd = argv[1];

	if (strcmp (cmd, "help") == 0)
		return vsd_help (argc - 2, argv + 2);

	if (strcmp (cmd, "dump") == 0){
		vsd_dump (argc - 2, argv + 2);
		gsf_shutdown();
		return 0;	
	}

	if (strcmp (cmd, "test") == 0)
		return vsd_parse_cmd_test();
		
	g_printerr ("Run '%s help' to see a list subcommands.\n", argv[0]);
	return 1;
}
