On Wed, Sep 05, 2012 at 04:16:47PM -0400, Brad Smith wrote:
> The following diff backports various fixes for libdvdnav for issues
> which result in crashing or issues with playback with certain DVDs.
> 
> Tested with Xine with a bunch of DVDs on amd64.

An updated diff with two additional fixes.


Index: Makefile
===================================================================
RCS file: /home/cvs/ports/multimedia/libdvdnav/Makefile,v
retrieving revision 1.18
diff -u -p -r1.18 Makefile
--- Makefile    5 Sep 2012 08:09:27 -0000       1.18
+++ Makefile    5 Sep 2012 18:28:31 -0000
@@ -5,14 +5,14 @@ SHARED_ONLY=  Yes
 COMMENT=       DVD navigation library
 
 DISTNAME=      libdvdnav-4.2.0
-REVISION=      1
+REVISION=      2
 EPOCH=         0
 CATEGORIES=    multimedia
 MASTER_SITES=  ${HOMEPAGE}releases/
 EXTRACT_SUFX=  .tar.bz2
 
-SHARED_LIBS=   dvdnav          6.1 \
-               dvdnavmini      6.1
+SHARED_LIBS=   dvdnav          6.2 \
+               dvdnavmini      6.2
 
 HOMEPAGE=      http://dvdnav.mplayerhq.hu/
 
@@ -22,7 +22,7 @@ PERMIT_DISTFILES_FTP= Yes
 PERMIT_PACKAGE_CDROM=  Yes
 PERMIT_PACKAGE_FTP=    Yes
 
-WANTLIB += dvdread pthread
+WANTLIB=       dvdread pthread
 
 AUTOCONF_VERSION= 2.61
 AUTOMAKE_VERSION= 1.10
Index: patches/patch-src_dvdnav_c
===================================================================
RCS file: patches/patch-src_dvdnav_c
diff -N patches/patch-src_dvdnav_c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ patches/patch-src_dvdnav_c  5 Sep 2012 18:50:18 -0000
@@ -0,0 +1,159 @@
+$OpenBSD$
+
+- Check that a VOB is open in case we need to open one
+- Add a function to create a dpu of a dvdnav handle
+- Prevent overflow by pre-casting to int64_t
+- Remove unneeded address-of of CLUT
+- Make sure we get nav packets for all cells in multi angle features
+- Test still like a boolean value and not an integer value
+- Always check whether a still is being handled
+
+--- src/dvdnav.c.orig  Wed Sep  5 14:23:55 2012
++++ src/dvdnav.c       Wed Sep  5 14:24:07 2012
+@@ -71,6 +71,67 @@ static dvdnav_status_t dvdnav_clear(dvdnav_t * this) {
+   return DVDNAV_STATUS_OK;
+ }
+ 
++dvdnav_status_t dvdnav_dup(dvdnav_t **dest, dvdnav_t *src) {
++  dvdnav_t *this;
++
++  (*dest) = NULL;
++  this = (dvdnav_t*)malloc(sizeof(dvdnav_t));
++  if(!this)
++    return DVDNAV_STATUS_ERR;
++
++  memcpy(this, src, sizeof(dvdnav_t));
++  this->file = NULL;
++
++  pthread_mutex_init(&this->vm_lock, NULL);
++
++  this->vm = vm_new_copy(src->vm);
++  if(!this->vm) {
++    printerr("Error initialising the DVD VM.");
++    pthread_mutex_destroy(&this->vm_lock);
++    free(this);
++    return DVDNAV_STATUS_ERR;
++  }
++
++  /* Start the read-ahead cache. */
++  this->cache = dvdnav_read_cache_new(this);
++
++  (*dest) = this;
++  return DVDNAV_STATUS_OK;
++}
++
++dvdnav_status_t dvdnav_free_dup(dvdnav_t *this) {
++
++#ifdef LOG_DEBUG
++  fprintf(MSG_OUT, "libdvdnav: free_dup:called\n");
++#endif
++
++  if (this->file) {
++    pthread_mutex_lock(&this->vm_lock);
++    DVDCloseFile(this->file);
++#ifdef LOG_DEBUG
++    fprintf(MSG_OUT, "libdvdnav: close:file closing\n");
++#endif
++    this->file = NULL;
++    pthread_mutex_unlock(&this->vm_lock);
++  }
++
++  /* Free the VM */
++  if(this->vm)
++    vm_free_copy(this->vm);
++
++  pthread_mutex_destroy(&this->vm_lock);
++
++  /* We leave the final freeing of the entire structure to the cache,
++   * because we don't know, if there are still buffers out in the wild,
++   * that must return first. */
++  if(this->cache)
++    dvdnav_read_cache_free(this->cache);
++  else
++    free(this);
++
++  return DVDNAV_STATUS_OK;
++}
++
+ dvdnav_status_t dvdnav_open(dvdnav_t** dest, const char *path) {
+   dvdnav_t *this;
+   struct timeval time;
+@@ -203,12 +264,12 @@ int64_t dvdnav_convert_time(dvd_time_t *time) {
+   int64_t result;
+   int64_t frames;
+ 
+-  result  = (time->hour    >> 4  ) * 10 * 60 * 60 * 90000;
+-  result += (time->hour    & 0x0f)      * 60 * 60 * 90000;
+-  result += (time->minute  >> 4  )      * 10 * 60 * 90000;
+-  result += (time->minute  & 0x0f)           * 60 * 90000;
+-  result += (time->second  >> 4  )           * 10 * 90000;
+-  result += (time->second  & 0x0f)                * 90000;
++  result  = ((int64_t)(time->hour    >> 4  )) * 10 * 60 * 60 * 90000;
++  result += ((int64_t)(time->hour    & 0x0f))      * 60 * 60 * 90000;
++  result += ((int64_t)(time->minute  >> 4  ))      * 10 * 60 * 90000;
++  result += ((int64_t)(time->minute  & 0x0f))           * 60 * 90000;
++  result += ((int64_t)(time->second  >> 4  ))           * 10 * 90000;
++  result += ((int64_t)(time->second  & 0x0f))                * 90000;
+ 
+   frames  = ((time->frame_u & 0x30) >> 4) * 10;
+   frames += ((time->frame_u & 0x0f)     )     ;
+@@ -336,9 +397,10 @@ static int32_t dvdnav_get_vobu(dvdnav_t *this, dsi_t *
+     dvdnav_angle_change(this, 1);
+   }
+ #endif
++  /* only use ILVU information if we are at the last vobunit in ILVU */
++  /* otherwise we will miss nav packets from vobunits inbetween */
++  if(num_angle != 0 && (nav_dsi->sml_pbi.category & DSI_ILVU_MASK) == 
(DSI_ILVU_BLOCK | DSI_ILVU_LAST)) {
+ 
+-  if(num_angle != 0) {
+-
+     if((next = nav_pci->nsml_agli.nsml_agl_dsta[angle-1]) != 0) {
+       if((next & 0x3fffffff) != 0) {
+       if(next & 0x80000000)
+@@ -518,8 +580,10 @@ dvdnav_status_t dvdnav_get_next_cache_block(dvdnav_t *
+     return DVDNAV_STATUS_OK;
+   }
+ 
+-  /* Check to see if we need to change the currently opened VOB */
+-  if((this->position_current.vts != this->position_next.vts) ||
++  /* Check to see if we need to change the currently opened VOB or open
++   * a new one because we don't currently have an opened VOB. */
++  if((this->file == NULL) ||
++     (this->position_current.vts != this->position_next.vts) ||
+      (this->position_current.domain != this->position_next.domain)) {
+     dvd_read_domain_t domain;
+     int32_t vtsN;
+@@ -655,7 +719,7 @@ dvdnav_status_t dvdnav_get_next_cache_block(dvdnav_t *
+     fprintf(MSG_OUT, "libdvdnav: SPU_CLUT_CHANGE\n");
+ #endif
+     (*len) = 16 * sizeof(uint32_t);
+-    memcpy(*buf, &(state->pgc->palette), 16 * sizeof(uint32_t));
++    memcpy(*buf, state->pgc->palette, sizeof(state->pgc->palette));
+     this->spu_clut_changed = 0;
+     pthread_mutex_unlock(&this->vm_lock);
+     return DVDNAV_STATUS_OK;
+@@ -731,16 +795,15 @@ dvdnav_status_t dvdnav_get_next_cache_block(dvdnav_t *
+       /* we are about to leave a cell, so a lot of state changes could occur;
+        * under certain conditions, the application should get in sync with us 
before this,
+        * otherwise it might show stills or menus too shortly */
+-      if ((this->position_current.still || this->pci.hli.hl_gi.hli_ss) && 
!this->sync_wait_skip) {
++      if ((this->position_current.still || this->pci.hli.hl_gi.hli_ss) && 
!this->sync_wait_skip)
+         this->sync_wait = 1;
+-      } else {
+-      if( this->position_current.still == 0 || this->skip_still ) {
+-        /* no active cell still -> get us to the next cell */
+-        vm_get_next_cell(this->vm);
+-        this->position_current.still = 0; /* still gets activated at end of 
cell */
+-        this->skip_still = 0;
+-        this->sync_wait_skip = 0;
+-      }
++
++      if(!this->position_current.still || this->skip_still ) {
++      /* no active cell still -> get us to the next cell */
++      vm_get_next_cell(this->vm);
++      this->position_current.still = 0; /* still gets activated at end of 
cell */
++      this->skip_still = 0;
++      this->sync_wait_skip = 0;
+       }
+       /* handle related state changes in next iteration */
+       (*event) = DVDNAV_NOP;
Index: patches/patch-src_dvdnav_dvdnav_h
===================================================================
RCS file: patches/patch-src_dvdnav_dvdnav_h
diff -N patches/patch-src_dvdnav_dvdnav_h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ patches/patch-src_dvdnav_dvdnav_h   12 Sep 2012 00:39:17 -0000
@@ -0,0 +1,36 @@
+$OpenBSD$
+
+- Add a function to create a dpu of a dvdnav handle
+- Fix C++ compatibility broken in r1208
+- Allow backward search for SEEK_CUR
+
+--- src/dvdnav/dvdnav.h.orig   Sat Feb 26 15:32:32 2011
++++ src/dvdnav/dvdnav.h        Tue Sep 11 20:35:47 2012
+@@ -89,6 +89,9 @@ typedef int32_t dvdnav_status_t;
+  */
+ dvdnav_status_t dvdnav_open(dvdnav_t **dest, const char *path);
+ 
++dvdnav_status_t dvdnav_dup(dvdnav_t **dest, dvdnav_t *src);
++dvdnav_status_t dvdnav_free_dup(dvdnav_t *this);
++
+ /*
+  * Closes a dvdnav_t previously opened with dvdnav_open(), freeing any
+  * memory associated with it.
+@@ -281,7 +284,7 @@ dvdnav_status_t dvdnav_part_play(dvdnav_t *self, int32
+ /*
+  * Plays the specified title, starting from the specified program
+  */
+-dvdnav_status_t dvdnav_program_play(dvdnav_t *this, int32_t title, int32_t 
pgcn, int32_t pgn);
++dvdnav_status_t dvdnav_program_play(dvdnav_t *self, int32_t title, int32_t 
pgcn, int32_t pgn);
+ 
+ /*
+  * Stores in *times an array (that the application *must* free) of
+@@ -370,7 +373,7 @@ dvdnav_status_t dvdnav_part_search(dvdnav_t *self, int
+  * fcntl.h.
+  */
+ dvdnav_status_t dvdnav_sector_search(dvdnav_t *self,
+-                                   uint64_t offset, int32_t origin);
++                                   int64_t offset, int32_t origin);
+ 
+ /*
+  returns the current stream time in PTS ticks as reported by the IFO 
structures
Index: patches/patch-src_dvdnav_internal_h
===================================================================
RCS file: patches/patch-src_dvdnav_internal_h
diff -N patches/patch-src_dvdnav_internal_h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ patches/patch-src_dvdnav_internal_h 5 Sep 2012 18:43:57 -0000
@@ -0,0 +1,21 @@
+$OpenBSD$
+
+Bit fields for ILVU
+
+--- src/dvdnav_internal.h.orig Wed Sep  5 14:23:14 2012
++++ src/dvdnav_internal.h      Wed Sep  5 14:23:26 2012
+@@ -76,6 +76,14 @@ static inline int _private_gettimeofday( struct timeva
+ #define DVD_VIDEO_LB_LEN 2048
+ #endif
+ 
++typedef enum {
++  DSI_ILVU_PRE   = 1 << 15, /* set during the last 3 VOBU preceeding an 
interleaved block. */
++  DSI_ILVU_BLOCK = 1 << 14, /* set for all VOBU in an interleaved block */
++  DSI_ILVU_FIRST = 1 << 13, /* set for the first VOBU for a given angle or 
scene within a ILVU, or the first VOBU in the preparation (PREU) sequence */
++  DSI_ILVU_LAST  = 1 << 12, /* set for the last VOBU for a given angle or 
scene within a ILVU, or the last VOBU in the preparation (PREU) sequence */
++  DSI_ILVU_MASK  = 0xf000
++} DSI_ILVU;
++
+ typedef struct read_cache_s read_cache_t;
+ 
+ /*
Index: patches/patch-src_highlight_c
===================================================================
RCS file: patches/patch-src_highlight_c
diff -N patches/patch-src_highlight_c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ patches/patch-src_highlight_c       5 Sep 2012 18:45:11 -0000
@@ -0,0 +1,34 @@
+$OpenBSD$
+
+Pointer validation fixing
+
+--- src/highlight.c.orig       Wed Sep  5 14:21:14 2012
++++ src/highlight.c    Wed Sep  5 14:21:20 2012
+@@ -242,8 +242,13 @@ static btni_t *get_current_button(dvdnav_t *this, pci_
+ }
+ 
+ static dvdnav_status_t button_auto_action(dvdnav_t *this, pci_t *pci) {
+-  if (get_current_button(this, pci)->auto_action_mode)
++  btni_t *button_ptr;
++  if ((button_ptr = get_current_button(this, pci)) == NULL)
++      return DVDNAV_STATUS_ERR;
++
++  if (button_ptr->auto_action_mode)
+     return dvdnav_button_activate(this, pci);
++
+   return DVDNAV_STATUS_OK;
+ }
+ 
+@@ -366,7 +371,11 @@ dvdnav_status_t dvdnav_button_activate(dvdnav_t *this,
+     return DVDNAV_STATUS_ERR;
+   }
+ 
+-  button_ptr = get_current_button(this, pci);
++  if ((button_ptr = get_current_button(this, pci)) == NULL) {
++    pthread_mutex_unlock(&this->vm_lock);
++    return DVDNAV_STATUS_ERR;
++  }
++
+   /* Finally, make the VM execute the appropriate code and probably
+    * schedule a jump */
+ #ifdef BUTTON_TESTING
Index: patches/patch-src_remap_c
===================================================================
RCS file: patches/patch-src_remap_c
diff -N patches/patch-src_remap_c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ patches/patch-src_remap_c   5 Sep 2012 18:48:38 -0000
@@ -0,0 +1,67 @@
+$OpenBSD$
+
+- Initialize epos
+- Pointer validation fixing
+
+--- src/remap.c.orig   Wed Sep  5 14:20:01 2012
++++ src/remap.c        Wed Sep  5 14:20:08 2012
+@@ -62,6 +62,9 @@ struct remap_s {
+ 
+ static remap_t* remap_new( char *title) {
+     remap_t *map = malloc( sizeof(remap_t));
++    if (map == NULL)
++      return NULL;
++
+     map->title = strdup(title);
+     map->maxblocks = 0;
+     map->nblocks = 0;
+@@ -139,8 +142,10 @@ static void remap_add_node( remap_t *map, block_t bloc
+     } else {
+         /* new block */
+       if (map->nblocks >= map->maxblocks) {
++          if ((map->blocks = realloc( map->blocks, sizeof( block_t)*( 
map->maxblocks + 20))) == NULL)
++              return;
++
+           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) {
+@@ -155,10 +160,12 @@ static int parseblock(char *buf, int *dom, int *tt, in
+                     unsigned long *start, unsigned long *end) {
+     long tmp;
+     char *tok;
+-    char *epos;
++    char *epos = NULL;
+     char *marker[]={"domain", "title", "program", "start", "end"};
+     int st = 0;
+-    tok = strtok( buf, " ");
++    if ((tok = strtok( buf, " ")) == NULL)
++        return st;
++
+     while (st < 5) {
+         if (strcmp(tok, marker[st])) return -st-1000;
+         tok = strtok( NULL, " ");
+@@ -183,7 +190,7 @@ static int parseblock(char *buf, int *dom, int *tt, in
+               break;
+       }
+       st++;
+-        tok = strtok( NULL, " ");
++        if (!(tok = strtok( NULL, " "))) return -st-2000;
+     }
+     return st;
+ }
+@@ -214,7 +221,12 @@ remap_t* remap_loadmap( char *title) {
+     }
+ 
+     /* Load the map file */
+-    map = remap_new( title);
++    if ((map = remap_new( title)) == NULL) {
++      fprintf(MSG_OUT, "libdvdnav: Unable to load map '%s'\n", title);
++        fclose(fp);
++      return NULL;
++    }
++
+     while (fgets( buf, sizeof(buf), fp) != NULL) {
+         if (buf[0] == '\n' || buf[0] == '#' || buf[0] == 0) continue;
+         if (strncasecmp( buf, "debug", 5) == 0) {
Index: patches/patch-src_searching_c
===================================================================
RCS file: patches/patch-src_searching_c
diff -N patches/patch-src_searching_c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ patches/patch-src_searching_c       12 Sep 2012 00:40:31 -0000
@@ -0,0 +1,182 @@
+$OpenBSD$
+
+- Skip PGCs w/ a cell number of 0
+- Ignore parts where the pgc start byte is above the last byte
+- Make sure pgc is valid before dereferencing
+- Check cell new row before using it to index into cell_playback
+- Initialize next_vobu
+- Rework functions that call vm_copy_vm()
+- Fix calculation for multi-angle DVDs
+- Allow backward search for SEEK_CUR
+
+--- src/searching.c.orig       Fri Oct  7 13:06:24 2011
++++ src/searching.c    Tue Sep 11 20:38:00 2012
+@@ -73,7 +73,7 @@ static dvdnav_status_t dvdnav_scan_admap(dvdnav_t *thi
+   }
+   if(admap) {
+     uint32_t address = 0;
+-    uint32_t vobu_start, next_vobu;
++    uint32_t vobu_start, next_vobu = 0;
+     int admap_entries = (admap->last_byte + 1 - 
VOBU_ADMAP_SIZE)/VOBU_ADMAP_SIZE;
+ 
+     /* Search through ADMAP for best sector */
+@@ -182,7 +182,7 @@ dvdnav_status_t dvdnav_time_search(dvdnav_t *this,
+ }
+ 
+ dvdnav_status_t dvdnav_sector_search(dvdnav_t *this,
+-                                   uint64_t offset, int32_t origin) {
++                                   int64_t offset, int32_t origin) {
+   uint32_t target = 0;
+   uint32_t current_pos;
+   uint32_t cur_sector;
+@@ -213,7 +213,7 @@ dvdnav_status_t dvdnav_sector_search(dvdnav_t *this,
+     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: seeking to offset=%lld pos=%u length=%u\n", 
offset, target, length);
+   fprintf(MSG_OUT, "libdvdnav: Before cellN=%u blockN=%u\n", state->cellN, 
state->blockN);
+ #endif
+ 
+@@ -231,11 +231,16 @@ dvdnav_status_t dvdnav_sector_search(dvdnav_t *this,
+     target = offset;
+     break;
+    case SEEK_CUR:
+-    if(target + offset >= length) {
++    if((signed)target + offset >= length) {
+       printerr("Request to seek behind end.");
+       pthread_mutex_unlock(&this->vm_lock);
+       return DVDNAV_STATUS_ERR;
+     }
++    if((signed)target + offset < 0) {
++      printerr("Request to seek before start.");
++      pthread_mutex_unlock(&this->vm_lock);
++      return DVDNAV_STATUS_ERR;
++    }
+     target += offset;
+     break;
+    case SEEK_END:
+@@ -403,8 +408,7 @@ dvdnav_status_t dvdnav_next_pg_search(dvdnav_t *this) 
+   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;
++    goto fail;
+   }
+ 
+ #ifdef LOG_DEBUG
+@@ -412,17 +416,25 @@ dvdnav_status_t dvdnav_next_pg_search(dvdnav_t *this) 
+ #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 (try_vm == NULL) {
++    printerr("Unable to copy the VM.");
++    goto fail;
++  }
++
+   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);
++    if (try_vm == NULL) {
++      printerr("Unable to copy the VM.");
++      goto fail;
++    }
+     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;
++      goto fail;
+     }
+   }
+   this->cur_cell_time = 0;
+@@ -437,6 +449,10 @@ dvdnav_status_t dvdnav_next_pg_search(dvdnav_t *this) 
+   pthread_mutex_unlock(&this->vm_lock);
+ 
+   return DVDNAV_STATUS_OK;
++
++fail:
++  pthread_mutex_unlock(&this->vm_lock);
++  return DVDNAV_STATUS_ERR;
+ }
+ 
+ dvdnav_status_t dvdnav_menu_call(dvdnav_t *this, DVDMenuID_t menu) {
+@@ -445,13 +461,17 @@ dvdnav_status_t dvdnav_menu_call(dvdnav_t *this, DVDMe
+   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;
++    goto fail;
+   }
+ 
+   this->cur_cell_time = 0;
+   /* make a copy of current VM and try to navigate the copy to the menu */
+   try_vm = vm_new_copy(this->vm);
++  if (try_vm == NULL) {
++    printerr("Unable to copy VM.");
++    goto fail;
++  }
++
+   if ( (menu == DVD_MENU_Escape) && (this->vm->state.domain != VTS_DOMAIN)) {
+     /* Try resume */
+     if (vm_jump_resume(try_vm) && !try_vm->stopped) {
+@@ -477,9 +497,12 @@ dvdnav_status_t dvdnav_menu_call(dvdnav_t *this, DVDMe
+   } else {
+     vm_free_copy(try_vm);
+     printerr("No such menu or menu not reachable.");
+-    pthread_mutex_unlock(&this->vm_lock);
+-    return DVDNAV_STATUS_ERR;
++    goto fail;
+   }
++
++fail:
++  pthread_mutex_unlock(&this->vm_lock);
++  return DVDNAV_STATUS_ERR;
+ }
+ 
+ dvdnav_status_t dvdnav_get_position(dvdnav_t *this, uint32_t *pos,
+@@ -530,6 +553,8 @@ dvdnav_status_t dvdnav_get_position(dvdnav_t *this, ui
+   *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->block_type == BLOCK_TYPE_ANGLE_BLOCK && cell->block_mode != 
BLOCK_MODE_FIRST_CELL)
++        continue;
+     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 */
+@@ -616,13 +641,29 @@ uint32_t dvdnav_describe_title_chapters(dvdnav_t *this
+   length = 0;
+   for(i=0; i<parts; i++) {
+     uint32_t cellnr, endcellnr;
++    if (ifo->vts_pgcit->pgci_srp[ptt[i].pgcn-1].pgc_start_byte >= 
ifo->vts_pgcit->last_byte) {
++      printerr("PGC start out of bounds");
++      continue;
++    }
+     pgc = ifo->vts_pgcit->pgci_srp[ptt[i].pgcn-1].pgc;
++    if (pgc == NULL) {
++      printerr("PGC missing.");
++      continue;
++    }
+     if(ptt[i].pgn > pgc->nr_of_programs) {
+       printerr("WRONG part number.");
+       goto fail;
+     }
+ 
+-    cellnr = pgc->program_map[ptt[i].pgn-1];
++    if (pgc->nr_of_cells == 0) {
++      printerr("Number of cells cannot be 0");
++      continue;
++    }
++    if ((cellnr = pgc->program_map[ptt[i].pgn-1]) == 0) {
++      printerr("Cell new row cannot be 0");
++      continue;
++    }
++
+     if(ptt[i].pgn < pgc->nr_of_programs)
+       endcellnr = pgc->program_map[ptt[i].pgn];
+     else
Index: patches/patch-src_vm_vm_c
===================================================================
RCS file: patches/patch-src_vm_vm_c
diff -N patches/patch-src_vm_vm_c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ patches/patch-src_vm_vm_c   5 Sep 2012 19:00:47 -0000
@@ -0,0 +1,324 @@
+$OpenBSD$
+
+- Reset the vm if necessary
+- Use vm_close() w/in vm.c where appropriate
+- Add the static function vm_close()
+- Check the return value of dvd_read_name
+- Rewrite dvd_read_name to return a value
+- Prevent general CPP macro from causing strange behavior
+- Replace assert w/ a conditional and a null return
+- Initialize link_values
+- Pointer validation fixing
+- Return 0 instead of an assert
+
+--- src/vm/vm.c.orig   Wed Sep  5 14:18:33 2012
++++ src/vm/vm.c        Wed Sep  5 14:18:50 2012
+@@ -59,7 +59,7 @@
+ #endif
+ 
+ /*
+-#define STRICT
++#define DVDNAV_STRICT
+ */
+ 
+ /* Local prototypes */
+@@ -101,8 +101,8 @@ static int get_PGCN(vm_t *vm);
+ static pgcit_t* get_MENU_PGCIT(vm_t *vm, ifo_handle_t *h, uint16_t lang);
+ static pgcit_t* get_PGCIT(vm_t *vm);
+ 
+-
+ /* Helper functions */
++static void vm_close(vm_t *vm);
+ 
+ #ifdef TRACE
+ static void vm_print_current_domain_state(vm_t *vm) {
+@@ -162,64 +162,86 @@ static int os2_open(const char *name, int oflag)
+ }
+ #endif
+ 
+-static void dvd_read_name(char *name, char *serial, const char *device) {
+-    /* Because we are compiling with _FILE_OFFSET_BITS=64
+-     * all off_t are 64bit.
+-     */
+-    off_t off;
+-    int fd, i;
+-    uint8_t data[DVD_VIDEO_LB_LEN];
++static int dvd_read_name(char *name, char *serial, const char *device) {
++  /* Because we are compiling with _FILE_OFFSET_BITS=64
++   * all off_t are 64bit.
++   */
++  off_t off;
++  ssize_t read_size = 0;
++  int fd = -1, i;
++  uint8_t data[DVD_VIDEO_LB_LEN];
+ 
+-    /* Read DVD name */
+-    fd = open(device, O_RDONLY);
+-    if (fd > 0) {
+-      off = lseek( fd, 32 * (off_t) DVD_VIDEO_LB_LEN, SEEK_SET );
+-      if( off == ( 32 * (off_t) DVD_VIDEO_LB_LEN ) ) {
+-        off = read( fd, data, DVD_VIDEO_LB_LEN );
+-        close(fd);
+-        if (off == ( (off_t) DVD_VIDEO_LB_LEN )) {
+-          fprintf(MSG_OUT, "libdvdnav: DVD Title: ");
+-          for(i=25; i < 73; i++ ) {
+-            if((data[i] == 0)) break;
+-            if((data[i] > 32) && (data[i] < 127)) {
+-              fprintf(MSG_OUT, "%c", data[i]);
+-            } else {
+-              fprintf(MSG_OUT, " ");
+-            }
+-          }
+-          strncpy(name, (char*) &data[25], 48);
+-          name[48] = 0;
+-          fprintf(MSG_OUT, "\nlibdvdnav: DVD Serial Number: ");
+-          for(i=73; i < 89; i++ ) {
+-            if((data[i] == 0)) break;
+-            if((data[i] > 32) && (data[i] < 127)) {
+-              fprintf(MSG_OUT, "%c", data[i]);
+-            } else {
+-              fprintf(MSG_OUT, " ");
+-            }
+-          }
+-          strncpy(serial, (char*) &data[73], (i-73));
+-          serial[14] = 0;
+-          fprintf(MSG_OUT, "\nlibdvdnav: DVD Title (Alternative): ");
+-          for(i=89; i < 128; i++ ) {
+-            if((data[i] == 0)) break;
+-            if((data[i] > 32) && (data[i] < 127)) {
+-              fprintf(MSG_OUT, "%c", data[i]);
+-            } else {
+-              fprintf(MSG_OUT, " ");
+-            }
+-          }
+-          fprintf(MSG_OUT, "\n");
+-        } else {
+-          fprintf(MSG_OUT, "libdvdnav: Can't read name block. Probably not a 
DVD-ROM device.\n");
+-        }
+-      } else {
+-        fprintf(MSG_OUT, "libdvdnav: Can't seek to block %u\n", 32 );
+-      }
+-      close(fd);
++  /* Read DVD name */
++  if (device == NULL) {
++    fprintf(MSG_OUT, "libdvdnav: Device name string NULL\n");
++    goto fail;
++  }
++  if ((fd = open(device, O_RDONLY)) == -1) {
++    fprintf(MSG_OUT, "libdvdnav: Unable to open device file %s.\n", device);
++    goto fail;
++  }
++
++  if ((off = lseek( fd, 32 * (off_t) DVD_VIDEO_LB_LEN, SEEK_SET )) == (off_t) 
- 1) {
++    fprintf(MSG_OUT, "libdvdnav: Unable to seek to the title block %u.\n", 
32);
++    goto fail;
++  }
++
++  if( off != ( 32 * (off_t) DVD_VIDEO_LB_LEN ) ) {
++    fprintf(MSG_OUT, "libdvdnav: Can't seek to block %u\n", 32 );
++    goto fail;
++  }
++
++  if ((read_size = read( fd, data, DVD_VIDEO_LB_LEN )) == -1) {
++    fprintf(MSG_OUT, "libdvdnav: Can't read name block. Probably not a 
DVD-ROM device.\n");
++    goto fail;
++  }
++
++  close(fd);
++  fd = -1;
++  if (read_size != DVD_VIDEO_LB_LEN) {
++    fprintf(MSG_OUT, "libdvdnav: Can't read name block. Probably not a 
DVD-ROM device.\n");
++    goto fail;
++  }
++
++  fprintf(MSG_OUT, "libdvdnav: DVD Title: ");
++  for(i=25; i < 73; i++ ) {
++    if((data[i] == 0)) break;
++    if((data[i] > 32) && (data[i] < 127)) {
++      fprintf(MSG_OUT, "%c", data[i]);
+     } else {
+-    fprintf(MSG_OUT, "NAME OPEN FAILED\n");
++      fprintf(MSG_OUT, " ");
++    }
+   }
++  strncpy(name, (char*) &data[25], 48);
++  name[48] = 0;
++  fprintf(MSG_OUT, "\nlibdvdnav: DVD Serial Number: ");
++  for(i=73; i < 89; i++ ) {
++    if((data[i] == 0)) break;
++    if((data[i] > 32) && (data[i] < 127)) {
++      fprintf(MSG_OUT, "%c", data[i]);
++    } else {
++      fprintf(MSG_OUT, " ");
++    }
++  }
++  strncpy(serial, (char*) &data[73], (i-73));
++  serial[14] = 0;
++  fprintf(MSG_OUT, "\nlibdvdnav: DVD Title (Alternative): ");
++  for(i=89; i < 128; i++ ) {
++    if((data[i] == 0)) break;
++    if((data[i] > 32) && (data[i] < 127)) {
++      fprintf(MSG_OUT, "%c", data[i]);
++    } else {
++      fprintf(MSG_OUT, " ");
++    }
++  }
++  fprintf(MSG_OUT, "\n");
++  return 1;
++
++fail:
++  if (fd >= 0)
++    close(fd);
++
++  return 0;
+ }
+ 
+ static int ifoOpenNewVTSI(vm_t *vm, dvd_reader_t *dvd, int vtsN) {
+@@ -268,7 +290,7 @@ vm_t* vm_new_vm() {
+ }
+ 
+ void vm_free_vm(vm_t *vm) {
+-  vm_stop(vm);
++  vm_close(vm);
+   free(vm);
+ }
+ 
+@@ -294,6 +316,12 @@ dvd_reader_t *vm_get_dvd_reader(vm_t *vm) {
+ /* Basic Handling */
+ 
+ int vm_start(vm_t *vm) {
++  if (vm->stopped) {
++    if (!vm_reset(vm, NULL))
++      return 0;
++
++    vm->stopped = 0;
++  }
+   /* Set pgc to FP (First Play) pgc */
+   set_FP_PGC(vm);
+   process_command(vm, play_PGC(vm));
+@@ -301,6 +329,10 @@ int vm_start(vm_t *vm) {
+ }
+ 
+ void vm_stop(vm_t *vm) {
++  vm->stopped = 1;
++}
++
++static void vm_close(vm_t *vm) {
+   if(vm->vmgi) {
+     ifoClose(vm->vmgi);
+     vm->vmgi=NULL;
+@@ -352,7 +384,7 @@ int vm_reset(vm_t *vm, const char *dvdroot) {
+ 
+   if (vm->dvd && dvdroot) {
+     /* a new dvd device has been requested */
+-    vm_stop(vm);
++    vm_close(vm);
+   }
+   if (!vm->dvd) {
+     vm->dvd = DVDOpen(dvdroot);
+@@ -390,8 +422,8 @@ int vm_reset(vm_t *vm, const char *dvdroot) {
+       /* return 0; Not really used for now.. */
+     }
+     /* ifoRead_TXTDT_MGI(vmgi); Not implemented yet */
+-    dvd_read_name(vm->dvd_name, vm->dvd_serial, dvdroot);
+-    vm->map  = remap_loadmap(vm->dvd_name);
++    if (dvd_read_name(vm->dvd_name, vm->dvd_serial, dvdroot) == 1)
++      vm->map  = remap_loadmap(vm->dvd_name);
+   }
+   if (vm->vmgi) {
+     int i, mask;
+@@ -414,7 +446,8 @@ vm_t *vm_new_copy(vm_t *source) {
+   int pgcN = get_PGCN(source);
+   int pgN  = (source->state).pgN;
+ 
+-  assert(pgcN);
++  if (target == NULL || pgcN == 0)
++    goto fail;
+ 
+   memcpy(target, source, sizeof(vm_t));
+ 
+@@ -424,15 +457,22 @@ vm_t *vm_new_copy(vm_t *source) {
+   if (vtsN > 0) {
+     (target->state).vtsN = 0;
+     if (!ifoOpenNewVTSI(target, target->dvd, vtsN))
+-      assert(0);
++      goto fail;
+ 
+     /* restore pgc pointer into the new vtsi */
+     if (!set_PGCN(target, pgcN))
+-      assert(0);
++      goto fail;
++
+     (target->state).pgN = pgN;
+   }
+ 
+   return target;
++
++fail:
++  if (target != NULL)
++    vm_free_vm(target);
++
++  return NULL;
+ }
+ 
+ void vm_merge(vm_t *target, vm_t *source) {
+@@ -1050,7 +1090,7 @@ static link_t play_PGC_PG(vm_t *vm, int pgN) {
+ }
+ 
+ static link_t play_PGC_post(vm_t *vm) {
+-  link_t link_values;
++  link_t link_values = { LinkNoLink, 0, 0, 0 };
+ 
+ #ifdef TRACE
+   fprintf(MSG_OUT, "libdvdnav: play_PGC_post:\n");
+@@ -1129,7 +1169,7 @@ static link_t play_Cell(vm_t *vm) {
+     case 1: /*  Angle block */
+       /* Loop and check each cell instead? So we don't get outside the block? 
*/
+       (vm->state).cellN += (vm->state).AGL_REG - 1;
+-#ifdef STRICT
++#ifdef DVDNAV_STRICT
+       assert((vm->state).cellN <= (vm->state).pgc->nr_of_cells);
+       assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_mode 
!= 0);
+       assert((vm->state).pgc->cell_playback[(vm->state).cellN - 1].block_type 
== 1);
+@@ -1187,15 +1227,6 @@ static link_t play_Cell_post(vm_t *vm) {
+   if(cell->cell_cmd_nr != 0) {
+     link_t link_values;
+ 
+-/*  These asserts are now not needed.
+- *  Some DVDs have no cell commands listed in the PGC,
+- *  but the Cell itself points to a cell command that does not exist.
+- *  For this situation, just ignore the cell command and continue.
+- *
+- *  assert((vm->state).pgc->command_tbl != NULL);
+- *  assert((vm->state).pgc->command_tbl->nr_of_cell >= cell->cell_cmd_nr);
+- */
+-
+     if ((vm->state).pgc->command_tbl != NULL &&
+         (vm->state).pgc->command_tbl->nr_of_cell >= cell->cell_cmd_nr) {
+ #ifdef TRACE
+@@ -1762,7 +1793,8 @@ static int set_PGCN(vm_t *vm, int pgcN) {
+   pgcit_t *pgcit;
+ 
+   pgcit = get_PGCIT(vm);
+-  assert(pgcit != NULL);  /* ?? Make this return -1 instead */
++  if (pgcit == NULL)
++    return 0;
+ 
+   if(pgcN < 1 || pgcN > pgcit->nr_of_pgci_srp) {
+ #ifdef TRACE
+@@ -1797,12 +1829,11 @@ static int set_PGN(vm_t *vm) {
+   (vm->state).pgN = new_pgN;
+ 
+   if((vm->state).domain == VTS_DOMAIN) {
+-    playback_type_t *pb_ty;
+     if((vm->state).TTN_REG > vm->vmgi->tt_srpt->nr_of_srpts)
+       return 0; /* ?? */
+-    pb_ty = &vm->vmgi->tt_srpt->title[(vm->state).TTN_REG - 1].pb_ty;
+-      vm_get_current_title_part(vm, &dummy, &part);
+-      (vm->state).PTTN_REG = part;
++
++    vm_get_current_title_part(vm, &dummy, &part);
++    (vm->state).PTTN_REG = part;
+   }
+   return 1;
+ }

-- 
This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.

Reply via email to