$OpenBSD: patch-src_searching_c,v 1.1 2012/09/26 00:04:09 brad Exp $

- 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
