/*
 * Copyright (C) 2000
 *
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <windows.h>
#include <winbase.h>
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#include <time.h>
#include <dos.h>
#include <dir.h>

static unsigned char	_reverse[0x100];
static unsigned char	_table[0x100] = {
	0x33, 0x73, 0x3B, 0x26, 0x63, 0x23, 0x6B, 0x76, 0x3E, 0x7E, 0x36, 0x2B, 0x6E, 0x2E, 0x66, 0x7B,
	0xD3, 0x93, 0xDB, 0x06, 0x43, 0x03, 0x4B, 0x96, 0xDE, 0x9E, 0xD6, 0x0B, 0x4E, 0x0E, 0x46, 0x9B,
	0x57, 0x17, 0x5F, 0x82, 0xC7, 0x87, 0xCF, 0x12, 0x5A, 0x1A, 0x52, 0x8F, 0xCA, 0x8A, 0xC2, 0x1F,
	0xD9, 0x99, 0xD1, 0x00, 0x49, 0x09, 0x41, 0x90, 0xD8, 0x98, 0xD0, 0x01, 0x48, 0x08, 0x40, 0x91,
	0x3D, 0x7D, 0x35, 0x24, 0x6D, 0x2D, 0x65, 0x74, 0x3C, 0x7C, 0x34, 0x25, 0x6C, 0x2C, 0x64, 0x75,
	0xDD, 0x9D, 0xD5, 0x04, 0x4D, 0x0D, 0x45, 0x94, 0xDC, 0x9C, 0xD4, 0x05, 0x4C, 0x0C, 0x44, 0x95,
	0x59, 0x19, 0x51, 0x80, 0xC9, 0x89, 0xC1, 0x10, 0x58, 0x18, 0x50, 0x81, 0xC8, 0x88, 0xC0, 0x11,
	0xD7, 0x97, 0xDF, 0x02, 0x47, 0x07, 0x4F, 0x92, 0xDA, 0x9A, 0xD2, 0x0F, 0x4A, 0x0A, 0x42, 0x9F,
	0x53, 0x13, 0x5B, 0x86, 0xC3, 0x83, 0xCB, 0x16, 0x5E, 0x1E, 0x56, 0x8B, 0xCE, 0x8E, 0xC6, 0x1B,
	0xB3, 0xF3, 0xBB, 0xA6, 0xE3, 0xA3, 0xEB, 0xF6, 0xBE, 0xFE, 0xB6, 0xAB, 0xEE, 0xAE, 0xE6, 0xFB,
	0x37, 0x77, 0x3F, 0x22, 0x67, 0x27, 0x6F, 0x72, 0x3A, 0x7A, 0x32, 0x2F, 0x6A, 0x2A, 0x62, 0x7F,
	0xB9, 0xF9, 0xB1, 0xA0, 0xE9, 0xA9, 0xE1, 0xF0, 0xB8, 0xF8, 0xB0, 0xA1, 0xE8, 0xA8, 0xE0, 0xF1,
	0x5D, 0x1D, 0x55, 0x84, 0xCD, 0x8D, 0xC5, 0x14, 0x5C, 0x1C, 0x54, 0x85, 0xCC, 0x8C, 0xC4, 0x15,
	0xBD, 0xFD, 0xB5, 0xA4, 0xED, 0xAD, 0xE5, 0xF4, 0xBC, 0xFC, 0xB4, 0xA5, 0xEC, 0xAC, 0xE4, 0xF5,
	0x39, 0x79, 0x31, 0x20, 0x69, 0x29, 0x61, 0x70, 0x38, 0x78, 0x30, 0x21, 0x68, 0x28, 0x60, 0x71,
	0xB7, 0xF7, 0xBF, 0xA2, 0xE7, 0xA7, 0xEF, 0xF2, 0xBA, 0xFA, 0xB2, 0xAF, 0xEA, 0xAA, 0xE2, 0xFF,
};

//----------------------------------------------------------------------------------------------------------

inline void _ClockLfsr0Forward(int &lfsr0)
{
	int	temp;

	temp = (lfsr0 << 3) | (lfsr0 >> 14);
	lfsr0 = (lfsr0 >> 8) | ((((((temp << 3) ^ temp) << 3) ^ temp ^ lfsr0) & 0xFF) << 9);
}

inline void _ClockLfsr1Forward(int &lfsr1)
{
	lfsr1 = (lfsr1 >> 8) | ((((((((lfsr1 >> 8) ^ lfsr1) >> 1) ^ lfsr1) >> 3) ^ lfsr1) & 0xFF) << 17);
}

inline void _ClockBackward(int &lfsr0, int &lfsr1)
{
	int	temp0, temp1;

	lfsr0 = ((lfsr0 << 8) ^ ((((lfsr0 >> 3) ^ lfsr0) >> 6) & 0xFF)) & ((1 << 17) - 1);
	temp0 = ((lfsr1 >> 17) ^ (lfsr1 >> 4)) & 0xFF;
	temp1 = (lfsr1 << 5) | (temp0 >> 3);
	temp1 = ((temp1 >> 1) ^ temp1) & 0xFF;
	lfsr1 = ((lfsr1 << 8) | ((((((temp1 >> 2) ^ temp1) >> 1) ^ temp1) >> 3) ^ temp1 ^ temp0)) & ((1 << 25) - 1);
}

static void _Salt(int &lfsr0, int &lfsr1, const unsigned char salt[5])
{
	lfsr0 ^= (_reverse[salt[0]] << 9) | _reverse[salt[1]];
	lfsr1 ^= ((_reverse[salt[2]] & 0xE0) << 17) | ((_reverse[salt[2]] & 0x1F) << 16) | (_reverse[salt[3]] << 8) | _reverse[salt[4]];
}

static void _PrintKey(int lfsr0, int lfsr1)
{
	printf("key:");
	printf(" %02X", _reverse[lfsr0 >> 9]);
	printf(" %02X", _reverse[lfsr0 & 0xFF]);
	printf(" %02X", _reverse[((lfsr1 >> 16) & 0x1F) | ((lfsr1 >> 17) & 0xE0)]);
	printf(" %02X", _reverse[(lfsr1 >> 8) & 0xFF]);
	printf(" %02X", _reverse[lfsr1 & 0xFF]);
}

static int _FindLfsr(const unsigned char *crypt, int offset, const unsigned char *plain, int &result0, int &result1)
{
	int		loop0, loop1, lfsr0, lfsr1, carry, count;

	for(loop0 = count = 0; loop0 != (1 << 18); loop0++) {
		lfsr0 = loop0 >> 1;
		carry = loop0 & 0x01;
		for(loop1 = lfsr1 = 0; loop1 != 4; loop1++) {
			_ClockLfsr0Forward(lfsr0);
			carry = (_table[crypt[offset + loop1]] ^ plain[loop1]) - ((lfsr0 >> 9) ^ 0xFF) - carry;
			lfsr1 = (lfsr1 >> 8) | ((carry & 0xFF) << 17);
			carry = (carry >> 8) & 0x01;
		}
		for(; loop1 != 7; loop1++) {
			_ClockLfsr0Forward(lfsr0);
			_ClockLfsr1Forward(lfsr1);
			carry += ((lfsr0 >> 9) ^ 0xFF) + (lfsr1 >> 17);
			if((carry & 0xFF) != (_table[crypt[offset + loop1]] ^ plain[loop1])) {
				break;
			}
			carry >>= 8;
		}
		if(loop1 == 7) {
			for(loop1 = 0; loop1 != 6; loop1++) {
				_ClockBackward(lfsr0, lfsr1);
			}
			carry = ((lfsr0 >> 9) ^ 0xFF) + (lfsr1 >> 17) + (loop0 & 0x01);
			if((carry & 0xFF) == (_table[crypt[offset]] ^ plain[0])) {
				for(loop1 = 0; loop1 != offset + 1; loop1++) {
					_ClockBackward(lfsr0, lfsr1);
				}
				if(lfsr0 & 0x100 && lfsr1 & 0x200000) {
					result0 = lfsr0;
					result1 = lfsr1;
					count++;
				}
			}
		}
	}
	return count;
}

int quit_check(void) {
	int i;
	if ( kbhit() ) {
		i = getch();
		if (i == 'q' || i == 'Q') {
			return (1);
		}
	}
	return(0);
}

void _checkWinver() {
	DWORD dwVersion;
	dwVersion = GetVersion();
	if (dwVersion < 0x80000000)   {
		printf("\nautomatic authenticate won't work with WinNT/Win2000, yet - sorry");
		printf("\n\nplay your DVD with a player to do this");	
		exit(1);
	}
}

static int _FindKey(char *filename, int &lfsr0, int &lfsr1)
{
	unsigned char	buffer[0x800], plain[7] = { 0x00, 0x00, 0x01, 0xBE, 0x00, 0x00, 0xFF };
	char authstring[80];
	int				result, offset, left, flag, block, count, abort,i;
	FILE			*file;

	result = 1;
	printf("\rscanning %s for key now ...\t\t \n",filename);
	if((file = fopen(filename, "rb")) == 0) {
		printf("error: can't open input file '%s'\n", filename);
		exit (1);
	} else {
		for(flag = block = 0; fread(buffer, 1, sizeof buffer, file) == sizeof buffer; block++) {
			if ((block % 100)==0) {
				printf("\rscanning, block %d", block);
				fflush(stdout);
				if ( kbhit() ) {
					i = getch();
					switch(i) {
						case 'q':
						case 'Q':
							fclose(file);
							exit (1);
						case 'n':
						case 'N':
						//	printf("\rsearching key on next vobfile				 ");
							fclose(file);
							return (2);
						case 's':
						case 'S':
							printf("\n\nskipping keysearch...(ignoring key)\n\n");
							fclose(file);
							return (0);
					}
				}
			}
			if(buffer[0x14] & 0x10) {
				flag |= 0x01;
				if(buffer[0x00] == 0x00 && buffer[0x01] == 0x00 && buffer[0x02] == 0x01 && buffer[0x03] == 0xBA
				   && buffer[0x0E] == 0x00 && buffer[0x0F] == 0x00 && buffer[0x10] == 0x01) {
					offset = 0x14 + (buffer[0x12] << 8) + buffer[0x13];
					if(0x80 <= offset && offset <= 0x7F9) {
						flag |= 0x02;
						left = 0x800 - offset - 6;
						plain[4] = (char) (left >> 8);
						plain[5] = (char) left;
						if((count = _FindLfsr(buffer + 0x80, offset - 0x80, plain, lfsr0, lfsr1)) == 1) {
							_Salt(lfsr0, lfsr1, buffer + 0x54);
							result = 0;
							break;
						} else if(count) {
							printf("\rblock %d reported %d possible keys, skipping\n", block, count);
						}
					}
				}
			}
		}
		fclose(file);
		if(block < 250 && result ) {
			return (3);
		}
		if(result && feof(file)==0 ) {
			printf("\ncould not retrieve key from file '%s'\n", filename);
			return (1);
		} else {
			printf("\rscanning, done        		  \n");
			if(result) {
				printf("error: unable to deduce key from input file (%s)\n", flag & 0x02 ? "the algorithm failed" : flag & 0x01 ? "there were no vulnerable blocks" : "there were no encrypted blocks");
			}
		}
		fclose(file);
	}
	return result;
}

static void _Decrypt(unsigned char *buffer, int lfsr0, int lfsr1)
{
	int	loop0, carry;

	_Salt(lfsr0, lfsr1, buffer + 0x54);
	for(loop0 = carry = 0, buffer += 0x80; loop0 != 0x800 - 0x80; loop0++, buffer++) {
		_ClockLfsr0Forward(lfsr0);
		_ClockLfsr1Forward(lfsr1);
		carry += ((lfsr0 >> 9) ^ 0xFF) + (lfsr1 >> 17);
		*buffer = (unsigned char) (_table[*buffer] ^ carry);
		carry >>= 8;
	}
}

static int _DecryptFile(const char *filename0, const char *filename1, int lfsr0, int lfsr1, int option,int vob_flag,int *ac3rip, int &skip_vobid)
{
	unsigned char	buffer[0x800],ac3buffer[0x800];
      int      result, block, choice,display_message_id=0,loop,loop1,ac3_flag=0, ac3buffsize, ac3str_info;
	int tmin, tsec;
	float	filesize;
	FILE	*file0,*file1;
	HANDLE input_file,ac3file1,ac3file2,ac3file3,ac3file4;
	DWORD dwRead = 0;
	time_t t1, t2;
	char ac3filename[80];
	loop=0;
	while (ac3rip[loop]!=0) {
			sprintf(ac3filename,"audio_%i.ac3",ac3rip[loop]);
	switch (loop) {
		case 0:
			ac3_flag=1;
			ac3file1 = CreateFile(ac3filename,GENERIC_WRITE,FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS,NULL);
			SetFilePointer(ac3file1,NULL,NULL,FILE_END);
			break;
		case 1:
			ac3_flag=1;
			ac3file2 = CreateFile(ac3filename,GENERIC_WRITE,FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS,NULL);
			SetFilePointer(ac3file2,NULL,NULL,FILE_END);
			break;
		case 2:
			ac3_flag=1;
			ac3file3 = CreateFile(ac3filename,GENERIC_WRITE,FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS,NULL);
			SetFilePointer(ac3file3,NULL,NULL,FILE_END);
			break;
		case 3:
			ac3_flag=1;
			ac3file4 = CreateFile(ac3filename,GENERIC_WRITE,FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS,NULL);
			SetFilePointer(ac3file4,NULL,NULL,FILE_END);
		}
		loop++;
	}
	if((file0 = fopen(filename0, "rb")) == 0) {
		printf("error: can't open input file '%s'\n", filename0);
		exit (1);
	}
	fseek(file0,0,SEEK_END);
	filesize=ftell(file0)/2048;
	if (filesize == 0 ) {
		printf("\nfile has no data\n");
		exit(1);
	}
	fseek(file0,0,SEEK_SET);
	if (option == 1) {
// unnecessary - no option 1 passed
//	input_file = CreateFile(filename1,OPEN_ALWAYS,FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS,NULL);
	} else {
		if (option == 2) {
			input_file = CreateFile(filename1,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS,NULL);
			SetFilePointer(input_file,NULL,NULL,FILE_END);
		} else {
			if((file1 = fopen(filename1, "rb")) != 0) {
				fclose(file1);
        			printf("\n'%s' already exists: (O)verwrite,(A)ppend, (Q)uit?\n\n", filename1);
				while (1) {
					choice=getch();
					switch (choice) {
    						case 'o':
    						case 'O':
							input_file = CreateFile(filename1,GENERIC_WRITE,FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS,NULL);
							choice = 'q';
							break;
    						case 'a':
    						case 'A':
							input_file = CreateFile(filename1,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS,NULL);
							SetFilePointer(input_file,NULL,NULL,FILE_END);
							choice = 'q';   		
							break;
    						case 'Q':
    						case 'q': choice = 'q'; exit (1);
					}
					if (choice == 'q' ) break;
					}
				} else {
					input_file = CreateFile(filename1,GENERIC_WRITE,FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS,NULL);
				}
			}
		}
		t1 = time(NULL);
		for(block = 0;; block++) {
		if(block % 100 == 0) {
 			t2 = time(NULL);
 			tsec = difftime(t2,t1);
			tmin = (tsec/60);
			tsec = tsec - (tmin*60);
			printf("\rdecrypting, %.2f%% done\t %i:%02i",100-((filesize-block)/filesize)*100,tmin,tsec);
			fflush(stdout);
			if	(quit_check() == 1) {
					CloseHandle (input_file);
					CloseHandle(ac3file1);CloseHandle(ac3file2);CloseHandle(ac3file3);CloseHandle(ac3file4);
					fclose(file0);
					exit (1);
			}
		}
		if(fread(buffer, 1, sizeof buffer, file0) != sizeof buffer) {
			result = 0;
			break;
		}
		if(buffer[0x14] & 0x10) {
			_Decrypt(buffer, lfsr0, lfsr1);
			buffer[0x14] &= ~0x10;
                }
                if (vob_flag>0) {
		    	 if (buffer[38]==0x00 && buffer[39]==0x00 && buffer[40]==0x01 && buffer[41]==0xBF && buffer[42]==0x03 && buffer[43]==0xD4) {
// search for VOB_ID vob_flag=1
//search for multiangle info and skip movie according to first found info
// skip current vob_id if bytes detected
                      if (vob_flag==1) {
                              if ((buffer[1071]!=0x00) || (buffer[1072]!=0x00) ) {
//						skip_vobid=0;
//					} else {
					if (buffer[1056]!=skip_vobid ) {
						skip_vobid=buffer[1056]+1;
						if (buffer[1056]!=display_message_id) {
							printf("\r Multiangle detected, skipping vob-id %2i now\n",skip_vobid);
							display_message_id=buffer[1056];
						}
}
//while in multiangle part, skip next vob_id
						while (buffer[1056]==skip_vobid) {
							if(fread(buffer, 1, sizeof buffer, file0) != sizeof buffer) {
								break;
							}
							if(buffer[0x14] & 0x10) {
								_Decrypt(buffer, lfsr0, lfsr1);
								buffer[0x14] &= ~0x10;
						     	}
							if (buffer[38]==0x00 && buffer[39]==0x00 && buffer[40]==0x01 && buffer[41]==0xBF && buffer[42]==0x03 && buffer[43]==0xD4) {
								if  (buffer[1056]!=skip_vobid)
									break;
							}
							buffer[1056]=skip_vobid;
						}
					}
buffer[1071]=0x00;
buffer[1072]=0x00;
				}
			} 
		}
		if (ac3_flag==1) {
			if (buffer[14]==0x00 && buffer[15]==0x00 && buffer[16]==0x01 && buffer[17]==0xBD) {
	loop1=0;
	ac3str_info=buffer[22]+23;
	ac3buffsize=2044-ac3str_info;
	while (ac3rip[loop1]!=0) {
		if (ac3rip[loop1]+48==buffer[ac3str_info]) {
			break;
		}
		loop1++;
	}
	if (buffer[ac3str_info] == ac3rip[loop1]+48 && ac3rip[loop1]!=0) {
					for (loop=0;loop<(2048-(ac3str_info));loop++) {
						ac3buffer[loop]=buffer[ac3str_info+4+loop];
// check for bad audio buffer streams (matrix workaround)
						if ((loop>8) && ac3buffer[loop-8]==0x00 && ac3buffer[loop-7]==0x00 && ac3buffer[loop-6]==0x01 && ac3buffer[loop-5]==0xBE && ac3buffer[loop-2]==0xFF && ac3buffer[loop-1]==0xFF && ac3buffer[loop]==0xFF ) {
							ac3buffsize=loop-8;
							break;
						}
					}
					switch(loop1) {
			case 0:
						if ( WriteFile(ac3file1,ac3buffer,ac3buffsize,&dwRead,NULL) == 0) {
							printf("\nerror: can't write %s \n",ac3file2);
							CloseHandle(ac3file1);CloseHandle(ac3file2);CloseHandle(ac3file3);CloseHandle(ac3file4);
							fclose(file0);
							exit(1);
						}
						break;
			case 1:
						if ( WriteFile(ac3file2,ac3buffer,ac3buffsize,&dwRead,NULL) == 0) {
							printf("\nerror: can't write to %s \n",ac3file2);
							CloseHandle(ac3file1);CloseHandle(ac3file2);CloseHandle(ac3file3);CloseHandle(ac3file4);
							fclose(file0);
							exit(1);
						}
						break;
			case 2:
						if ( WriteFile(ac3file3,ac3buffer,ac3buffsize,&dwRead,NULL) == 0) {
							printf("\nerror: can't write to %s \n",ac3file2);
							CloseHandle(ac3file1);CloseHandle(ac3file2);CloseHandle(ac3file3);CloseHandle(ac3file4);							fclose(file0);
							exit(1);
						}
						break;
			case 3:
						if ( WriteFile(ac3file4,ac3buffer,ac3buffsize,&dwRead,NULL) == 0) {
							printf("\nerror: can't write to %s \n",ac3file2);
							CloseHandle(ac3file1);CloseHandle(ac3file2);CloseHandle(ac3file3);CloseHandle(ac3file4);
							fclose(file0);
							exit(1);
						}
					}
				}
			}
		}
		if (option != 1) {
			if ( WriteFile(input_file,buffer,sizeof buffer,&dwRead,NULL) == 0) {
				printf("\nerror: can't write to output file\n");
				CloseHandle (input_file);
				CloseHandle(ac3file1);CloseHandle(ac3file2);CloseHandle(ac3file3);CloseHandle(ac3file4);
				fclose(file0);
				exit(1);
			}
		}
	}
	printf("\rdecrypting, %i%% done\t %i:%02i              \n", 100,tmin,tsec);
	CloseHandle (input_file);
	CloseHandle(ac3file1);CloseHandle(ac3file2);CloseHandle(ac3file3);CloseHandle(ac3file4);
	fclose(file0);
	return result;
}

void patch_region (void){
	int buffer;
	char filename1[80]="Video_ts.ifo";
	char filename2[80]="Video_ts.bup";
	FILE *file;
	if((file = fopen(filename1, "r+")) == 0) {
		printf("\nerror: can't open file '%s'\n", filename1);
		printf("\nrun vobdec from same directory as %s",filename1);
		printf("\nand make sure write protection is disabled");
		exit(1);	
	}
	fseek(file,35,0);
	buffer = 192;
	




(buffer,file);
	fclose(file);
	if((file = fopen(filename2, "r+b")) == 0) {
		printf("\nerror: can't open file '%s'\n", filename2);
		printf("\nrun vobdec from same directory as %s",filename2);
		printf("\nand make sure write protection is disabled");
		exit(1);	
	}
	fseek(file,35,0);
	fputc(buffer,file);
	fclose(file);
	printf("\npatched files %s and %s successfully",filename1,filename2);
}

void disable_macrovision (char *filename){
	int buffer,loop,j,correct,i;
	FILE *file;
	unsigned char fbuffer[6];
	int	fstreamfind[6]={0,0,1,191,3,212};
	printf("\npatching macrovision on file '%s'\n",filename);
	printf("\npress 'y' to confirm\nany other key to abort...");
	i=getch();
	if (i!='y' && i!='Y') exit(1);
	printf("\n\npatching file...");
	if((file = fopen(filename, "r+b")) == 0) {
		printf("\nerror: can't open file '%s' for patching\n", filename);
		printf("\nmake sure write protection is disabled");
		exit(1);	
	}
	fseek(file,0,0);
	while(!feof(file)) {
		j++;
		if ((j % 100) == 0) {
			if (quit_check() == 1) { 
				fclose(file);
				exit (1);
			}
		}
		fseek(file,38,SEEK_CUR);
		if(fread(fbuffer,1,sizeof fbuffer, file) == 0) {
			printf("\end of file reached");
                  fclose(file);
			exit(1);
		}
		correct = 1;
		for (loop=0;loop<6;loop++) {
			if ( fbuffer[loop] != fstreamfind[loop] ) {
				correct = 0;
			}
		}
		if ( correct == 1 ) {
			fseek(file,5,SEEK_CUR);
			fputc(0,file);
		} else{
			fseek(file,6,SEEK_CUR);
		}
			fseek(file,1998,SEEK_CUR);
	}
	printf("\npatched file %s successfully",filename);
}


int region_free_check(char *drive,char *vtsfilename) {
	int buffer,i,max_aud,lang_known=0,reg_flag=0;
	char dir[70] =":\\video_ts\\Video_ts.ifo";
	char dir2[70] =":\\video_ts\\Vts_01_0.ifo";
	char language[80];
	unsigned char lang_flag[3];
	char in_filename[80];
	char DVDname[80];
	FILE *file;
	dir2[15]=vtsfilename[16];
	dir2[16]=vtsfilename[17];	
	strcpy (in_filename,drive);
	strcat (in_filename,dir);
	sprintf(DVDname,"%c:\\",drive[0]);
	GetVolumeInformation(DVDname,DVDname,80,NULL,0,0,0,0);
	for (i=0;i<sizeof DVDname;i++) {
		if (DVDname[i] == '_')
			DVDname[i] = ' ';
	}
	printf("\nDVD '%s'",DVDname);
	if((file = fopen(in_filename, "rb")) == 0) {
		printf("error: can't open file '%s'\n", in_filename);
		}
	fseek(file,35,0);
	buffer = fgetc(file);
	switch(buffer) {
		case 192: printf(" is region free\n");
				reg_flag=1;
				break;
		case 254: printf(" is region 1");
				break;
		case 253: printf(" is region 2");
				break;
		case 251: printf(" is region 3");
				break;
		case 247: printf(" is region 4");
				break;
		case 239: printf(" is region 5");
				break;
		case 223: printf(" is region 6");
	}
	fclose(file);
	strcpy (in_filename,drive);
	strcat (in_filename,dir2);
	if((file = fopen(in_filename, "rb")) == 0) {
		printf("error: can't open file '%s'\n", in_filename);
		return (0);
	}
	fseek(file,515,0);
	buffer = fgetc(file);
	max_aud = buffer;
	fseek(file,512,0);
	if (max_aud == 1) {
		printf("\nfound only audio stream 0x80");
	} else {
		printf("\nfound audio streams 0x80 to 0x8%i  ",max_aud-1);
	}
	for (i=0;i<max_aud;i++) {
		fseek(file,6,SEEK_CUR);
		fread(lang_flag,1,2,file);
		if(strcmp(lang_flag,"en")==0) {
			strcpy (language,"English");lang_known =1;
		} else {
			if(strcmp(lang_flag,"de")==0) {
				strcpy (language,"German");lang_known =1;
			}
			if(strcmp(lang_flag,"da")==0) {
				strcpy (language,"Danish");lang_known =1;
			}
			if(strcmp(lang_flag,"fr")==0) {
				strcpy (language,"French");lang_known =1;
			}
			if(strcmp(lang_flag,"cs")==0) {
				strcpy (language,"Czech");lang_known =1;
			}
			if(strcmp(lang_flag,"es")==0) {
				strcpy (language,"Spanish");lang_known =1;
			}
			if(strcmp(lang_flag,"no")==0) {
				strcpy (language,"Norwegian");lang_known =1;
			}
			if(strcmp(lang_flag,"pl")==0) {
				strcpy (language,"Polish");lang_known =1;
			}
			if(strcmp(lang_flag,"tr")==0) {
				strcpy (language,"Turkish");lang_known =1;
			}
			if(strcmp(lang_flag,"el")==0) {
				strcpy (language,"Greek");lang_known =1;
			}
			if(strcmp(lang_flag,"sv")==0) {
				strcpy (language,"Swedish");lang_known =1;
			}
			if(strcmp(lang_flag,"fi")==0) {
				strcpy (language,"Finnish");lang_known =1;
			}
		}
		if (lang_known==1) {
			printf("\n0x8%i is language %s",i,language);
		} else {
			printf("\n0x8%i is language %c%c",i,lang_flag[0],lang_flag[1]);
		}
		lang_known =0;	
	}
	if (reg_flag==1) {
		fclose(file);
		return (0);
	}
	fclose(file);
	return (1);
}

void audio_info(char *filename) {
	int buffer,i,j=0,correct,loop,loop2,found_flag=0;
	unsigned char fbuffer[2048];
	unsigned char ac3flag[1];
	unsigned char fstreamfind[4]={0x00,0x00,0x01,0xBD};
	FILE *file;
	DWORD  dwRead;
	double filesize;
	HANDLE input_file;
	if((file = fopen(filename, "rb")) == 0) {
		fclose(file);
		printf("\nerror: can't open file '%s'\n", filename);
		exit(1);
	}
// search for ac3 audio
	ac3flag[0] = 48+80; //80+x
	printf("\n retrieving AC3 info\n");
	fseek(file,0,SEEK_SET);
	while (!feof(file)) {
		j++;
		if (j> 10000) {
			printf("could not find AC3 in file");
			exit(1);
		}
		if ((j % 100) == 0) {
			if	(quit_check() == 1) {
				fclose(file);
				exit (1);
			}
		}
		if(fread(fbuffer, 1, sizeof fbuffer, file) == 0) {
			printf("\nend of file reached ");
               		fclose(file);
			exit(1);
		}
//search for audio stream
		correct = 1;
		for (loop=0;loop<4;loop++) {
			if ( fbuffer[(loop+14)] != fstreamfind[loop] ) {
				correct = 0;
			}
		}
//search for language
		if ( correct == 1 ) {
			if (fbuffer[28] == 0x80) {
				if (found_flag==1) {
					fclose(file);
					exit(1);
				}
				printf("\nfound AC3 stream 0x80 (most likely english)");
				found_flag=1;
				i=1;
			} else {
				if (fbuffer[28]== ac3flag[0]+i) {
					i++;
					printf("\nfound AC3 stream 0x%x", fbuffer[28]);
				}
			}
		}	
	}
}

void info() {
	printf("\nfull DVD RIP	   	 : vobdec x         merge DVD into 1 file\n");
	printf("full DVD RIP	   	 : vobdec s         separate files\n");
	printf("single .vob file   	 : vobdec [1..99]   rip single files only\n");
	printf("rip multiple VOB files   : vobdec [1] [99]  rip VOBs [1-99], [x] for merging\n");
	printf("regular decryption  	 : vobdec [infile] [outfile] [K0 K1 K2 K3 K4]\n");
      printf(" optional:   'vobdec vts# [...]'      use other # than default vts1 \n");
      printf("	     'key #####' 	      pass key (10 digits) to program\n");
      printf("	     '-0'                     disables multiangle detection\n");
      printf("	     '-ac3 [80] [81]..'       parallel ac3-stream rip from DVD\n");
      printf("	     '+ac3 [80] [81]..'       get only ac3-stream from DVD\n");
      printf("	     '-a'	 	      authenticate DVD\n");
	printf("\nstrip file from LBA #    : vobdec strip [#LBA] [infile] [outfile]\n");
	printf("search Cell-IDs #LBA 	 : vobdec lba [infile] \n");
      printf("search + filedump        : vobdec lba [infile] [outfile]\n");
      printf("truncate file       	 : vobdec trunc [#LBA] [infile]\n");
      printf("show AC3 file info 	 : vobdec ac3 [vobfile]\n");
      printf("merge files       	 : vobdec merge [file1]...[file2]...[targetfile]\n");
      printf("rip ac3 streams      	 : vobdec ac3 [vobfile] [ac3file] [ac3 number]\n");
      printf("remove region info 	 : vobdec regionfree 	(only for .ifo, .bup files)\n");
      printf("remove macrovision	 : vobdec demacro [vobfile]\n");
      printf("show DVD/AC3 info 	 : vobdec info");
}

void def_name(char *filename,char *drive,char *part1,char *part2,char *part3) {
 	strcpy (filename,drive);
 	strcat (filename,part1);
	strcat (filename,part2);
	strcat (filename,part3);
}

void truncate_file(double trunc_point,char *filename) {
	long trunc_long;
	int i;
	double filesize;
	HANDLE input_file;
	input_file = CreateFile(filename,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_WRITE_THROUGH,NULL);
// test if file exits
	if (GetLastError()==2) {
		printf("couldn't open file %s",filename);
		exit(1);
	}
 	filesize = GetFileSize(input_file,NULL);
	if (trunc_point >= filesize) {
		printf("\ntruncpoint %.0lf bytes / filesize %.0lf bytes",trunc_point,filesize);
		printf("\n\ntruncpoint out of filesize - aborting truncation");
		exit(1);
	}
	printf("\ntruncating %s at %.0lf bytes / LBA # %.0lf (y)?",filename,trunc_point,trunc_point/2048);
	printf("\nany other key will abort");
	i = getch();
        if (i != 'y' && i != 'Y') exit(1);
	SetFilePointer(input_file,0,NULL,FILE_BEGIN);
// 2GB limit due to long input - work around it
	if (trunc_point < 2147483646) {
		trunc_long=trunc_point;
		SetFilePointer(input_file,trunc_long,NULL,FILE_CURRENT);
	} else {
		while (trunc_point > 2147483646) {
			SetFilePointer(input_file,2147483646,NULL,FILE_CURRENT);
			trunc_point -= 2147483646;
		}
		trunc_long=trunc_point;
		SetFilePointer(input_file,trunc_long,NULL,FILE_CURRENT);
	}
	if (SetEndOfFile(input_file)==0) {
		printf("\ntruncation failed");
	} else {
		printf("\nfile truncated");
	}
	CloseHandle (input_file);
}

void append_file (char *sourcefile,char *targetfile) {
	int ibuffer,counter,i;
	FILE *infile,*outfile;
	double	filesize,filesize2,filesize3;
	DWORD  dwRead,dwWrite;
	HANDLE input_file,output_file;
	char	buffer[2048];
	input_file = CreateFile(sourcefile,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
	if (GetLastError()==2) {
                printf("\ncouldn't open file %s",sourcefile);
		exit(1);
	}
	output_file = CreateFile(targetfile,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS,NULL);
	if (GetLastError()==2) {
                printf("\ncouldn't open file %s",targetfile);
		exit(1);
	}
 	filesize = GetFileSize(output_file,NULL);
 	filesize2 = GetFileSize(input_file,NULL);
	printf("\ntargetfile %20s: %13.0lf bytes",targetfile,filesize);
	printf("\nsourcefile %20s: %13.0lf bytes",sourcefile,filesize2);
	printf("\n\nmerging...\n");	
	SetFilePointer(input_file,0,NULL,FILE_BEGIN);
	SetFilePointer(output_file,0,NULL,FILE_END);
	while (  (ReadFile(input_file,buffer,2048,&dwRead,NULL) != 0)  ) {
		if  (dwRead == 0) {
				break;
		}
		if ( WriteFile(output_file,buffer,dwRead,&dwWrite,NULL)== 0 || (dwWrite==0)){
			CloseHandle (input_file);
			CloseHandle (output_file);
		      printf("\nerror writing to file");
			printf("\n\ntry to truncate file %s to original size? (y)\nany other key will abort",targetfile);
			i = getch();
			if (i == 'y' || i == 'Y') { 
				if (filesize==0) {
					remove(targetfile);
				} else {
					truncate_file(filesize,targetfile);
				}
			}
			exit(1);
		}
		counter++;
		if (counter % 100 == 0) {
			counter=0;
			if	(quit_check() == 1) {
				CloseHandle (input_file);
				CloseHandle (output_file);
				exit (1);
			}
		}
 	}
	CloseHandle (input_file);
	CloseHandle (output_file);
	input_file = CreateFile(targetfile,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
 	filesize3 = GetFileSize(input_file,NULL);
	CloseHandle (input_file);
	printf("\n\nmerged %s: %5.0lf bytes",targetfile,filesize3);
	if (filesize3-filesize2-filesize ==0) {
		printf("\n\nmerging of files was succesful");
// merge multiple, limit, filesize check in stripping, too
		printf("\ndo you want to delete original file %s now? (y/n)",sourcefile);
		i = getch();
		if (i == 'y' || i == 'Y') { 
			remove (sourcefile);
		}
	} else {
		printf("\nmerging of files failed");
// undo change by resetting filepointer
		printf("\n\ntry to truncate file %s to original size? (y)\nany other key will abort",targetfile);
		i = getch();
                if (i == 'y' || i == 'Y') { 
                        if (filesize==0) {
                                remove(targetfile);
                        } else {
                                truncate_file(filesize,targetfile);
                        }
                }
	}
}

void strip_file(long lba,char *in_filename,char *out_filename) {
	int    i;
	unsigned char buffer[204800];
	double  split_byte,filesize,filesize2,lbadouble;
	long byte_shift;
	unsigned long counter=0;
	DWORD  dwRead;
	FILE   *infile,*outfile;
	HANDLE input_file;
	input_file = CreateFile(in_filename,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
 	filesize = GetFileSize(input_file,NULL); //in LBA
	CloseHandle (input_file);
	if (lba >= filesize/2048) {
		printf("\nLBA is out of files range (max LBA is %.0lf)",filesize/2048);
		exit(1);
	}
// workaround 2 GB limit
	split_byte = lba;
	split_byte = split_byte * 2048;
	printf("\ndumping %s to %s @ LBA %li\n",in_filename,out_filename,lba);
	if ((infile = fopen(in_filename,"rb")) == NULL) {
		printf("couldn't open %s abort process",in_filename);
		exit(1);
	}
	fseek(infile,0,SEEK_SET);
	while (split_byte > 2147483646) {
		fseek(infile,2147483646,SEEK_CUR);
		split_byte -= 2147483646;

	} 

	byte_shift = split_byte;
	fseek(infile,byte_shift,SEEK_CUR);
	if ((outfile = fopen(out_filename,"wb")) == NULL) {
		printf("\ncouldn't open %s abort process",out_filename);
		exit(1);
	}
	while ((i=(fread(buffer, 1, sizeof buffer, infile))) != 0) {
	   	fwrite(buffer,i,1,outfile);
		counter++;
//		if (counter % 10 == 0) {
			printf("\r %.0lf00 blocks left",(filesize/2048-lba-counter*100)/100 );
			if	(quit_check() == 1) { 
					fclose(infile);
					fclose(outfile);
					exit (1);
			}
//		}
	}
 	fclose(infile);fclose(outfile);
	input_file = 	CreateFile(out_filename,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
 	filesize2 = GetFileSize(input_file,NULL);
	CloseHandle (input_file);
	lbadouble= lba;
	lbadouble *= 2048;
	printf("\r %8.0lf blocks left",0);
	printf("\n\n%s has %15.0lf bytes", in_filename,filesize);
	printf("\n%s has %15.0lf bytes", out_filename,filesize2);
	printf("\nsplitting point was at %3.0lf bytes / LBA #%.0lf", lbadouble,lbadouble/2048);
	if ((filesize2 == filesize-lbadouble) && filesize2 != 0) {
		printf("\nsuccesully dumped file...\n");
	} else {
		printf("\nerror: could not dump file correct");	
		printf("\n%s should be %.0lf bytes, is %.0lf bytes",out_filename,filesize-lbadouble, filesize2);
		printf("\n\nremove file %s (y)",out_filename);
		printf("\nany other key will preserve file");
		i=getch();
		if ( i=='y' || i=='Y') {
			if (remove(out_filename) == 0) {
				printf("\nfile deleted");
			}
				else {
				printf("\n\ndelete failed");
			}
		}
// option to remove file
		exit(1);
	}
	printf("\norginal file will be truncated now");
	printf("\n (c) to continue, any other key to abort process");
	i = getch();
	if ( (i != 'c') && (i != 'C') ) {
		exit(1);
	}
	split_byte = lba;
	split_byte = split_byte * 2048;
	truncate_file(split_byte,in_filename);
}


void check_valid_id (char *filename,int *first_cell,int *last_cell) {
	int	dir_flag=0,buffer,j,i,correct;
	int	streamfind[6]={0,0,1,191,3,212};
	FILE *file;
	double	filesize;
	long 	lbasize;
	DWORD  dwRead;
	HANDLE input_file;
	if((file = fopen(filename, "rb")) == 0) {
		printf("\nerror: can't open file '%s'\n", filename);
		exit(1);
	}
	fclose(file);
	input_file = CreateFile(filename,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
 	filesize = GetFileSize(input_file,NULL); //in LBA
	CloseHandle (input_file);
	lbasize=filesize/2048;
	if (lbasize != filesize/2048) {
		printf("\nincorrect filesize - run 'vobdec trunc %li %s' first", lbasize,filename);
		exit(1);
	}
	if((file = fopen(filename, "rb")) == 0) {
		printf("\nerror: can't open file '%s'\n", filename);
		exit(1);
	}
	fseek(file,-2048,SEEK_END);
	printf("\nopening file '%s for CELL-ID detection'\n\n", filename);
	while (*last_cell == 0 || *first_cell == 0) {
		j++;
		if ((j % 100) == 0) {
			j=0;
			if (quit_check() == 1) { 
				fclose(file);
				exit (1);
			}
		}
		fseek(file,38,SEEK_CUR);
		correct = 1;
		for (i=0;i<6;i++) {
			buffer = fgetc(file);
			if ( buffer != streamfind[i] ) {
				correct = 0;
			}
		}
		if ( correct == 1 ) {
			fseek(file,1014,SEEK_CUR);
			buffer = fgetc(file);
			if (dir_flag == 0) {
				*last_cell=buffer;
				dir_flag = 1;
				fseek(file,0,SEEK_SET);
			} else {
				*first_cell=buffer;
			}
		} else {
			fseek(file,2004,SEEK_CUR);
		}
		if (dir_flag == 0) {
			fseek(file,-4096,SEEK_CUR);//this is going back 2048 bytes overall actually
		}
	}
	
	if (*last_cell == *first_cell) {
		printf("\nonly CELL-ID %i found - no clean truncation possible",*first_cell);
		fclose(file);
		exit(1);
	} else	{
		if (*last_cell < *first_cell) {
			printf("\nfound cell-IDs %i to %i in wrong order - make sure, you merged VOB correctly",*first_cell,*last_cell);
			fclose(file);
			exit(1);
		}
	}
	printf("\nfound cell-IDs %i to %i, searching lba positions now\n",*first_cell,*last_cell);
	fclose(file);
}

void scan_foraudio (char *filename,char *outfilename,int *ac3rip) {
	int buffer,i,j=0,correct,loop,loop1,loop2;
	long ac3str_info,ac3buffsize,read_data;
	unsigned char fbuffer[204800];
	unsigned char audiobuffer[2048];
	unsigned char ac3flag[1];
	char ac3filename[80];
	unsigned char fstreamfind[4]={0x00,0x00,0x01,0xBD};
	FILE *file;
	DWORD  dwRead;
	HANDLE ac3file1,ac3file2,ac3file3,ac3file4;
	for (loop=0;loop<sizeof outfilename;loop++) {
		if (outfilename[loop]=='.')
			outfilename[loop]='_';
	}
	if((file = fopen(filename, "rb")) == 0) {
		printf("\nerror: can't open file '%s'\n", filename);
		exit(1);
	}
	printf("\ndumping audio streams:\n");
	loop=0;
	while (ac3rip[loop]!=0) {
			sprintf(ac3filename,"%s_%i.ac3",outfilename,ac3rip[loop]);
			printf("0x%i to %s\n",ac3rip[loop],ac3filename);
	switch (loop) {
		case 0:
			ac3file1 = CreateFile(ac3filename,GENERIC_WRITE,FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS,NULL);
			break;
		case 1:
			ac3file2 = CreateFile(ac3filename,GENERIC_WRITE,FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS,NULL);
			break;
		case 2:
			ac3file3 = CreateFile(ac3filename,GENERIC_WRITE,FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS,NULL);
			break;
		case 3:
			ac3file4 = CreateFile(ac3filename,GENERIC_WRITE,FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS,NULL);

		}
		loop++;
	}
	fseek(file,0,SEEK_SET);
	while (!feof(file)) {
		j++;
		if ((j % 10) == 0) {
			printf("\r scanning LBA #%i00",j);				
			if (quit_check() == 1) {
					CloseHandle(ac3file1);CloseHandle(ac3file2);CloseHandle(ac3file3);CloseHandle(ac3file4);
					fclose(file);
				return;
			}
		}
		read_data=fread(fbuffer, 1, sizeof fbuffer, file);
		if (read_data== 0) {
			printf("\nend of file reached ");
			fclose(file);
			CloseHandle(ac3file1);CloseHandle(ac3file2);CloseHandle(ac3file3);CloseHandle(ac3file4);
			exit(1);
		}
//search for audio stream
		for (loop2=0;loop2<read_data/2048;loop2++) {
			correct = 1;
			for (loop=0;loop<4;loop++) {
				if ( fbuffer[(loop+14)+(loop2*2048)] != fstreamfind[loop] ) {
					correct = 0;
				}
			}
//search for language
			if ( correct == 1 ) {
				ac3str_info=fbuffer[(loop2*2048)+22]+(loop2*2048)+23;
				ac3buffsize=(2044-(ac3str_info-(loop2*2048)));
loop1=0;
	while (ac3rip[loop1]!=0) {
		if (ac3rip[loop1]+48==fbuffer[ac3str_info]) {
			break;
		}
		loop1++;
	}
				if (fbuffer[ac3str_info] == ac3rip[loop1]+48 && ac3rip[loop1]!=0) {
					for (loop=0;loop<(2048-(ac3str_info-(loop2*2048)));loop++) {
						audiobuffer[loop]=fbuffer[ac3str_info+4+loop];
						if ((loop>8) && audiobuffer[loop-8]==0x00 && audiobuffer[loop-7]==0x00 && audiobuffer[loop-6]==0x01 && audiobuffer[loop-5]==0xBE && audiobuffer[loop-2]==0xFF && audiobuffer[loop-1]==0xFF && audiobuffer[loop]==0xFF ) {
							ac3buffsize=loop-8;
							break;
						}
					}
					switch(loop1) {
			case 0:
						if ( WriteFile(ac3file1,audiobuffer,ac3buffsize,&dwRead,NULL) == 0) {
							printf("\nerror: can't write %s \n",ac3file2);
							CloseHandle(ac3file1);CloseHandle(ac3file2);CloseHandle(ac3file3);CloseHandle(ac3file4);
							fclose(file);
							exit(1);
						}
						break;
			case 1:
						if ( WriteFile(ac3file2,audiobuffer,ac3buffsize,&dwRead,NULL) == 0) {
							printf("\nerror: can't write to %s \n",ac3file2);
							CloseHandle(ac3file1);CloseHandle(ac3file2);CloseHandle(ac3file3);CloseHandle(ac3file4);
							fclose(file);
							exit(1);
						}
						break;
			case 2:
						if ( WriteFile(ac3file3,audiobuffer,ac3buffsize,&dwRead,NULL) == 0) {
							printf("\nerror: can't write to %s \n",ac3file2);
							CloseHandle(ac3file1);CloseHandle(ac3file2);CloseHandle(ac3file3);CloseHandle(ac3file4);							fclose(file);
							exit(1);
						}
						break;
			case 3:
						if ( WriteFile(ac3file4,audiobuffer,ac3buffsize,&dwRead,NULL) == 0) {
							printf("\nerror: can't write to %s \n",ac3file2);
							CloseHandle(ac3file1);CloseHandle(ac3file2);CloseHandle(ac3file3);CloseHandle(ac3file4);
							fclose(file);
							exit(1);
						}
					}

				}
			}
		}
	}
      printf("\ndone.");
	CloseHandle(ac3file1);CloseHandle(ac3file2);CloseHandle(ac3file3);CloseHandle(ac3file4);
	fclose(file);
}

// forward search is about 3 times faster than backwards(why?), so I won't dump this function
void search_cell_ids (char *filename) {
	int buffer,i,j,cell_id,loop,correct,last_cell=0,first_cell=0,search_cell;
	unsigned char fbuffer[6];
        long lbajump,filepos,curr_pos,cell_size,last_lba;
	unsigned char fstreamfind[6]={0x00,0x00,0x01,0xBF,0x03,0xD4};
	FILE *file;
	double filesize;
	DWORD  dwRead;
	double free;
	HANDLE input_file;
// function could be optimized, but runs at ok speed, now
	input_file = CreateFile(filename,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
 	filesize = GetFileSize(input_file,NULL);
	CloseHandle (input_file);
//search for first and last cell-id first for fast abort+loop input
	check_valid_id (filename,&first_cell,&last_cell);
	if((file = fopen(filename, "rb")) == 0) {
		printf("\nerror: can't open file '%s'\n", filename);
		exit(1);
	}
//now search fully
	fseek(file,0,SEEK_SET);
	search_cell = first_cell+1;
	curr_pos=0;
	for (loop=first_cell;loop<last_cell;loop++) {
		cell_id = 0;
		while (cell_id == 0 ) {
			j++;
			if ((j % 100) == 0) {
				j=0;
				if (quit_check() == 1) { 
					fclose(file);
					exit (1);
				}
			}
			fseek(file,38,SEEK_CUR);
//get filepointerpos
			if(fread(fbuffer, 1, sizeof fstreamfind, file) != sizeof fstreamfind) {
				printf("\nerror reading LBA from file ");
                                fclose(file);
				exit(1);
			}
			correct = 1;
			for (i=0;i<6;i++) {
				if ( fbuffer[i] != fstreamfind[i] ) {
					correct = 0;
				}
			}
			if ( correct == 1 ) {
				fseek(file,1014,SEEK_CUR);
				buffer = fgetc(file);
				if ( buffer < search_cell && filesize-curr_pos>2000 ) {
// jump 2000 lba could be optimized according to filesize/cell_id number
					fseek(file,4094941,SEEK_CUR);
					curr_pos += 2000;
//                               	last_lba=curr_pos;
				} else {
//search each LBA backwards now - part could be optimized
					fseek(file,-1059,SEEK_CUR);
					last_lba=curr_pos;
					while (cell_id == 0) {
						fseek(file,38,SEEK_CUR);
						if(fread(fbuffer, 1, sizeof fstreamfind, file) != sizeof fstreamfind) {
						printf("\nerror reading LBA from file ");
                                                fclose(file);
						exit(1);
						}
						correct = 1;
						for (i=0;i<6;i++) {
							if ( fbuffer[i] != fstreamfind[i] ) {
								correct = 0;
							}
						}
						if ( correct == 1 ) {
							fseek(file,1014,SEEK_CUR);
							buffer = fgetc(file);
							if (buffer == search_cell-1) {
								printf("\nCELL-ID %3i found at LBA #%li ",buffer+1,last_lba);
								cell_id=buffer+1;
								search_cell++;
								fseek(file,-1059,SEEK_CUR);
								break;//exit loop+search next
							} else {
								fseek(file,-1015,SEEK_CUR);
								last_lba=curr_pos;
							}
						}
//jump to previous lba
						fseek(file,-2092,SEEK_CUR);
						curr_pos --;
					}
				}
			} else {
				fseek(file,2004,SEEK_CUR);
				curr_pos++;
			}
		}
	}
        printf("\ndone.");
	fclose(file);
}

void search_back_cell_ids (char *filename, char *outfilename) {
	int buffer,i,j,cell_id,loop,correct,last_cell=0,first_cell=0,search_cell,fpos;
	long lbajump,filepos,curr_pos,cell_size,strip_lba,lbasize;
	unsigned char fstreamfind[6]={0x00,0x00,0x01,0xBF,0x03,0xD4};
	unsigned char fbuffer[6];
	FILE *file;
	double	filesize;
	DWORD  dwRead;
	HANDLE input_file;

	input_file = CreateFile(filename,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
 	filesize = GetFileSize(input_file,NULL); //in LBA
	CloseHandle (input_file);
	lbasize=filesize/2048;
	check_valid_id (filename,&first_cell,&last_cell);
	if((file = fopen(filename, "rb")) == 0) {
		printf("\nerror: can't open file '%s'\n", filename);
		exit(1);
	}
	fseek(file,-2048,SEEK_END);
	search_cell = last_cell;
	curr_pos=lbasize-1;
	for (loop=first_cell;loop<last_cell;loop++) {
		cell_id = 0;
		while (cell_id == 0 ) {
			j++;
			if ((j % 100) == 0) {
				j=0;
				if (quit_check() == 1) {
					fclose(file);
					exit (1);
				}
			}
			fseek(file,38,SEEK_CUR);
			if(fread(fbuffer, 1, sizeof fstreamfind, file) != sizeof fstreamfind) {
				printf("\error reading LBA for streaminfo");
			}
			correct = 1;
			for (i=0;i<6;i++) {
				if ( fbuffer[i] != fstreamfind[i] ) {
					correct = 0;
				}
			}
//interresting part
			if ( correct == 1 ) {
				fseek(file,1014,SEEK_CUR);
				buffer = fgetc(file);
				if (buffer > search_cell-1 && curr_pos>2000 ) {
// jump 2000 lba could be optimized according to filesize/cell_id number
					fseek(file,-4097059,SEEK_CUR);
					curr_pos -= 2000;
				} else {
//search each LBA forward now - part could be optimized
					fseek(file,-1059,SEEK_CUR);
					while (cell_id == 0) {
						fseek(file,38,SEEK_CUR);
						if(fread(fbuffer, 1, sizeof fstreamfind, file) != sizeof fstreamfind) {
							printf("\error reading LBA for streaminfo");
						}
						correct = 1;
						for (i=0;i<6;i++) {
						if ( fbuffer[i] != fstreamfind[i] ) {
							correct = 0;
							}
						}
						if ( correct == 1 ) {
							fseek(file,1014,SEEK_CUR);
							buffer = fgetc(file);
							if (buffer == search_cell) {
								printf("\nCELL-ID %3i found at LBA #%li ",buffer,curr_pos);
								strip_lba= curr_pos;
								cell_id=buffer+1;
								search_cell--;
								fseek(file,989,SEEK_CUR);
								curr_pos++;
								break;//exit loop+search next
							} else {
								fseek(file,-1015,SEEK_CUR);
							}
//jump to next lba
                                                }
						fseek(file,2004,SEEK_CUR);
						curr_pos ++;
					}
				}
			} else {
				fseek(file,-2092,SEEK_CUR);
				curr_pos--;
			}
		}
		printf("\n\n(d)ump cell-id %i LBA %li to file %s?",search_cell+1,strip_lba,outfilename);
		printf("\n(c)ontinue search\n...any other key will abort");
		i=getch();
		if (i=='d' || i=='D') {
			fclose(file);
			strip_file(strip_lba,filename,outfilename);
			exit(1);
		} else {
                	if (i != 'c' && i != 'C') {
        	               exit(1);
                	}
			printf("\n\ncontinuing search...\n");
        	}
	}
	printf("\ndone.");
	fclose(file);
}

void _authenticateDVD(int drive,int *drive_id) {
	int i,j;
	char authstring[80];
	DWORD dwVersion;
	FILE *_tmpfile;
	dwVersion = GetVersion();
	printf("\rAuthentication of DVD drive ...");
//---	_checkWinversion;
	if (searchpath("dodsrip.exe") == NULL) {
		printf("\n\nerror: can't open dodsrip.exe");
		printf("\nMake sure dodsrip.exe is in same directory as vobdec.exe\n");
		exit(1);
	}
	if (  dwVersion < 0x80000000 && drive_id[0] == 1000 ) { 
		for (i='0';i<'5';i++) {
			for (j='0';j<'5';j++) {
				sprintf(authstring,"dodsrip /h %c /t %c /l %c g 0 1 _tmp.vob >NUL",i,j,drive_id[2]);
				remove("_tmp.vob");
				system(authstring);
				if ((_tmpfile=fopen("_tmp.vob","rb")) != NULL) {
					printf("\tDVD successfully authenticated");
					printf("\nuse '-a%c%c' for next authentication run \n\n",i,j);
					fclose(_tmpfile);
					remove("_tmp.vob");
					return;
				}
			}
		}
		printf("\n\n error: could not authenticate DVD drive !!! ");
		printf("\n\n start DVD with a DVD-player to do this, or:");
		printf("\n\n see ctrl pan->system->device man->open cdrom->properties->settings");
		printf("\n enter HOST-ID as first value, Target-ID as second value");
		printf("\n e.g. 'vobdec -a01' for Host:0, Target-ID:1\n");
		exit(1);
	}
	if (drive_id[0] == 1000 )   {
		sprintf(authstring,"dodsrip /d %c g 0 1 _tmp.vob >NUL",drive);
		remove("_tmp.vob");
		system(authstring);
		if ((_tmpfile=fopen("_tmp.vob","rb")) != NULL) {
			fclose(_tmpfile);
			remove("_tmp.vob");
			printf("\t DVD successfully authenticated               \n");
		} else {
			printf("\n\nerror: DVD authentication failed               ");
			printf("\n\n try using a DVD player to do this              \n");
			exit(1);
		}
	} else {
		sprintf(authstring,"dodsrip /h %c /t %c /l %c g 0 1 _tmp.vob >NUL",drive_id[0],drive_id[1],drive_id[2]);
		system(authstring);
		if ((_tmpfile=fopen("_tmp.vob","rb")) == NULL) {
			printf("\n\n error: use different values to authenticate DVD!!! ");
			printf("\n\n see ctrl pan->system->device man->open cdrom->properties->settings");
			printf("\n enter HOST-ID as first value, Target-ID as second value\n");
			printf("\n or try 'vobdec -a' to auto detect IDs\n");
			exit (1);
		} else {
			printf("\t DVD successfully authenticated  		");
			fclose(_tmpfile);
			remove("_tmp.vob");
		}
	}
}

int _loopkeysearch(char *filename,int &lfsr0,int &lfsr1) {
	int i, loop=0;
	int _dummy[3]={1000,'0','0'};
	char authstring[80];
	printf("\n'Q': Quit, 'N': scan Next vobfile, 'S': Skip key scan (undecrypted DVDs only)\n\n");

	while (fopen(filename,"rb") != 0) {
		i=(_FindKey(filename,lfsr0, lfsr1));
		if (i==0) {
			return 0;
		}
		if ( i==3 && loop<1 ) {
			printf("\n");
			_authenticateDVD(filename[0], _dummy);
			printf("\n");
			i=(_FindKey(filename,lfsr0, lfsr1));
			if (i==0) {
				return 0;
			}
		}
		loop++;
		filename[strlen(filename)-5]++;
	}
	if (loop==0) {
		printf("\nerror: could not find file %s on DVD", filename);
	} else {
		printf("\nerror: could not retrieve any key, DVD seems to be not encrypted");
	}
	return 1;
}


int main(int argc, char **argv)
{
	unsigned char	key[5], dummy;
	int	loop0, loop1, value, lfsr0, lfsr1, option=0,i,j,skip_vobid=0,region_flag,keyflag=0,vob_flag=1,auth_flag=0;
	char 	filename[40] = "x:\\video_ts\\vts_01_1.vob", ac3name[40];
	int   ac3rip[8]={0,0,0,0,0,0,0,0};
	int   DVD_info[3]={1000,'0','0'};
	char	drive[3] = "x";
 	char	part1[20] = ":\\video_ts\\vts_01_";
 	char	part2[3] ="1";
 	char	part3[12] = ".vob";
	char  authstring[80];
	unsigned char  char2hex[3]="\0";
	char 	outfile[80]="x.vob";
	double byte_number;
	FILE *file;
	clrscr();
	printf("\nVobDec+ 0.311 - VOB Decryption Utility\t\t('Q' to Quit)\n");
	for(loop0 = 0; loop0 != 0x100; loop0++) {
		for(loop1 = value = 0; loop1 != 8; loop1++) {
			value |= ((loop0 >> loop1) & 0x01) << (7 - loop1);
		}
		_reverse[loop0] = (unsigned char) value;
	}
	if (argc == 1) {
	info ();
	exit (1);
	}
	if ( (argc == 2) && ((strcmp(argv[1],"info")==0) || (strcmp(argv[1],"INFO")==0) )) {
		for(loop0 = 99; loop0 < 123; loop0++) {
			drive[0]=loop0;
			def_name(filename,drive,":\\","","");
			if(GetDriveType(filename)==DRIVE_CDROM) {
				def_name(filename,drive,part1,part2,part3);
			     	if ((fopen(filename,"rb")) != 0) {
					printf ("\nfound DVD on drive %c:\n",drive[0]);
					region_flag = (region_free_check(drive,filename));
				}
			}
		}
		exit(1);
	}
	for (loop1=1;loop1<argc;loop1++) {
		if ( (strcmp(argv[loop1],"-0")==0) ) {
			vob_flag=0;
			for (loop0=loop1;loop0<argc-1;loop0++) {
				argv[loop0] = argv[loop0+1];
			}
			argc--;			
			loop1=1;
		}
		if ( (strcmp(argv[loop1],"key")==0 || strcmp(argv[loop1],"KEY")==0) && (argc>loop1+1) ) {
			if (strlen(argv[loop1+1])==10 ) { 
     	   		 	printf("\nusing ");
			 	for(loop0 = 0; loop0 < 5; loop0++) {
					char2hex[0]=argv[loop1+1] [loop0*2];
     			      	char2hex[1]= argv[loop1+1] [loop0*2+1];
					if(sscanf(char2hex, "%X%c", &value, &dummy) != 1) {
						printf("error: can't parse '%s' as a hex key byte\n",char2hex);
						exit(1);
					}
					key[loop0] = (unsigned char) value;
     				      printf("%x",key[loop0]);
				}
				keyflag=1;
				_Salt(lfsr0 = 0x100, lfsr1 = 0x200000, key);
				printf(" as key now\n");
				for (loop0=loop1;loop0<argc-2;loop0++) {
					argv[loop0] = argv[loop0+2];
				}
				argc -=2;
				loop1=1;
			} else {
				printf("\nkey must have length of 10 decimals, your key had %i decimals\n", (strlen(argv[loop1+1])));
				exit (1);
			}
		}
		if ( (strcmp(argv[loop1],"-ac3")==0) ||(strcmp(argv[loop1],"-AC3")==0) || (strcmp(argv[loop1],"+ac3")==0) ||(strcmp(argv[loop1],"+AC3")==0) ) {
			if ( (strcmp(argv[loop1],"+ac3")==0) ||(strcmp(argv[loop1],"+AC3")==0) ) {
				option=1;
			}
			for (i=loop1;i<argc-1;i++) {
				if (i-loop1>3) {
					printf("\nonly up to 4 audio streams allowed");
					exit(1);
				}
				ac3rip[i-loop1]=atoi(argv[i+1]);
				if (ac3rip[i-loop1]<80 || ac3rip[i-loop1]>88) {
					break;
				}
				sprintf(ac3name,"audio_%i.ac3",ac3rip[i-loop1]);
				if((file=fopen(ac3name, "rb")) != 0) { 
        				printf("\n'%s' already exists:\ntype 'd' to delete file, any other key to append to this ac3 file\n", ac3name);
					j = getch();
					if ( j == 'd' || j == 'D' ) {
						fclose(file);
						remove(ac3name);
					}
				}
			}
			if (ac3rip[0]<80 || ac3rip[0]>88) {
				printf("\nwrong entry for ac3stream");
				exit(1);
			}
			for (loop0=loop1;loop0<argc-i+loop1-1;loop0++) {
				argv[loop0] = argv[loop0+i-loop1+1];
			}
			argc-=i-loop1+1;
			loop1=1;
		}
		if ( argv[loop1] [0] =='-' && argv[loop1] [1] =='a' && (strlen(argv[loop1])<6) ) {
			i=strlen(argv[loop1])-2;
			for (loop0=0;loop0<i;loop0++) {
				DVD_info[loop0]= (argv[loop1] [loop0+2]);
			}
			auth_flag=1;
			for (loop0=loop1;loop0<argc-1;loop0++) {
				argv[loop0]=argv[loop0+1];
			}
			argc--;
			loop1=1;
		}
		if  (( argv[loop1] [0] =='v' && argv[loop1] [1] =='t' && argv[loop1] [2] =='s') && (strlen(argv[loop1])<6) ) {
			if (strlen(argv[loop1])==4) {
				filename[17]=argv[loop1] [3];
				part1[16]=argv[loop1] [3];
			} else {
				if (strlen(argv[loop1])==5) {
					filename[17]=argv[loop1] [4];
					part1[16]=argv[loop1] [4];
					filename[16]=argv[loop1] [3];
					part1[15]=argv[loop1] [3];
				} else {
					printf("\n wrong vts entry...\n");
					exit(1);
				}
			}
			for (loop0=loop1;loop0<argc-1;loop0++) {
				argv[loop0]=argv[loop0+1];
			}
			argc--;
			loop1=1;
		}
	}
	if ( (strcmp(argv[1],"demacro")==0) || (strcmp(argv[1],"DEMACRO")==0) ) {
		if (argc == 3) {
			disable_macrovision(argv[2]);
		} else {
			printf("\nerror: Macrovision patch failed\n");
			printf("\nwrong parameters entered: run 'vobdec' to get commands info");
		}
		exit(1);
	}
	if ( (strcmp(argv[1],"regionfree")==0) || (strcmp(argv[1],"REGIONFREE")==0) ) {
		if (argc == 2) {
			patch_region();
		} else {
			printf("\nerror: Regionfree patch failed\n");
			printf("\nwrong parameters entered: run 'vobdec' to get commands info");
		}
			exit(1);
	}
	if ( (argc == 3) &&((strcmp(argv[1],"ac3")==0) || (strcmp(argv[1],"AC3")==0) )) {
		audio_info(argv[2]);
		exit(1);
	}
	if ( (argc > 4) && (argc < 9) && ((strcmp(argv[1],"ac3")==0) || (strcmp(argv[1],"AC3")==0) )) {
		for (i=4;i<argc;i++) {
			ac3rip[i-4]=atoi(argv[i]);
			if( ac3rip[i-4]<80 || ac3rip[i-4]>89) {
				printf("\nwrong audio paratmeter entered");
				exit(1);
			}
		}
		scan_foraudio (argv[2],argv[3],ac3rip);
		exit(1);
	}
	if ( (argc == 4 ) && ((strcmp(argv[1],"trunc")==0) || (strcmp(argv[1],"TRUNC")==0)) ) {
		byte_number=atof(argv[2]);
		if (byte_number ==0) {
			info();
			exit(1);
		}
		byte_number *=2048;
		truncate_file(byte_number,argv[3]);
		exit(1);
	}
	if ( (strcmp(argv[1],"trunc")==0) || (strcmp(argv[1],"TRUNC")==0) ) {
		if (argc == 5 && (strcmp(argv[2],"-b")==0)) {
			byte_number=atof(argv[3]);
			if (byte_number==0) {
				info();
				exit(1);
			}
			truncate_file(byte_number,argv[4]);
		} else {
			printf("\nerror: file truncation failed\n");
			printf("\nwrong parameters entered: run 'vobdec' to get commands info");
		}
		exit(1);
	}
	if ( (argc > 3) && ((strcmp(argv[1],"merge")==0) || (strcmp(argv[1],"MERGE")==0)) ) {
		for (loop0=2;loop0<argc-1;loop0++) {
			append_file (argv[loop0],argv[argc-1]);
		}
		exit(1);
	}
	if ( (argc == 3) && ((strcmp(argv[1],"lba")==0) || (strcmp(argv[1],"LBA")==0) )) {
		search_cell_ids(argv[2]);
		exit(1);
	}
	if (  (strcmp(argv[1],"lba")==0) || (strcmp(argv[1],"LBA")==0) ) {
		if (argc == 4) {
			search_back_cell_ids(argv[2],argv[3]);
		} else {
			printf("\nerror: Cell-ID detection failed\n");
			printf("\nwrong parameters entered: run 'vobdec' to get commands info");
		}
		exit(1);
	}
	if ( (strcmp(argv[1],"strip")==0) || (strcmp(argv[1],"STRIP")==0) ) {
		if (argc == 5) {
			i = atoi(argv[2]);
			if (i == 0) {
				info();
				exit(1);
			}
			strip_file(i,argv[3],argv[4]);
		} else {
			printf("\nerror: File stripping failed\n");
			printf("\nwrong parameters entered: run 'vobdec' to get commands info");
		}
		exit(1);
	}
	i = atoi(argv[1]);
	if ( (strcmp(argv[1],"X") != 0) && (strcmp(argv[1],"x") != 0) && (strcmp(argv[1],"s") != 0) && (strcmp(argv[1],"S") != 0) && (i == 0 ) && (argv[1] [0] != '0') && (argc!=1) ) {
	switch(argc) {
		case 8:
			for(loop0 = 0; loop0 != 5; loop0++) {
				if(sscanf(argv[loop0 + 3], "%X%c", &value, &dummy) != 1) {
					printf("error: can't parse '%s' as a hex key byte\n", argv[loop0 + 3]);
					return 1;
				}
				key[loop0] = (unsigned char) value;
			}
			_Salt(lfsr0 = 0x100, lfsr1 = 0x200000, key);
		case 3:
		case 2:
			break;
		default:
			info();
			return 1;
	}
	if (auth_flag==1) {
		printf("\n");
		_authenticateDVD(argv[1] [0],DVD_info);
	}
	if(argc != 8  && keyflag==0 && _loopkeysearch(argv[1], lfsr0, lfsr1)) {
		return 1;
	}
	_PrintKey(lfsr0, lfsr1);
	if(argc != 2 && _DecryptFile(argv[1], argv[2], lfsr0, lfsr1, option, vob_flag, ac3rip,skip_vobid)) {
		return 1;
	}
	return 0;
	} else {
	if ( i > 99 )	{
		info();
		exit (1);
	}
	loop1 = 1;
	for(loop0 = 99; loop0 < 123; loop0++) {
		drive[0]=loop0;
		def_name(filename,drive,":\\","","");
		if(GetDriveType(filename)==DRIVE_CDROM) {
 		  	def_name(filename,drive,part1,part2,part3);
		      if ((fopen(filename,"rb")) != 0) {
				loop0 = 1000;
				if (auth_flag==1) {
					printf("\n");
					_authenticateDVD(filename[0],DVD_info);
					if (argc==1) exit(1);
				}
				printf ("\nfound DVD on drive %c:\n",drive[0]);
				region_flag = (region_free_check(drive,filename));
				if (keyflag==1) 
					break;
				if (region_flag == 0) {
					printf("\nDVD most likely not encrypted");
					printf("\n press 's' to skip key search, any other key will start key search now");
					region_flag = getch();
				}
				if ( region_flag != 'S' && region_flag != 's' ) {
					printf ("\nretrieving key...\n");
					if( _loopkeysearch(filename,lfsr0, lfsr1)) return 1;
					_PrintKey(lfsr0, lfsr1);
				}
			   	break;
			}
		}

	}
	if (loop0 != 1000) {
		printf("\ncouldn't find a DVD/file - make sure disk is accessible\n\n");
		exit(1);
      }
	if ( i > 0 || argv[1] [0] == '0') {
// encode files from file_x to file_y counting up
		if (argc == 4 || argc == 3 || argc == 2) {
				if (argc == 2) {
					j = i;
				} else {
					j = atoi(argv[2]);
				}
				if (j < i) { 
					printf("\nwrong input parameter");
					exit (1);
				}
				for (loop0=i;loop0<=j;loop0++) {
					itoa(loop0,part2,10);
					def_name(filename,drive,part1,part2,part3);
					if ( argv [argc-1] [0] == 'x' || argv [argc-1] [0] == 'X')  {					
						def_name(outfile,"","","x",".vob");
						if (loop0-i > 0) option = 2;
					} else {
						for (loop1=0;loop1<12;loop1++) {
							outfile[loop1]=filename[loop1+12];
						}
					}
					if ( region_flag != 1 ) {
						printf ("\ncopying file %s ---> %s\n",filename,outfile);				
					} else {
						printf ("\ndecrypting file %s ---> %s\n",filename,outfile);
					}
					if ( _DecryptFile(filename, outfile, lfsr0, lfsr1, option,vob_flag,ac3rip,skip_vobid)) return 1;
				}
				exit(1);
		}
	}
	if (  argv[1] [0] == 'x' || argv[1] [0] == 'X' || argv[1] [0] == 's' || argv[1] [0] == 'S') {
		filename[strlen(filename)-5] = '1';
		do {  
			if ( argv[1] [0] == 's' || argv[1] [0] == 'S') {
				for (loop0=0;loop0<12;loop0++) {
					outfile[loop0]=filename[loop0+12];
				}			}
			if ( ( argv[1] [0] == 'x' || argv[1] [0] == 'X' ) && (loop1 > 1) ) {
				option = 2;
			}
			if ( region_flag != 1 ) {
				printf ("\ncopying file %s ---> %s\n",filename,outfile);				
			} else {
				printf ("\ndecrypting file %s ---> %s\n",filename,outfile);
			}
			if ( _DecryptFile(filename, outfile, lfsr0, lfsr1, option,vob_flag,ac3rip,skip_vobid)) return 1;
				loop1++;
				itoa(loop1,part2,10);
				def_name(filename,drive,part1,part2,part3);
		} while ((fopen(filename,"rb")) != 0);
		exit (1);
	}
	}
	printf("\nwrong input parameter");
	exit (1);
}

