/*
 * $RCSfile: lib_cdinfo.cpp,v $
 * $Author: swaj $
 * $Revision: 1.4 $
 */

/*
 * This code is from cdinfo and has the following copyrights:
 * (c) 1996,1997  Gerd Knorr <kraxel@cs.tu-berlin.de>
 * and Heiko Eissfeldt <heiko@colossus.escape.de>
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <stdlib.h>

#include <linux/cdrom.h>

#include "defines.h"
#include "debugging.h"
#include "lib_time.h"
#include "lib_cdinfo.h"
#include "lib_main.h"

static 
void cannibalize_buffer (char *buff)
{
	int len = strlen(buff);

	if (!len)
		return;

	int i;
	for (i=len-1; i>0; i--)
	{
		switch (buff[i]) {
		case 0x20:
			buff[i] = 0x0;
			break;
		default:
			return;
		}
	}
}

void Ccdrom::read_creation_data (void)
{
	memset (buffer6, 0, 2048);
	memset (sbuffer, 0, 256);
	memset (sbuffer2, 0, 256);
	memset (sbuffer3, 0, 256);

	lseek (fd, 2048*16, SEEK_SET);
	read (fd, buffer6, 2048);

	memcpy (sbuffer,  buffer6 + PUBLISHER_OFFSET, PUBLISHER_LEN);
	memcpy (sbuffer2, buffer6 + PREPARER_OFFSET , PREPARER_LEN);
	memcpy (sbuffer3, buffer6 + SOFTWARE_OFFSET, SOFTWARE_LEN);

	cannibalize_buffer (sbuffer);
	cannibalize_buffer (sbuffer2);
	cannibalize_buffer (sbuffer3);
}

void Ccdrom::read_super(int offset)
{
    /* sector 16, super block */
    memset(buffer,0,2048);
    lseek(fd,2048*(offset+16),SEEK_SET);
    read(fd,buffer,2048);
}

void Ccdrom::read_super2(int offset)
{
    /* sector 0, for photocd check */
    memset(buffer2,0,2048);
    lseek(fd,2048*offset,SEEK_SET);
    read(fd,buffer2,2048);
}

void Ccdrom::read_super3(int offset)
{
    /* sector 4, for ufs check */
    memset(buffer3,0,2048);
    lseek(fd,2048*(offset+4),SEEK_SET);
    read(fd,buffer3,2048);
}

void Ccdrom::read_super4(int offset)
{
    /* sector 17, for bootable CD check */
    memset(buffer4,0,2048);
    lseek(fd,2048*(offset+17),SEEK_SET);
    read(fd,buffer4,2048);
    read_creation_data();
}

void Ccdrom::read_super5(int offset)
{
    /* sector 150, for Video CD check */
    memset(buffer5,0,2048);
    lseek(fd,2048*(offset+150),SEEK_SET);
    read(fd,buffer5,2048);
}

int Ccdrom::is_isofs(void)
{
    return 0 == strncmp(&buffer[1],"CD001",5);
}

int Ccdrom::is_hs(void)
{
    return 0 == strncmp(&buffer[9],"CDROM",5);
}

int Ccdrom::is_cdi(void)
{
    return (0 == strncmp(&buffer[1],"CD-I",4));
}

int Ccdrom::is_cd_rtos(void)
{
    return (0 == strncmp(&buffer[8],"CD-RTOS",7));
}

int Ccdrom::is_bridge(void)
{
    return (0 == strncmp(&buffer[16],"CD-BRIDGE",9));
}

int Ccdrom::is_xa(void)
{
    return 0 == strncmp(&buffer[1024],"CD-XA001",8);
}

int Ccdrom::is_cdtv(void)
{
    return (0 == strncmp(&buffer[8],"CDTV",4));
}

int Ccdrom::is_photocd(void)
{
    return 0 == strncmp(&buffer2[64], "PPPPHHHHOOOOTTTTOOOO____CCCCDDDD", 24);
}

int Ccdrom::is_hfs(void)
{
    return (0 == strncmp(&buffer2[512],"PM",2)) ||
           (0 == strncmp(&buffer2[512],"TS",2)) ||
	   (0 == strncmp(&buffer2[1024], "BD",2));
}

int Ccdrom::is_ext2(void)
{
    return 0 == strncmp(&buffer2[0x438],"\x53\xef",2);
}

int Ccdrom::is_ufs(void)
{
    return 0 == strncmp(&buffer3[1372],"\x54\x19\x01\x0" ,4);
}

int Ccdrom::is_bootable(void)
{
    return 0 == strncmp(&buffer4[7],"EL TORITO",9);
}

int Ccdrom::is_video_cdi(void)
{
    return 0 == strncmp(&buffer5[0],"VIDEO_CD",8);
}

int Ccdrom::get_size(void)		/* iso9660 volume space in 2048 byte units */
{
    return ((buffer[80] & 0xff) |
	    ((buffer[81] & 0xff) << 8) |
	    ((buffer[82] & 0xff) << 16) |
	    ((buffer[83] & 0xff) << 24));
}

int Ccdrom::guess_filesystem(int start_session)
{
    int ret = 0;

    read_super(start_session);

#undef _DEBUG
#ifdef _DEBUG
    /* buffer is defined */
    if (is_cdi())     printf("CD-I, ");
    if (is_cd_rtos()) printf("CD-RTOS, ");
    if (is_isofs())   printf("ISOFS, ");
    if (is_hs())      printf("HS, ");
    if (is_bridge())  printf("BRIDGE, ");
    if (is_xa())      printf("XA, ");
    if (is_cdtv())    printf("CDTV, ");
    puts("");
#endif

    /* filesystem */
    if (is_cdi() && is_cd_rtos() && !is_bridge() && !is_xa()) {
        return FS_INTERACTIVE;
    } else {	/* read sector 0 ONLY, when NO greenbook CD-I !!!! */

        read_super2(start_session);

#ifdef _DEBUG
	/* buffer2 is defined */
	if (is_photocd()) printf("PHOTO CD, ");
	if (is_hfs()) printf("HFS, ");
	if (is_ext2()) printf("EXT2 FS, ");
	puts("");
#endif
        if (is_hs())
	    ret |= FS_HIGH_SIERRA;
	else if (is_isofs()) {
	    if (is_cd_rtos() && is_bridge())
	        ret = FS_ISO_9660_INTERACTIVE;
	    else if (is_hfs())
	        ret = FS_ISO_HFS;
	    else
	        ret = FS_ISO_9660;
	    isofs_size = get_size();

	    read_super4(start_session);

#ifdef _DEBUG
	    /* buffer4 is defined */
	    if (is_bootable()) printf("BOOTABLE, ");
	    puts("");
#endif
	    if (is_bootable())
		ret |= BOOTABLE;

	    if (is_bridge() && is_xa() && is_isofs() && is_cd_rtos()) {
	        read_super5(start_session);

#ifdef _DEBUG
		/* buffer5 is defined */
		if (is_video_cdi()) printf("VIDEO-CDI, ");
		puts("");
#endif
		if (is_video_cdi())
		    ret |= VIDEOCDI;
	    }
	} else if (is_hfs())
	    ret |= FS_HFS;
	else if (is_ext2())
	    ret |= FS_EXT2;
	else {

	    read_super3(start_session);

#ifdef _DEBUG
	    /* buffer3 is defined */
	    if (is_ufs()) printf("UFS, ");
	    puts("");
#endif
	    if (is_ufs())
	        ret |= FS_UFS;
	    else
	        ret |= FS_UNKNOWN;
	}
    }
    /* other checks */
    if (is_xa())
        ret |= XA;
    if (is_photocd())
	ret |= PHOTO_CD;
    if (is_cdtv())
	ret |= CDTV;
    return ret;
}



/*
 * __END__
 */






