/*  Copyright (C) 2006,2007 Salvatore Santagati <salvatore.santagati@gmail.com>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    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.,
    59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

/* Support Large File */

#define _FILE_OFFSET_BITS 64

#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#define VERSION "0.1.3"
#define BLOCK_ISO_CD 2048

/* Signature for Image ISO-9660 */
const char ISO_9660_START[] = { 
  (char) 0x01,
  (char) 0x43,
  (char) 0x44,
  (char) 0x30,
  (char) 0x30,
  (char) 0x31,
  (char) 0x01,
  (char) 0x00
};

const char ISO_9660[] = { 
  (char) 0x02,
  (char) 0x43,
  (char) 0x44,
  (char) 0x30,
  (char) 0x30,
  (char) 0x31,
  (char) 0x01,
  (char) 0x00
};

const char ISO_9660_END[] = { 
  (char) 0xFF,
  (char) 0x43,
  (char) 0x44,
  (char) 0x30,
  (char) 0x30,
  (char) 0x31,
  (char) 0x01,
  (char) 0x00
};

/* Signature for RAW image */
const char SYNC_RAW[12] = { 
  (char) 0x00,
  (char) 0xFF,
  (char) 0xFF,
  (char) 0xFF,
  (char) 0xFF,
  (char) 0xFF,
  (char) 0xFF,
  (char) 0xFF,
  (char) 0xFF,
  (char) 0xFF,
  (char) 0xFF,
  (char) 0x00
};

const char SYNC_RAW_2[8] = {
  (char) 0x00,
  (char) 0x00,
  (char) 0x08,
  (char) 0x00,
  (char) 0x00,
  (char) 0x00,
  (char) 0x08,
  (char) 0x00,
};


long img_size;
int  img_detect = 2;

int  img_header = 0;
int  img_ecc = 0;
int  img_size_sector = 0;
int  img_offset;



FILE *fsource, *fdest;


int previous_percent=-1;
void main_percent (int percent_bar)
// Prints a progress bar, takes a percentage as argument.
{
  //int progress_bar, progress_space;
  
  if (percent_bar==previous_percent) return;  // Nothing changed, don't waste CPU cycles.
  
  printf("%3d%% [:%.*s>%.*s:]\r",percent_bar,percent_bar/5,"====================",
                                        20-(percent_bar/5),"                    ");

}


void
usage ()
{

  printf ("Web     : http://developer.berlios.de/projects/iat\n");
  printf ("Email   : salvatore.santagati@gmail.com\n");
  printf ("Irc     : irc.freenode.net #ignus\n");
  printf ("Note	   : What's My Age Again? \n");
  
  printf ("Usage :\n");
  printf ("iat  OPTIONS[inputfile] OPTIONS[outputfile]\n\n");
//  printf ("OPTIONS\n");
//  printf ("\t-i	--iso     		Generate iso image from bin image\n");
//  printf ("\t-l	--log     		Generate log  for debug image\n");
//  printf ("\t-v	--verbose 	 	Print verbose messages\n");
//  printf ("\t-o --output filename       Write output to file\n");
  printf ("\t-h --help    		Display this notice\n\n");
}



int image_convert()
{
	
	long source_length, i;
	char buf[2448];


	fseek (fsource, 0L, SEEK_END);
	source_length = (ftell (fsource) - img_offset) / img_size_sector;
	
	  
	      fseek (fsource, img_offset, SEEK_SET);

	      {
		for (i = 0; i < source_length; i++)

		  {
		    main_percent(i*100/source_length);
		    	
		    fseek (fsource, img_header, SEEK_CUR);
		    if (fread (buf, sizeof (char),  BLOCK_ISO_CD, fsource));

		    else
		      {
			printf ("%s\n", strerror (errno));
			exit (EXIT_FAILURE);
		      };
		    if (fwrite (buf, sizeof (char),  BLOCK_ISO_CD, fdest));

		    else
		      {
			printf ("%s\n", strerror (errno));
			exit (EXIT_FAILURE);
		      };
		    fseek (fsource, img_ecc, SEEK_CUR);
	      	}
	      }
 	printf ("100%% [:=====================:]\n");	
return 0;
}


int image_detection() 
{
    char buf[8];
    char raw[12];
    int i;
    int block_image_start = 0;
    int block_image_end = 0; 
    int block_image_temp = 0;
    int block_image = 0;
    int block_image_detect = 0;	
    int img_header_temp = 0;
    int raw_2_check = 0;
    int raw_check = 0;


    
	fseek(fsource, 0L, SEEK_END);
    
	img_size = (((ftell(fsource))) / 8);

	for (i = 0; img_detect == 2; i = i + 1)
	{
		fseek(fsource, 0L, SEEK_SET);
		fseek(fsource, i, SEEK_CUR);
		fread(buf, sizeof(char), 8, fsource);
		fread(raw, sizeof(char), 12, fsource);
		
		if (!memcmp(ISO_9660_START, buf, 8))
	    	{
	    		printf("Detect Signature ISO9660 START at %d\n", i);
			if (block_image_start == 0) block_image_start = i ;
		}
	

		if (!memcmp(ISO_9660, buf, 8))
	    	{
	    		printf("Detect Signature ISO9660 at %d\n", i);
			if (block_image_end == 0)
				{
					block_image_end = i;
					block_image_temp = block_image_end - block_image_start;
				}
				
			img_detect++;
		}

		if (!memcmp(ISO_9660_END, buf, 8))
	    	{
	    		printf("Detect Signature ISO9660 END at %d\n", i);
			if (block_image_end == 0)
				{
					block_image_end = i;
					block_image_temp = block_image_end - block_image_start;
				}
	    		img_detect++;
	    	}
	   

		if (!memcmp(SYNC_RAW_2, buf, 8)) 
		{
	    		printf("Detect Signature RAW 2 at %d\n", i);
			if (raw_2_check == 0) 
			{
				img_header = img_header + 8;
				raw_2_check = 1;
	    		} 
	  
		}
		  
		if (!memcmp(SYNC_RAW, raw, 12))
		{
			printf("Detect Signature RAW at %d\n", i);
			if (raw_check == 0) 
			{
		    		img_header = img_header + 16;
		    		raw_check = 1;
			}

		}  

	    
		if ((img_size * 8) <= i) 
	 	{
			img_detect = -1;
			printf("Image is broken\n");
			return 0;
		}
		
	}
	
	/* Detect Block structure of image */

	for (block_image_detect = 1; block_image_detect == 1; block_image_temp =(block_image_temp / 2))
		{
			if (block_image_temp >= 2048)
			{
				switch (block_image_temp) 
					{
						case 2048  : 									block_image = block_image_temp;
								block_image_detect++;
								break;
						case 2352  :	
								block_image = block_image_temp;
								block_image_detect++;
								break;
						case 2336  :
								block_image = block_image_temp;
								block_image_detect++;
								break;
						case 2448  :
								block_image = block_image_temp;
								block_image_detect++;
								break;
						default :
								break;
					}
			
			}

			else block_image_detect = -1;

		}

      if (block_image_detect == -1);
	else      
		img_size_sector = block_image;	

      /* Size header of image */

     img_header_temp = block_image_start - block_image * 16;

     if ((img_header_temp == 8) || (img_header_temp == 16) || (img_header_temp == 24))
     {     
	img_header = img_header_temp;     
     }	


     /* Size ECC of image */

     img_ecc = block_image - img_header - BLOCK_ISO_CD;

		
     /* Dump of image */

    img_offset = block_image_start - block_image * 16 - img_header;	


    printf("\n Image offset start at %d", img_offset);
    printf("\n Sector header %d bit", img_header);
    printf("\n Sector ECC %d bit", img_ecc);
    printf("\n Block %d\n", block_image);	

    
return 1;

}

int main(int argc, char **argv) 
{

	printf("Iso9660 Analyzer Tool v%s by Salvatore Santagati\n", VERSION);
	printf("Licensed under GPL v2 or later\n");


	if ((fsource = fopen(argv[1], "rb")) != NULL)
		{
			if (image_detection() == 0)
				printf("This image is not CD IMAGE\n");
			else if  (argc > 2)
				{
					if ((fdest = fopen(argv[2],"wb")) != NULL)
					{
						image_convert();
						fclose(fdest);
					}
					else
						{			
							printf("%s\n", strerror(errno));
							usage();
						}
				}
			
		}		
	else	
		{	
			printf("%s\n", strerror(errno));
			usage();
			exit(EXIT_FAILURE);
		}   	
	
	return 1;				
	 
}   

