// Typen zur Info der Struktur, aus dvdbackup
typedef struct
{
  int size_ifo;
  int size_menu;
  int size_bup;
  int number_of_vob_files;
  int size_vob[10];
} title_set_t;

typedef struct
{
  int number_of_title_sets;
  title_set_t *title_set;
} title_set_info_t;


typedef struct
{
  int title;
  int title_set;
  int vts_title;
  int chapters;
  int aspect_ratio;
  int angles;
  int audio_tracks;
  int audio_channels;
  int sub_pictures;
} titles_t;

typedef struct
{
  int main_title_set;
  int number_of_titles;
  titles_t *titles;
} titles_info_t;

typedef struct _dvdstruktur
{
  long titelSet, titel, audioTracks, untertitelTracks;
  char szAudio[256];
  char szUntertitel[256];
  char szVideoAngaben[128];
  char szVideoDVDWizard[128];
  char szTitelVideo[128];
  AudioMap_t audioMap;
  SubMap_t   subMap;
} dvdstruktur;
dvdstruktur dvdStruktur[200];

/*
   Simple helper macros for generating Perl structures
*/
static int _lvl = 0;
static int _lvl_type[256];
#define INDENT  { int i; for(i=0; i<_lvl; i++) printf("  "); }
#define DEF(name, x...) {               \
 INDENT;                                \
 printf("%s => ", name);                \
 printf(x); printf(",\n");              \
}
#define HASH(name) {                                      \
 INDENT;                                                        \
 (name ?       \
   printf((_lvl ? "%s => {\n" : "our %%%s = (\n"), name) : \
   printf("{\n"));      \
 _lvl++; _lvl_type[_lvl] = 0;                                   \
}
#define ARRAY(name) {     \
 INDENT;      \
 printf(_lvl ? "%s => [\n" : "our @%s = (\n", name); \
 _lvl_type[_lvl] = 1; _lvl++;    \
}
#define RETURN  { _lvl--; INDENT;     \
 opt_p ? printf("%s\n",       \
    _lvl ?   (_lvl_type[_lvl] ? "]," : "},") : ");") : _lvl++;  \
}
#define START {  \
  HASH("lsdvd"); \
}
#define STOP {  \
  while(_lvl) RETURN; \
}

static struct
{
  char code[3];
  char name[20];
}
language[] =
{
  {
  "  ", "Not Specified"},
  {
  "aa", "Afar"},
  {
  "ab", "Abkhazian"},
  {
  "af", "Afrikaans"},
  {
  "am", "Amharic"},
  {
  "ar", "Arabic"},
  {
  "as", "Assamese"},
  {
  "ay", "Aymara"},
  {
  "az", "Azerbaijani"},
  {
  "ba", "Bashkir"},
  {
  "be", "Byelorussian"},
  {
  "bg", "Bulgarian"},
  {
  "bh", "Bihari"},
  {
  "bi", "Bislama"},
  {
  "bn", "Bengali; Bangla"},
  {
  "bo", "Tibetan"},
  {
  "br", "Breton"},
  {
  "ca", "Catalan"},
  {
  "co", "Corsican"},
  {
  "cs", "Czech"},
  {
  "cy", "Welsh"},
  {
  "da", "Dansk"},
  {
  "de", "Deutsch"},
  {
  "dz", "Bhutani"},
  {
  "el", "Greek"},
  {
  "en", "English"},
  {
  "eo", "Esperanto"},
  {
  "es", "Espanol"},
  {
  "et", "Estonian"},
  {
  "eu", "Basque"},
  {
  "fa", "Persian"},
  {
  "fi", "Suomi"},
  {
  "fj", "Fiji"},
  {
  "fo", "Faroese"},
  {
  "fr", "Francais"},
  {
  "fy", "Frisian"},
  {
  "ga", "Gaelic"},
  {
  "gd", "Scots Gaelic"},
  {
  "gl", "Galician"},
  {
  "gn", "Guarani"},
  {
  "gu", "Gujarati"},
  {
  "ha", "Hausa"},
  {
  "he", "Hebrew"},
  {
  "hi", "Hindi"},
  {
  "hr", "Hrvatski"},
  {
  "hu", "Magyar"},
  {
  "hy", "Armenian"},
  {
  "ia", "Interlingua"},
  {
  "id", "Indonesian"},
  {
  "ie", "Interlingue"},
  {
  "ik", "Inupiak"},
  {
  "in", "Indonesian"},
  {
  "is", "Islenska"},
  {
  "it", "Italiano"},
  {
  "iu", "Inuktitut"},
  {
  "iw", "Hebrew"},
  {
  "ja", "Japanese"},
  {
  "ji", "Yiddish"},
  {
  "jw", "Javanese"},
  {
  "ka", "Georgian"},
  {
  "kk", "Kazakh"},
  {
  "kl", "Greenlandic"},
  {
  "km", "Cambodian"},
  {
  "kn", "Kannada"},
  {
  "ko", "Korean"},
  {
  "ks", "Kashmiri"},
  {
  "ku", "Kurdish"},
  {
  "ky", "Kirghiz"},
  {
  "la", "Latin"},
  {
  "ln", "Lingala"},
  {
  "lo", "Laothian"},
  {
  "lt", "Lithuanian"},
  {
  "lv", "Latvian, Lettish"},
  {
  "mg", "Malagasy"},
  {
  "mi", "Maori"},
  {
  "mk", "Macedonian"},
  {
  "ml", "Malayalam"},
  {
  "mn", "Mongolian"},
  {
  "mo", "Moldavian"},
  {
  "mr", "Marathi"},
  {
  "ms", "Malay"},
  {
  "mt", "Maltese"},
  {
  "my", "Burmese"},
  {
  "na", "Nauru"},
  {
  "ne", "Nepali"},
  {
  "nl", "Nederlands"},
  {
  "no", "Norsk"},
  {
  "oc", "Occitan"},
  {
  "om", "Oromo"},
  {
  "or", "Oriya"},
  {
  "pa", "Punjabi"},
  {
  "pl", "Polish"},
  {
  "ps", "Pashto, Pushto"},
  {
  "pt", "Portugues"},
  {
  "qu", "Quechua"},
  {
  "rm", "Rhaeto-Romance"},
  {
  "rn", "Kirundi"},
  {
  "ro", "Romanian"},
  {
  "ru", "Russian"},
  {
  "rw", "Kinyarwanda"},
  {
  "sa", "Sanskrit"},
  {
  "sd", "Sindhi"},
  {
  "sg", "Sangho"},
  {
  "sh", "Serbo-Croatian"},
  {
  "si", "Sinhalese"},
  {
  "sk", "Slovak"},
  {
  "sl", "Slovenian"},
  {
  "sm", "Samoan"},
  {
  "sn", "Shona"},
  {
  "so", "Somali"},
  {
  "sq", "Albanian"},
  {
  "sr", "Serbian"},
  {
  "ss", "Siswati"},
  {
  "st", "Sesotho"},
  {
  "su", "Sundanese"},
  {
  "sv", "Svenska"},
  {
  "sw", "Swahili"},
  {
  "ta", "Tamil"},
  {
  "te", "Telugu"},
  {
  "tg", "Tajik"},
  {
  "th", "Thai"},
  {
  "ti", "Tigrinya"},
  {
  "tk", "Turkmen"},
  {
  "tl", "Tagalog"},
  {
  "tn", "Setswana"},
  {
  "to", "Tonga"},
  {
  "tr", "Turkish"},
  {
  "ts", "Tsonga"},
  {
  "tt", "Tatar"},
  {
  "tw", "Twi"},
  {
  "ug", "Uighur"},
  {
  "uk", "Ukrainian"},
  {
  "ur", "Urdu"},
  {
  "uz", "Uzbek"},
  {
  "vi", "Vietnamese"},
  {
  "vo", "Volapuk"},
  {
  "wo", "Wolof"},
  {
  "xh", "Xhosa"},
  {
  "yi", "Yiddish"},
  {
  "yo", "Yoruba"},
  {
  "za", "Zhuang"},
  {
  "zh", "Chinese"},
  {
  "zu", "Zulu"},
  {
  "xx", "Unknown"},
  {
"\0", "Unknown"}};
char *video_format[2] = { "NTSC", "PAL" };

/* 28.9.2003: Chicken run's aspect ratio is 16:9 or 1.85:1, at index
   1.  Addionaly using ' in the quoting makes the perl output not
   parse so changed to " */
char *aspect_ratio[4] = { "4/3", "16/9", "\"?:?\"", "16/9" };
char *quantization[4] = { "16bit", "20bit", "24bit", "drc" };
char *mpeg_version[2] = { "mpeg1", "mpeg2" };

/* 28.9.2003: The European chicken run title has height index 3, and
   576 lines seems right, mplayer -vop cropdetect shows from 552 to
   576 lines.  What the correct value is for index 2 is harder to say */
char *video_height[4] = { "480", "576", "???", "576" };
char *video_width[4] = { "720", "704", "352", "352" };
char *permitted_df[4] = { "P&S + Letter", "Pan&Scan", "Letterbox", "?" };
char *audio_format[7] =
  { "ac3", "?", "mpeg1", "mpeg2", "lpcm ", "sdds ", "dts" };
/* 28.9.2003: Chicken run again, it has frequency index of 1.
   According to dvd::rip the frequency is 48000 */
char *sample_freq[2] = { "48000", "48000" };
char *audio_type[5] =
  { "Undefined", "Normal", "Impaired", "Comments1", "Comments2" };
char *subp_type[16] =
  { "Undefined", "Normal", "Large", "Children", "reserved", "Normal_CC",
"Large_CC", "Children_CC",
  "reserved", "Forced", "reserved", "reserved", "reserved", "Director",
    "Large_Director", "Children_Director"
};
double frames_per_s[4] = { -1.0, 25.00, -1.0, 29.97 };

char *program_name;

// Datei oeffnen mit Warnung, wenn nicht erfolgreich
FILE * fopen_warnung (char* szFileName, char* szRechte, long lSprache);

// Input Buffer leeren
void eatToNL (FILE * inputStream);

// Eingabe einer Zahl (wird benoetigt fuer Auswahl Titel / Audiotracks
void input_zahlen (long *lZahl1, long *lZahl2, long lMaximum);

// Test, ob noch Reste vom letzten Rip im Filmverzeichnis
void checkLastRip (char *szFilmVerzeichnis, long lSprache);

// Test, ob das gewuenschte Programm vorhanden ist.
long check_program (char *szProgram, long lSprache, long lMeldung);

// Berechnet Groessen der VOB-Dateien
long long calculate_filesize (char *szVerzeichnis, char *szVideoTS, 
                              char *szVobTS, char *szVtsTS);

// Gibt die Groesse einer Datei zurueck, ohne die stat Beschraenkung auf < 2 GB
long long filesize64 (char *szFileName, char *szTmpDir);

// Berechnet freien Festplattenplatz
long long calculate_discfree (char *szPfad, long lSprache, char *szTmpDir);

// Findet Device-ID eines Verzeichnisses
dev_t device_number (char *szPfad);

// Zeit in Millisekunden umrechnen
int dvdtime2msec (dvd_time_t * dt);

// berechnet Zeit fuer Chapterunterteilung
int millisekunden (dvd_time_t * dt);

// Funktionen aus dvdbackup zur Anzeige der DVD-Struktur
int get_title_name (const char *dvd_device, char *title, long lSprache);
char * lang_name (char *code);
void DVDFreeTitleSetInfo (title_set_info_t * title_set_info);
void DVDFreeTitlesInfo (titles_info_t * titles_info);
title_set_info_t * DVDGetFileSet (dvd_reader_t * _dvd);

// dvd_wizard starten
void
dvd_wizard (char *szNiceRip, char *dvdwizard_name, char *szDVDWizardVideoAngaben,
	    char *szTitel,
	    char *szHintergrundBild,
	    char *szChapter,
	    char *szAudio1, char *szAudio2,
	    char *szDVDDir,
	    char *szVobFile,
	    long lDelete, char *szUntertitelOptionen, char *szPaletteFile,
            long lSprache);

// Homeverzeichnis: Platzhalter "~" durch vollen Pfad ersetzen
void
insertHomeDir (char * szDir);

// Sound abspielen
void 
play_sound_if_ready (char * lxdvdrip_wav_name);


// Liefert Requantisierungsfaktor zurueck
double stream_faktor (char * szDevice, long lTitel, char * szRipTracks);

// DVD vor dem Brennen unmounten 
// Problem: DVD-RW ist gemountet durch Automounter
void unmount_dvd (char * szDevice, char * szTmpDir);

// Lies ein Wort aus der Configdatei
// Returncodes: 1 = OK, 2=OK&&EOL, 3=OK&&EOF, 0=EOF
int lies_wort (FILE* f, char* szWort);

