vdr/xine-lib-vdr/src/input/libdvdnav Makefile.am Makefile.in bswap.h decoder.c decoder.h dvd_input.c dvd_input.h dvd_reader.c dvd_reader.h dvd_types.h dvd_udf.c dvd_udf.h dvdnav.c dvdnav.h dvdnav_events.h dvdnav_internal.h dvdread_internal.h highlight.c ifo_read.c ifo_read.h ifo_types.h md5.c md5.h nav_print.c nav_print.h nav_read.c nav_read.h nav_types.h navigation.c read_cache.c read_cache.h remap.c remap.h searching.c settings.c vm.c vm.h vmcmd.c vmcmd.h

Darren Salt pkg-vdr-dvb-changes@lists.alioth.debian.org
Mon, 04 Apr 2005 22:29:38 +0000


Update of /cvsroot/pkg-vdr-dvb/vdr/xine-lib-vdr/src/input/libdvdnav
In directory haydn:/tmp/cvs-serv2129/src/input/libdvdnav

Added Files:
	Makefile.am Makefile.in bswap.h decoder.c decoder.h 
	dvd_input.c dvd_input.h dvd_reader.c dvd_reader.h dvd_types.h 
	dvd_udf.c dvd_udf.h dvdnav.c dvdnav.h dvdnav_events.h 
	dvdnav_internal.h dvdread_internal.h highlight.c ifo_read.c 
	ifo_read.h ifo_types.h md5.c md5.h nav_print.c nav_print.h 
	nav_read.c nav_read.h nav_types.h navigation.c read_cache.c 
	read_cache.h remap.c remap.h searching.c settings.c vm.c vm.h 
	vmcmd.c vmcmd.h 
Log Message:
Import of VDR-patched xine-lib.

--- NEW FILE: nav_print.c ---
(This appears to be a binary file; contents omitted.)

--- NEW FILE: decoder.h ---
(This appears to be a binary file; contents omitted.)

--- NEW FILE: dvd_reader.c ---
(This appears to be a binary file; contents omitted.)

--- NEW FILE: ifo_read.c ---
(This appears to be a binary file; contents omitted.)

--- NEW FILE: dvd_input.h ---
#ifndef DVD_INPUT_H_INCLUDED
#define DVD_INPUT_H_INCLUDED

/*
 * Copyright (C) 2001, 2002 Samuel Hocevar <sam@zoy.org>,
 *                          Håkan Hjort <d95hjort@dtek.chalmers.se>
 *
 * 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, USA.
 */

/**
 * Defines and flags.  Make sure they fit the libdvdcss API!
 */
#define DVDINPUT_NOFLAGS         0

#define DVDINPUT_READ_DECRYPT    (1 << 0)

typedef struct dvd_input_s *dvd_input_t;

/**
 * Pointers which will be filled either the input methods functions.
 */
extern dvd_input_t (*dvdinput_open)  (const char *);
extern int         (*dvdinput_close) (dvd_input_t);
extern int         (*dvdinput_seek)  (dvd_input_t, int);
extern int         (*dvdinput_title) (dvd_input_t, int); 
extern int         (*dvdinput_read)  (dvd_input_t, void *, int, int);
extern char *      (*dvdinput_error) (dvd_input_t);

/**
 * Setup function accessed by dvd_reader.c.  Returns 1 if there is CSS support.
 */
int dvdinput_setup(void);

#endif /* DVD_INPUT_H_INCLUDED */

--- NEW FILE: nav_print.h ---
#ifndef NAV_PRINT_H_INCLUDED
#define NAV_PRINT_H_INCLUDED

/*
 * Copyright (C) 2001, 2002 Billy Biggs <vektor@dumbterm.net>,
 *                          Håkan Hjort <d95hjort@dtek.chalmers.se>
 *
 * 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
 */

#include "nav_types.h"

/**
 * Pretty printing of the NAV packets, PCI and DSI structs.
 */

#ifdef __cplusplus
extern "C" {
#endif

/**
 * Prints information contained in the PCI to stdout.
 *
 * @param pci Pointer to the PCI data structure to be printed.
 */
void navPrint_PCI(pci_t *);
  
/**
 * Prints information contained in the DSI to stdout.
 *
 * @param dsi Pointer to the DSI data structure to be printed.
 */
void navPrint_DSI(dsi_t *);

#ifdef __cplusplus
};
#endif
#endif /* NAV_PRINT_H_INCLUDED */

--- NEW FILE: decoder.c ---
(This appears to be a binary file; contents omitted.)

--- NEW FILE: ifo_read.h ---
(This appears to be a binary file; contents omitted.)

--- NEW FILE: dvd_reader.h ---
#ifndef DVD_READER_H_INCLUDED
#define DVD_READER_H_INCLUDED

/*
 * Copyright (C) 2001, 2002 Billy Biggs <vektor@dumbterm.net>,
 *                          Håkan Hjort <d95hjort@dtek.chalmers.se>,
 *                          Björn Englund <d4bjorn@dtek.chalmers.se>
 *
 * 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
 */

#ifdef _MSC_VER
#include <config.h>

#include <stdio.h>
#include <stdlib.h>
#endif

#include <sys/types.h>
#include <inttypes.h>

/**
 * The DVD access interface.
 *
 * This file contains the functions that form the interface to to
 * reading files located on a DVD.
 */

/**
 * The current version.
 */
#define DVDREAD_VERSION 904

/**
 * The length of one Logical Block of a DVD.
 */
#define DVD_VIDEO_LB_LEN 2048

/**
 * Maximum length of filenames allowed in UDF.
 */
#define MAX_UDF_FILE_NAME_LEN 2048

#ifdef __cplusplus
extern "C" {
#endif
  
/**
 * Opaque type that is used as a handle for one instance of an opened DVD.
 */
typedef struct dvd_reader_s dvd_reader_t;
  
/**
 * Opaque type for a file read handle, much like a normal fd or FILE *.
 */
typedef struct dvd_file_s dvd_file_t;

/**
 * Opens a block device of a DVD-ROM file, or an image file, or a directory
 * name for a mounted DVD or HD copy of a DVD.
 *
 * If the given file is a block device, or is the mountpoint for a block
 * device, then that device is used for CSS authentication using libdvdcss.
 * If no device is available, then no CSS authentication is performed, 
 * and we hope that the image is decrypted.
 *
 * If the path given is a directory, then the files in that directory may be
 * in any one of these formats:
 *
 *   path/VIDEO_TS/VTS_01_1.VOB
 *   path/video_ts/vts_01_1.vob
 *   path/VTS_01_1.VOB
 *   path/vts_01_1.vob
 *
 * @param path Specifies the the device, file or directory to be used. 
 * @return If successful a a read handle is returned. Otherwise 0 is returned.
 *
 * dvd = DVDOpen(path);
 */
dvd_reader_t *DVDOpen( const char * );

/**
 * Closes and cleans up the DVD reader object.
 *
 * You must close all open files before calling this function.
 *
 * @param dvd A read handle that should be closed.
 *
 * DVDClose(dvd);
 */
void DVDClose( dvd_reader_t * );

/**
 * 
 */
typedef enum {
  DVD_READ_INFO_FILE,        /**< VIDEO_TS.IFO  or VTS_XX_0.IFO (title) */
  DVD_READ_INFO_BACKUP_FILE, /**< VIDEO_TS.BUP  or VTS_XX_0.BUP (title) */
  DVD_READ_MENU_VOBS,        /**< VIDEO_TS.VOB  or VTS_XX_0.VOB (title) */
  DVD_READ_TITLE_VOBS        /**< VTS_XX_[1-9].VOB (title).  All files in 
				  the title set are opened and read as a
				  single file. */
} dvd_read_domain_t;

/**
 * Opens a file on the DVD given the title number and domain.
 *
 * If the title number is 0, the video manager information is opened
 * (VIDEO_TS.[IFO,BUP,VOB]).  Returns a file structure which may be
 * used for reads, or 0 if the file was not found.
 *
 * @param dvd  A dvd read handle.
 * @param titlenum Which Video Title Set should be used, VIDEO_TS is 0.
 * @param domain Which domain. 
 * @return If successful a a file read handle is returned, otherwise 0.
 *
 * dvd_file = DVDOpenFile(dvd, titlenum, domain); */
dvd_file_t *DVDOpenFile( dvd_reader_t *, int, dvd_read_domain_t );

/**
 * Closes a file and frees the associated structure.
 *
 * @param dvd_file  The file read handle to be closed.
 *
 * DVDCloseFile(dvd_file);
 */
void DVDCloseFile( dvd_file_t * );

/**
 * Reads block_count number of blocks from the file at the given block offset.
 * Returns number of blocks read on success, -1 on error.  This call is only
 * for reading VOB data, and should not be used when reading the IFO files.  
 * When reading from an encrypted drive, blocks are decrypted using libdvdcss 
 * where required.
 *
 * @param dvd_file  A file read handle.
 * @param offset Block offset from the start of the file to start reading at.
 * @param block_count Number of block to read.
 * @param data Pointer to a buffer to write the data into.
 * @return Returns number of blocks read on success, -1 on error.
 *
 * blocks_read = DVDReadBlocks(dvd_file, offset, block_count, data);
 */
ssize_t DVDReadBlocks( dvd_file_t *, int, size_t, unsigned char * );

/**
 * Seek to the given position in the file.  Returns the resulting position in
 * bytes from the beginning of the file.  The seek position is only used for
 * byte reads from the file, the block read call always reads from the given
 * offset.
 *
 * @param dvd_file  A file read handle.
 * @param seek_offset Byte offset from the start of the file to seek to.
 * @return The resulting position in bytes from the beginning of the file.
 *
 * offset_set = DVDFileSeek(dvd_file, seek_offset);
 */
int32_t DVDFileSeek( dvd_file_t *, int32_t );

/**
 * Reads the given number of bytes from the file.  This call can only be used
 * on the information files, and may not be used for reading from a VOB.  This
 * reads from and increments the currrent seek position for the file.
 *
 * @param dvd_file  A file read handle.
 * @param data Pointer to a buffer to write the data into.
 * @param bytes Number of bytes to read.
 * @return Returns number of bytes read on success, -1 on error.
 *
 * bytes_read = DVDReadBytes(dvd_file, data, bytes);
 */
ssize_t DVDReadBytes( dvd_file_t *, void *, size_t );

/**
 * Returns the file size in blocks.
 *
 * @param dvd_file  A file read handle.
 * @return The size of the file in blocks, -1 on error.
 *
 * blocks = DVDFileSize(dvd_file);
 */
ssize_t DVDFileSize( dvd_file_t * );

/**
 * Get a unique 128 bit disc ID.
 * This is the MD5 sum of VIDEO_TS.IFO and the VTS_0?_0.IFO files
 * in title order (those that exist).
 * If you need a 'text' representation of the id, print it as a
 * hexadecimal number, using lowercase letters, discid[0] first. 
 * I.e. the same format as the command-line 'md5sum' program uses.
 *
 * @param dvd A read handle to get the disc ID from
 * @param discid The buffer to put the disc ID into. The buffer must
 *               have room for 128 bits (16 chars).
 * @return 0 on success, -1 on error.
 */
int DVDDiscID( dvd_reader_t *, unsigned char * );

/**
 * Get the UDF VolumeIdentifier and VolumeSetIdentifier
 * from the PrimaryVolumeDescriptor.
 *
 * @param dvd A read handle to get the disc ID from
 * @param volid The buffer to put the VolumeIdentifier into.
 *              The VolumeIdentifier is latin-1 encoded (8bit unicode)
 *              null terminated and max 32 bytes (including '\0')
 * @param volid_size No more than volid_size bytes will be copied to volid.
 *                   If the VolumeIdentifier is truncated because of this
 *                   it will still be null terminated.
 * @param volsetid The buffer to put the VolumeSetIdentifier into.
 *                 The VolumeIdentifier is 128 bytes as
 *                 stored in the UDF PrimaryVolumeDescriptor.
 *                 Note that this is not a null terminated string.
 * @param volsetid_size At most volsetid_size bytes will be copied to volsetid.
 * @return 0 on success, -1 on error.
 */
int DVDUDFVolumeInfo( dvd_reader_t *, char *, unsigned int,
		      unsigned char *, unsigned int );

/**
 * Get the ISO9660 VolumeIdentifier and VolumeSetIdentifier
 *
 * * Only use this function as fallback if DVDUDFVolumeInfo returns 0   *
 * * this will happen on a disc mastered only with a iso9660 filesystem *
 * * All video DVD discs have UDF filesystem                            *
 *
 * @param dvd A read handle to get the disc ID from
 * @param volid The buffer to put the VolumeIdentifier into.
 *              The VolumeIdentifier is coded with '0-9','A-Z','_'
 *              null terminated and max 33 bytes (including '\0')
 * @param volid_size No more than volid_size bytes will be copied to volid.
 *                   If the VolumeIdentifier is truncated because of this
 *                   it will still be null terminated.
 * @param volsetid The buffer to put the VolumeSetIdentifier into.
 *                 The VolumeIdentifier is 128 bytes as
 *                 stored in the ISO9660 PrimaryVolumeDescriptor.
 *                 Note that this is not a null terminated string.
 * @param volsetid_size At most volsetid_size bytes will be copied to volsetid.
 * @return 0 on success, -1 on error.
 */
int DVDISOVolumeInfo( dvd_reader_t *, char *, unsigned int,
		      unsigned char *, unsigned int );

/**
 * Sets the level of caching that is done when reading from a device
 *
 * @param dvd A read handle to get the disc ID from
 * @param level The level of caching wanted.
 *             -1 - returns the current setting.
 *              0 - UDF Cache turned off.
 *              1 - (default level) Pointers to IFO files and some data from
 *                  PrimaryVolumeDescriptor are cached. 
 *
 * @return The level of caching.
 */
int DVDUDFCacheLevel( dvd_reader_t *, int );

#ifdef __cplusplus
};
#endif
#endif /* DVD_READER_H_INCLUDED */

--- NEW FILE: dvd_types.h ---
(This appears to be a binary file; contents omitted.)

--- NEW FILE: vm.c ---
(This appears to be a binary file; contents omitted.)

--- NEW FILE: dvdnav_events.h ---
/* 
 * Copyright (C) 2001 Rich Wareham <richwareham@users.sourceforge.net>
 * 
 * This file is part of libdvdnav, a DVD navigation library.
 * 
 * libdvdnav 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.
 * 
 * libdvdnav 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
 *
 * $Id: dvdnav_events.h,v 1.1 2005/04/04 22:29:35 dsalt-guest Exp $
 *
 */

/*
 * This header defines events and event types 
 */

#ifndef DVDNAV_EVENTS_H_INCLUDED
#define DVDNAV_EVENTS_H_INCLUDED

#include "ifo_types.h"
#include "dvd_reader.h"
#include "nav_types.h"


/*
 * DVDNAV_BLOCK_OK
 *
 * A regular data block from the DVD has been returned.
 * This one should be demuxed and decoded for playback.
 */
#define DVDNAV_BLOCK_OK			 0


/*
 * DVDNAV_NOP
 *
 * Just ignore this.
 */
#define DVDNAV_NOP			 1


/*
 * DVDNAV_STILL_FRAME
 *
 * We have reached a still frame. The player application should wait
 * the amount of time specified by the still's length while still handling
 * user input to make menus and other interactive stills work.
 * The last delivered frame should be kept showing.
 * Once the still has timed out, call dvdnav_skip_still().
 * A length of 0xff means an infinite still which has to be skipped
 * indirectly by some user interaction.
 */
#define DVDNAV_STILL_FRAME		 2

typedef struct {
  /* The length (in seconds) the still frame should be displayed for,
   * or 0xff if infinite. */
  int length;
} dvdnav_still_event_t;


/*
 * DVDNAV_SPU_STREAM_CHANGE
 *
 * Inform the SPU decoding/overlaying engine to switch SPU channels.
 */
#define DVDNAV_SPU_STREAM_CHANGE	 3

typedef struct {
  /* The physical (MPEG) stream number for widescreen SPU display.
   * Use this, if you blend the SPU on an anamorphic image before
   * unsqueezing it. */
  int physical_wide;

  /* The physical (MPEG) stream number for letterboxed display.
   * Use this, if you blend the SPU on an anamorphic image after
   * unsqueezing it. */
  int physical_letterbox;

  /* The physical (MPEG) stream number for pan&scan display.
   * Use this, if you blend the SPU on an anamorphic image after
   * unsqueezing it the pan&scan way. */
  int physical_pan_scan;
  
  /* The logical (DVD) stream number. */
  int logical;
} dvdnav_spu_stream_change_event_t;


/*
 * DVDNAV_AUDIO_STREAM_CHANGE
 *
 * Inform the audio decoder to switch channels.
 */
#define DVDNAV_AUDIO_STREAM_CHANGE	 4

typedef struct {
  /* The physical (MPEG) stream number. */
  int physical;

  /* The logical (DVD) stream number. */
  int logical;
} dvdnav_audio_stream_change_event_t;


/*
 * DVDNAV_VTS_CHANGE
 *
 * Some status information like video aspect and video scale permissions do
 * not change inside a VTS. Therefore this event can be used to query such
 * information only when necessary and update the decoding/displaying
 * accordingly.
 */
#define DVDNAV_VTS_CHANGE		 5

typedef struct {
  int old_vtsN;                 /* the old VTS number */
  dvd_read_domain_t old_domain; /* the old domain */
  int new_vtsN;                 /* the new VTS number */
  dvd_read_domain_t new_domain; /* the new domain */
} dvdnav_vts_change_event_t;


/*
 * DVDNAV_CELL_CHANGE
 *
 * Some status information like the current Title and Part numbers do not
 * change inside a cell. Therefore this event can be used to query such
 * information only when necessary and update the decoding/displaying
 * accordingly.
 * Some useful information for accurate time display is also reported
 * together with this event.
 */
#define DVDNAV_CELL_CHANGE		 6

typedef struct {
  int     cellN;       /* the new cell number */
  int     pgN;         /* the current program number */
  int64_t cell_length; /* the length of the current cell in PTS ticks */
  int64_t pg_length;   /* the length of the current program in PTS ticks */
  int64_t pgc_length;  /* the length of the current program chain in PTS ticks */
  int64_t cell_start;  /* the start time of the current cell relatively to the PGC in PTS ticks */
  int64_t pg_start;    /* the start time of the current PG relatively to the PGC in PTS ticks */
} dvdnav_cell_change_event_t;


/*
 * DVDNAV_NAV_PACKET
 *
 * NAV packets are useful for various purposes. They define the button
 * highlight areas and VM commands of DVD menus, so they should in any
 * case be sent to the SPU decoder/overlaying engine for the menus to work.
 * NAV packets also provide a way to detect PTS discontinuities, because
 * they carry the start and end PTS values for the current VOBU.
 * (pci.vobu_s_ptm and pci.vobu_e_ptm) Whenever the start PTS of the
 * current NAV does not match the end PTS of the previous NAV, a PTS
 * discontinuity has occured.
 * NAV packets can also be used for time display, because they are
 * timestamped relatively to the current Cell.
 */
#define DVDNAV_NAV_PACKET		 7


/*
 * DVDNAV_STOP
 *
 * Applications should end playback here. A subsequent dvdnav_get_next_block()
 * call will restart the VM from the beginning of the DVD.
 */
#define DVDNAV_STOP			 8


/*
 * DVDNAV_HIGHLIGHT
 *
 * The current button highlight changed. Inform the overlaying engine to
 * highlight a different button. Please note, that at the moment only mode 1
 * highlights are reported this way. That means, when the button highlight
 * has been moved around by some function call, you will receive an event
 * telling you the new button. But when a button gets activated, you have
 * to handle the mode 2 highlighting (that is some different colour the
 * button turns to on activation) in your application.
 */
#define DVDNAV_HIGHLIGHT		 9

typedef struct {
  /* highlight mode: 0 - hide, 1 - show, 2 - activate, currently always 1 */
  int display;

  /* FIXME: these fields are currently not set */
  uint32_t palette;     /* The CLUT entries for the highlight palette 
			   (4-bits per entry -> 4 entries) */
  uint16_t sx,sy,ex,ey; /* The start/end x,y positions */
  uint32_t pts;         /* Highlight PTS to match with SPU */

  /* button number for the SPU decoder/overlaying engine */
  uint32_t buttonN;
} dvdnav_highlight_event_t;


/*
 * DVDNAV_SPU_CLUT_CHANGE
 *
 * Inform the SPU decoder/overlaying engine to update its colour lookup table.
 * The CLUT is given as 16 uint32_t's in the buffer.
 */
#define DVDNAV_SPU_CLUT_CHANGE		10


/*
 * DVDNAV_HOP_CHANNEL
 *
 * A non-seamless operation has been performed. Applications can drop all
 * their internal fifo's content, which will speed up the response.
 */
#define DVDNAV_HOP_CHANNEL		12


/*
 * DVDNAV_WAIT
 *
 * We have reached a point in DVD playback, where timing is critical.
 * Player application with internal fifos can introduce state
 * inconsistencies, because libdvdnav is always the fifo's length
 * ahead in the stream compared to what the application sees.
 * Such applications should wait until their fifos are empty
 * when they receive this type of event.
 * Once this is achieved, call dvdnav_skip_wait().
 */
#define DVDNAV_WAIT			13


#endif /* DVDNAV_EVENTS_H_INCLUDED */

--- NEW FILE: read_cache.h ---
/* 
 * Copyright (C) 2000 Rich Wareham <richwareham@users.sourceforge.net>
 * 
 * This file is part of libdvdnav, a DVD navigation library.
 * 
 * libdvdnav 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.
 * 
 * libdvdnav 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
 *
 * $Id: read_cache.h,v 1.1 2005/04/04 22:29:36 dsalt-guest Exp $
 *
 */

#ifndef __DVDNAV_READ_CACHE_H
#define __DVDNAV_READ_CACHE_H

#include "dvdnav_internal.h"

/* Opaque cache type -- defined in dvdnav_internal.h */
/* typedef struct read_cache_s read_cache_t; */

/* EXPERIMENTAL: Setting the following to 1 will use an experimental multi-threaded
 *               read-ahead cache. 
 */
#define _MULTITHREAD_ 0

/* Constructor/destructors */
read_cache_t *dvdnav_read_cache_new(dvdnav_t* dvd_self);
void dvdnav_read_cache_free(read_cache_t* self);

/* This function MUST be called whenever self->file changes. */
void dvdnav_read_cache_clear(read_cache_t *self);
/* This function is called just after reading the NAV packet. */
void dvdnav_pre_cache_blocks(read_cache_t *self, int sector, size_t block_count);
/* This function will do the cache read.
 * The buffer handed in must be malloced to take one dvd block.
 * On a cache hit, a different buffer will be returned though.
 * Those buffers must _never_ be freed. */
int dvdnav_read_cache_block(read_cache_t *self, int sector, size_t block_count, uint8_t **buf);

#endif /* __DVDNAV_READ_CACHE_H */

--- NEW FILE: nav_types.h ---
(This appears to be a binary file; contents omitted.)

--- NEW FILE: Makefile.in ---
# Makefile.in generated by automake 1.9.3 from Makefile.am.
# @configure_input@

# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004  Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.

@SET_MAKE@


SOURCES = $(libdvdnav_la_SOURCES)

srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
top_builddir = ../../..
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
INSTALL = @INSTALL@
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
target_triplet = @target@
DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
	$(srcdir)/Makefile.in $(top_srcdir)/misc/Makefile.common
subdir = src/input/libdvdnav
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/_xine.m4 $(top_srcdir)/m4/aa.m4 \
	$(top_srcdir)/m4/alsa.m4 $(top_srcdir)/m4/arts.m4 \
	$(top_srcdir)/m4/as.m4 $(top_srcdir)/m4/caca.m4 \
	$(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/directx.m4 \
	$(top_srcdir)/m4/dl.m4 $(top_srcdir)/m4/dvdnav.m4 \
	$(top_srcdir)/m4/esd.m4 $(top_srcdir)/m4/ffmpeg.m4 \
	$(top_srcdir)/m4/freetype2.m4 $(top_srcdir)/m4/gettext.m4 \
	$(top_srcdir)/m4/glibc21.m4 $(top_srcdir)/m4/iconv.m4 \
	$(top_srcdir)/m4/irixal.m4 $(top_srcdir)/m4/lcmessage.m4 \
	$(top_srcdir)/m4/libFLAC.m4 $(top_srcdir)/m4/libfame.m4 \
	$(top_srcdir)/m4/ogg.m4 $(top_srcdir)/m4/opengl.m4 \
	$(top_srcdir)/m4/pkg.m4 $(top_srcdir)/m4/progtest.m4 \
	$(top_srcdir)/m4/sdl.m4 $(top_srcdir)/m4/speex.m4 \
	$(top_srcdir)/m4/theora.m4 $(top_srcdir)/m4/vorbis.m4 \
	$(top_srcdir)/m4/xv.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
LTLIBRARIES = $(noinst_LTLIBRARIES)
am__DEPENDENCIES_1 =
libdvdnav_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
am_libdvdnav_la_OBJECTS = decoder.lo dvdnav.lo highlight.lo \
	navigation.lo read_cache.lo remap.lo searching.lo settings.lo \
	vm.lo vmcmd.lo ifo_read.lo md5.lo nav_print.lo nav_read.lo \
	dvd_reader.lo dvd_input.lo dvd_udf.lo
libdvdnav_la_OBJECTS = $(am_libdvdnav_la_OBJECTS)
DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
	$(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC)
LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
	$(AM_LDFLAGS) $(LDFLAGS) -o $@
SOURCES = $(libdvdnav_la_SOURCES)
DIST_SOURCES = $(libdvdnav_la_SOURCES)
HEADERS = $(noinst_HEADERS)
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
AAINFO = @AAINFO@
AALIB_CFLAGS = @AALIB_CFLAGS@
AALIB_CONFIG = @AALIB_CONFIG@
AALIB_LIBS = @AALIB_LIBS@
ACLOCAL = @ACLOCAL@
ACLOCAL_DIR = @ACLOCAL_DIR@
ALLOCA = @ALLOCA@
ALSA_CFLAGS = @ALSA_CFLAGS@
ALSA_LIBS = @ALSA_LIBS@
ALSA_STATIC_LIB = @ALSA_STATIC_LIB@
AMDEP_FALSE = @AMDEP_FALSE@
AMDEP_TRUE = @AMDEP_TRUE@
AMTAR = @AMTAR@
AR = @AR@
ARTS_CFLAGS = @ARTS_CFLAGS@
ARTS_CONFIG = @ARTS_CONFIG@
ARTS_LIBS = @ARTS_LIBS@
AS = @AS@
ASFLAGS = @ASFLAGS@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BUILD_ASF_FALSE = @BUILD_ASF_FALSE@
BUILD_ASF_TRUE = @BUILD_ASF_TRUE@
BUILD_DHA_KMOD_FALSE = @BUILD_DHA_KMOD_FALSE@
BUILD_DHA_KMOD_TRUE = @BUILD_DHA_KMOD_TRUE@
BUILD_FAAD_FALSE = @BUILD_FAAD_FALSE@
BUILD_FAAD_TRUE = @BUILD_FAAD_TRUE@
BUILD_INCLUDED_LIBINTL = @BUILD_INCLUDED_LIBINTL@
CACA_CFLAGS = @CACA_CFLAGS@
CACA_CONFIG = @CACA_CONFIG@
CACA_LIBS = @CACA_LIBS@
CATALOGS = @CATALOGS@
CATOBJEXT = @CATOBJEXT@
CC = @CC@
CCAS = @CCAS@
CCASCOMPILE = @CCASCOMPILE@
CCASFLAGS = @CCASFLAGS@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DATADIRNAME = @DATADIRNAME@
DEBUG_CFLAGS = @DEBUG_CFLAGS@
DEFS = @DEFS@
DEPCOMP = @DEPCOMP@
DEPDIR = @DEPDIR@
DEPMOD = @DEPMOD@
DIRECTFB_CFLAGS = @DIRECTFB_CFLAGS@
DIRECTFB_LIBS = @DIRECTFB_LIBS@
DIRECTX_AUDIO_LIBS = @DIRECTX_AUDIO_LIBS@
DIRECTX_CPPFLAGS = @DIRECTX_CPPFLAGS@
DIRECTX_VIDEO_LIBS = @DIRECTX_VIDEO_LIBS@
DLLTOOL = @DLLTOOL@
DVDNAV_CFLAGS = @DVDNAV_CFLAGS@
DVDNAV_CONFIG = @DVDNAV_CONFIG@
DVDNAV_LIBS = @DVDNAV_LIBS@
DYNAMIC_LD_LIBS = @DYNAMIC_LD_LIBS@
ECHO = @ECHO@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
ENABLE_VCD_FALSE = @ENABLE_VCD_FALSE@
ENABLE_VCD_TRUE = @ENABLE_VCD_TRUE@
ESD_CFLAGS = @ESD_CFLAGS@
ESD_CONFIG = @ESD_CONFIG@
ESD_LIBS = @ESD_LIBS@
EXEEXT = @EXEEXT@
EXTRA_X_CFLAGS = @EXTRA_X_CFLAGS@
EXTRA_X_LIBS = @EXTRA_X_LIBS@
F77 = @F77@
FFLAGS = @FFLAGS@
FFMPEG_CPPFLAGS = @FFMPEG_CPPFLAGS@
FFMPEG_LIBS = @FFMPEG_LIBS@
FIG2DEV = @FIG2DEV@
FREETYPE_CONFIG = @FREETYPE_CONFIG@
FT2_CFLAGS = @FT2_CFLAGS@
FT2_LIBS = @FT2_LIBS@
GENCAT = @GENCAT@
GLIBC21 = @GLIBC21@
GLUT_LIBS = @GLUT_LIBS@
GLU_LIBS = @GLU_LIBS@
GMOFILES = @GMOFILES@
GMSGFMT = @GMSGFMT@
GNOME_VFS_CFLAGS = @GNOME_VFS_CFLAGS@
GNOME_VFS_LIBS = @GNOME_VFS_LIBS@
GOOM_LIBS = @GOOM_LIBS@
HAVE_AA_FALSE = @HAVE_AA_FALSE@
HAVE_AA_TRUE = @HAVE_AA_TRUE@
HAVE_ALSA09_FALSE = @HAVE_ALSA09_FALSE@
HAVE_ALSA09_TRUE = @HAVE_ALSA09_TRUE@
HAVE_ALSA_FALSE = @HAVE_ALSA_FALSE@
HAVE_ALSA_TRUE = @HAVE_ALSA_TRUE@
HAVE_ARMV4L_FALSE = @HAVE_ARMV4L_FALSE@
HAVE_ARMV4L_TRUE = @HAVE_ARMV4L_TRUE@
HAVE_ARTS_FALSE = @HAVE_ARTS_FALSE@
HAVE_ARTS_TRUE = @HAVE_ARTS_TRUE@
HAVE_BSDI_CDROM = @HAVE_BSDI_CDROM@
HAVE_CACA_FALSE = @HAVE_CACA_FALSE@
HAVE_CACA_TRUE = @HAVE_CACA_TRUE@
HAVE_CDROM_IOCTLS_FALSE = @HAVE_CDROM_IOCTLS_FALSE@
HAVE_CDROM_IOCTLS_TRUE = @HAVE_CDROM_IOCTLS_TRUE@
HAVE_COREAUDIO_FALSE = @HAVE_COREAUDIO_FALSE@
HAVE_COREAUDIO_TRUE = @HAVE_COREAUDIO_TRUE@
HAVE_DARWIN_CDROM = @HAVE_DARWIN_CDROM@
HAVE_DIRECTFB_FALSE = @HAVE_DIRECTFB_FALSE@
HAVE_DIRECTFB_TRUE = @HAVE_DIRECTFB_TRUE@
HAVE_DIRECTX_FALSE = @HAVE_DIRECTX_FALSE@
HAVE_DIRECTX_TRUE = @HAVE_DIRECTX_TRUE@
HAVE_DVDNAV_FALSE = @HAVE_DVDNAV_FALSE@
HAVE_DVDNAV_TRUE = @HAVE_DVDNAV_TRUE@
HAVE_DXR3_FALSE = @HAVE_DXR3_FALSE@
HAVE_DXR3_TRUE = @HAVE_DXR3_TRUE@
HAVE_ESD_FALSE = @HAVE_ESD_FALSE@
HAVE_ESD_TRUE = @HAVE_ESD_TRUE@
HAVE_FB_FALSE = @HAVE_FB_FALSE@
HAVE_FB_TRUE = @HAVE_FB_TRUE@
HAVE_FFMMX_FALSE = @HAVE_FFMMX_FALSE@
HAVE_FFMMX_TRUE = @HAVE_FFMMX_TRUE@
HAVE_FFMPEG_FALSE = @HAVE_FFMPEG_FALSE@
HAVE_FFMPEG_TRUE = @HAVE_FFMPEG_TRUE@
HAVE_FIG2DEV_FALSE = @HAVE_FIG2DEV_FALSE@
HAVE_FIG2DEV_TRUE = @HAVE_FIG2DEV_TRUE@
HAVE_FLAC_FALSE = @HAVE_FLAC_FALSE@
HAVE_FLAC_TRUE = @HAVE_FLAC_TRUE@
HAVE_FREEBSD_CDROM = @HAVE_FREEBSD_CDROM@
HAVE_GNOME_VFS_FALSE = @HAVE_GNOME_VFS_FALSE@
HAVE_GNOME_VFS_TRUE = @HAVE_GNOME_VFS_TRUE@
HAVE_IRIXAL_FALSE = @HAVE_IRIXAL_FALSE@
HAVE_IRIXAL_TRUE = @HAVE_IRIXAL_TRUE@
HAVE_LIBFAME_FALSE = @HAVE_LIBFAME_FALSE@
HAVE_LIBFAME_TRUE = @HAVE_LIBFAME_TRUE@
HAVE_LIBMNG_FALSE = @HAVE_LIBMNG_FALSE@
HAVE_LIBMNG_TRUE = @HAVE_LIBMNG_TRUE@
HAVE_LIBPNG_FALSE = @HAVE_LIBPNG_FALSE@
HAVE_LIBPNG_TRUE = @HAVE_LIBPNG_TRUE@
HAVE_LIBRTE_FALSE = @HAVE_LIBRTE_FALSE@
HAVE_LIBRTE_TRUE = @HAVE_LIBRTE_TRUE@
HAVE_LIBSMBCLIENT_FALSE = @HAVE_LIBSMBCLIENT_FALSE@
HAVE_LIBSMBCLIENT_TRUE = @HAVE_LIBSMBCLIENT_TRUE@
HAVE_LINUX_CDROM = @HAVE_LINUX_CDROM@
HAVE_LINUX_FALSE = @HAVE_LINUX_FALSE@
HAVE_LINUX_TRUE = @HAVE_LINUX_TRUE@
HAVE_MACOSX_VIDEO_FALSE = @HAVE_MACOSX_VIDEO_FALSE@
HAVE_MACOSX_VIDEO_TRUE = @HAVE_MACOSX_VIDEO_TRUE@
HAVE_MLIB_FALSE = @HAVE_MLIB_FALSE@
HAVE_MLIB_TRUE = @HAVE_MLIB_TRUE@
HAVE_OPENGL_FALSE = @HAVE_OPENGL_FALSE@
HAVE_OPENGL_TRUE = @HAVE_OPENGL_TRUE@
HAVE_OSS_FALSE = @HAVE_OSS_FALSE@
HAVE_OSS_TRUE = @HAVE_OSS_TRUE@
HAVE_POLYPAUDIO_FALSE = @HAVE_POLYPAUDIO_FALSE@
HAVE_POLYPAUDIO_TRUE = @HAVE_POLYPAUDIO_TRUE@
HAVE_SDL_FALSE = @HAVE_SDL_FALSE@
HAVE_SDL_TRUE = @HAVE_SDL_TRUE@
HAVE_SGMLTOOLS_FALSE = @HAVE_SGMLTOOLS_FALSE@
HAVE_SGMLTOOLS_TRUE = @HAVE_SGMLTOOLS_TRUE@
HAVE_SOLARIS_CDROM = @HAVE_SOLARIS_CDROM@
HAVE_SPEEX_FALSE = @HAVE_SPEEX_FALSE@
HAVE_SPEEX_TRUE = @HAVE_SPEEX_TRUE@
HAVE_STK_FALSE = @HAVE_STK_FALSE@
HAVE_STK_TRUE = @HAVE_STK_TRUE@
HAVE_SUNAUDIO_FALSE = @HAVE_SUNAUDIO_FALSE@
HAVE_SUNAUDIO_TRUE = @HAVE_SUNAUDIO_TRUE@
HAVE_SUNDGA_FALSE = @HAVE_SUNDGA_FALSE@
HAVE_SUNDGA_TRUE = @HAVE_SUNDGA_TRUE@
HAVE_SUNFB_FALSE = @HAVE_SUNFB_FALSE@
HAVE_SUNFB_TRUE = @HAVE_SUNFB_TRUE@
HAVE_SYNCFB_FALSE = @HAVE_SYNCFB_FALSE@
HAVE_SYNCFB_TRUE = @HAVE_SYNCFB_TRUE@
HAVE_THEORA_FALSE = @HAVE_THEORA_FALSE@
HAVE_THEORA_TRUE = @HAVE_THEORA_TRUE@
HAVE_V4L_FALSE = @HAVE_V4L_FALSE@
HAVE_V4L_TRUE = @HAVE_V4L_TRUE@
HAVE_VCDNAV_FALSE = @HAVE_VCDNAV_FALSE@
HAVE_VCDNAV_TRUE = @HAVE_VCDNAV_TRUE@
HAVE_VIDIX_FALSE = @HAVE_VIDIX_FALSE@
HAVE_VIDIX_TRUE = @HAVE_VIDIX_TRUE@
HAVE_VLDXVMC_FALSE = @HAVE_VLDXVMC_FALSE@
HAVE_VLDXVMC_TRUE = @HAVE_VLDXVMC_TRUE@
HAVE_VORBIS_FALSE = @HAVE_VORBIS_FALSE@
HAVE_VORBIS_TRUE = @HAVE_VORBIS_TRUE@
HAVE_W32DLL_FALSE = @HAVE_W32DLL_FALSE@
HAVE_W32DLL_TRUE = @HAVE_W32DLL_TRUE@
HAVE_WIN32_CDROM = @HAVE_WIN32_CDROM@
HAVE_X11_FALSE = @HAVE_X11_FALSE@
HAVE_X11_TRUE = @HAVE_X11_TRUE@
HAVE_XVMC_FALSE = @HAVE_XVMC_FALSE@
HAVE_XVMC_TRUE = @HAVE_XVMC_TRUE@
HAVE_XV_FALSE = @HAVE_XV_FALSE@
HAVE_XV_TRUE = @HAVE_XV_TRUE@
HAVE_XXMC_FALSE = @HAVE_XXMC_FALSE@
HAVE_XXMC_TRUE = @HAVE_XXMC_TRUE@
HAVE_ZLIB_FALSE = @HAVE_ZLIB_FALSE@
HAVE_ZLIB_TRUE = @HAVE_ZLIB_TRUE@
HOST_OS_DARWIN_FALSE = @HOST_OS_DARWIN_FALSE@
HOST_OS_DARWIN_TRUE = @HOST_OS_DARWIN_TRUE@
INCLUDED_INTL_FALSE = @INCLUDED_INTL_FALSE@
INCLUDED_INTL_TRUE = @INCLUDED_INTL_TRUE@
INCLUDES = @INCLUDES@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_M4_FALSE = @INSTALL_M4_FALSE@
INSTALL_M4_TRUE = @INSTALL_M4_TRUE@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
INSTOBJEXT = @INSTOBJEXT@
INTLBISON = @INTLBISON@
INTLDIR = @INTLDIR@
INTLLIBS = @INTLLIBS@
INTLOBJS = @INTLOBJS@
INTL_LIBTOOL_SUFFIX_PREFIX = @INTL_LIBTOOL_SUFFIX_PREFIX@
IRIXAL_CFLAGS = @IRIXAL_CFLAGS@
IRIXAL_LIBS = @IRIXAL_LIBS@
IRIXAL_STATIC_LIB = @IRIXAL_STATIC_LIB@
KSTAT_LIBS = @KSTAT_LIBS@
LDFLAGS = @LDFLAGS@
LIBCDIO_CFLAGS = @LIBCDIO_CFLAGS@
LIBCDIO_LIBS = @LIBCDIO_LIBS@
LIBFAME_CFLAGS = @LIBFAME_CFLAGS@
LIBFAME_CONFIG = @LIBFAME_CONFIG@
LIBFAME_LIBS = @LIBFAME_LIBS@
LIBFFMPEG_CFLAGS = @LIBFFMPEG_CFLAGS@
LIBFLAC_CFLAGS = @LIBFLAC_CFLAGS@
LIBFLAC_LIBS = @LIBFLAC_LIBS@
LIBICONV = @LIBICONV@
LIBISO9660_LIBS = @LIBISO9660_LIBS@
LIBMODPLUG_CFLAGS = @LIBMODPLUG_CFLAGS@
LIBMODPLUG_LIBS = @LIBMODPLUG_LIBS@
LIBMPEG2_CFLAGS = @LIBMPEG2_CFLAGS@
LIBNAME = @LIBNAME@
LIBOBJS = @LIBOBJS@
LIBPNG_CONFIG = @LIBPNG_CONFIG@
LIBS = @LIBS@
LIBSMBCLIENT_LIBS = @LIBSMBCLIENT_LIBS@
LIBSTK_CFLAGS = @LIBSTK_CFLAGS@
LIBSTK_LIBS = @LIBSTK_LIBS@
LIBTOOL = $(SHELL) $(top_builddir)/libtool-nofpic
LIBTOOL_DEPS = @LIBTOOL_DEPS@
LIBVCDINFO_LIBS = @LIBVCDINFO_LIBS@
LIBVCD_CFLAGS = @LIBVCD_CFLAGS@
LIBVCD_LIBS = @LIBVCD_LIBS@
LIBVCD_SYSDEP = @LIBVCD_SYSDEP@
LINUX_CDROM_TIMEOUT = @LINUX_CDROM_TIMEOUT@
LINUX_INCLUDE = @LINUX_INCLUDE@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_AGE = @LT_AGE@
LT_CURRENT = @LT_CURRENT@
LT_REVISION = @LT_REVISION@
MAKEINFO = @MAKEINFO@
MKINSTALLDIRS = @MKINSTALLDIRS@
MKNOD = @MKNOD@
MLIB_CFLAGS = @MLIB_CFLAGS@
MLIB_LIBS = @MLIB_LIBS@
MNG_LIBS = @MNG_LIBS@
MSGFMT = @MSGFMT@
NET_LIBS = @NET_LIBS@
OBJC = @OBJC@
OBJCDEPMODE = @OBJCDEPMODE@
OBJCFLAGS = @OBJCFLAGS@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OGG_CFLAGS = @OGG_CFLAGS@
OGG_LIBS = @OGG_LIBS@
OPENGL_CFLAGS = @OPENGL_CFLAGS@
OPENGL_LIBS = @OPENGL_LIBS@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_VERSION = @PACKAGE_VERSION@
PASS1_CFLAGS = @PASS1_CFLAGS@
PASS2_CFLAGS = @PASS2_CFLAGS@
PATH_SEPARATOR = @PATH_SEPARATOR@
PKG_CONFIG = @PKG_CONFIG@
PNG_CFLAGS = @PNG_CFLAGS@
PNG_LIBS = @PNG_LIBS@
POFILES = @POFILES@
POLYPAUDIO_CFLAGS = @POLYPAUDIO_CFLAGS@
POLYPAUDIO_LIBS = @POLYPAUDIO_LIBS@
POSUB = @POSUB@
PPC_ARCH_FALSE = @PPC_ARCH_FALSE@
PPC_ARCH_TRUE = @PPC_ARCH_TRUE@
RANLIB = @RANLIB@
RT_LIBS = @RT_LIBS@
SDL_CFLAGS = @SDL_CFLAGS@
SDL_CONFIG = @SDL_CONFIG@
SDL_LIBS = @SDL_LIBS@
SET_MAKE = @SET_MAKE@
SGMLTOOLS = @SGMLTOOLS@
SHELL = @SHELL@
SPEC_VERSION = @SPEC_VERSION@
SPEEX_CFLAGS = @SPEEX_CFLAGS@
SPEEX_LIBS = @SPEEX_LIBS@
STATIC = @STATIC@
STRIP = @STRIP@
SUNDGA_CFLAGS = @SUNDGA_CFLAGS@
SUNDGA_LIBS = @SUNDGA_LIBS@
TAR_NAME = @TAR_NAME@
THEORAENC_LIBS = @THEORAENC_LIBS@
THEORAFILE_LIBS = @THEORAFILE_LIBS@
THEORA_CFLAGS = @THEORA_CFLAGS@
THEORA_LIBS = @THEORA_LIBS@
THREAD_CFLAGS = @THREAD_CFLAGS@
THREAD_CFLAGS_CONFIG = @THREAD_CFLAGS_CONFIG@
THREAD_INCLUDES = @THREAD_INCLUDES@
THREAD_LIBS = @THREAD_LIBS@
THREAD_LIBS_CONFIG = @THREAD_LIBS_CONFIG@
USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
USE_NLS = @USE_NLS@
VERSION = @VERSION@
VORBISENC_LIBS = @VORBISENC_LIBS@
VORBISFILE_LIBS = @VORBISFILE_LIBS@
VORBIS_CFLAGS = @VORBIS_CFLAGS@
VORBIS_LIBS = @VORBIS_LIBS@
W32DLL_DEP = @W32DLL_DEP@
W32_NO_OPTIMIZE = @W32_NO_OPTIMIZE@
WIN32_CPPFLAGS = @WIN32_CPPFLAGS@
WIN32_FALSE = @WIN32_FALSE@
WIN32_TRUE = @WIN32_TRUE@
XGETTEXT = @XGETTEXT@
XINE_ACFLAGS = @XINE_ACFLAGS@
XINE_BIN_AGE = @XINE_BIN_AGE@
XINE_BUILD_CC = @XINE_BUILD_CC@
XINE_BUILD_DATE = @XINE_BUILD_DATE@
XINE_BUILD_OS = @XINE_BUILD_OS@
XINE_CONFIG_PREFIX = @XINE_CONFIG_PREFIX@
XINE_DATADIR = @XINE_DATADIR@
XINE_FONTDIR = @XINE_FONTDIR@
XINE_FONTPATH = @XINE_FONTPATH@
XINE_IFACE_AGE = @XINE_IFACE_AGE@
XINE_LOCALEDIR = @XINE_LOCALEDIR@
XINE_LOCALEPATH = @XINE_LOCALEPATH@
XINE_MAJOR = @XINE_MAJOR@
XINE_MINOR = @XINE_MINOR@
XINE_PLUGINDIR = @XINE_PLUGINDIR@
XINE_PLUGINPATH = @XINE_PLUGINPATH@
XINE_PLUGIN_MIN_SYMS = @XINE_PLUGIN_MIN_SYMS@
XINE_SCRIPTPATH = @XINE_SCRIPTPATH@
XINE_SUB = @XINE_SUB@
XVMC_LIB = @XVMC_LIB@
XV_LIB = @XV_LIB@
XXMC_LIB = @XXMC_LIB@
X_CFLAGS = @X_CFLAGS@
X_EXTRA_LIBS = @X_EXTRA_LIBS@
X_LIBS = @X_LIBS@
X_PRE_LIBS = @X_PRE_LIBS@
ZLIB_INCLUDES = @ZLIB_INCLUDES@
ZLIB_LIBS = @ZLIB_LIBS@
ZLIB_LIBS_CONFIG = @ZLIB_LIBS_CONFIG@
ac_ct_AR = @ac_ct_AR@
ac_ct_AS = @ac_ct_AS@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DLLTOOL = @ac_ct_DLLTOOL@
ac_ct_F77 = @ac_ct_F77@
ac_ct_OBJDUMP = @ac_ct_OBJDUMP@
ac_ct_RANLIB = @ac_ct_RANLIB@
ac_ct_STRIP = @ac_ct_STRIP@
am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
am__fastdepOBJC_FALSE = @am__fastdepOBJC_FALSE@
am__fastdepOBJC_TRUE = @am__fastdepOBJC_TRUE@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
datadir = @datadir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
prefix = @prefix@
program_transform_name = @program_transform_name@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
sysconfdir = @sysconfdir@
target = @target@
target_alias = @target_alias@
target_cpu = @target_cpu@
target_os = @target_os@
target_vendor = @target_vendor@
w32_path = @w32_path@
XINE_LIB = $(top_builddir)/src/xine-engine/libxine.la
AM_CPPFLAGS = -D_LARGEFILE64_SOURCE -DDVDNAV_COMPILE -DHAVE_DLFCN_H
noinst_LTLIBRARIES = libdvdnav.la
libdvdnav_la_SOURCES = \
	decoder.c \
	dvdnav.c \
	highlight.c \
	navigation.c \
	read_cache.c \
	remap.c \
	searching.c \
	settings.c \
	vm.c \
	vmcmd.c \
	ifo_read.c \
	md5.c \
	nav_print.c \
	nav_read.c \
	dvd_reader.c \
	dvd_input.c \
        dvd_udf.c

libdvdnav_la_LIBADD = $(THREAD_LIBS)
libdvdnav_la_LDFLAGS = -avoid-version -module
noinst_HEADERS = \
	decoder.h \
	dvdnav.h \
	dvdnav_events.h \
	dvdnav_internal.h \
	dvdread_internal.h \
	remap.h \
	vm.h \
	vmcmd.h \
	read_cache.h \
	dvd_types.h \
	ifo_read.h \
	ifo_types.h \
	md5.h \
	nav_print.h \
	nav_read.h \
	nav_types.h \
	dvd_reader.h \
	dvd_input.h \
	dvd_udf.h \
	bswap.h 

all: all-am

.SUFFIXES:
.SUFFIXES: .c .lo .o .obj
$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am $(top_srcdir)/misc/Makefile.common $(am__configure_deps)
	@for dep in $?; do \
	  case '$(am__configure_deps)' in \
	    *$$dep*) \
	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
		&& exit 0; \
	      exit 1;; \
	  esac; \
	done; \
	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu  src/input/libdvdnav/Makefile'; \
	cd $(top_srcdir) && \
	  $(AUTOMAKE) --gnu  src/input/libdvdnav/Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
	@case '$?' in \
	  *config.status*) \
	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
	  *) \
	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
	esac;

$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh

$(top_srcdir)/configure:  $(am__configure_deps)
	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh

clean-noinstLTLIBRARIES:
	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
	@list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
	  test "$$dir" != "$$p" || dir=.; \
	  echo "rm -f \"$${dir}/so_locations\""; \
	  rm -f "$${dir}/so_locations"; \
	done
libdvdnav.la: $(libdvdnav_la_OBJECTS) $(libdvdnav_la_DEPENDENCIES) 
	$(LINK)  $(libdvdnav_la_LDFLAGS) $(libdvdnav_la_OBJECTS) $(libdvdnav_la_LIBADD) $(LIBS)

mostlyclean-compile:
	-rm -f *.$(OBJEXT)

distclean-compile:
	-rm -f *.tab.c

@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decoder.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dvd_input.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dvd_reader.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dvd_udf.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dvdnav.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/highlight.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifo_read.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nav_print.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nav_read.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/navigation.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/read_cache.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/remap.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/searching.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/settings.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vm.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vmcmd.Plo@am__quote@

.c.o:
@am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@	$(COMPILE) -c $<

.c.obj:
@am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`

.c.lo:
@am__fastdepCC_TRUE@	if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<

mostlyclean-libtool:
	-rm -f *.lo

clean-libtool:
	-rm -rf .libs _libs

distclean-libtool:
	-rm -f libtool
uninstall-info-am:

ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
	unique=`for i in $$list; do \
	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
	  done | \
	  $(AWK) '    { files[$$0] = 1; } \
	       END { for (i in files) print i; }'`; \
	mkid -fID $$unique
tags: TAGS

TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
		$(TAGS_FILES) $(LISP)
	tags=; \
	here=`pwd`; \
	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
	unique=`for i in $$list; do \
	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
	  done | \
	  $(AWK) '    { files[$$0] = 1; } \
	       END { for (i in files) print i; }'`; \
	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
	  test -n "$$unique" || unique=$$empty_fix; \
	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
	    $$tags $$unique; \
	fi
ctags: CTAGS
CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
		$(TAGS_FILES) $(LISP)
	tags=; \
	here=`pwd`; \
	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
	unique=`for i in $$list; do \
	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
	  done | \
	  $(AWK) '    { files[$$0] = 1; } \
	       END { for (i in files) print i; }'`; \
	test -z "$(CTAGS_ARGS)$$tags$$unique" \
	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
	     $$tags $$unique

GTAGS:
	here=`$(am__cd) $(top_builddir) && pwd` \
	  && cd $(top_srcdir) \
	  && gtags -i $(GTAGS_ARGS) $$here

distclean-tags:
	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags

distdir: $(DISTFILES)
	$(mkdir_p) $(distdir)/../../../misc
	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
	list='$(DISTFILES)'; for file in $$list; do \
	  case $$file in \
	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
	    $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
	  esac; \
	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
	    dir="/$$dir"; \
	    $(mkdir_p) "$(distdir)$$dir"; \
	  else \
	    dir=''; \
	  fi; \
	  if test -d $$d/$$file; then \
	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
	    fi; \
	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
	  else \
	    test -f $(distdir)/$$file \
	    || cp -p $$d/$$file $(distdir)/$$file \
	    || exit 1; \
	  fi; \
	done
check-am: all-am
check: check-am
all-am: Makefile $(LTLIBRARIES) $(HEADERS)
installdirs:
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am

install-am: all-am
	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am

installcheck: installcheck-am
install-strip:
	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
	  `test -z '$(STRIP)' || \
	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install

clean-generic:

distclean-generic:
	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
clean: clean-am

clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
	mostlyclean-am

distclean: distclean-am
	-rm -rf ./$(DEPDIR)
	-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
	distclean-libtool distclean-tags

dvi: dvi-am

dvi-am:

html: html-am

info: info-am

info-am:

install-data-am:
	@$(NORMAL_INSTALL)
	$(MAKE) $(AM_MAKEFLAGS) install-data-hook

install-exec-am:

install-info: install-info-am

install-man:

installcheck-am:

maintainer-clean: maintainer-clean-am
	-rm -rf ./$(DEPDIR)
	-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic

mostlyclean: mostlyclean-am

mostlyclean-am: mostlyclean-compile mostlyclean-generic \
	mostlyclean-libtool

pdf: pdf-am

pdf-am:

ps: ps-am

ps-am:

uninstall-am: uninstall-info-am
	@$(NORMAL_INSTALL)
	$(MAKE) $(AM_MAKEFLAGS) uninstall-hook

.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
	clean-libtool clean-noinstLTLIBRARIES ctags distclean \
	distclean-compile distclean-generic distclean-libtool \
	distclean-tags distdir dvi dvi-am html html-am info info-am \
	install install-am install-data install-data-am \
	install-data-hook install-exec install-exec-am install-info \
	install-info-am install-man install-strip installcheck \
	installcheck-am installdirs maintainer-clean \
	maintainer-clean-generic mostlyclean mostlyclean-compile \
	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
	tags uninstall uninstall-am uninstall-hook uninstall-info-am


$(XINE_LIB):
	@cd $(top_srcdir)/src/xine-engine && $(MAKE)

install-data-hook:
	@if test $$MAKELEVEL -le 4 ; then \
	  if test -x "$(top_srcdir)/post-install.sh" ; then \
	    $(top_srcdir)/post-install.sh ; \
	  fi \
	fi

pass1:
	@$(MAKE) MULTIPASS_CFLAGS="$(PASS1_CFLAGS)"

pass2:
	@$(MAKE) MULTIPASS_CFLAGS="$(PASS2_CFLAGS)"

debug:
	@$(MAKE) CFLAGS="$(DEBUG_CFLAGS)"

install-debug: debug
	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
	@list='$(SUBDIRS)'; for subdir in $$list; do \
	  (cd $$subdir && $(MAKE) $@) || exit; \
	done;
	$(MAKE) $(AM_MAKEFLAGS) install-data-hook

install-includeHEADERS: $(include_HEADERS)
	@$(NORMAL_INSTALL)
	$(install_sh) -d $(DESTDIR)$(includedir)/xine
	@list='$(include_HEADERS)'; for p in $$list; do \
	  if test -f "$$p"; then d= ; else d="$(srcdir)/"; fi; \
	  echo " $(INSTALL_DATA) $$d$$p $(DESTDIR)$(includedir)/xine/$$p"; \
	  $(INSTALL_DATA) $$d$$p $(DESTDIR)$(includedir)/xine/$$p; \
	done

uninstall-includeHEADERS:
	@$(NORMAL_UNINSTALL)
	list='$(include_HEADERS)'; for p in $$list; do \
	  rm -f $(DESTDIR)$(includedir)/xine/$$p; \
	done

uninstall-hook:
	@if echo '$(libdir)' | egrep ^'$(XINE_PLUGINDIR)' >/dev/null; then \
	  list='$(lib_LTLIBRARIES)'; for p in $$list; do \
	    p="`echo $$p | sed -e 's/\.la$$/\.so/g;s|^.*/||'`"; \
	    echo " rm -f $(DESTDIR)$(libdir)/$$p"; \
	    rm -f $(DESTDIR)$(libdir)/$$p; \
	  done; \
	fi

mostlyclean-generic:
	-rm -f *~ \#* .*~ .\#*

maintainer-clean-generic:
	-@echo "This command is intended for maintainers to use;"
	-@echo "it deletes files that may require special tools to rebuild."
	-rm -f Makefile.in
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

--- NEW FILE: vm.h ---
(This appears to be a binary file; contents omitted.)

--- NEW FILE: read_cache.c ---
/*
 * Copyright (C) 2000 Rich Wareham <richwareham@users.sourceforge.net>
 *               2001-2004 the dvdnav project
 *
 * This file is part of libdvdnav, a DVD navigation library.
 *
 * libdvdnav 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.
 *
 * libdvdnav 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
 *
 * $Id: read_cache.c,v 1.1 2005/04/04 22:29:36 dsalt-guest Exp $
 *
 */
/*
 * There was a multithreaded read ahead cache in here for some time, but
 * it had only been used for a short time. If you want to have a look at it,
 * search the CVS attic.
 */

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

#include "dvdnav.h"
#include "dvdnav_internal.h"
#include "read_cache.h"
#include <sys/time.h>
#include <time.h>

#define READ_CACHE_CHUNKS 10

/* all cache chunks must be memory aligned to allow use of raw devices */
#define ALIGNMENT 2048

#define READ_AHEAD_SIZE_MIN 4
#define READ_AHEAD_SIZE_MAX 512

typedef struct read_cache_chunk_s {
  uint8_t     *cache_buffer;
  uint8_t     *cache_buffer_base;  /* used in malloc and free for alignment */
  int32_t      cache_start_sector; /* -1 means cache invalid */
  int32_t      cache_read_count;   /* this many sectors are already read */
  size_t       cache_block_count;  /* this many sectors will go in this chunk */
  size_t       cache_malloc_size;
  int          cache_valid;
  int          usage_count;  /* counts how many buffers where issued from this chunk */
} read_cache_chunk_t;

struct read_cache_s {
  read_cache_chunk_t  chunk[READ_CACHE_CHUNKS];
  int                 current;
  int                 freeing;  /* is set to one when we are about to dispose the cache */
  uint32_t            read_ahead_size;
  int                 read_ahead_incr;
  int                 last_sector;
  pthread_mutex_t     lock;

  /* Bit of strange cross-linking going on here :) -- Gotta love C :) */
  dvdnav_t           *dvd_self;
};

/*
#define READ_CACHE_TRACE 0
*/

#ifdef __GNUC__
# if READ_CACHE_TRACE
#  define dprintf(fmt, args...) fprintf(MSG_OUT, "libdvdnav: %s: "fmt,  __func__ , ## args)
# else
#  define dprintf(fmt, args...) /* Nowt */
# endif
#else
# if READ_CACHE_TRACE
#  define dprintf(fmt, ...) fprintf(MSG_OUT, "libdvdnav: %s: "fmt,  __func__ , __VA_ARGS__)
# else
#ifdef _MSC_VER
#  define dprintf(fmt, str) /* Nowt */
#else
#  define dprintf(fmt, ...) /* Nowt */
#endif /* _MSC_VER */
# endif
#endif


read_cache_t *dvdnav_read_cache_new(dvdnav_t* dvd_self) {
  read_cache_t *self;
  int i;

  self = (read_cache_t *)malloc(sizeof(read_cache_t));

  if(self) {
    self->current = 0;
    self->freeing = 0;
    self->dvd_self = dvd_self;
    self->last_sector = 0;
    self->read_ahead_size = READ_AHEAD_SIZE_MIN;
    self->read_ahead_incr = 0;
    pthread_mutex_init(&self->lock, NULL);
    dvdnav_read_cache_clear(self);
    for (i = 0; i < READ_CACHE_CHUNKS; i++) {
      self->chunk[i].cache_buffer = NULL;
      self->chunk[i].usage_count = 0;
    }
  }

  return self;
}

void dvdnav_read_cache_free(read_cache_t* self) {
  dvdnav_t *tmp;
  int i;

  pthread_mutex_lock(&self->lock);
  self->freeing = 1;
  for (i = 0; i < READ_CACHE_CHUNKS; i++)
    if (self->chunk[i].cache_buffer && self->chunk[i].usage_count == 0) {
      free(self->chunk[i].cache_buffer_base);
      self->chunk[i].cache_buffer = NULL;
    }
  pthread_mutex_unlock(&self->lock);

  for (i = 0; i < READ_CACHE_CHUNKS; i++)
    if (self->chunk[i].cache_buffer) return;

  /* all buffers returned, free everything */
  tmp = self->dvd_self;
  pthread_mutex_destroy(&self->lock);
  free(self);
  free(tmp);
}

/* This function MUST be called whenever self->file changes. */
void dvdnav_read_cache_clear(read_cache_t *self) {
  int i;

  if(!self)
   return;

  pthread_mutex_lock(&self->lock);
  for (i = 0; i < READ_CACHE_CHUNKS; i++)
    self->chunk[i].cache_valid = 0;
  pthread_mutex_unlock(&self->lock);
}

/* This function is called just after reading the NAV packet. */
void dvdnav_pre_cache_blocks(read_cache_t *self, int sector, size_t block_count) {
  int i, use;

  if(!self)
    return;

  if(!self->dvd_self->use_read_ahead)
    return;

  pthread_mutex_lock(&self->lock);

  /* find a free cache chunk that best fits the required size */
  use = -1;
  for (i = 0; i < READ_CACHE_CHUNKS; i++)
    if (self->chunk[i].usage_count == 0 && self->chunk[i].cache_buffer &&
        self->chunk[i].cache_malloc_size >= block_count &&
        (use == -1 || self->chunk[use].cache_malloc_size > self->chunk[i].cache_malloc_size))
      use = i;

  if (use == -1) {
    /* we haven't found a cache chunk, so we try to reallocate an existing one */
    for (i = 0; i < READ_CACHE_CHUNKS; i++)
      if (self->chunk[i].usage_count == 0 && self->chunk[i].cache_buffer &&
          (use == -1 || self->chunk[use].cache_malloc_size < self->chunk[i].cache_malloc_size))
        use = i;
    if (use >= 0) {
      self->chunk[use].cache_buffer_base = realloc(self->chunk[use].cache_buffer_base,
        block_count * DVD_VIDEO_LB_LEN + ALIGNMENT);
      self->chunk[use].cache_buffer =
        (uint8_t *)(((uintptr_t)self->chunk[use].cache_buffer_base & ~((uintptr_t)(ALIGNMENT - 1))) + ALIGNMENT);
      dprintf("pre_cache DVD read realloc happened\n");
      self->chunk[use].cache_malloc_size = block_count;
    } else {
      /* we still haven't found a cache chunk, let's allocate a new one */
      for (i = 0; i < READ_CACHE_CHUNKS; i++)
        if (!self->chunk[i].cache_buffer) {
	  use = i;
	  break;
	}
      if (use >= 0) {
        /* We start with a sensible figure for the first malloc of 500 blocks.
         * Some DVDs I have seen venture to 450 blocks.
         * This is so that fewer realloc's happen if at all.
         */
	self->chunk[i].cache_buffer_base =
	  malloc((block_count > 500 ? block_count : 500) * DVD_VIDEO_LB_LEN + ALIGNMENT);
	self->chunk[i].cache_buffer =
	  (uint8_t *)(((uintptr_t)self->chunk[i].cache_buffer_base & ~((uintptr_t)(ALIGNMENT - 1))) + ALIGNMENT);
	self->chunk[i].cache_malloc_size = block_count > 500 ? block_count : 500;
	dprintf("pre_cache DVD read malloc %d blocks\n",
	  (block_count > 500 ? block_count : 500 ));
      }
    }
  }

  if (use >= 0) {
    self->chunk[use].cache_start_sector = sector;
    self->chunk[use].cache_block_count = block_count;
    self->chunk[use].cache_read_count = 0;
    self->chunk[use].cache_valid = 1;
    self->current = use;
  } else {
    dprintf("pre_caching was impossible, no cache chunk available\n");
  }
  pthread_mutex_unlock(&self->lock);
}

int dvdnav_read_cache_block(read_cache_t *self, int sector, size_t block_count, uint8_t **buf) {
  int i, use;
  int start;
  int size;
  int incr;
  uint8_t *read_ahead_buf;
  int32_t res;

  if(!self)
    return 0;

  use = -1;

  if(self->dvd_self->use_read_ahead) {
    /* first check, if sector is in current chunk */
    read_cache_chunk_t cur = self->chunk[self->current];
    if (cur.cache_valid && sector >= cur.cache_start_sector &&
        sector <= (cur.cache_start_sector + cur.cache_read_count) &&
        sector + block_count <= cur.cache_start_sector + cur.cache_block_count)
      use = self->current;
    else
      for (i = 0; i < READ_CACHE_CHUNKS; i++)
        if (self->chunk[i].cache_valid &&
            sector >= self->chunk[i].cache_start_sector &&
            sector <= (self->chunk[i].cache_start_sector + self->chunk[i].cache_read_count) &&
            sector + block_count <= self->chunk[i].cache_start_sector + self->chunk[i].cache_block_count)
            use = i;
  }

  if (use >= 0) {
    read_cache_chunk_t *chunk;
    
    /* Increment read-ahead size if sector follows the last sector */
    if (sector == (self->last_sector + 1)) {
      if (self->read_ahead_incr < READ_AHEAD_SIZE_MAX)
        self->read_ahead_incr++;
    } else {
      self->read_ahead_size = READ_AHEAD_SIZE_MIN;
      self->read_ahead_incr = 0;
    }
    self->last_sector = sector;

    /* The following resources need to be protected by a mutex :
     *   self->chunk[*].cache_buffer
     *   self->chunk[*].cache_malloc_size
     *   self->chunk[*].usage_count
     */
    pthread_mutex_lock(&self->lock);
    chunk = &self->chunk[use];
    read_ahead_buf = chunk->cache_buffer + chunk->cache_read_count * DVD_VIDEO_LB_LEN;
    *buf = chunk->cache_buffer + (sector - chunk->cache_start_sector) * DVD_VIDEO_LB_LEN;
    chunk->usage_count++;
    pthread_mutex_unlock(&self->lock);

    dprintf("libdvdnav: sector=%d, start_sector=%d, last_sector=%d\n", sector, chunk->cache_start_sector, chunk->cache_start_sector + chunk->cache_block_count);

    /* read_ahead_size */
    incr = self->read_ahead_incr >> 1;
    if ((self->read_ahead_size + incr) > READ_AHEAD_SIZE_MAX) {
      self->read_ahead_size = READ_AHEAD_SIZE_MAX;
    } else {
      self->read_ahead_size += incr;
    }

    /* real read size */
    start = chunk->cache_start_sector + chunk->cache_read_count;
    if (chunk->cache_read_count + self->read_ahead_size > chunk->cache_block_count) {
      size = chunk->cache_block_count - chunk->cache_read_count;
    } else {
      size = self->read_ahead_size;
      /* ensure that the sector we want will be read */
      if (sector >= chunk->cache_start_sector + chunk->cache_read_count + size)
        size = sector - chunk->cache_start_sector - chunk->cache_read_count;
    }
    dprintf("libdvdnav: read_ahead_size=%d, size=%d\n", self->read_ahead_size, size);

    if (size)
      chunk->cache_read_count += DVDReadBlocks(self->dvd_self->file,
                                               start,
                                               size,
                                               read_ahead_buf);

    res = DVD_VIDEO_LB_LEN * block_count;

  } else {

    if (self->dvd_self->use_read_ahead)
      dprintf("cache miss on sector %d\n", sector);

    res = DVDReadBlocks(self->dvd_self->file,
                        sector,
                        block_count,
                        *buf) * DVD_VIDEO_LB_LEN;
  }

  return res;

}

dvdnav_status_t dvdnav_free_cache_block(dvdnav_t *self, unsigned char *buf) {
  read_cache_t *cache;
  int i;

  if (!self)
    return DVDNAV_STATUS_ERR;

  cache = self->cache;
  if (!cache)
    return DVDNAV_STATUS_ERR;

  pthread_mutex_lock(&cache->lock);
  for (i = 0; i < READ_CACHE_CHUNKS; i++) {
    if (cache->chunk[i].cache_buffer && buf >= cache->chunk[i].cache_buffer &&
        buf < cache->chunk[i].cache_buffer + cache->chunk[i].cache_malloc_size * DVD_VIDEO_LB_LEN) {
      cache->chunk[i].usage_count--;
    }
  }
  pthread_mutex_unlock(&cache->lock);

  if (cache->freeing)
    /* when we want to dispose the cache, try freeing it now */
    dvdnav_read_cache_free(cache);

  return DVDNAV_STATUS_OK;
}

--- NEW FILE: Makefile.am ---
include $(top_srcdir)/misc/Makefile.common

AM_CPPFLAGS = -D_LARGEFILE64_SOURCE -DDVDNAV_COMPILE -DHAVE_DLFCN_H

noinst_LTLIBRARIES = libdvdnav.la

libdvdnav_la_SOURCES = \
	decoder.c \
	dvdnav.c \
	highlight.c \
	navigation.c \
	read_cache.c \
	remap.c \
	searching.c \
	settings.c \
	vm.c \
	vmcmd.c \
	ifo_read.c \
	md5.c \
	nav_print.c \
	nav_read.c \
	dvd_reader.c \
	dvd_input.c \
        dvd_udf.c
libdvdnav_la_LIBADD = $(THREAD_LIBS)
libdvdnav_la_LDFLAGS = -avoid-version -module

noinst_HEADERS = \
	decoder.h \
	dvdnav.h \
	dvdnav_events.h \
	dvdnav_internal.h \
	dvdread_internal.h \
	remap.h \
	vm.h \
	vmcmd.h \
	read_cache.h \
	dvd_types.h \
	ifo_read.h \
	ifo_types.h \
	md5.h \
	nav_print.h \
	nav_read.h \
	nav_types.h \
	dvd_reader.h \
	dvd_input.h \
	dvd_udf.h \
	bswap.h 

--- NEW FILE: ifo_types.h ---
(This appears to be a binary file; contents omitted.)

--- NEW FILE: remap.h ---
/* 
 * This file is part of libdvdnav, a DVD navigation library.
 * 
 * libdvdnav 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.
 * 
 * libdvdnav 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
 *
 * $Id: remap.h,v 1.1 2005/04/04 22:29:36 dsalt-guest Exp $
 */

#ifndef __REMAP__H
#define __REMAP__H
typedef struct block_s block_t;

typedef struct remap_s remap_t;

remap_t* remap_loadmap( char *title);

unsigned long remap_block( 
	remap_t *map, int domain, int title, int program, 
	unsigned long cblock, unsigned long offset);

#endif

--- NEW FILE: dvd_udf.c ---
/*
 * This code is based on dvdudf by:
 *   Christian Wolff <scarabaeus@convergence.de>.
 *
 * Modifications by:
 *   Billy Biggs <vektor@dumbterm.net>.
 *   Björn Englund <d4bjorn@dtek.chalmers.se>.
 *
 * dvdudf: parse and read the UDF volume information of a DVD Video
 * Copyright (C) 1999 Christian Wolff for convergence integrated media
 * GmbH The author can be reached at scarabaeus@convergence.de, the
 * project's page is at http://linuxtv.org/dvd/
 * 
 * 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
[...961 lines suppressed...]
 */
int UDFGetVolumeSetIdentifier(dvd_reader_t *device, uint8_t *volsetid,
			      unsigned int volsetid_size)
{
  struct pvd_t pvd;

  /* get primary volume descriptor */
  if(!UDFGetPVD(device, &pvd)) {
    return 0;
  }


  if(volsetid_size > 128) {
    volsetid_size = 128;
  }
  
  memcpy(volsetid, pvd.VolumeSetIdentifier, volsetid_size);
  
  return 128;
}

--- NEW FILE: bswap.h ---
#ifndef BSWAP_H_INCLUDED
#define BSWAP_H_INCLUDED

/*
 * Copyright (C) 2000, 2001 Billy Biggs <vektor@dumbterm.net>,
 *                          Håkan Hjort <d95hjort@dtek.chalmers.se>
 *
 * 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
 */

#include <config.h>

#if defined(WORDS_BIGENDIAN)
/* All bigendian systems are fine, just ignore the swaps. */  
#define B2N_16(x) (void)(x)
#define B2N_32(x) (void)(x)
#define B2N_64(x) (void)(x)

#else 

/* For __FreeBSD_version */
#if defined(HAVE_SYS_PARAM_H)
#include <sys/param.h>
#endif

#if defined(__linux__)
#include <byteswap.h>
#define B2N_16(x) x = bswap_16(x)
#define B2N_32(x) x = bswap_32(x)
#define B2N_64(x) x = bswap_64(x)

#elif defined(__NetBSD__)
#include <sys/endian.h>
#define B2N_16(x) BE16TOH(x)
#define B2N_32(x) BE32TOH(x)
#define B2N_64(x) BE64TOH(x)

#elif defined(__OpenBSD__)
#include <sys/endian.h>
#define B2N_16(x) x = swap16(x)
#define B2N_32(x) x = swap32(x)
#define B2N_64(x) x = swap64(x)

#elif defined(__FreeBSD__) && __FreeBSD_version >= 470000
#include <sys/endian.h>
#define B2N_16(x) x = be16toh(x)
#define B2N_32(x) x = be32toh(x)
#define B2N_64(x) x = be64toh(x)

/* This is a slow but portable implementation, it has multiple evaluation 
 * problems so beware.
 * Old FreeBSD's and Solaris don't have <byteswap.h> or any other such 
 * functionality! 
 */

#elif defined(__FreeBSD__) || defined(__sun) || defined(__bsdi__) || defined(WIN32) || defined(__CYGWIN__)
#define B2N_16(x) \
 x = ((((x) & 0xff00) >> 8) | \
      (((x) & 0x00ff) << 8))
#define B2N_32(x) \
 x = ((((x) & 0xff000000) >> 24) | \
      (((x) & 0x00ff0000) >>  8) | \
      (((x) & 0x0000ff00) <<  8) | \
      (((x) & 0x000000ff) << 24))
#define B2N_64(x) \
 x = ((((x) & 0xff00000000000000) >> 56) | \
      (((x) & 0x00ff000000000000) >> 40) | \
      (((x) & 0x0000ff0000000000) >> 24) | \
      (((x) & 0x000000ff00000000) >>  8) | \
      (((x) & 0x00000000ff000000) <<  8) | \
      (((x) & 0x0000000000ff0000) << 24) | \
      (((x) & 0x000000000000ff00) << 40) | \
      (((x) & 0x00000000000000ff) << 56))

#else

/* If there isn't a header provided with your system with this functionality
 * add the relevant || define( ) to the portable implementation above.
 */
#error "You need to add endian swap macros for you're system"

#endif

#endif /* WORDS_BIGENDIAN */

#endif /* BSWAP_H_INCLUDED */

--- NEW FILE: vmcmd.h ---
(This appears to be a binary file; contents omitted.)

--- NEW FILE: dvd_udf.h ---
#ifndef DVD_UDF_H_INCLUDED
#define DVD_UDF_H_INCLUDED

/*
 * This code is based on dvdudf by:
 *   Christian Wolff <scarabaeus@convergence.de>.
 *
 * Modifications by:
 *   Billy Biggs <vektor@dumbterm.net>.
 *   Björn Englund <d4bjorn@dtek.chalmers.se>.
 * 
 * dvdudf: parse and read the UDF volume information of a DVD Video
 * Copyright (C) 1999 Christian Wolff for convergence integrated media
 * GmbH The author can be reached at scarabaeus@convergence.de, the
 * project's page is at http://linuxtv.org/dvd/
 * 
 * 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.  Or, point your browser to
 * http://www.gnu.org/copyleft/gpl.html
 */

#include <inttypes.h>

#include "dvd_reader.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
 * Looks for a file on the UDF disc/imagefile and returns the block number
 * where it begins, or 0 if it is not found.  The filename should be an
 * absolute pathname on the UDF filesystem, starting with '/'.  For example,
 * '/VIDEO_TS/VTS_01_1.IFO'.  On success, filesize will be set to the size of
 * the file in bytes.
 */
uint32_t UDFFindFile( dvd_reader_t *device, char *filename, uint32_t *size );

void FreeUDFCache(void *cache);
int UDFGetVolumeIdentifier(dvd_reader_t *device,
			   char *volid, unsigned int volid_size);
int UDFGetVolumeSetIdentifier(dvd_reader_t *device,
			      uint8_t *volsetid, unsigned int volsetid_size);
void *GetUDFCacheHandle(dvd_reader_t *device);
void SetUDFCacheHandle(dvd_reader_t *device, void *cache);

#ifdef __cplusplus
};
#endif
#endif /* DVD_UDF_H_INCLUDED */

--- NEW FILE: remap.c ---
/*
 * This file is part of libdvdnav, a DVD navigation library.
 *
 * libdvdnav 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.
 *
 * libdvdnav 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
 *
 * $Id: remap.c,v 1.1 2005/04/04 22:29:36 dsalt-guest Exp $
 */

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

#ifndef _MSC_VER 
#include <sys/param.h>
#include <sys/fcntl.h>
#else
#ifndef MAXPATHLEN
#define MAXPATHLEN 255
#endif
#endif /* _MSC_VER */

#include <assert.h>
#include "remap.h"
#include "dvdnav_internal.h"

struct block_s {
    int domain;
    int title;
    int program;
    unsigned long start_block;
    unsigned long end_block;
};

struct remap_s {
    char *title;
    int maxblocks;
    int nblocks;
    int debug;
    struct block_s *blocks;
};

static remap_t* remap_new( char *title) {
    remap_t *map = malloc( sizeof(remap_t));
    map->title = strdup(title);
    map->maxblocks = 0;
    map->nblocks = 0;
    map->blocks = NULL;
    map->debug = 0;
    return map;
}

static int compare_block( block_t *a, block_t *b) {
    /* returns -1 if a precedes b, 1 if a follows b, and 0 if a and b overlap */
    if (a->domain < b->domain) {
	return -1;
    } else if (a->domain > b->domain) {
	return 1;
    }

    if (a->title < b->title) {
	return -1;
    } else if (a->title > b->title) {
	return 1;
    }

    if (a->program < b->program) {
	return -1;
    } else if (a->program > b->program) {
	return 1;
    }

    if (a->end_block < b->start_block) {
	return -1;
    } else if (a->start_block > b->end_block) {
	/*
	 * if a->start_block == b->end_block then the two regions
	 * aren't strictly overlapping, but they should be merged 
	 * anyway since there are zero blocks between them
	 */
	return 1;
    }

    return 0;
}

static block_t *findblock( remap_t *map, block_t *key) {
    int lb = 0;
    int ub = map->nblocks - 1;
    int mid;
    int res;

    while (lb <= ub) {
	mid = lb + (ub - lb)/2;
	res = compare_block( key, &map->blocks[mid]);
	if (res < 0) {
	    ub = mid-1;
	} else if (res > 0) {
	    lb = mid+1;
	} else {
	    return &map->blocks[mid];
	}
    }
    return NULL;
}

static void mergeblock( block_t *b, block_t tmp) {
    if (tmp.start_block < b->start_block) b->start_block = tmp.start_block;
    if (tmp.end_block > b->end_block) b->end_block = tmp.end_block;
}

static void remap_add_node( remap_t *map, block_t block) {
    block_t *b;
    int n;
    b = findblock( map, &block);
    if (b) {
	/* overlaps an existing block */
	mergeblock( b, block);
    } else {
        /* new block */
	if (map->nblocks >= map->maxblocks) {
	    map->maxblocks += 20;
	    map->blocks = realloc( map->blocks, sizeof( block_t)*map->maxblocks);
	}
	n = map->nblocks++;
	while (n > 0 && compare_block( &block, &map->blocks[ n-1]) < 0) {
	    map->blocks[ n] = map->blocks[ n-1];
	    n--;
	}
	map->blocks[ n] = block;
    }
}

static int parseblock(char *buf, int *dom, int *tt, int *pg, 
		      unsigned long *start, unsigned long *end) {
    long tmp;
    char *tok;
    char *epos;
    char *marker[]={"domain", "title", "program", "start", "end"};
    int st = 0;
    tok = strtok( buf, " ");
    while (st < 5) {
        if (strcmp(tok, marker[st])) return -st-1000;
        tok = strtok( NULL, " ");
        if (!tok) return -st-2000;
        tmp = strtol( tok, &epos, 0);
        if (*epos != 0 && *epos != ',') return -st-3000;
        switch (st) {
	    case 0:
		*dom = (int)tmp;
		break;
	    case 1:
		*tt = (int)tmp;
		break;
	    case 2:
		*pg = (int)tmp;
		break;
	    case 3:
		*start = tmp;
		break;
	    case 4:
		*end = tmp;
		break;
	} 
	st++;
        tok = strtok( NULL, " ");
    }
    return st;
}

remap_t* remap_loadmap( char *title) {
    char buf[160];
    char fname[MAXPATHLEN];
    char *home;
    int res;
    FILE *fp;
    block_t tmp;
    remap_t *map;

    /* Build the map filename */
    home = getenv("HOME"); assert(home);
    strncpy(fname, home, sizeof(fname));
    strncat(fname, "/.dvdnav/", sizeof(fname));
    strncat(fname, title, sizeof(fname));
    strncat(fname, ".map", sizeof(fname));

    /* Open the map file */
    fp = fopen( fname, "r");
    if (!fp) {
	fprintf(MSG_OUT, "libdvdnav: Unable to find map file '%s'\n", fname);
	return NULL;
    }

    /* Load the map file */
    map = remap_new( title);
    while (fgets( buf, sizeof(buf), fp) != NULL) {
        if (buf[0] == '\n' || buf[0] == '#' || buf[0] == 0) continue;
        if (strncasecmp( buf, "debug", 5) == 0) {
	    map->debug = 1;
	} else {
	    res = parseblock( buf, 
		&tmp.domain, &tmp.title, &tmp.program, &tmp.start_block, &tmp.end_block);
	    if (res != 5) {
		fprintf(MSG_OUT, "libdvdnav: Ignoring map line (%d): %s\n", res, buf);
		continue;
	    }
	    remap_add_node( map, tmp);
	}
    }

    if (map->nblocks == 0 && map->debug == 0) return NULL;
    return map;
}

unsigned long remap_block( 
	remap_t *map, int domain, int title, int program, 
	unsigned long cblock, unsigned long offset) 
{
    block_t key;
    block_t *b;

    if (map->debug) {
	fprintf(MSG_OUT, "libdvdnav: %s: domain %d, title %d, program %d, start %lx, next %lx\n",
	    map->title, domain, title, program, cblock, cblock+offset);
    }

    key.domain = domain;
    key.title = title;
    key.program = program;
    key.start_block = key.end_block = cblock + offset;
    b = findblock( map, &key);
    
    if (b) {
       if (map->debug) {
	   fprintf(MSG_OUT, "libdvdnav: Redirected to %lx\n", b->end_block);
       }
       return b->end_block - cblock;
    }
    return offset;
}

--- NEW FILE: dvdnav_internal.h ---
/* 
 * Copyright (C) 2001-2004 Rich Wareham <richwareham@users.sourceforge.net>
 * 
 * This file is part of libdvdnav, a DVD navigation library.
 * 
 * libdvdnav 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.
 * 
 * libdvdnav 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
 *
 * $Id: dvdnav_internal.h,v 1.1 2005/04/04 22:29:35 dsalt-guest Exp $
 *
 */

#ifndef DVDNAV_INTERNAL_H_INCLUDED
#define DVDNAV_INTERNAL_H_INCLUDED

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

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <limits.h>
#include <string.h>

#ifdef WIN32

/* pthread_mutex_* wrapper for win32 */
#include <windows.h>
#include <process.h>
typedef CRITICAL_SECTION pthread_mutex_t;
#define pthread_mutex_init(a, b) InitializeCriticalSection(a)
#define pthread_mutex_lock(a)    EnterCriticalSection(a)
#define pthread_mutex_unlock(a)  LeaveCriticalSection(a)
#define pthread_mutex_destroy(a)

/* replacement gettimeofday implementation */
#include <sys/timeb.h>
static inline int _private_gettimeofday( struct timeval *tv, void *tz )
{
  struct timeb t;
  ftime( &t );
  tv->tv_sec = t.time;
  tv->tv_usec = t.millitm * 1000;
  return 0;
}
#define gettimeofday(TV, TZ) _private_gettimeofday((TV), (TZ))
#include <io.h> /* read() */
#define lseek64 _lseeki64

#else

#include <pthread.h>

#endif /* WIN32 */

/* Uncomment for VM command tracing */
/* #define TRACE */

#include "decoder.h"
#include "dvdnav.h"
#include "vm.h"
#include "vmcmd.h"

/* where should libdvdnav write its messages (stdout/stderr) */
#define MSG_OUT stdout

/* Maximum length of an error string */
#define MAX_ERR_LEN 255

/* Use the POSIX PATH_MAX if available */
#ifdef PATH_MAX
#define MAX_PATH_LEN PATH_MAX
#else
#define MAX_PATH_LEN 255 /* Arbitrary */
#endif

#ifndef DVD_VIDEO_LB_LEN
#define DVD_VIDEO_LB_LEN 2048
#endif

typedef struct read_cache_s read_cache_t;

/*
 * These are defined here because they are
 * not in ifo_types.h, they maybe one day 
 */

#ifndef audio_status_t
typedef struct {
#ifdef WORDS_BIGENDIAN
  unsigned int available     : 1;
  unsigned int zero1         : 4;
  unsigned int stream_number : 3;
  uint8_t zero2;
#else
  uint8_t zero2;
  unsigned int stream_number : 3;
  unsigned int zero1         : 4;  
  unsigned int available     : 1;
#endif
} ATTRIBUTE_PACKED audio_status_t;
#endif

#ifndef spu_status_t
typedef struct {
#ifdef WORDS_BIGENDIAN
  unsigned int available               : 1;
  unsigned int zero1                   : 2;
  unsigned int stream_number_4_3       : 5;
  unsigned int zero2                   : 3;
  unsigned int stream_number_wide      : 5;
  unsigned int zero3                   : 3;
  unsigned int stream_number_letterbox : 5;
  unsigned int zero4                   : 3;
  unsigned int stream_number_pan_scan  : 5;
#else
  unsigned int stream_number_pan_scan  : 5;
  unsigned int zero4                   : 3;
  unsigned int stream_number_letterbox : 5;
  unsigned int zero3                   : 3;
  unsigned int stream_number_wide      : 5;
  unsigned int zero2                   : 3;
  unsigned int stream_number_4_3       : 5;
  unsigned int zero1                   : 2;
  unsigned int available               : 1;
#endif
} ATTRIBUTE_PACKED spu_status_t;
#endif

typedef struct dvdnav_vobu_s {
  int32_t vobu_start;  /* Logical Absolute. MAX needed is 0x300000 */
  int32_t vobu_length;
  int32_t blockN;      /* Relative offset */
  int32_t vobu_next;   /* Relative offset */
} dvdnav_vobu_t;  
   
/** The main DVDNAV type **/

struct dvdnav_s {
  /* General data */
  char        path[MAX_PATH_LEN]; /* Path to DVD device/dir */
  dvd_file_t *file;               /* Currently opened file */
 
  /* Position data */
  vm_position_t position_next;
  vm_position_t position_current;
  dvdnav_vobu_t vobu;  

  /* NAV data */
  pci_t pci;
  dsi_t dsi;
  uint32_t last_cmd_nav_lbn;      /* detects when a command is issued on an already left NAV */
  
  /* Flags */
  int skip_still;                 /* Set when skipping a still */
  int sync_wait;                  /* applications should wait till they are in sync with us */
  int sync_wait_skip;             /* Set when skipping wait state */
  int spu_clut_changed;           /* The SPU CLUT changed */ 
  int started;                    /* vm_start has been called? */
  int use_read_ahead;             /* 1 - use read-ahead cache, 0 - don't */
  int pgc_based;                  /* positioning works PGC based instead of PG based */
  
  /* VM */
  vm_t *vm;
  pthread_mutex_t vm_lock;

  /* Read-ahead cache */
  read_cache_t *cache;

  /* Errors */
  char err_str[MAX_ERR_LEN];
};

/** USEFUL MACROS **/

#ifdef __GNUC__
#define printerrf(format, args...) snprintf(this->err_str, MAX_ERR_LEN, format, ## args);
#else
#ifdef _MSC_VER
#define printerrf(str) snprintf(this->err_str, MAX_ERR_LEN, str);
#else
#define printerrf(...) snprintf(this->err_str, MAX_ERR_LEN, __VA_ARGS__);
#endif /* WIN32 */
#endif
#define printerr(str) strncpy(this->err_str, str, MAX_ERR_LEN);

#endif /* DVDNAV_INTERNAL_H_INCLUDED */

--- NEW FILE: vmcmd.c ---
(This appears to be a binary file; contents omitted.)

--- NEW FILE: highlight.c ---
/* 
 * Copyright (C) 2000 Rich Wareham <richwareham@users.sourceforge.net>
 * 
 * This file is part of libdvdnav, a DVD navigation library.
 * 
 * libdvdnav 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.
 * 
 * libdvdnav 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
 *
 * $Id: highlight.c,v 1.1 2005/04/04 22:29:35 dsalt-guest Exp $
 *
 */

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

#include <assert.h>
#include "nav_types.h"
#include "dvdnav_internal.h"

/*
#define BUTTON_TESTING
*/

#ifdef BUTTON_TESTING

#include "nav_print.h"

static void print_time(dvd_time_t *dtime) {
  const char *rate;

  assert((dtime->hour>>4) < 0xa && (dtime->hour&0xf) < 0xa);
  assert((dtime->minute>>4) < 0x7 && (dtime->minute&0xf) < 0xa);
  assert((dtime->second>>4) < 0x7 && (dtime->second&0xf) < 0xa);
  assert((dtime->frame_u&0xf) < 0xa);

  fprintf(MSG_OUT,"%02x:%02x:%02x.%02x",
         dtime->hour,
         dtime->minute,
         dtime->second,
         dtime->frame_u & 0x3f);
  switch((dtime->frame_u & 0xc0) >> 6) {
  case 1:
    rate = "25.00";
    break;
  case 3:
    rate = "29.97";
    break;
  default:
    rate = "(please send a bug report)";
    break;
  }
  fprintf(MSG_OUT," @ %s fps", rate);
}

static void nav_print_PCI_GI(pci_gi_t *pci_gi) {
  int32_t i;

  fprintf(MSG_OUT,"libdvdnav: pci_gi:\n");
  fprintf(MSG_OUT,"libdvdnav: nv_pck_lbn    0x%08x\n", pci_gi->nv_pck_lbn);
  fprintf(MSG_OUT,"libdvdnav: vobu_cat      0x%04x\n", pci_gi->vobu_cat);
  fprintf(MSG_OUT,"libdvdnav: vobu_uop_ctl  0x%08x\n", *(uint32_t*)&pci_gi->vobu_uop_ctl);
  fprintf(MSG_OUT,"libdvdnav: vobu_s_ptm    0x%08x\n", pci_gi->vobu_s_ptm);
  fprintf(MSG_OUT,"libdvdnav: vobu_e_ptm    0x%08x\n", pci_gi->vobu_e_ptm);
  fprintf(MSG_OUT,"libdvdnav: vobu_se_e_ptm 0x%08x\n", pci_gi->vobu_se_e_ptm);
  fprintf(MSG_OUT,"libdvdnav: e_eltm        ");
  print_time(&pci_gi->e_eltm);
  fprintf(MSG_OUT,"\n");

  fprintf(MSG_OUT,"libdvdnav: vobu_isrc     \"");
  for(i = 0; i < 32; i++) {
    char c = pci_gi->vobu_isrc[i];
    if((c >= ' ') && (c <= '~'))
      fprintf(MSG_OUT,"%c", c);
    else
      fprintf(MSG_OUT,".");
  }
  fprintf(MSG_OUT,"\"\n");
}

static void nav_print_NSML_AGLI(nsml_agli_t *nsml_agli) {
  int32_t i, j = 0;

  for(i = 0; i < 9; i++)
    j |= nsml_agli->nsml_agl_dsta[i];
  if(j == 0)
    return;

  fprintf(MSG_OUT,"libdvdnav: nsml_agli:\n");
  for(i = 0; i < 9; i++)
    if(nsml_agli->nsml_agl_dsta[i])
      fprintf(MSG_OUT,"libdvdnav: nsml_agl_c%d_dsta  0x%08x\n", i + 1,
             nsml_agli->nsml_agl_dsta[i]);
}

static void nav_print_HL_GI(hl_gi_t *hl_gi, int32_t *btngr_ns, int32_t *btn_ns) {

  if((hl_gi->hli_ss & 0x03) == 0)
    return;

  fprintf(MSG_OUT,"libdvdnav: hl_gi:\n");
  fprintf(MSG_OUT,"libdvdnav: hli_ss        0x%01x\n", hl_gi->hli_ss & 0x03);
  fprintf(MSG_OUT,"libdvdnav: hli_s_ptm     0x%08x\n", hl_gi->hli_s_ptm);
  fprintf(MSG_OUT,"libdvdnav: hli_e_ptm     0x%08x\n", hl_gi->hli_e_ptm);
  fprintf(MSG_OUT,"libdvdnav: btn_se_e_ptm  0x%08x\n", hl_gi->btn_se_e_ptm);

  *btngr_ns = hl_gi->btngr_ns;
  fprintf(MSG_OUT,"libdvdnav: btngr_ns      %d\n",  hl_gi->btngr_ns);
  fprintf(MSG_OUT,"libdvdnav: btngr%d_dsp_ty    0x%02x\n", 1, hl_gi->btngr1_dsp_ty);
  fprintf(MSG_OUT,"libdvdnav: btngr%d_dsp_ty    0x%02x\n", 2, hl_gi->btngr2_dsp_ty);
  fprintf(MSG_OUT,"libdvdnav: btngr%d_dsp_ty    0x%02x\n", 3, hl_gi->btngr3_dsp_ty);

  fprintf(MSG_OUT,"libdvdnav: btn_ofn       %d\n", hl_gi->btn_ofn);
  *btn_ns = hl_gi->btn_ns;
  fprintf(MSG_OUT,"libdvdnav: btn_ns        %d\n", hl_gi->btn_ns);
  fprintf(MSG_OUT,"libdvdnav: nsl_btn_ns    %d\n", hl_gi->nsl_btn_ns);
  fprintf(MSG_OUT,"libdvdnav: fosl_btnn     %d\n", hl_gi->fosl_btnn);
  fprintf(MSG_OUT,"libdvdnav: foac_btnn     %d\n", hl_gi->foac_btnn);
}

static void nav_print_BTN_COLIT(btn_colit_t *btn_colit) {
  int32_t i, j;

  j = 0;
  for(i = 0; i < 6; i++)
    j |= btn_colit->btn_coli[i/2][i&1];
  if(j == 0)
    return;

  fprintf(MSG_OUT,"libdvdnav: btn_colit:\n");
  for(i = 0; i < 3; i++)
    for(j = 0; j < 2; j++)
      fprintf(MSG_OUT,"libdvdnav: btn_cqoli %d  %s_coli:  %08x\n",
             i, (j == 0) ? "sl" : "ac",
             btn_colit->btn_coli[i][j]);
}

static void nav_print_BTNIT(btni_t *btni_table, int32_t btngr_ns, int32_t btn_ns) {
  int32_t i, j, k;

  fprintf(MSG_OUT,"libdvdnav: btnit:\n");
  fprintf(MSG_OUT,"libdvdnav: btngr_ns: %i\n", btngr_ns);
  fprintf(MSG_OUT,"libdvdnav: btn_ns: %i\n", btn_ns);

  if(btngr_ns == 0)
    return;

  for(i = 0; i < btngr_ns; i++) {
    for(j = 0; j < (36 / btngr_ns); j++) {
      if(j < btn_ns) {
        btni_t *btni = &btni_table[(36 / btngr_ns) * i + j];

        fprintf(MSG_OUT,"libdvdnav: group %d btni %d:  ", i+1, j+1);
        fprintf(MSG_OUT,"btn_coln %d, auto_action_mode %d\n",
               btni->btn_coln, btni->auto_action_mode);
        fprintf(MSG_OUT,"libdvdnav: coords   (%d, %d) .. (%d, %d)\n",
               btni->x_start, btni->y_start, btni->x_end, btni->y_end);

        fprintf(MSG_OUT,"libdvdnav: up %d, ", btni->up);
        fprintf(MSG_OUT,"down %d, ", btni->down);
        fprintf(MSG_OUT,"left %d, ", btni->left);
        fprintf(MSG_OUT,"right %d\n", btni->right);
        for(k = 0; k < 8; k++) {
          fprintf(MSG_OUT, "libdvdnav: %02x ", btni->cmd.bytes[k]);
        }
        fprintf(MSG_OUT, "| ");
#ifdef TRACE
        vm_print_mnemonic(&btni->cmd);
#endif
        fprintf(MSG_OUT, "\n");
      }
    }
  }
}

static void nav_print_HLI(hli_t *hli) {
  int32_t btngr_ns = 0, btn_ns = 0;

  fprintf(MSG_OUT,"libdvdnav: hli:\n");
  nav_print_HL_GI(&hli->hl_gi, & btngr_ns, & btn_ns);
  nav_print_BTN_COLIT(&hli->btn_colit);
  nav_print_BTNIT(hli->btnit, btngr_ns, btn_ns);
}

void nav_print_PCI(pci_t *pci) {
  fprintf(MSG_OUT,"libdvdnav: pci packet:\n");
  nav_print_PCI_GI(&pci->pci_gi);
  nav_print_NSML_AGLI(&pci->nsml_agli);
  nav_print_HLI(&pci->hli);
}

#endif


/* Highlighting API calls */

dvdnav_status_t dvdnav_get_current_highlight(dvdnav_t *this, int32_t *button) {
  
  if(!this || !button) {
    printerr("Passed a NULL pointer.");
    return DVDNAV_STATUS_ERR;
  }

  /* Simply return the appropriate value based on the SPRM */
  if(((*button) = this->position_current.button) == -1)
    (*button) = this->vm->state.HL_BTNN_REG >> 10;
  
  return DVDNAV_STATUS_OK;
}

static btni_t *get_current_button(dvdnav_t *this, pci_t *pci) {
  int32_t button = 0;

  if(!this || !pci) {
    printerr("Passed a NULL pointer.");
    return NULL;
  }
  if(!pci->hli.hl_gi.hli_ss) {
    printerr("Not in a menu.");
    return NULL;
  }
  if(this->last_cmd_nav_lbn == pci->pci_gi.nv_pck_lbn) {
    printerr("This NAV has already been left.");
    return NULL;
  }

  button = this->vm->state.HL_BTNN_REG >> 10;
#ifdef BUTTON_TESTING
  nav_print_PCI(pci);
#endif
  
  return &(pci->hli.btnit[button-1]);
}

static dvdnav_status_t button_auto_action(dvdnav_t *this, pci_t *pci) {
  if (get_current_button(this, pci)->auto_action_mode)
    return dvdnav_button_activate(this, pci);
  return DVDNAV_STATUS_OK;
}

dvdnav_status_t dvdnav_upper_button_select(dvdnav_t *this, pci_t *pci) {
  btni_t *button_ptr;
  
  if(!(button_ptr = get_current_button(this, pci)))
    return DVDNAV_STATUS_ERR;

  dvdnav_button_select(this, pci, button_ptr->up);
  return button_auto_action(this, pci);
}

dvdnav_status_t dvdnav_lower_button_select(dvdnav_t *this, pci_t *pci) {
  btni_t *button_ptr;
  
  if(!(button_ptr = get_current_button(this, pci)))
    return DVDNAV_STATUS_ERR;

  dvdnav_button_select(this, pci, button_ptr->down);
  return button_auto_action(this, pci);
}

dvdnav_status_t dvdnav_right_button_select(dvdnav_t *this, pci_t *pci) {
  btni_t *button_ptr;
  
  if(!(button_ptr = get_current_button(this, pci)))
    return DVDNAV_STATUS_ERR;

  dvdnav_button_select(this, pci, button_ptr->right);
  return button_auto_action(this, pci);
}

dvdnav_status_t dvdnav_left_button_select(dvdnav_t *this, pci_t *pci) {
  btni_t *button_ptr;
  
  if(!(button_ptr = get_current_button(this, pci)))
    return DVDNAV_STATUS_ERR;

  dvdnav_button_select(this, pci, button_ptr->left);
  return button_auto_action(this, pci);
}

dvdnav_status_t dvdnav_get_highlight_area(pci_t *nav_pci , int32_t button, int32_t mode, 
					  dvdnav_highlight_area_t *highlight) {
  btni_t *button_ptr;

#ifdef BUTTON_TESTING
  fprintf(MSG_OUT, "libdvdnav: Button get_highlight_area %i\n", button);
#endif
  
  if(!nav_pci->hli.hl_gi.hli_ss)
    return DVDNAV_STATUS_ERR;
  if((button <= 0) || (button > nav_pci->hli.hl_gi.btn_ns))
    return DVDNAV_STATUS_ERR;


  button_ptr = &nav_pci->hli.btnit[button-1];

  highlight->sx = button_ptr->x_start;
  highlight->sy = button_ptr->y_start;
  highlight->ex = button_ptr->x_end;
  highlight->ey = button_ptr->y_end;
  if(button_ptr->btn_coln != 0) {
    highlight->palette = nav_pci->hli.btn_colit.btn_coli[button_ptr->btn_coln-1][mode];
  } else {
    highlight->palette = 0;
  }
  highlight->pts = nav_pci->hli.hl_gi.hli_s_ptm;
  highlight->buttonN = button;
#ifdef BUTTON_TESTING
  fprintf(MSG_OUT, "libdvdnav: highlight: Highlight area is (%u,%u)-(%u,%u), display = %i, button = %u\n",
               button_ptr->x_start, button_ptr->y_start,
               button_ptr->x_end, button_ptr->y_end,
               1,
               button);
#endif

  return DVDNAV_STATUS_OK;
}

dvdnav_status_t dvdnav_button_activate(dvdnav_t *this, pci_t *pci) {
  int32_t button;
  btni_t *button_ptr = NULL;

  if(!this || !pci) {
    printerr("Passed a NULL pointer.");
    return DVDNAV_STATUS_ERR;
  }
  if(!pci->hli.hl_gi.hli_ss) {
    printerr("Not in a menu.");
    return DVDNAV_STATUS_ERR;
  }
  if(this->last_cmd_nav_lbn == pci->pci_gi.nv_pck_lbn) {
    printerr("This NAV has already been left.");
    return DVDNAV_STATUS_ERR;
  }
  pthread_mutex_lock(&this->vm_lock); 

  button = this->vm->state.HL_BTNN_REG >> 10;

  if((button <= 0) || (button > pci->hli.hl_gi.btn_ns)) {
    /* Special code to handle still menus with no buttons.
     * The navigation is expected to report to the application that a STILL is
     * underway. In turn, the application is supposed to report to the user
     * that the playback is paused. The user is then expected to undo the pause,
     * ie: hit play. At that point, the navigation should release the still and
     * go to the next Cell.
     * Explanation by Mathieu Lacage <mathieu_lacage@realmagic.fr>
     * Code added by jcdutton.
     */
    if (this->position_current.still != 0) {
      /* In still, but no buttons. */
      vm_get_next_cell(this->vm);
      this->position_current.still = 0;
      this->sync_wait = 0;
      this->last_cmd_nav_lbn = pci->pci_gi.nv_pck_lbn;
      pthread_mutex_unlock(&this->vm_lock);
      /* clear error message */
      printerr("");
      return DVDNAV_STATUS_OK;
    }
    pthread_mutex_unlock(&this->vm_lock); 
    return DVDNAV_STATUS_ERR;
  }
  
  button_ptr = get_current_button(this, pci);
  /* Finally, make the VM execute the appropriate code and probably
   * scedule a jump */
#ifdef BUTTON_TESTING
  fprintf(MSG_OUT, "libdvdnav: Evaluating Button Activation commands.\n");
#endif
  if(vm_exec_cmd(this->vm, &(button_ptr->cmd)) == 1) {
    /* Command caused a jump */
    this->vm->hop_channel++;
    this->position_current.still = 0;
    this->last_cmd_nav_lbn = pci->pci_gi.nv_pck_lbn;
  }
  
  pthread_mutex_unlock(&this->vm_lock); 
  return DVDNAV_STATUS_OK;
}

dvdnav_status_t dvdnav_button_activate_cmd(dvdnav_t *this, int32_t button, vm_cmd_t *cmd)
{
  if(!this || !cmd) {
    printerr("Passed a NULL pointer.");
    return DVDNAV_STATUS_ERR;
  }
  
  pthread_mutex_lock(&this->vm_lock);
  /* make the VM execute the appropriate code and probably
   * schedule a jump */
#ifdef BUTTON_TESTING
  fprintf(MSG_OUT, "libdvdnav: dvdnav_button_activate_cmd: Evaluating Button Activation commands.\n");
#endif
  if(button > 0) {
    this->vm->state.HL_BTNN_REG = (button << 10);
    if(vm_exec_cmd(this->vm, cmd) == 1) {
      /* Command caused a jump */
      this->vm->hop_channel++;
    }
  }
  /* Always remove still, because some still menus have no buttons. */
  this->position_current.still = 0;
  this->sync_wait = 0;
  pthread_mutex_unlock(&this->vm_lock);
  return DVDNAV_STATUS_OK;
}  

dvdnav_status_t dvdnav_button_select(dvdnav_t *this, pci_t *pci, int32_t button) {
  
  if(!this || !pci) {
    printerr("Passed a NULL pointer.");
    return DVDNAV_STATUS_ERR;
  }
  if(!pci->hli.hl_gi.hli_ss) {
    printerr("Not in a menu.");
    return DVDNAV_STATUS_ERR;
  }
  if(this->last_cmd_nav_lbn == pci->pci_gi.nv_pck_lbn) {
    printerr("This NAV has already been left.");
    return DVDNAV_STATUS_ERR;
  }
 
#ifdef BUTTON_TESTING
  fprintf(MSG_OUT, "libdvdnav: Button select %i\n", button); 
#endif
  
  if((button <= 0) || (button > pci->hli.hl_gi.btn_ns)) {
    printerr("Button does not exist.");
    return DVDNAV_STATUS_ERR;
  }
  
  this->vm->state.HL_BTNN_REG = (button << 10);
  this->position_current.button = -1; /* Force Highligh change */

  return DVDNAV_STATUS_OK;
}

dvdnav_status_t dvdnav_button_select_and_activate(dvdnav_t *this, pci_t *pci, 
						  int32_t button) {
  /* A trivial function */
  if(dvdnav_button_select(this, pci, button) != DVDNAV_STATUS_ERR)
    return dvdnav_button_activate(this, pci);
  return DVDNAV_STATUS_ERR;
}

dvdnav_status_t dvdnav_mouse_select(dvdnav_t *this, pci_t *pci, int32_t x, int32_t y) {
  int32_t button, cur_button;
  int32_t best,dist,d;
  int32_t mx,my,dx,dy;

  if(!this || !pci) {
    printerr("Passed a NULL pointer.");
    return DVDNAV_STATUS_ERR;
  }
  if(!pci->hli.hl_gi.hli_ss) {
    printerr("Not in a menu.");
    return DVDNAV_STATUS_ERR;
  }
  if(this->last_cmd_nav_lbn == pci->pci_gi.nv_pck_lbn) {
    printerr("This NAV has already been left.");
    return DVDNAV_STATUS_ERR;
  }

  cur_button = this->vm->state.HL_BTNN_REG >> 10;

  best = 0;
  dist = 0x08000000; /* >> than  (720*720)+(567*567); */
  
  /* Loop through all buttons */
  for(button = 1; button <= pci->hli.hl_gi.btn_ns; button++) {
    btni_t *button_ptr = &(pci->hli.btnit[button-1]);

    if((x >= button_ptr->x_start) && (x <= button_ptr->x_end) &&
       (y >= button_ptr->y_start) && (y <= button_ptr->y_end)) {
      mx = (button_ptr->x_start + button_ptr->x_end)/2;
      my = (button_ptr->y_start + button_ptr->y_end)/2;
      dx = mx - x;
      dy = my - y;
      d = (dx*dx) + (dy*dy);
      /* If the mouse is within the button and the mouse is closer
       * to the center of this button then it is the best choice. */
      if(d < dist) {
        dist = d;
        best = button;
      }
    }
  }
  /* As an efficiency measure, only re-select the button
   * if it is different to the previously selected one. */
  if (best != 0 && best != cur_button)
    dvdnav_button_select(this, pci, best);

  /* return DVDNAV_STATUS_OK only if we actually found a matching button */
  return best ? DVDNAV_STATUS_OK : DVDNAV_STATUS_ERR;
}

dvdnav_status_t dvdnav_mouse_activate(dvdnav_t *this, pci_t *pci, int32_t x, int32_t y) {
  /* A trivial function */
  if(dvdnav_mouse_select(this, pci, x,y) != DVDNAV_STATUS_ERR)
    return dvdnav_button_activate(this, pci);
  return DVDNAV_STATUS_ERR;
}

--- NEW FILE: dvdnav.h ---
/* 
 * Copyright (C) 2001 Rich Wareham <richwareham@users.sourceforge.net>
 * 
 * This file is part of libdvdnav, a DVD navigation library.
 * 
 * libdvdnav 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.
 * 
 * libdvdnav 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
 *
 * $Id: dvdnav.h,v 1.1 2005/04/04 22:29:35 dsalt-guest Exp $
 *
 */

/*
 * This is the main header file applications should include if they want
 * to access dvdnav functionality.
 */

#ifndef DVDNAV_H_INCLUDED
#define DVDNAV_H_INCLUDED

#ifdef __cplusplus
extern "C" {
#endif

#ifdef DVDNAV_COMPILE
#  include "dvdnav_events.h"
#  include "dvd_types.h"
#  include "dvd_reader.h"
#  include "ifo_types.h" /* For vm_cmd_t */
#else
#  include <dvdnav/dvdnav_events.h>
#  include <dvdnav/dvd_types.h>
#  include <dvdnav/dvd_reader.h>
#  include <dvdnav/ifo_types.h> /* For vm_cmd_t */
#endif



/*********************************************************************
 * dvdnav data types                                                 *
 *********************************************************************/

/*
 * Opaque data-type can be viewed as a 'DVD handle'. You should get
 * a pointer to a dvdnav_t from the dvdnav_open() function.
 * Never call free() on the pointer, you have to give it back with
 * dvdnav_close().
 */
typedef struct dvdnav_s dvdnav_t;

/* Status as reported by most of libdvdnav's functions */
typedef int32_t dvdnav_status_t;

/*
 * Unless otherwise stated, all functions return DVDNAV_STATUS_OK if
 * they succeeded, otherwise DVDNAV_STATUS_ERR is returned and the error may
 * be obtained by calling dvdnav_err_to_string().
 */
#define DVDNAV_STATUS_ERR 0
#define DVDNAV_STATUS_OK  1


/*********************************************************************
 * initialisation & housekeeping functions                           *
 *********************************************************************/

/*
 * These functions allow you to open a DVD device and associate it
 * with a dvdnav_t.
 */

/*
 * Attempts to open the DVD drive at the specified path and pre-cache
 * the CSS-keys. libdvdread is used to access the DVD, so any source
 * supported by libdvdread can be given with "path". Currently,
 * libdvdread can access: DVD drives, DVD image files, DVD file-by-file
 * copies.
 *
 * The resulting dvdnav_t handle will be written to *dest.
 */
dvdnav_status_t dvdnav_open(dvdnav_t **dest, const char *path);

/*
 * Closes a dvdnav_t previously opened with dvdnav_open(), freeing any 
 * memory associated with it.
 */
dvdnav_status_t dvdnav_close(dvdnav_t *self);

/*
 * Resets the DVD virtual machine and cache buffers.
 */
dvdnav_status_t dvdnav_reset(dvdnav_t *self);

/*
 * Fills a pointer with a value pointing to a string describing
 * the path associated with an open dvdnav_t. It assigns *path to NULL
 * on error.
 */
dvdnav_status_t dvdnav_path(dvdnav_t *self, const char **path);

/*
 * Returns a human-readable string describing the last error.
 */
const char* dvdnav_err_to_string(dvdnav_t *self);


/*********************************************************************
 * changing and reading DVD player characteristics                   *
 *********************************************************************/

/*
 * These functions allow you to manipulate the various global characteristics
 * of the DVD playback engine.
 */

/*
 * Sets the region mask (bit 0 set implies region 1, bit 1 set implies
 * region 2, etc) of the virtual machine. Generally you will only need to set
 * this if you are playing RCE discs which query the virtual machine as to its
 * region setting. 
 *
 * This has _nothing_ to do with the region setting of the DVD drive.
 */
dvdnav_status_t dvdnav_set_region_mask(dvdnav_t *self, int32_t region_mask);

/*
 * Returns the region mask (bit 0 set implies region 1, bit 1 set implies
 * region 2, etc) of the virtual machine.
 *
 * This has _nothing_ to do with the region setting of the DVD drive.
 */
dvdnav_status_t dvdnav_get_region_mask(dvdnav_t *self, int32_t *region_mask);

/*
 * Specify whether read-ahead caching should be used. You may not want this if your
 * decoding engine does its own buffering.
 *
 * The default read-ahead cache does not use an additional thread for the reading
 * (see read_cache.c for a threaded cache, but note that this code is currently
 * unmaintained). It prebuffers on VOBU level by reading ahead several buffers
 * on every read request. The speed of this prebuffering has been optimized to
 * also work on slow DVD drives.
 *
 * If in addition you want to prevent memcpy's to improve performance, have a look
 * at dvdnav_get_next_cache_block().
 */
dvdnav_status_t dvdnav_set_readahead_flag(dvdnav_t *self, int32_t read_ahead_flag);

/*
 * Query whether read-ahead caching/buffering will be used.
 */
dvdnav_status_t dvdnav_get_readahead_flag(dvdnav_t *self, int32_t *read_ahead_flag);

/*
 * Specify whether the positioning works PGC or PG based.
 * Programs (PGs) on DVDs are similar to Chapters and a program chain (PGC)
 * usually covers a whole feature. This affects the behaviour of the
 * functions dvdnav_get_position() and dvdnav_sector_search(). See there.
 * Default is PG based positioning.
 */
dvdnav_status_t dvdnav_set_PGC_positioning_flag(dvdnav_t *self, int32_t pgc_based_flag);

/*
 * Query whether positioning is PG or PGC based.
 */
dvdnav_status_t dvdnav_get_PGC_positioning_flag(dvdnav_t *self, int32_t *pgc_based_flag);


/*********************************************************************
 * reading data                                                      *
 *********************************************************************/

/*
 * These functions are used to poll the playback enginge and actually get data 
 * off the DVD.
 */

/*
 * Attempts to get the next block off the DVD and copies it into the buffer 'buf'. 
 * If there is any special actions that may need to be performed, the value
 * pointed to by 'event' gets set accordingly.
 *
 * If 'event' is DVDNAV_BLOCK_OK then 'buf' is filled with the next block
 * (note that means it has to be at /least/ 2048 bytes big). 'len' is
 * then set to 2048.
 *
 * Otherwise, buf is filled with an appropriate event structure and
 * len is set to the length of that structure.
 *
 * See the dvdnav_events.h header for information on the various events.
 */
dvdnav_status_t dvdnav_get_next_block(dvdnav_t *self, uint8_t *buf,
				      int32_t *event, int32_t *len);

/*
 * This basically does the same as dvdnav_get_next_block. The only difference is
 * that it avoids a memcopy, when the requested block was found in the cache.
 * I such a case (cache hit) this function will return a different pointer than
 * the one handed in, pointing directly into the relevant block in the cache.
 * Those pointers must _never_ be freed but instead returned to the library via
 * dvdnav_free_cache_block().
 */
dvdnav_status_t dvdnav_get_next_cache_block(dvdnav_t *self, uint8_t **buf,
					    int32_t *event, int32_t *len);

/*
 * All buffers which came from the internal cache (when dvdnav_get_next_cache_block()
 * returned a buffer different from the one handed in) have to be freed with this
 * function. Although handing in other buffers not from the cache doesn't cause any harm.
 */
dvdnav_status_t dvdnav_free_cache_block(dvdnav_t *self, unsigned char *buf);

/*
 * If we are currently in a still-frame this function skips it.
 *
 * See also the DVDNAV_STILL_FRAME event.
 */
dvdnav_status_t dvdnav_still_skip(dvdnav_t *self);

/*
 * If we are currently in WAIT state, that is: the application is required to
 * wait for its fifos to become empty, calling this signals libdvdnav that this
 * is achieved and that it can continue.
 *
 * See also the DVDNAV_WAIT event.
 */
dvdnav_status_t dvdnav_wait_skip(dvdnav_t *self);

/*
 * Returns the still time from the currently playing cell.
 * The still time is given in seconds with 0xff meaning an indefinite still.
 *
 * This function can be used to detect still frames before they are reached.
 * Some players might need this to prepare for a frame to be shown for a
 * longer time than usual.
 */
uint32_t dvdnav_get_next_still_flag(dvdnav_t *self);

/*
 * Stops playback. The next event obtained with one of the get_next_block
 * functions will be a DVDNAV_STOP event.
 *
 * It is not required to call this before dvdnav_close().
 */
dvdnav_status_t dvdnav_stop(dvdnav_t *self);


/*********************************************************************
 * title/part navigation                                             *
 *********************************************************************/

/*
 * Returns the number of titles on the disk.
 */
dvdnav_status_t dvdnav_get_number_of_titles(dvdnav_t *self, int32_t *titles);

/*
 * Returns the number of parts within the given title.
 */
dvdnav_status_t dvdnav_get_number_of_parts(dvdnav_t *self, int32_t title, int32_t *parts);

/*
 * Plays the specified title of the DVD from its beginning (that is: part 1).
 */
dvdnav_status_t dvdnav_title_play(dvdnav_t *self, int32_t title);

/*
 * Plays the specified title, starting from the specified part.
 */
dvdnav_status_t dvdnav_part_play(dvdnav_t *self, int32_t title, int32_t part);

/*
 * Play the specified amount of parts of the specified title of
 * the DVD then STOP.
 *
 * Currently unimplemented!
 */
dvdnav_status_t dvdnav_part_play_auto_stop(dvdnav_t *self, int32_t title,
					   int32_t part, int32_t parts_to_play);

/*
 * Play the specified title starting from the specified time.
 *
 * Currently unimplemented!
 */
dvdnav_status_t dvdnav_time_play(dvdnav_t *self, int32_t title,
				 uint64_t time);

/*
 * Stop playing the current position and jump to the specified menu.
 *
 * See also DVDMenuID_t from libdvdread
 */
dvdnav_status_t dvdnav_menu_call(dvdnav_t *self, DVDMenuID_t menu);

/*
 * Return the title number and part currently being played.
 * A title of 0 indicates, we are in a menu. In this case, part
 * is set to the current menu's ID.
 */
dvdnav_status_t dvdnav_current_title_info(dvdnav_t *self, int32_t *title,
					  int32_t *part);

/*
 * Return the current position (in blocks) within the current
 * title and the length (in blocks) of said title.
 * 
 * Current implementation is wrong and likely to behave unpredictably!
 * Use is discouraged!
 */
dvdnav_status_t dvdnav_get_position_in_title(dvdnav_t *self,
					     uint32_t *pos,
					     uint32_t *len);

/*
 * This function is only available for compatibility reasons.
 *
 * Stop playing the current position and start playback of the current title
 * from the specified part.
 */
dvdnav_status_t dvdnav_part_search(dvdnav_t *self, int32_t part);


/*********************************************************************
 * program chain/program navigation                                  *
 *********************************************************************/

/*
 * Stop playing the current position and start playback from the last
 * VOBU boundary before the given sector. The sector number is not
 * meant to be an absolute physical DVD sector, but a relative sector
 * in the current program. This function cannot leave the current
 * program and will fail, if asked to do so.
 *
 * If program chain based positioning is enabled
 * (see dvdnav_set_PGC_positioning_flag()), this will seek to the relative
 * sector inside the current program chain.
 *
 * 'origin' can be one of SEEK_SET, SEEK_CUR, SEEK_END as defined in
 * fcntl.h.
 */
dvdnav_status_t dvdnav_sector_search(dvdnav_t *self, 
				     uint64_t offset, int32_t origin);

/*
 * Stop playing the current position and start playback of the title
 * from the specified timecode.
 *
 * Currently unimplemented!
 */
dvdnav_status_t dvdnav_time_search(dvdnav_t *self, 
				   uint64_t time);

/*
 * Stop playing current position and play the "GoUp"-program chain.
 * (which generally leads to the title menu or a higer-level menu).
 */
dvdnav_status_t dvdnav_go_up(dvdnav_t *self);

/*
 * Stop playing the current position and start playback at the
 * previous program (if it exists).
 */
dvdnav_status_t dvdnav_prev_pg_search(dvdnav_t *self);

/*
 * Stop playing the current position and start playback at the
 * first program.
 */
dvdnav_status_t dvdnav_top_pg_search(dvdnav_t *self);

/*
 * Stop playing the current position and start playback at the
 * next program (if it exists).
 */
dvdnav_status_t dvdnav_next_pg_search(dvdnav_t *self);

/*
 * Return the current position (in blocks) within the current
 * program and the length (in blocks) of current program.
 *
 * If program chain based positioning is enabled
 * (see dvdnav_set_PGC_positioning_flag()), this will return the
 * relative position in and the length of the current program chain.
 */
dvdnav_status_t dvdnav_get_position(dvdnav_t *self, uint32_t *pos,
				    uint32_t *len);


/*********************************************************************
 * menu highlights                                                   *
 *********************************************************************/

/*
 * Most functions related to highlights take a NAV PCI packet as a parameter.
 * While you can get the such a packet from libdvdnav, for players with internal
 * FIFOs, this will result in errors, because due to the FIFO length, libdvdnav will
 * be ahead in the stream compared to what the user is seeing on screen.
 * Therefore, player applications who have a NAV packet available, which is
 * better in sync with the actual playback should always pass this one to these
 * functions.
 */

/*
 * Get the currently highlighted button 
 * number (1..36) or 0 if no button is highlighted.
 */
dvdnav_status_t dvdnav_get_current_highlight(dvdnav_t *self, int32_t *button);

/*
 * Returns the Presentation Control Information (PCI) structure associated
 * with the current position.
 *
 * Read the general notes above.
 * See also libdvdreads nav_types.h for definition of pci_t.
 */
pci_t* dvdnav_get_current_nav_pci(dvdnav_t *self);

/*
 * Returns the DSI (data search information) structure associated
 * with the current position.
 *
 * Read the general notes above.
 * See also libdvdreads nav_types.h for definition of dsi_t.
 */
dsi_t* dvdnav_get_current_nav_dsi(dvdnav_t *self);

/*
 * Get the area associated with a certain button.
 */
dvdnav_status_t dvdnav_get_highlight_area(pci_t *nav_pci , int32_t button, int32_t mode,
					  dvdnav_highlight_area_t *highlight);

/*
 * Move button highlight around as suggested by function name (e.g. with arrow keys).
 */
dvdnav_status_t dvdnav_upper_button_select(dvdnav_t *self, pci_t *pci);
dvdnav_status_t dvdnav_lower_button_select(dvdnav_t *self, pci_t *pci);
dvdnav_status_t dvdnav_right_button_select(dvdnav_t *self, pci_t *pci);
dvdnav_status_t dvdnav_left_button_select(dvdnav_t *self, pci_t *pci);

/*
 * Activate ("press") the currently highlighted button.
 */
dvdnav_status_t dvdnav_button_activate(dvdnav_t *self, pci_t *pci);

/*
 * Highlight a specific button.
 */
dvdnav_status_t dvdnav_button_select(dvdnav_t *self, pci_t *pci, int32_t button);

/*
 * Activate ("press") specified button.
 */
dvdnav_status_t dvdnav_button_select_and_activate(dvdnav_t *self, pci_t *pci, int32_t button);

/*
 * Activate (press) a button and execute specified command.
 */
dvdnav_status_t dvdnav_button_activate_cmd(dvdnav_t *self, int32_t button, vm_cmd_t *cmd);

/*
 * Select button at specified video frame coordinates.
 */
dvdnav_status_t dvdnav_mouse_select(dvdnav_t *self, pci_t *pci, int32_t x, int32_t y);

/*
 * Activate ("press") button at specified video frame coordinates.
 */
dvdnav_status_t dvdnav_mouse_activate(dvdnav_t *self, pci_t *pci, int32_t x, int32_t y);


/*********************************************************************
 * languages                                                         *
 *********************************************************************/

/* 
 * The language codes expected by these functions are two character
 * codes as defined in ISO639.
 */

/*
 * Set which menu language we should use per default.
 */
dvdnav_status_t dvdnav_menu_language_select(dvdnav_t *self,
					   char *code);

/*
 * Set which audio language we should use per default.
 */
dvdnav_status_t dvdnav_audio_language_select(dvdnav_t *self,
					    char *code);

/*
 * Set which spu language we should use per default.
 */
dvdnav_status_t dvdnav_spu_language_select(dvdnav_t *self,
					  char *code);


/*********************************************************************
 * obtaining stream attributes                                       *
 *********************************************************************/

/*
 * Return a string describing the title of the DVD.
 * This is an ID string encoded on the disc by the author. In many cases
 * this is a descriptive string such as `THE_MATRIX' but sometimes is sigularly
 * uninformative such as `PDVD-011421'. Some DVD authors even forget to set this,
 * so you may also read the default of the authoring software they used, like
 * `DVDVolume'.
 */
dvdnav_status_t dvdnav_get_title_string(dvdnav_t *self, const char **title_str);

/*
 * Get video aspect code.
 * The aspect code does only change on VTS boundaries.
 * See the DVDNAV_VTS_CHANGE event.
 * 
 * 0 -- 4:3, 2 -- 16:9
 */
uint8_t dvdnav_get_video_aspect(dvdnav_t *self);

/*
 * Get video scaling permissions.
 * The scaling permission does only change on VTS boundaries.
 * See the DVDNAV_VTS_CHANGE event.
 *
 * bit0 set = deny letterboxing, bit1 set = deny pan&scan
 */
uint8_t dvdnav_get_video_scale_permission(dvdnav_t *self);

/*
 * Converts a *logical* audio stream id into language code
 * (returns 0xffff if no such stream).
 */
uint16_t dvdnav_audio_stream_to_lang(dvdnav_t *self, uint8_t stream);

/*
 * Converts a *logical* subpicture stream id into country code 
 * (returns 0xffff if no such stream).
 */
uint16_t dvdnav_spu_stream_to_lang(dvdnav_t *self, uint8_t stream);

/*
 * Converts a *physical* (MPEG) audio stream id into a logical stream number.
 */
int8_t dvdnav_get_audio_logical_stream(dvdnav_t *self, uint8_t audio_num);

/*
 * Converts a *physical* (MPEG) subpicture stream id into a logical stream number.
 */
int8_t dvdnav_get_spu_logical_stream(dvdnav_t *self, uint8_t subp_num);

/*
 * Get active audio stream.
 */
int8_t dvdnav_get_active_audio_stream(dvdnav_t *self);

/*
 * Get active spu stream.
 */
int8_t dvdnav_get_active_spu_stream(dvdnav_t *self);


/*********************************************************************
 * multiple angles                                                   *
 *********************************************************************/

/*
 * The libdvdnav library abstracts away the difference between seamless and
 * non-seamless angles. From the point of view of the programmer you just set the
 * angle number and all is well in the world. You will always see only the
 * selected angle coming from the get_next_block functions.
 *
 * Note:
 * It is quite possible that some tremendously strange DVD feature might change the
 * angle number from under you. Generally you should always view the results from
 * dvdnav_get_angle_info() as definitive only up to the next time you call
 * dvdnav_get_next_block().
 */

/*
 * Sets the current angle. If you try to follow a non existant angle
 * the call fails.
 */
dvdnav_status_t dvdnav_angle_change(dvdnav_t *self, int32_t angle);

/*
 * Returns the current angle and number of angles present.
 */
dvdnav_status_t dvdnav_get_angle_info(dvdnav_t *self, int32_t *current_angle,
				      int32_t *number_of_angles);

/*********************************************************************
 * domain queries                                                    *
 *********************************************************************/

/*
 * Are we in the First Play domain?
 */
int8_t dvdnav_is_domain_fp(dvdnav_t *self);

/*
 * Are we in the Video management Menu domain?
 */
int8_t dvdnav_is_domain_vmgm(dvdnav_t *self);

/*
 * Are we in the Video Title Menu domain?
 */
int8_t dvdnav_is_domain_vtsm(dvdnav_t *self);

/*
 * Are we in the Video Title Set domain?
 */
int8_t dvdnav_is_domain_vts(dvdnav_t *self);


#ifdef __cplusplus
}
#endif

#endif /* DVDNAV_H_INCLUDED */

--- NEW FILE: dvdnav.c ---
/* 
 * Copyright (C) 2000 Rich Wareham <richwareham@users.sourceforge.net>
 * 
 * This file is part of libdvdnav, a DVD navigation library.
 * 
 * libdvdnav 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.
 * 
 * libdvdnav 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
 *
[...1049 lines suppressed...]
  pthread_mutex_unlock(&this->vm_lock);

  return DVDNAV_STATUS_OK;
}

pci_t* dvdnav_get_current_nav_pci(dvdnav_t *this) {
  if(!this) return 0;
  return &this->pci;
}

dsi_t* dvdnav_get_current_nav_dsi(dvdnav_t *this) {
  if(!this) return 0;
  return &this->dsi;
}

uint32_t dvdnav_get_next_still_flag(dvdnav_t *this) {
  if(!this) return -1;
  return this->position_next.still;
}


--- NEW FILE: searching.c ---
/*
 * Copyright (C) 2000 Rich Wareham <richwareham@users.sourceforge.net>
 * 
 * This file is part of libdvdnav, a DVD navigation library.
 * 
 * libdvdnav 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.
 * 
 * libdvdnav 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
 *
 * $Id: searching.c,v 1.1 2005/04/04 22:29:36 dsalt-guest Exp $
 *
 */

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

#include <assert.h>
#include "dvdnav_internal.h"

/*
#define LOG_DEBUG
*/

/* Searching API calls */

dvdnav_status_t dvdnav_time_search(dvdnav_t *this,
				   uint64_t time) {
  /* FIXME: Time search the current PGC based on the xxx table */
  return DVDNAV_STATUS_OK;
}

/* Scan the ADMAP for a particular block number. */
/* Return placed in vobu. */
/* Returns error status */
/* FIXME: Maybe need to handle seeking outside current cell. */
static dvdnav_status_t dvdnav_scan_admap(dvdnav_t *this, int32_t domain, uint32_t seekto_block, uint32_t *vobu) {
  vobu_admap_t *admap = NULL;

#ifdef LOG_DEBUG
  fprintf(MSG_OUT, "libdvdnav: Seeking to target %u ...\n", seekto_block);
#endif
  *vobu = -1;

  /* Search through the VOBU_ADMAP for the nearest VOBU
   * to the target block */
  switch(domain) {
  case FP_DOMAIN:
  case VMGM_DOMAIN:
    admap = this->vm->vmgi->menu_vobu_admap;
    break;
  case VTSM_DOMAIN:
    admap = this->vm->vtsi->menu_vobu_admap;
    break;
  case VTS_DOMAIN:
    admap = this->vm->vtsi->vts_vobu_admap;
    break;
  default:
    fprintf(MSG_OUT, "libdvdnav: Error: Unknown domain for seeking.\n");
  }
  if(admap) {
    uint32_t address = 0;
    uint32_t vobu_start, next_vobu;
    int32_t found = 0;

    /* Search through ADMAP for best sector */
    vobu_start = SRI_END_OF_CELL;
    /* FIXME: Implement a faster search algorithm */
    while((!found) && ((address<<2) < admap->last_byte)) {
      next_vobu = admap->vobu_start_sectors[address];

      /* fprintf(MSG_OUT, "libdvdnav: Found block %u\n", next_vobu); */

      if(vobu_start <= seekto_block &&
          next_vobu > seekto_block) {
        found = 1;
      } else {
        vobu_start = next_vobu;
      }
      address ++;
    }
    if(found) {
      *vobu = vobu_start;
      return DVDNAV_STATUS_OK;
    } else {
      fprintf(MSG_OUT, "libdvdnav: Could not locate block\n");
      return DVDNAV_STATUS_ERR;
    }
  }
  fprintf(MSG_OUT, "libdvdnav: admap not located\n");
  return DVDNAV_STATUS_ERR;
}

dvdnav_status_t dvdnav_sector_search(dvdnav_t *this,
				     uint64_t offset, int32_t origin) {
  uint32_t target = 0;
  uint32_t length = 0;
  uint32_t first_cell_nr, last_cell_nr, cell_nr;
  int32_t found;
  cell_playback_t *cell;
  dvd_state_t *state;
  dvdnav_status_t result;

  if(this->position_current.still != 0) {
    printerr("Cannot seek in a still frame.");
    return DVDNAV_STATUS_ERR;
  }
  
  result = dvdnav_get_position(this, &target, &length);
  if(!result) {
    return DVDNAV_STATUS_ERR;
  }
 
  pthread_mutex_lock(&this->vm_lock);
  state = &(this->vm->state);
  if(!state->pgc) {
    printerr("No current PGC.");
    pthread_mutex_unlock(&this->vm_lock);
    return DVDNAV_STATUS_ERR;
  }
#ifdef LOG_DEBUG
  fprintf(MSG_OUT, "libdvdnav: seeking to offset=%lu pos=%u length=%u\n", offset, target, length); 
  fprintf(MSG_OUT, "libdvdnav: Before cellN=%u blockN=%u\n", state->cellN, state->blockN);
#endif

  switch(origin) {
   case SEEK_SET:
    if(offset > length) {
      printerr("Request to seek behind end.");
      pthread_mutex_unlock(&this->vm_lock);
      return DVDNAV_STATUS_ERR;
    }
    target = offset;
    break;
   case SEEK_CUR:
    if(target + offset > length) {
      printerr("Request to seek behind end.");
      pthread_mutex_unlock(&this->vm_lock);
      return DVDNAV_STATUS_ERR;
    }
    target += offset;
    break;
   case SEEK_END:
    if(length - offset < 0) {
      printerr("Request to seek before start.");
      pthread_mutex_unlock(&this->vm_lock);
      return DVDNAV_STATUS_ERR;
    }
    target = length - offset;
    break;
   default:
    /* Error occured */
    printerr("Illegal seek mode.");
    pthread_mutex_unlock(&this->vm_lock);
    return DVDNAV_STATUS_ERR;
  }
  
  if (this->pgc_based) {
    first_cell_nr = 1;
    last_cell_nr = state->pgc->nr_of_cells;
  } else {
    /* Find start cell of program. */
    first_cell_nr = state->pgc->program_map[state->pgN-1];
    /* Find end cell of program */
    if(state->pgN < state->pgc->nr_of_programs)
      last_cell_nr = state->pgc->program_map[state->pgN] - 1;
    else
      last_cell_nr = state->pgc->nr_of_cells;
  }

  found = 0;
  for(cell_nr = first_cell_nr; (cell_nr <= last_cell_nr) && !found; cell_nr ++) {
    cell =  &(state->pgc->cell_playback[cell_nr-1]);
    length = cell->last_sector - cell->first_sector + 1;
    if (target >= length) {
      target -= length;
    } else {
      /* convert the target sector from Cell-relative to absolute physical sector */
      target += cell->first_sector;
      found = 1;
      break;
    }
  }

  if(found) {
    int32_t vobu;
#ifdef LOG_DEBUG
    fprintf(MSG_OUT, "libdvdnav: Seeking to cell %i from choice of %i to %i\n",
	    cell_nr, first_cell_nr, last_cell_nr);
#endif
    if (dvdnav_scan_admap(this, state->domain, target, &vobu) == DVDNAV_STATUS_OK) {
      int32_t start = state->pgc->cell_playback[cell_nr-1].first_sector;
      
      if (vm_jump_cell_block(this->vm, cell_nr, vobu - start)) {
#ifdef LOG_DEBUG
        fprintf(MSG_OUT, "libdvdnav: After cellN=%u blockN=%u target=%x vobu=%x start=%x\n" ,
          state->cellN, state->blockN, target, vobu, start);
#endif
        this->vm->hop_channel += HOP_SEEK;
        pthread_mutex_unlock(&this->vm_lock);
        return DVDNAV_STATUS_OK;
      }
    }
  }
  
  fprintf(MSG_OUT, "libdvdnav: Error when seeking\n");
  fprintf(MSG_OUT, "libdvdnav: FIXME: Implement seeking to location %u\n", target); 
  printerr("Error when seeking.");
  pthread_mutex_unlock(&this->vm_lock);
  return DVDNAV_STATUS_ERR;
}

dvdnav_status_t dvdnav_part_search(dvdnav_t *this, int32_t part) {
  int32_t title, old_part;
  
  if (dvdnav_current_title_info(this, &title, &old_part) == DVDNAV_STATUS_OK)
    return dvdnav_part_play(this, title, part);
  return DVDNAV_STATUS_ERR;
}

dvdnav_status_t dvdnav_prev_pg_search(dvdnav_t *this) {

  if(!this) {
    printerr("Passed a NULL pointer.");
    return DVDNAV_STATUS_ERR;
  }
  
  pthread_mutex_lock(&this->vm_lock);
  if(!this->vm->state.pgc) {
    printerr("No current PGC.");
    pthread_mutex_unlock(&this->vm_lock);
    return DVDNAV_STATUS_ERR;
  }

#ifdef LOG_DEBUG
  fprintf(MSG_OUT, "libdvdnav: previous chapter\n");
#endif
  if (!vm_jump_prev_pg(this->vm)) {
    fprintf(MSG_OUT, "libdvdnav: previous chapter failed.\n");
    printerr("Skip to previous chapter failed.");
    pthread_mutex_unlock(&this->vm_lock);
    return DVDNAV_STATUS_ERR;
  }
  this->position_current.still = 0;
  this->vm->hop_channel++;
#ifdef LOG_DEBUG
  fprintf(MSG_OUT, "libdvdnav: previous chapter done\n");
#endif
  pthread_mutex_unlock(&this->vm_lock);

  return DVDNAV_STATUS_OK;
}

dvdnav_status_t dvdnav_top_pg_search(dvdnav_t *this) {

  if(!this) {
    printerr("Passed a NULL pointer.");
    return DVDNAV_STATUS_ERR;
  }
    
  pthread_mutex_lock(&this->vm_lock);
  if(!this->vm->state.pgc) {
    printerr("No current PGC.");
    pthread_mutex_unlock(&this->vm_lock);
    return DVDNAV_STATUS_ERR;
  }

#ifdef LOG_DEBUG
  fprintf(MSG_OUT, "libdvdnav: top chapter\n");
#endif
  if (!vm_jump_top_pg(this->vm)) {
    fprintf(MSG_OUT, "libdvdnav: top chapter failed.\n");
    printerr("Skip to top chapter failed.");
    pthread_mutex_unlock(&this->vm_lock);
    return DVDNAV_STATUS_ERR;
  }
  this->position_current.still = 0;
  this->vm->hop_channel++;
#ifdef LOG_DEBUG
  fprintf(MSG_OUT, "libdvdnav: top chapter done\n");
#endif
  pthread_mutex_unlock(&this->vm_lock);

  return DVDNAV_STATUS_OK;
}

dvdnav_status_t dvdnav_next_pg_search(dvdnav_t *this) {
  vm_t *try_vm;

  if(!this) {
    printerr("Passed a NULL pointer.");
    return DVDNAV_STATUS_ERR;
  }

  pthread_mutex_lock(&this->vm_lock);
  if(!this->vm->state.pgc) {
    printerr("No current PGC.");
    pthread_mutex_unlock(&this->vm_lock);
    return DVDNAV_STATUS_ERR;
  }

#ifdef LOG_DEBUG
  fprintf(MSG_OUT, "libdvdnav: next chapter\n");
#endif
  /* make a copy of current VM and try to navigate the copy to the next PG */
  try_vm = vm_new_copy(this->vm);
  if (!vm_jump_next_pg(try_vm) || try_vm->stopped) {
    vm_free_copy(try_vm);
    /* next_pg failed, try to jump at least to the next cell */
    try_vm = vm_new_copy(this->vm);
    vm_get_next_cell(try_vm);
    if (try_vm->stopped) {
      vm_free_copy(try_vm);
      fprintf(MSG_OUT, "libdvdnav: next chapter failed.\n");
      printerr("Skip to next chapter failed.");
      pthread_mutex_unlock(&this->vm_lock);
      return DVDNAV_STATUS_ERR;
    }
  }
  /* merge changes on success */
  vm_merge(this->vm, try_vm);
  vm_free_copy(try_vm);
  this->position_current.still = 0;
  this->vm->hop_channel++;
#ifdef LOG_DEBUG
  fprintf(MSG_OUT, "libdvdnav: next chapter done\n");
#endif
  pthread_mutex_unlock(&this->vm_lock);

  return DVDNAV_STATUS_OK;
}

dvdnav_status_t dvdnav_menu_call(dvdnav_t *this, DVDMenuID_t menu) {
  vm_t *try_vm;
  
  if(!this) {
    printerr("Passed a NULL pointer.");
    return DVDNAV_STATUS_ERR;
  }

  pthread_mutex_lock(&this->vm_lock);
  if(!this->vm->state.pgc) {
    printerr("No current PGC.");
    pthread_mutex_unlock(&this->vm_lock);
    return DVDNAV_STATUS_ERR;
  }
  
  /* make a copy of current VM and try to navigate the copy to the menu */
  try_vm = vm_new_copy(this->vm);
  if ( (menu == DVD_MENU_Escape) && (this->vm->state.domain != VTS_DOMAIN)) {
    /* Try resume */
    if (vm_jump_resume(try_vm) && !try_vm->stopped) {
        /* merge changes on success */
        vm_merge(this->vm, try_vm);
        vm_free_copy(try_vm);
        this->position_current.still = 0;
        this->vm->hop_channel++;
        pthread_mutex_unlock(&this->vm_lock); 
        return DVDNAV_STATUS_OK;
    }
  }
  if (menu == DVD_MENU_Escape) menu = DVD_MENU_Root;
 
  if (vm_jump_menu(try_vm, menu) && !try_vm->stopped) {
    /* merge changes on success */
    vm_merge(this->vm, try_vm);
    vm_free_copy(try_vm);
    this->position_current.still = 0;
    this->vm->hop_channel++;
    pthread_mutex_unlock(&this->vm_lock); 
    return DVDNAV_STATUS_OK;
  } else {
    vm_free_copy(try_vm);
    printerr("No such menu or menu not reachable.");
    pthread_mutex_unlock(&this->vm_lock); 
    return DVDNAV_STATUS_ERR;
  }
}

dvdnav_status_t dvdnav_get_position(dvdnav_t *this, uint32_t *pos,
				    uint32_t *len) {
  uint32_t cur_sector;
  int32_t cell_nr, first_cell_nr, last_cell_nr;
  cell_playback_t *cell;
  dvd_state_t *state;

  if(!this || !pos || !len) {
    printerr("Passed a NULL pointer.");
    return DVDNAV_STATUS_ERR;
  }
  if(!this->started) {
    printerr("Virtual DVD machine not started.");
    return DVDNAV_STATUS_ERR;
  }

  pthread_mutex_lock(&this->vm_lock);
  state = &(this->vm->state);
  if(!state->pgc || this->vm->stopped) {
    printerr("No current PGC.");
    pthread_mutex_unlock(&this->vm_lock);
    return DVDNAV_STATUS_ERR;
  }
  if (this->position_current.hop_channel  != this->vm->hop_channel ||
      this->position_current.domain       != state->domain         ||
      this->position_current.vts          != state->vtsN           ||
      this->position_current.cell_restart != state->cell_restart) {
    printerr("New position not yet determined.");
    pthread_mutex_unlock(&this->vm_lock);
    return DVDNAV_STATUS_ERR;
  }

  /* Get current sector */
  cur_sector = this->vobu.vobu_start + this->vobu.blockN;

  if (this->pgc_based) {
    first_cell_nr = 1;
    last_cell_nr = state->pgc->nr_of_cells;
  } else {
    /* Find start cell of program. */
    first_cell_nr = state->pgc->program_map[state->pgN-1];
    /* Find end cell of program */
    if(state->pgN < state->pgc->nr_of_programs)
      last_cell_nr = state->pgc->program_map[state->pgN] - 1;
    else
      last_cell_nr = state->pgc->nr_of_cells;
  }

  *pos = -1;
  *len = 0;
  for (cell_nr = first_cell_nr; cell_nr <= last_cell_nr; cell_nr++) {
    cell = &(state->pgc->cell_playback[cell_nr-1]);
    if (cell_nr == state->cellN) {
      /* the current sector is in this cell,
       * pos is length of PG up to here + sector's offset in this cell */
      *pos = *len + cur_sector - cell->first_sector;
    }
    *len += cell->last_sector - cell->first_sector + 1;
  }
  
  assert((signed)*pos != -1);

  pthread_mutex_unlock(&this->vm_lock);

  return DVDNAV_STATUS_OK;
}

dvdnav_status_t dvdnav_get_position_in_title(dvdnav_t *this,
					     uint32_t *pos,
					     uint32_t *len) {
  uint32_t cur_sector;
  uint32_t first_cell_nr;
  uint32_t last_cell_nr;
  cell_playback_t *first_cell;
  cell_playback_t *last_cell;
  dvd_state_t *state;

  if(!this || !pos || !len) {
    printerr("Passed a NULL pointer.");
    return DVDNAV_STATUS_ERR;
  }

  state = &(this->vm->state);
  if(!state->pgc) {
    printerr("No current PGC.");
    return DVDNAV_STATUS_ERR;
  }

  /* Get current sector */
  cur_sector = this->vobu.vobu_start + this->vobu.blockN;

  /* Now find first and last cells in title. */
  first_cell_nr = state->pgc->program_map[0];
  first_cell = &(state->pgc->cell_playback[first_cell_nr-1]);
  last_cell_nr = state->pgc->nr_of_cells;
  last_cell = &(state->pgc->cell_playback[last_cell_nr-1]);
  
  *pos = cur_sector - first_cell->first_sector;
  *len = last_cell->last_sector - first_cell->first_sector;
  
  return DVDNAV_STATUS_OK;
}

--- NEW FILE: navigation.c ---
/* 
 * Copyright (C) 2000 Rich Wareham <richwareham@users.sourceforge.net>
 * 
 * This file is part of libdvdnav, a DVD navigation library.
 * 
 * libdvdnav 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.
 * 
 * libdvdnav 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
 *
 * $Id: navigation.c,v 1.1 2005/04/04 22:29:36 dsalt-guest Exp $
 *
 */

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

#include "dvdnav_internal.h"

/* Navigation API calls */

dvdnav_status_t dvdnav_still_skip(dvdnav_t *this) {
  if(!this) {
    printerr("Passed a NULL pointer.");
    return DVDNAV_STATUS_ERR;
  }

  this->position_current.still = 0;
  this->skip_still = 1;
  this->sync_wait = 0;
  this->sync_wait_skip = 1;

  return DVDNAV_STATUS_OK;
}

dvdnav_status_t dvdnav_wait_skip(dvdnav_t *this) {
  if(!this) {
    printerr("Passed a NULL pointer.");
    return DVDNAV_STATUS_ERR;
  }

  this->sync_wait = 0;
  this->sync_wait_skip = 1;

  return DVDNAV_STATUS_OK;
}

dvdnav_status_t dvdnav_get_number_of_titles(dvdnav_t *this, int32_t *titles) {
  if(!this || !titles) {
    printerr("Passed a NULL pointer.");
    return DVDNAV_STATUS_ERR;
  }
  if (!this->vm->vmgi) {
    printerr("Bad VM state.");
    return DVDNAV_STATUS_ERR;
  }

  (*titles) = vm_get_vmgi(this->vm)->tt_srpt->nr_of_srpts;

  return DVDNAV_STATUS_OK;
}

dvdnav_status_t dvdnav_get_number_of_parts(dvdnav_t *this, int32_t title, int32_t *parts) {
  if(!this || !parts) {
    printerr("Passed a NULL pointer.");
    return DVDNAV_STATUS_ERR;
  }
  if (!this->vm->vmgi) {
    printerr("Bad VM state.");
    return DVDNAV_STATUS_ERR;
  }
  if ((title < 1) || (title > vm_get_vmgi(this->vm)->tt_srpt->nr_of_srpts) ) {
    printerr("Passed a title number out of range.");
    return DVDNAV_STATUS_ERR;
  }

  (*parts) = vm_get_vmgi(this->vm)->tt_srpt->title[title-1].nr_of_ptts;

  return DVDNAV_STATUS_OK;
}

dvdnav_status_t dvdnav_current_title_info(dvdnav_t *this, int32_t *title, int32_t *part) {
  int32_t retval;
  
  if(!this || !title || !part) {
    printerr("Passed a NULL pointer.");
    return DVDNAV_STATUS_ERR;
  }
  
  pthread_mutex_lock(&this->vm_lock);
  if (!this->vm->vtsi || !this->vm->vmgi) {
    printerr("Bad VM state.");
    pthread_mutex_unlock(&this->vm_lock);
    return DVDNAV_STATUS_ERR;
  }
  if (!this->started) {
    printerr("Virtual DVD machine not started.");
    pthread_mutex_unlock(&this->vm_lock);
    return DVDNAV_STATUS_ERR;
  }
  if (!this->vm->state.pgc) {
    printerr("No current PGC.");
    pthread_mutex_unlock(&this->vm_lock);
    return DVDNAV_STATUS_ERR;
  }
  if ( (this->vm->state.domain == VTSM_DOMAIN)
      || (this->vm->state.domain == VMGM_DOMAIN) ) {
    /* Get current Menu ID: into *part. */
    vm_get_current_menu(this->vm, part);
    if (*part > -1) {
      *title = 0;
      pthread_mutex_unlock(&this->vm_lock);
      return DVDNAV_STATUS_OK;
    }
  }
  if (this->vm->state.domain == VTS_DOMAIN) {
    retval = vm_get_current_title_part(this->vm, title, part);
    pthread_mutex_unlock(&this->vm_lock);
    return retval ? DVDNAV_STATUS_OK : DVDNAV_STATUS_ERR;
  }
  printerr("Not in a title or menu.");
  pthread_mutex_unlock(&this->vm_lock);
  return DVDNAV_STATUS_ERR;
}

dvdnav_status_t dvdnav_title_play(dvdnav_t *this, int32_t title) {
  if(!this) {
    printerr("Passed a NULL pointer.");
    return DVDNAV_STATUS_ERR;
  }
  return dvdnav_part_play(this, title, 1);
}

dvdnav_status_t dvdnav_part_play(dvdnav_t *this, int32_t title, int32_t part) {
  int32_t retval;

  if(!this) {
    printerr("Passed a NULL pointer.");
    return DVDNAV_STATUS_ERR;
  }
  
  pthread_mutex_lock(&this->vm_lock);
  if (!this->vm->vmgi) {
    printerr("Bad VM state.");
    pthread_mutex_unlock(&this->vm_lock);
    return DVDNAV_STATUS_ERR;
  }
  if (!this->started) {
    /* don't report an error but be nice */
    vm_start(this->vm);
    this->started = 1;
  }
  if (!this->vm->state.pgc) {
    printerr("No current PGC.");
    pthread_mutex_unlock(&this->vm_lock);
    return DVDNAV_STATUS_ERR;
  }
  if((title < 1) || (title > this->vm->vmgi->tt_srpt->nr_of_srpts)) {
    printerr("Title out of range.");
    pthread_mutex_unlock(&this->vm_lock);
    return DVDNAV_STATUS_ERR;
  }
  if((part < 1) || (part > this->vm->vmgi->tt_srpt->title[title-1].nr_of_ptts)) {
    printerr("Part out of range.");
    pthread_mutex_unlock(&this->vm_lock);
    return DVDNAV_STATUS_ERR;
  }

  retval = vm_jump_title_part(this->vm, title, part);
  if (retval)
    this->vm->hop_channel++;
  pthread_mutex_unlock(&this->vm_lock);

  return retval ? DVDNAV_STATUS_OK : DVDNAV_STATUS_ERR;
}

dvdnav_status_t dvdnav_part_play_auto_stop(dvdnav_t *this, int32_t title,
					   int32_t part, int32_t parts_to_play) {
  /* FIXME: Implement auto-stop */
 if (dvdnav_part_play(this, title, part) == DVDNAV_STATUS_OK)
   printerr("Not implemented yet.");
 return DVDNAV_STATUS_ERR;
}

dvdnav_status_t dvdnav_time_play(dvdnav_t *this, int32_t title,
				 uint64_t time) {
  if(!this) {
    printerr("Passed a NULL pointer.");
    return DVDNAV_STATUS_ERR;
  }
  
  /* FIXME: Implement */
  printerr("Not implemented yet.");
  return DVDNAV_STATUS_ERR;
}

dvdnav_status_t dvdnav_stop(dvdnav_t *this) {
  if(!this) {
    printerr("Passed a NULL pointer.");
    return DVDNAV_STATUS_ERR;
  }
  
  pthread_mutex_lock(&this->vm_lock);
  this->vm->stopped = 1;
  pthread_mutex_unlock(&this->vm_lock);
  return DVDNAV_STATUS_OK;
}

dvdnav_status_t dvdnav_go_up(dvdnav_t *this) {
  if(!this) {
    printerr("Passed a NULL pointer.");
    return DVDNAV_STATUS_ERR;
  }

  /* A nice easy function... delegate to the VM */
  pthread_mutex_lock(&this->vm_lock);
  vm_jump_up(this->vm);
  pthread_mutex_unlock(&this->vm_lock);

  return DVDNAV_STATUS_OK;
}

--- NEW FILE: nav_read.h ---
(This appears to be a binary file; contents omitted.)

--- NEW FILE: md5.c ---
/* md5.c - Functions to compute MD5 message digest of files or memory blocks
   according to the definition of MD5 in RFC 1321 from April 1992.
   Copyright (C) 1995, 1996, 2001 Free Software Foundation, Inc.
   NOTE: The canonical source of this file is maintained with the GNU C
   Library.  Bugs can be reported to bug-glibc@prep.ai.mit.edu.

   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, 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.  */

/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.  */

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include <sys/types.h>

#if STDC_HEADERS || defined _LIBC
# include <stdlib.h>
# include <string.h>
#else
# ifndef HAVE_MEMCPY
#  define memcpy(d, s, n) bcopy ((s), (d), (n))
# endif
#endif

#include "md5.h"
/* #include "unlocked-io.h" */

#ifdef _LIBC
# include <endian.h>
# if __BYTE_ORDER == __BIG_ENDIAN
#  define WORDS_BIGENDIAN 1
# endif
#endif

#ifdef WORDS_BIGENDIAN
# define SWAP(n)							\
    (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
#else
# define SWAP(n) (n)
#endif


/* This array contains the bytes used to pad the buffer to the next
   64-byte boundary.  (RFC 1321, 3.1: Step 1)  */
static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ...  */ };


/* Initialize structure containing state of computation.
   (RFC 1321, 3.3: Step 3)  */
void
md5_init_ctx (ctx)
     struct md5_ctx *ctx;
{
  ctx->A = 0x67452301;
  ctx->B = 0xefcdab89;
  ctx->C = 0x98badcfe;
  ctx->D = 0x10325476;

  ctx->total[0] = ctx->total[1] = 0;
  ctx->buflen = 0;
}

/* Put result from CTX in first 16 bytes following RESBUF.  The result
   must be in little endian byte order.

   IMPORTANT: On some systems it is required that RESBUF is correctly
   aligned for a 32 bits value.  */
void *
md5_read_ctx (ctx, resbuf)
     const struct md5_ctx *ctx;
     void *resbuf;
{
  ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A);
  ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B);
  ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C);
  ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D);

  return resbuf;
}

/* Process the remaining bytes in the internal buffer and the usual
   prolog according to the standard and write the result to RESBUF.

   IMPORTANT: On some systems it is required that RESBUF is correctly
   aligned for a 32 bits value.  */
void *
md5_finish_ctx (ctx, resbuf)
     struct md5_ctx *ctx;
     void *resbuf;
{
  /* Take yet unprocessed bytes into account.  */
  md5_uint32 bytes = ctx->buflen;
  size_t pad;

  /* Now count remaining bytes.  */
  ctx->total[0] += bytes;
  if (ctx->total[0] < bytes)
    ++ctx->total[1];

  pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
  memcpy (&ctx->buffer[bytes], fillbuf, pad);

  /* Put the 64-bit file length in *bits* at the end of the buffer.  */
  *(md5_uint32 *) &ctx->buffer[bytes + pad] = SWAP (ctx->total[0] << 3);
  *(md5_uint32 *) &ctx->buffer[bytes + pad + 4] = SWAP ((ctx->total[1] << 3) |
							(ctx->total[0] >> 29));

  /* Process last bytes.  */
  md5_process_block (ctx->buffer, bytes + pad + 8, ctx);

  return md5_read_ctx (ctx, resbuf);
}

/* Compute MD5 message digest for bytes read from STREAM.  The
   resulting message digest number will be written into the 16 bytes
   beginning at RESBLOCK.  */
int
md5_stream (stream, resblock)
     FILE *stream;
     void *resblock;
{
  /* Important: BLOCKSIZE must be a multiple of 64.  */
#define BLOCKSIZE 4096
  struct md5_ctx ctx;
  char buffer[BLOCKSIZE + 72];
  size_t sum;

  /* Initialize the computation context.  */
  md5_init_ctx (&ctx);

  /* Iterate over full file contents.  */
  while (1)
    {
      /* We read the file in blocks of BLOCKSIZE bytes.  One call of the
	 computation function processes the whole buffer so that with the
	 next round of the loop another block can be read.  */
      size_t n;
      sum = 0;

      /* Read block.  Take care for partial reads.  */
      do
	{
	  n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);

	  sum += n;
	}
      while (sum < BLOCKSIZE && n != 0);
      if (n == 0 && ferror (stream))
        return 1;

      /* If end of file is reached, end the loop.  */
      if (n == 0)
	break;

      /* Process buffer with BLOCKSIZE bytes.  Note that
			BLOCKSIZE % 64 == 0
       */
      md5_process_block (buffer, BLOCKSIZE, &ctx);
    }

  /* Add the last bytes if necessary.  */
  if (sum > 0)
    md5_process_bytes (buffer, sum, &ctx);

  /* Construct result in desired memory.  */
  md5_finish_ctx (&ctx, resblock);
  return 0;
}

/* Compute MD5 message digest for LEN bytes beginning at BUFFER.  The
   result is always in little endian byte order, so that a byte-wise
   output yields to the wanted ASCII representation of the message
   digest.  */
void *
md5_buffer (buffer, len, resblock)
     const char *buffer;
     size_t len;
     void *resblock;
{
  struct md5_ctx ctx;

  /* Initialize the computation context.  */
  md5_init_ctx (&ctx);

  /* Process whole buffer but last len % 64 bytes.  */
  md5_process_bytes (buffer, len, &ctx);

  /* Put result in desired memory area.  */
  return md5_finish_ctx (&ctx, resblock);
}


void
md5_process_bytes (buffer, len, ctx)
     const void *buffer;
     size_t len;
     struct md5_ctx *ctx;
{
  /* When we already have some bits in our internal buffer concatenate
     both inputs first.  */
  if (ctx->buflen != 0)
    {
      size_t left_over = ctx->buflen;
      size_t add = 128 - left_over > len ? len : 128 - left_over;

      memcpy (&ctx->buffer[left_over], buffer, add);
      ctx->buflen += add;

      if (left_over + add > 64)
	{
	  md5_process_block (ctx->buffer, (left_over + add) & ~63, ctx);
	  /* The regions in the following copy operation cannot overlap.  */
	  memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
		  (left_over + add) & 63);
	  ctx->buflen = (left_over + add) & 63;
	}

      buffer = (const char *) buffer + add;
      len -= add;
    }

  /* Process available complete blocks.  */
  if (len > 64)
    {
      md5_process_block (buffer, len & ~63, ctx);
      buffer = (const char *) buffer + (len & ~63);
      len &= 63;
    }

  /* Move remaining bytes in internal buffer.  */
  if (len > 0)
    {
      memcpy (ctx->buffer, buffer, len);
      ctx->buflen = len;
    }
}


/* These are the four functions used in the four steps of the MD5 algorithm
   and defined in the RFC 1321.  The first function is a little bit optimized
   (as found in Colin Plumbs public domain implementation).  */
/* #define FF(b, c, d) ((b & c) | (~b & d)) */
#define FF(b, c, d) (d ^ (b & (c ^ d)))
#define FG(b, c, d) FF (d, b, c)
#define FH(b, c, d) (b ^ c ^ d)
#define FI(b, c, d) (c ^ (b | ~d))

/* Process LEN bytes of BUFFER, accumulating context into CTX.
   It is assumed that LEN % 64 == 0.  */

void
md5_process_block (buffer, len, ctx)
     const void *buffer;
     size_t len;
     struct md5_ctx *ctx;
{
  md5_uint32 correct_words[16];
  const md5_uint32 *words = buffer;
  size_t nwords = len / sizeof (md5_uint32);
  const md5_uint32 *endp = words + nwords;
  md5_uint32 A = ctx->A;
  md5_uint32 B = ctx->B;
  md5_uint32 C = ctx->C;
  md5_uint32 D = ctx->D;

  /* First increment the byte count.  RFC 1321 specifies the possible
     length of the file up to 2^64 bits.  Here we only compute the
     number of bytes.  Do a double word increment.  */
  ctx->total[0] += len;
  if (ctx->total[0] < len)
    ++ctx->total[1];

  /* Process all bytes in the buffer with 64 bytes in each round of
     the loop.  */
  while (words < endp)
    {
      md5_uint32 *cwp = correct_words;
      md5_uint32 A_save = A;
      md5_uint32 B_save = B;
      md5_uint32 C_save = C;
      md5_uint32 D_save = D;

      /* First round: using the given function, the context and a constant
	 the next context is computed.  Because the algorithms processing
	 unit is a 32-bit word and it is determined to work on words in
	 little endian byte order we perhaps have to change the byte order
	 before the computation.  To reduce the work for the next steps
	 we store the swapped words in the array CORRECT_WORDS.  */

#define OP(a, b, c, d, s, T)						\
      do								\
        {								\
	  a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T;		\
	  ++words;							\
	  a = rol (a, s);						\
	  a += b;							\
        }								\
      while (0)

      /* Before we start, one word to the strange constants.
	 They are defined in RFC 1321 as

	 T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64, or
	 perl -e 'foreach(1..64){printf "0x%08x\n", int (4294967296 * abs (sin $_))}'
       */

      /* Round 1.  */
      OP (A, B, C, D,  7, 0xd76aa478);
      OP (D, A, B, C, 12, 0xe8c7b756);
      OP (C, D, A, B, 17, 0x242070db);
      OP (B, C, D, A, 22, 0xc1bdceee);
      OP (A, B, C, D,  7, 0xf57c0faf);
      OP (D, A, B, C, 12, 0x4787c62a);
      OP (C, D, A, B, 17, 0xa8304613);
      OP (B, C, D, A, 22, 0xfd469501);
      OP (A, B, C, D,  7, 0x698098d8);
      OP (D, A, B, C, 12, 0x8b44f7af);
      OP (C, D, A, B, 17, 0xffff5bb1);
      OP (B, C, D, A, 22, 0x895cd7be);
      OP (A, B, C, D,  7, 0x6b901122);
      OP (D, A, B, C, 12, 0xfd987193);
      OP (C, D, A, B, 17, 0xa679438e);
      OP (B, C, D, A, 22, 0x49b40821);

      /* For the second to fourth round we have the possibly swapped words
	 in CORRECT_WORDS.  Redefine the macro to take an additional first
	 argument specifying the function to use.  */
#undef OP
#define OP(f, a, b, c, d, k, s, T)					\
      do 								\
	{								\
	  a += f (b, c, d) + correct_words[k] + T;			\
	  a = rol (a, s);						\
	  a += b;							\
	}								\
      while (0)

      /* Round 2.  */
      OP (FG, A, B, C, D,  1,  5, 0xf61e2562);
      OP (FG, D, A, B, C,  6,  9, 0xc040b340);
      OP (FG, C, D, A, B, 11, 14, 0x265e5a51);
      OP (FG, B, C, D, A,  0, 20, 0xe9b6c7aa);
      OP (FG, A, B, C, D,  5,  5, 0xd62f105d);
      OP (FG, D, A, B, C, 10,  9, 0x02441453);
      OP (FG, C, D, A, B, 15, 14, 0xd8a1e681);
      OP (FG, B, C, D, A,  4, 20, 0xe7d3fbc8);
      OP (FG, A, B, C, D,  9,  5, 0x21e1cde6);
      OP (FG, D, A, B, C, 14,  9, 0xc33707d6);
      OP (FG, C, D, A, B,  3, 14, 0xf4d50d87);
      OP (FG, B, C, D, A,  8, 20, 0x455a14ed);
      OP (FG, A, B, C, D, 13,  5, 0xa9e3e905);
      OP (FG, D, A, B, C,  2,  9, 0xfcefa3f8);
      OP (FG, C, D, A, B,  7, 14, 0x676f02d9);
      OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a);

      /* Round 3.  */
      OP (FH, A, B, C, D,  5,  4, 0xfffa3942);
      OP (FH, D, A, B, C,  8, 11, 0x8771f681);
      OP (FH, C, D, A, B, 11, 16, 0x6d9d6122);
      OP (FH, B, C, D, A, 14, 23, 0xfde5380c);
      OP (FH, A, B, C, D,  1,  4, 0xa4beea44);
      OP (FH, D, A, B, C,  4, 11, 0x4bdecfa9);
      OP (FH, C, D, A, B,  7, 16, 0xf6bb4b60);
      OP (FH, B, C, D, A, 10, 23, 0xbebfbc70);
      OP (FH, A, B, C, D, 13,  4, 0x289b7ec6);
      OP (FH, D, A, B, C,  0, 11, 0xeaa127fa);
      OP (FH, C, D, A, B,  3, 16, 0xd4ef3085);
      OP (FH, B, C, D, A,  6, 23, 0x04881d05);
      OP (FH, A, B, C, D,  9,  4, 0xd9d4d039);
      OP (FH, D, A, B, C, 12, 11, 0xe6db99e5);
      OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8);
      OP (FH, B, C, D, A,  2, 23, 0xc4ac5665);

      /* Round 4.  */
      OP (FI, A, B, C, D,  0,  6, 0xf4292244);
      OP (FI, D, A, B, C,  7, 10, 0x432aff97);
      OP (FI, C, D, A, B, 14, 15, 0xab9423a7);
      OP (FI, B, C, D, A,  5, 21, 0xfc93a039);
      OP (FI, A, B, C, D, 12,  6, 0x655b59c3);
      OP (FI, D, A, B, C,  3, 10, 0x8f0ccc92);
      OP (FI, C, D, A, B, 10, 15, 0xffeff47d);
      OP (FI, B, C, D, A,  1, 21, 0x85845dd1);
      OP (FI, A, B, C, D,  8,  6, 0x6fa87e4f);
      OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
      OP (FI, C, D, A, B,  6, 15, 0xa3014314);
      OP (FI, B, C, D, A, 13, 21, 0x4e0811a1);
      OP (FI, A, B, C, D,  4,  6, 0xf7537e82);
      OP (FI, D, A, B, C, 11, 10, 0xbd3af235);
      OP (FI, C, D, A, B,  2, 15, 0x2ad7d2bb);
      OP (FI, B, C, D, A,  9, 21, 0xeb86d391);

      /* Add the starting values of the context.  */
      A += A_save;
      B += B_save;
      C += C_save;
      D += D_save;
    }

  /* Put checksum in context given as argument.  */
  ctx->A = A;
  ctx->B = B;
  ctx->C = C;
  ctx->D = D;
}

--- NEW FILE: dvdread_internal.h ---
#ifndef DVDREAD_INTERNAL_H
#define DVDREAD_INTERNAL_H

#ifdef _MSC_VER
#include <unistd.h>
#endif /* _MSC_VER */

#define CHECK_VALUE(arg) \
 if(!(arg)) { \
   fprintf(stderr, "\n*** libdvdread: CHECK_VALUE failed in %s:%i ***" \
                   "\n*** for %s ***\n\n", \
                   __FILE__, __LINE__, # arg ); \
 }

#endif /* DVDREAD_INTERNAL_H */

--- NEW FILE: dvd_input.c ---
(This appears to be a binary file; contents omitted.)

--- NEW FILE: md5.h ---
/* md5.h - Declaration of functions and data types used for MD5 sum
   computing library functions.
   Copyright (C) 1995, 1996, 1999 Free Software Foundation, Inc.
   NOTE: The canonical source of this file is maintained with the GNU C
   Library.  Bugs can be reported to bug-glibc@prep.ai.mit.edu.

   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, 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.  */

#ifndef _MD5_H
#define _MD5_H 1

#include <stdio.h>

#if defined HAVE_LIMITS_H || _LIBC
# include <limits.h>
#endif

/* The following contortions are an attempt to use the C preprocessor
   to determine an unsigned integral type that is 32 bits wide.  An
   alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but
   doing that would require that the configure script compile and *run*
   the resulting executable.  Locally running cross-compiled executables
   is usually not possible.  */

#ifdef _LIBC
# include <sys/types.h>
typedef u_int32_t md5_uint32;
#else
# if defined __STDC__ && __STDC__
#  define UINT_MAX_32_BITS 4294967295U
# else
#  define UINT_MAX_32_BITS 0xFFFFFFFF
# endif

/* If UINT_MAX isn't defined, assume it's a 32-bit type.
   This should be valid for all systems GNU cares about because
   that doesn't include 16-bit systems, and only modern systems
   (that certainly have <limits.h>) have 64+-bit integral types.  */

# ifndef UINT_MAX
#  define UINT_MAX UINT_MAX_32_BITS
# endif

# if UINT_MAX == UINT_MAX_32_BITS
   typedef unsigned int md5_uint32;
# else
#  if USHRT_MAX == UINT_MAX_32_BITS
    typedef unsigned short md5_uint32;
#  else
#   if ULONG_MAX == UINT_MAX_32_BITS
     typedef unsigned long md5_uint32;
#   else
     /* The following line is intended to evoke an error.
        Using #error is not portable enough.  */
     "Cannot determine unsigned 32-bit data type."
#   endif
#  endif
# endif
#endif

#undef __P
#if defined (__STDC__) && __STDC__
#define	__P(x) x
#else
#define	__P(x) ()
#endif

/* Structure to save state of computation between the single steps.  */
struct md5_ctx
{
  md5_uint32 A;
  md5_uint32 B;
  md5_uint32 C;
  md5_uint32 D;

  md5_uint32 total[2];
  md5_uint32 buflen;
  char buffer[128];
};

/*
 * The following three functions are build up the low level used in
 * the functions `md5_stream' and `md5_buffer'.
 */

/* Initialize structure containing state of computation.
   (RFC 1321, 3.3: Step 3)  */
extern void md5_init_ctx __P ((struct md5_ctx *ctx));

/* Starting with the result of former calls of this function (or the
   initialization function update the context for the next LEN bytes
   starting at BUFFER.
   It is necessary that LEN is a multiple of 64!!! */
extern void md5_process_block __P ((const void *buffer, size_t len,
				    struct md5_ctx *ctx));

/* Starting with the result of former calls of this function (or the
   initialization function update the context for the next LEN bytes
   starting at BUFFER.
   It is NOT required that LEN is a multiple of 64.  */
extern void md5_process_bytes __P ((const void *buffer, size_t len,
				    struct md5_ctx *ctx));

/* Process the remaining bytes in the buffer and put result from CTX
   in first 16 bytes following RESBUF.  The result is always in little
   endian byte order, so that a byte-wise output yields to the wanted
   ASCII representation of the message digest.

   IMPORTANT: On some systems it is required that RESBUF be correctly
   aligned for a 32 bits value.  */
extern void *md5_finish_ctx __P ((struct md5_ctx *ctx, void *resbuf));


/* Put result from CTX in first 16 bytes following RESBUF.  The result is
   always in little endian byte order, so that a byte-wise output yields
   to the wanted ASCII representation of the message digest.

   IMPORTANT: On some systems it is required that RESBUF is correctly
   aligned for a 32 bits value.  */
extern void *md5_read_ctx __P ((const struct md5_ctx *ctx, void *resbuf));


/* Compute MD5 message digest for bytes read from STREAM.  The
   resulting message digest number will be written into the 16 bytes
   beginning at RESBLOCK.  */
extern int md5_stream __P ((FILE *stream, void *resblock));

/* Compute MD5 message digest for LEN bytes beginning at BUFFER.  The
   result is always in little endian byte order, so that a byte-wise
   output yields to the wanted ASCII representation of the message
   digest.  */
extern void *md5_buffer __P ((const char *buffer, size_t len, void *resblock));

/* The following is from gnupg-1.0.2's cipher/bithelp.h.  */
/* Rotate a 32 bit integer by n bytes */
#if defined __GNUC__ && defined __i386__
static inline md5_uint32
rol(md5_uint32 x, int n)
{
  __asm__("roll %%cl,%0"
	  :"=r" (x)
	  :"0" (x),"c" (n));
  return x;
}
#else
# define rol(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) )
#endif

#endif

--- NEW FILE: nav_read.c ---
(This appears to be a binary file; contents omitted.)

--- NEW FILE: settings.c ---
/* 
 * Copyright (C) 2000 Rich Wareham <richwareham@users.sourceforge.net>
 * 
 * This file is part of libdvdnav, a DVD navigation library.
 * 
 * libdvdnav 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.
 * 
 * libdvdnav 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
 *
 * $Id: settings.c,v 1.1 2005/04/04 22:29:36 dsalt-guest Exp $
 *
 */

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

#include "dvdnav_internal.h"

/* Characteristics/setting API calls */

dvdnav_status_t dvdnav_get_region_mask(dvdnav_t *this, int32_t *region) {
  if(!this || !region) {
    printerr("Passed a NULL this pointer.");
    return DVDNAV_STATUS_ERR;
  }

  (*region) = this->vm->state.registers.SPRM[20];
  return DVDNAV_STATUS_OK;
}

dvdnav_status_t dvdnav_set_region_mask(dvdnav_t *this, int32_t mask) {
  if(!this) {
    printerr("Passed a NULL this pointer.");
    return DVDNAV_STATUS_ERR;
  }

  pthread_mutex_lock(&this->vm_lock);
  this->vm->state.registers.SPRM[20] = (mask & 0xff);
  pthread_mutex_unlock(&this->vm_lock);
  return DVDNAV_STATUS_OK;
}

dvdnav_status_t dvdnav_set_readahead_flag(dvdnav_t *this, int32_t use_readahead) {
  if(!this) {
    printerr("Passed a NULL this pointer.");
    return DVDNAV_STATUS_ERR;
  }

  this->use_read_ahead = use_readahead;
  return DVDNAV_STATUS_OK;
}

dvdnav_status_t dvdnav_get_readahead_flag(dvdnav_t *this, int32_t *flag) {
  if(!this || !flag) {
    printerr("Passed a NULL this pointer.");
    return DVDNAV_STATUS_ERR;
  }

  (*flag) = this->use_read_ahead;
  return DVDNAV_STATUS_OK;
}

static dvdnav_status_t set_language_register(dvdnav_t *this, char *code, int reg) {
  if(!this || !code) {
    printerr("Passed a NULL this pointer.");
    return DVDNAV_STATUS_ERR;
  }
    
  if(!code[0] || !code[1]) {
    printerr("Passed illegal language code.");
    return DVDNAV_STATUS_ERR;
  }
  
  pthread_mutex_lock(&this->vm_lock);
  this->vm->state.registers.SPRM[reg] = (code[0] << 8) | code[1];
  pthread_mutex_unlock(&this->vm_lock);
  return DVDNAV_STATUS_OK;
}

dvdnav_status_t dvdnav_menu_language_select(dvdnav_t *this, char *code) {
  return set_language_register(this, code, 0);
}

dvdnav_status_t dvdnav_audio_language_select(dvdnav_t *this, char *code) {
  return set_language_register(this, code, 16);
}

dvdnav_status_t dvdnav_spu_language_select(dvdnav_t *this, char *code) {
  return set_language_register(this, code, 18);
}

dvdnav_status_t dvdnav_set_PGC_positioning_flag(dvdnav_t *this, int32_t pgc) {
  if(!this) {
    printerr("Passed a NULL this pointer.");
    return DVDNAV_STATUS_ERR;
  }

  this->pgc_based = pgc;
  return DVDNAV_STATUS_OK;
}

dvdnav_status_t dvdnav_get_PGC_positioning_flag(dvdnav_t *this, int32_t *flag) {
  if(!this || !flag) {
    printerr("Passed a NULL this pointer.");
    return DVDNAV_STATUS_ERR;
  }

  (*flag) = this->pgc_based;
  return DVDNAV_STATUS_OK;
}