#!/pro/bin/perl
# Uses ss2tk: show SpreadSheet file in Tk::TableMatrix::Spreadsheet (*)
#	  (m)'07 [26-06-2007] Copyright H.M.Brand 2005-2009
# Also uses code within the script from the Spreadsheet::XLSX Module by Dmitry Ovsyanko
# Copyright (C) 2008 by Dmitry Ovsyanko
# Coded by Paul Pruitt socrtwo@s2services.com
#
use strict;
use warnings;

use File::Basename;
use File::Path;
use Spreadsheet::ParseExcel;
use Spreadsheet::XLSX::Fmt2007;
use Spreadsheet::XLSX::Utility2007;
use Tk;
use Tk::DialogBox;
use Tk::FileSelect;
use Tk::JComboBox;

use Tk::Menu;
use Tk::Menubutton;
use Tk::NoteBook;
use Tk::Pretty;
use Tk::TableMatrix::Spreadsheet;

	my $worksheetnames;
	my $row;
	my $col;
	my $currloc = undef;  # location of active cell
	my $mw = new MainWindow(-title=>'Corrupt Excel 2007 xlsx2csv');
#
# Replaces the Tk icon with my own.
#
	my $icon = $mw->Photo(-file => 'excel-save-32X32.gif');
	$mw->iconimage($icon);
#
# Starts the menubar.
#
	my $mbar = $mw -> Menu();
	$mw -> configure(-menu => $mbar);
#
# Makes long button under menu bar.	
#
	my $but1 = $mw -> Button(-text=>"Step 1. Open the Workbook from the File Menu Or By Clicking Here", -command =>\&DoOpen)->pack; 
	my $frm_name = $mw -> Frame() -> pack(); #New Frame      
	my ($h, $w, $data, @nb, $sht);
#
# Produces initial spreadsheet grid to appear more like a spreadsheet like Excel.
#	
	my $label;
	my $label2;
	my $label3;
	my $jcb; 
	my $but2;
	my $but3;
	my $nb;
	my $ss = $mw ->Scrolled('Spreadsheet', 
			-rows => 22, 
			-cols => 22,          
			-width => 6,
			-height =>16,               
            -titlerows => 0,        
            -variable => $data, 
			-colstretchmode => 'last',               
			-bg => 'White',
            -rowstretchmode => 'last',               
            -selectmode => 'extended',               
			-browsecmd=> \&CheckLoc,
			-selecttype => 'row',
			-scrollbars => 'se',
            -sparsearray => 0  
                    )->pack; 
# 
# Main Menu Choices Setup section.
# 
	my $file = $mbar -> cascade(-label=>"File", -underline=>0, -tearoff => 0);
	my $help = $mbar -> cascade(-label =>"Help", -underline=>0, -tearoff => 0);
# 
# File Menu Choices section.
# 
	$file -> command(-label =>"Open", -underline => 0,
			-command => [\&DoOpen, "Open"]);
	$file -> command(-label =>"Convert All Salvageable Worksheets from Open Workbook to CSV", -underline => 0,
			-command => [\&convertall, "Open"]);	
	$file -> separator();
	$file -> command(-label =>"Exit", -underline => 1,
			-command => sub{ exit });
#
# Sets up About choice on the Help Menu.
#          
	$help -> command(-label =>"About", -underline => 0,
			-command => [\&AboutTxt, "About"]);
#
# Sets up which file will be accepted in getOpenFile dialogue Window below.
#   
	my $typesopen = [ ['Excel 2007 files', '.xlsx'],
						['All files',   '*'],];
MainLoop;
sub DoOpen {
	my $mainfilepath = $mw->getOpenFile(-filetypes => $typesopen,
						  -defaultextension => '.xlsx');
						   return unless $mainfilepath;
#
# Changes xlsx file to a zip one because CakeCMD will not unzip a file without a zip extension.
#
	my $zipexcelfilepath = $mainfilepath . '.zip'; 
	rename($mainfilepath, $zipexcelfilepath);
#
# Allows the $zipexcelfilepath to be used in subroutines.
#
	my $renamedmainfilepath = \$zipexcelfilepath;
#
# Check to see and won't proceed if target file is already open in Excel or some other program.
#
	unless (-e $zipexcelfilepath) {
			my $response = $mw->messageBox(-icon => 'question', -message => "$mainfilepath appears to be open in another program, please choose another file or close the file in that program and try again.", -title => 'Your Word 2007 File is Open in Another Program', -type => 'OK', -default => 'OK');
			return;
		}
#
# Don't know what this does.
#
	my $self = {};
#
# Removes xmls files and folders from previous xlsx file opening with this program.
#
	rmtree('xl');
#
# Uses CakeCmd to unzip the first three xml files from the compound zip file that is an xlsx spreadsheet.
#
	my $unzip = "cakecmd.exe";
	open my $wfh, "| $unzip extract \"$zipexcelfilepath\" xl/sharedStrings.xml \"\" " or die "Could not start $unzip: $!";
	open $wfh, "| $unzip extract \"$zipexcelfilepath\" xl/styles.xml \"\" " or die "Could not start $unzip: $!";
	open $wfh, "| $unzip extract \"$zipexcelfilepath\" xl/workbook.xml \"\" " or die "Could not start $unzip: $!";
#
# Makes the script sleep for 1 second while the unzipping catches up.
#
	my $num = 1;
		while($num--){
		sleep(1);
		}
#
# Reads in the Shared string file unzipped above.  This file contains all the text strings in the Excel file indexed.
#
	open FILE, "<xl/sharedStrings.xml";
	# or die "Couldn't open 'xl/sharedStrings.xml'"; #This is disabled because the script sometime crashes if activated
	my $file_contents = do { local $/; <FILE> };
#
# The code below through the reading in of the worksheets, is adapted from the Spreadsheet::XLSX module.
#	
	my $member_shared_strings = $file_contents;
	my $converter;
	$member_shared_strings = $file_contents;
	my @shared_strings = ();
		if ($member_shared_strings) {
			my $mstr = $member_shared_strings; #->contents; 
			$mstr =~ s/<t\/>/<t><\/t>/gsm;  # this handles an empty t tag in the xml <t/>
			foreach my $si ($mstr =~ /<si.*?>(.*?)<\/si/gsm) {
				my $str;
			foreach my $t ($si =~ /<t.*?>(.*?)<\/t/gsm) {
				$t = $converter -> convert ($t) if $converter;
				$str .= $t;
			}
			push @shared_strings, $str;
		}	
	}
#
# Reads in the styles xml file unzipped above.  Don't know if this file is necessary for CSV conversion.
#
	open FILE, "<xl/styles.xml";
	# or die 'Couldn't open '/styles.xml';
	$file_contents = do { local $/; <FILE> };
	my $member_styles = $file_contents;
    my @styles = ();

	my %style_info = ();

        if ($member_styles) {

			foreach my $t ($member_styles =~ /xf\ numFmtId="([^"]*)"(?!.*\/cellStyleXfs)/gsm) { #"
				   # $t = $converter -> convert ($t) if $converter;
					push @styles, $t;

                }
			my $default = $1 || '';

				foreach my $t1 (@styles){
					$member_styles =~ /numFmtId="$t1" formatCode="([^"]*)/;
					my $formatCode = $1 || '';
					if ($formatCode eq $default || not($formatCode)){
						if ($t1 == 9 || $t1==10){ $formatCode="0.00000%";}
						elsif ($t1 == 14){ $formatCode="m-d-yy";}
						else {
							$formatCode="";
						}
					}
					$style_info{$t1} = $formatCode;
					$default = $1 || '';
				}

        }

#
# Reads in the workbook xml file unzipped above.  From here we get the worksheet names and count.
#
		open FILE, "<xl/workbook.xml";
		# or die "Couldn't open 'xl/workbook.xml'"; #deactivated because it may cause script crashing.
	my $file_contents2 = do { local $/; <FILE> };
	my $member_workbook = $file_contents2;
#
# When the Spreadsheet::XLSX module was originally done, it would return $oBook which is the spreadsheet in some Perl array format?
#
	my $oBook = Spreadsheet::ParseExcel::Workbook->new;
	$oBook->{SheetCount} = 0;
	$oBook->{FmtClass} = Spreadsheet::XLSX::Fmt2007->new;
	$oBook->{Flg1904}=0;
		if ($member_workbook =~ /date1904="1"/){
			$oBook->{Flg1904}=1;
		}
	my @Worksheet = ();
	my @worksheetnames = ();
	my $sheet;
		foreach ($member_workbook =~ /\<(.*?)\/?\>/g) {
		
			/^(\w+)\s+/;
			
			my ($tag, $other) = ($1, $');

			my @pairs = split /\" /, $other;

			$tag eq 'sheet' or next;
#
# According to the xls2csv function of Spreadsheet::XLSX::Utility2007 the script won't work past 
# 702 columns which is column ZZ. Column A is counted as column 0. For some reason if you make 
# the MaxRow 1048575 and the Max Col 701 the script doesn't work as one might think to do.
#		
				$sheet = {
					MaxRow => 0,
					MaxCol => 0,
					MinRow => 1048575,
					MinCol => 701,
				};
		
				foreach ($other =~ /(\S+=".*?")/gsm) {

					my ($k, $v) = split /=?"/; #"
			
						if ($k eq 'name') {
							$sheet -> {Name} = $v;
#							
# The Spreadsheet::XLSX module has an optional text converter, 
# for instance can convert ASCII code to UTF-8 I think.	
# If this line is activated it convert worksheet name to say UTF-8.
#
#				$sheet -> {Name} = $converter -> convert ($sheet -> {Name}) if $converter;
#
							push @worksheetnames, $v;
						}
						elsif ($k eq 'r:id') {
							($sheet -> {Id}) = $v =~ m{rId(\d+)};
						};		
				}
			my $wsheet = Spreadsheet::ParseExcel::Worksheet->new(%$sheet);
			push @Worksheet, $wsheet;
			$oBook->{Worksheet}[$oBook->{SheetCount}] = $wsheet;
			$oBook->{SheetCount}+=1;		
		}
	print "$oBook->{SheetCount} \n";
#
# Allows @Worksheet to be used in subroutines below (I think).
#	
	$self -> {Worksheet} = \@Worksheet;
	my @minrow =();
	my @maxrow =();
	my @mincol =();
	my @maxcol =();
		foreach my $sheet (@Worksheet) {
#
# Name of each worksheet in the worksheets folder of the zipped xlsx file, is programatically expressed
#		
			my $member_name  = "xl/worksheets/sheet$sheet->{Id}.xml";
			open $wfh, "| $unzip extract \"$zipexcelfilepath\" $member_name \"\" " or die "Could not start $unzip: $!";	
			my $num = 1;
				while($num--){
					sleep(1);
				}
			open FILE, "<$member_name";
			# or die "Couldn't open $member_name";
			$file_contents = do { local $/; <FILE> };
			my $member_sheet = $file_contents;
			my ($row, $col);
			
			my $flag = 0;
			my $s    = 0; 
			my $s2   = 0;
			my $sty  = 0;
				foreach ($member_sheet =~ /(\<.*?\/?\>|.*?(?=\<))/g) {
					if (/^\<c r=\"([A-Z])([A-Z]?)(\d+)\"/) {
				
						$col = ord ($1) - 65;
				
							if ($2) {
								$col++;
								$col *= 26;
								$col += (ord ($2) - 65);
							}
				
						$row = $3 - 1;
						
						$s   = m/t=\"s\"/      ?  1 : 0;
						$s2  = m/t=\"str\"/    ?  1 : 0;
						$sty = m/s="([0-9]+)"/ ? $1 : 0;

					}
					elsif (/^<v/) {
						$flag = 1;
					}
					elsif (/^<\/v/) {
						$flag = 0;
					}
					elsif (length ($_) && $flag) {
						my $v = $s ? $shared_strings [$_] : $_;
							if ($v eq "</c>"){$v="";}
						my $type = "Text";
						my $thisstyle = "";
							if (not($s) && not($s2)){
							$type="Numeric";
							$thisstyle = $style_info{$styles[$sty]};
								if ($thisstyle =~ /(?<!Re)d|m|y/){
									$type="Date";
								}
							}	
						$sheet -> {MaxRow} = $row if $sheet -> {MaxRow} < $row;
						$sheet -> {MaxCol} = $col if $sheet -> {MaxCol} < $col;
						$sheet -> {MinRow} = $row if $sheet -> {MinRow} > $row;
						$sheet -> {MinCol} = $col if $sheet -> {MinCol} > $col;
						if ($v =~ /(.*)E\-(.*)/gsm && $type eq "Numeric"){
							$v=$1/(10**$2);  # this handles scientific notation for very small numbers
						}
						my $cell =Spreadsheet::ParseExcel::Cell->new(

							Val    => $v,
							Format => $thisstyle,
							Type => ""
							
						);

						$cell->{_Value} = $oBook->{FmtClass}->ValFmt($cell, $oBook);
						if ($type eq "Date" && $v<1){  #then this is Excel time field
							$cell->{Type}="Text";
							$cell->{Val}=$cell->{_Value};
						}
						$sheet -> {Cells} [$row] [$col] = $cell;
					}
					
				}
		
			$sheet -> {MinRow} = 0 if $sheet -> {MinRow} > $sheet -> {MaxRow};
			$sheet -> {MinCol} = 0 if $sheet -> {MinCol} > $sheet -> {MaxCol};
			my $minrowIteration = $sheet -> {MinRow};
			push @minrow, $minrowIteration;
			my $maxrowIteration = $sheet -> {MaxRow};
			push @maxrow, $maxrowIteration;
			my $mincolIteration = $sheet -> {MinCol};
			push @mincol, $mincolIteration;
			my $maxcolIteration = $sheet -> {MaxCol};
			push @maxcol, $maxcolIteration;
		}
#
# I think this references the arrays making them useful in subroutines.
#		
	my $worksheetnames = \@worksheetnames;
	my $minrow = \@minrow;
	my $maxrow = \@maxrow;
	my $mincol= \@mincol;
	my $maxcol= \@maxcol;
#
# This makes the original button # 1 disappear.
#	
	$but1 -> pack('forget');
#
# This section sets up the second button and the drop down combo box.
#
$ss-> pack('forget');
$mw-> pack('forget');
if (defined $label){$label-> pack('forget');}if (defined $jcb){$jcb-> pack('forget');}if (defined $label2){$label2-> pack('forget');}if (defined $label3){$label3-> pack('forget');}if (defined $but2){$but2-> pack('forget');}if (defined $but3){$but3-> pack('forget');}if (defined $nb){$nb-> pack('forget');}
#my ($label, $label2, $label3, $jcb, $but2, $but3)=@_;
	$label = $mw->Label(-text => 'Note CSV conversions may differ slightly from displayed data. The conversions seem to use the same kind of minor rounding that Excel itself uses.')->pack;
	$but2 = $mw -> Button(-text=>"Step 2. Convert All Salvageable Worksheets to CSV", -command =>\&convertall)->pack;
	$jcb = $mw -> JComboBox()->pack;
#
# This populates the JComboBox with the spreadsheet's worksheet names.
#	
		foreach $worksheetnames(@worksheetnames){
			$jcb->addItem("$worksheetnames");
			}
	$but3 = $mw -> Button(-text=>"Or Select a Worksheet to Save as a CSV File and Press this Button", -command =>\&push_button)->pack;
#
# Renames the xlsx file back to the xlsx extension by simply removing the zip added zip extension.
#
	rename ($zipexcelfilepath, $mainfilepath);				   
#
# Here begins code from H.Merijn Brand's ss2tk script, which is part of the Spreadsheet::Read distribution.
#
	
	my $title = $mainfilepath;
	my %unq;
#
# My version of Spreadsheet::Read is minimally changed from the original 
# to load my version # of Spreadsheet::XLSX (called Spreadsheet:XLSX::ZipMod2
#
use Spreadsheet::Read;
	my $ref = ReadData ("$mainfilepath");#	or die "Cannot read $title\n";
	$ref->[0]{sheets};	#	or die "No sheets in $title\n";
#
# Code creates a Perl/Tk notebook (tabbed windows).
#
	$nb = $mw->NoteBook ()->pack (qw(-side top -expand 1 -fill both ));
	my @nb;

		foreach my $sht (1 .. $ref->[0]{sheets}) {
			my $s = $ref->[$sht];
			$title .= " [ " . $s->{label} . " ]";

			my $pat = @ARGV ? qr/$ARGV[0]/i : undef; # Don't know if this is necessary as obviously there areno longer $ARGVs.

			my ($data, @data);
			my @c = (1, $s->{maxcol});
			my ($h, $w, @w) = (0, 1, 0, (0) x $c[1]); # data height, -width, and default column widths
				foreach my $r (1 .. $s->{maxrow}) {
					my @row = map {
						defined $s->{cell}[$_][$r] ? $s->{cell}[$_][$r] : "";
						} 1 .. $s->{maxcol};
					$pat and "@row" =~ $pat || next;
						foreach my $c (0 .. $#row) {
							$row[$c] or next;
							$c >= $w and $w = $c + 1;
							$data->{"$h,$c"} = $row[$c];
							push @data, "$h,$c";
							my $l = length $row[$c];
							$l > $w[$c] and $w[$c] = $l;
						}
					++$h % 100 or printf STDERR "%6d x %6d\r", $w, $h;
				}
    printf STDERR "%6d x %6d\n", $w, $h;

    $nb[$sht] = $nb->add ($sht,
			-label	=> $s->{label},
			-state	=> "normal",
			-anchor	=> "nw");
	
    my $ss = $nb[$sht]->Scrolled('Spreadsheet', 
			-rows => $h, 
			-cols => $w,          
			-width => 6, 
			-height =>16,               
			-titlerows => 0,        
			-variable => $data,                  
			-colstretchmode => 'last',							  
			-bg => 'White',
			-rowstretchmode => 'last',               
			-selectmode => 'extended',               
			-browsecmd=> \&CheckLoc,
			-selecttype => 'row',
			-scrollbars => 'se',
			-sparsearray => 0  
		)->pack; 
		$ss->tagConfigure("just", -anchor=>'w');

		foreach my $col (0..$w-1) {
			$ss->tagCol("just",$col);
		}
    my ($pv, $sv, $si) = ("", "", 0);
#
# Sets up search box in the lower left corner of the spreadsheet.
#	
sub search
    {
	$sv or return;
	$sv eq $pv && !$_[0] and return;
	$ss->selectionClear ("all");
		foreach my $i ($_[0] .. $#data, 0 .. ($_[0] - 1)) {
			$data->{$data[$i]} =~ m/$sv/i or next;
			$si = $i;
			$ss->activate     ($data[$si = $i]);
			$ss->selectionSet ($data[$si]);
			$ss->see          ($data[$si]);
			$pv = $sv;
			last;
			}
	} # search

    # Search frame
    my $sf = $nb[$sht]->Frame ()->pack (-side => "left", -expand => 1, -fill => "both");
    my $sl = $sf->Label (
	-text     => "Search",
	)->pack (-side => "left", -anchor => "sw");
    my $sb = $sf->Entry (
	-textvariable => \$sv,
	)->pack (-side => "left", -anchor => "sw");
    $sb->bind ("<Return>" => sub { search ($si = 0); });
    my $sn = $sf->Button (
	-text     => "Next",
	-command  => sub { search (++$si) },
	)->pack (-side => "left", -anchor => "sw");

    # Control frame
    my $cf = $nb[$sht]->Frame ()->pack (-side => "right", -expand => 1, -fill => "both");
    my $ce = $cf->Button (
	-text     => "Exit",
	-command  => \&exit,
	)->pack (-side => "right", -anchor => "se");

    # autosize columns on data (not on headers)
    $ss->colWidth (map { $_ => $w[$_] } 0 .. $#w);
    }
#
# Subroutine invoked after choosing an Excel worksheet and pusing the button to save it as a CSV file.
#
sub push_button {
#
# Gets the selected worksheet index number from the JComboBox choice.
#
	my $sheetnumber = $jcb->getSelectedIndex+1;
#
# Don't know if adding and then removing 1 is necessary, but there was a good 
# reason at the time and the script doesn't seem to work otherwise.
#	
	my $zeroedsheetnumber = $sheetnumber-1;
#
# Uses the Utility2007 function int2col to change the Column integer number back into column letters for use in the region.
#
	my $ChosenSheetMinColLet = &Spreadsheet::XLSX::Utility2007PDP::int2col($mincol[$zeroedsheetnumber]);
	my $ChosenSheetMaxCollet = &Spreadsheet::XLSX::Utility2007PDP::int2col($maxcol[$zeroedsheetnumber]);
	my $ChosenSheetMinRow = $minrow[$zeroedsheetnumber]+1;
	my $ChosenSheetMaxRow = $maxrow[$zeroedsheetnumber]+1;
	my $ChosenSheetRegion = "$sheetnumber\-$ChosenSheetMinColLet$ChosenSheetMinRow\:$ChosenSheetMaxCollet$ChosenSheetMaxRow";

	my $sfilename = $renamedmainfilepath ;
	my $sRegion = $ChosenSheetRegion ;
	my $iRotate = 0;
#
# As you can see the xls2csv (or xlsx2csv really) needs a region with column letters instead of numbers.
#	
	my $sCsvTxt = Spreadsheet::XLSX::Utility2007PDP::xls2csv($sfilename, $sRegion, $iRotate);
	my $tempcsv;
#
# This next bunch of code is used to create the name of the new csv 
# file with the name of the xlsx file followed by the worksheet name.
#	
	# my $path = $mainfilepath;
	# my($filename, $directories, $suffix) = fileparse($path, $suffix);
	# $suffix = 'xlsx';
	my $csvfilename = "$worksheetnames[$zeroedsheetnumber]".'.csv';
	open($tempcsv, "> $csvfilename") || die "Can't create temp.csv for output!\n";
		
	print ($tempcsv $sCsvTxt) if $tempcsv;	
	close $tempcsv;
#
# Success indicator message box displays with the name of the saved csv file.
#
	$mw->messageBox(-icon=>'info', -type=>'OK',
				-message=>"Your CSV files have been saved with the name $csvfilename, into the directory from where you launched corrupt-xlsx2csv.exe.");
#
# Subroutine for saving all the salvagable worksheets at once to CSV files.
# Very similar to the above routine.
#		
sub convertall {
	foreach my $sheet (@Worksheet) {
my $sheetnumber = $sheet->{Id};
my $zeroedsheetnumber = $sheetnumber-1;
print "My number of sheets is $sheetnumber \n";
print "My minimum row in sheet $worksheetnames[$zeroedsheetnumber] is $minrow[$zeroedsheetnumber] \n";
print "My maximum row in sheet $worksheetnames[$zeroedsheetnumber]is $maxrow[$zeroedsheetnumber] \n";
print "My minimum column in sheet $worksheetnames[$zeroedsheetnumber] is $mincol[$zeroedsheetnumber] \n";
print "My maximum column in sheet $worksheetnames[$zeroedsheetnumber] is $maxcol[$zeroedsheetnumber] \n";
my $ChosenSheetMinColLet = &Spreadsheet::XLSX::Utility2007PDP::int2col($mincol[$zeroedsheetnumber]);
my $ChosenSheetMaxCollet = &Spreadsheet::XLSX::Utility2007PDP::int2col($maxcol[$zeroedsheetnumber]);
my $ChosenSheetMinRow = $minrow[$zeroedsheetnumber]+1;
my $ChosenSheetMaxRow = $maxrow[$zeroedsheetnumber]+1;
my $ChosenSheetRegion = "$sheetnumber\-$ChosenSheetMinColLet$ChosenSheetMinRow\:$ChosenSheetMaxCollet$ChosenSheetMaxRow";
print $ChosenSheetRegion;
		my $sfilename = $renamedmainfilepath ;
		my $sRegion = $ChosenSheetRegion ;
        my $iRotate = 0;
        my $sCsvTxt = Spreadsheet::XLSX::Utility2007PDP::xls2csv($sfilename, $sRegion, $iRotate);
		my $tempcsv;
		my $path = $mainfilepath;
		my @suffixes = {'xlsx'};
		my($filename, $directories, $suffix) = fileparse($path, @suffixes);
		open($tempcsv, "> $filename\-$worksheetnames[$zeroedsheetnumber].csv") || die "Can't create temp.csv for output!\n";
		my $csvfilename = "$filename\-$worksheetnames[$zeroedsheetnumber].csv";
		my @csvfilenames = {};
		push @csvfilenames, $csvfilename;
		my $csvfilenames = @csvfilenames;
  print ($tempcsv $sCsvTxt) if $tempcsv;	
close $tempcsv;
}
$mw->messageBox(-icon=>'info', -type=>'OK',
            -message=>"Your CSV files have been saved with the names of the worksheets, into the directory from where you launched corrupt-xlsx2csv.exe.");
}
#
# Don't know what sub mysplit does and if it is still necessary.  It may be a left over from the other script
# used to display the spreadsheet.  It may be involved with decidnign whart separator is used with the CSV file.
#
sub mysplit {
  my($pat,$string,$num)=@_;
  if($pat eq "|" ) {
     return split(/\|/,$string,$num)
  }
  else {
    return split($pat,$string,$num)
 }
}
#
# This is probably from the other worksheet viewer and no longer necessary. 
# It helped located the active cell on a large worksheet.
#
sub CheckLoc {
   $currloc =$_[1];
}

sub AboutTxt {
my $popup=$mw->DialogBox(-title=>"ABOUT",
  -buttons=>["OK"],);
  $popup->add("Label", -justify=>"left", -text=>"
****Corrupt Excel 2007 XLSX2CSV Version 0.5 Beta****

***How to use this program***
1. Click on the File Menu or the Step 1. Button. Choose Open and your xlsx Excel 2007 file from 
which you wish to salvage csv files.
2. Click the option on the File Menu or on the Step 2. Button to save all the worksheets to CSV files.  
Alternatively you can use the drop down box to save a single worksheet as a CSV file.

***Important***
CakeCMD and therefore this program requires .Net version 2 available here: http://tinyurl.com/ms2-0-netframework.

If your data originally contains cells that have commas within them, then the data will be read as an additional 
cell-column for each comma. Further, the program will not display more than 702 columns properly. Also right now
the csv saving routine rounds off to 2 decimals places which is not a problem with the displayed version.

Please note, that these inaccuracies may limit the usefulness of the program in mission critical and production 
environments.  Accordingly, please us commercial software in these cases. 

Also, although the command window may be disturbing, it is preferable to the previous incarnation which flashed
multiple CMD windows during processing.  Future releases will try to eliminate this.

It's vital to have the excel-save-32X32.gif file in the same directory as corrupt-xlsx2csv.exe or the program will not start.

***Credits***
CakeCMD is by Leung Yat Chun Joseph: http://www.quickzip.org/softwares-cakecmd. It requires Microsoft .NET Framework 
Version 2.0: http://tinyurl.com/ms2-0-netframework.

Also note, the original ss2tk Perl script on which this script heavily relies is by H.Merijn Brand.  It's included 
in the source folder.

Special thanks to Sandeep Kumar, Dmitry Ovsyanko, Rob Polocz, Mr. Ritty from Mahalo, the folks at Perl Monks and my 
brother Andre, for technical support and encouragement.

***My Info***
My software website is http://www.godskingsandheroes.info/software/. Also visit my data recovery software list 
http://www.s2services.com. My E-Mail: socrtwo\@s2services.com.")->pack;
  $popup->Show
}
}
}
