[cvs-annodex] commit (/annodex): liboggz/trunk/src/liboggz/Makefile.am liboggz/trunk/src/liboggz/oggz_read.c +liboggz/trunk/src/liboggz/oggz_seek.c

conrad nobody at lists.annodex.net
Tue Feb 1 20:34:55 EST 2005


Update of /annodex (new revision 806)

Added files:
   liboggz/trunk/src/liboggz/oggz_seek.c

Modified files:
   liboggz/trunk/src/liboggz/Makefile.am
   liboggz/trunk/src/liboggz/oggz_read.c

Log Message:
cleanup -- move all seeking code out to oggz_seek.c


Modified: liboggz/trunk/src/liboggz/Makefile.am
===================================================================
--- liboggz/trunk/src/liboggz/Makefile.am	2005-02-01 08:59:55 UTC (rev 805)
+++ liboggz/trunk/src/liboggz/Makefile.am	2005-02-01 09:34:52 UTC (rev 806)
@@ -14,6 +14,7 @@
 	oggz_private.h oggz_byteorder.h oggz_compat.h oggz_macros.h \
 	oggz_io.c \
 	oggz_read.c oggz_write.c \
+	oggz_seek.c \
 	oggz_auto.c oggz_auto.h \
 	oggz_stream.c oggz_stream.h \
 	oggz_table.c \

Modified: liboggz/trunk/src/liboggz/oggz_read.c
===================================================================
--- liboggz/trunk/src/liboggz/oggz_read.c	2005-02-01 08:59:55 UTC (rev 805)
+++ liboggz/trunk/src/liboggz/oggz_read.c	2005-02-01 09:34:52 UTC (rev 806)
@@ -505,767 +505,7 @@
   return nread;
 }
 
-/* oggz_seek() (and oggz_purge()) related functions from here down */
 
-/*
- * The typical usage is:
- *
- *   oggz_set_data_start (oggz, oggz_tell (oggz));
- */
-int
-oggz_set_data_start (OGGZ * oggz, oggz_off_t offset)
-{
-  if (oggz == NULL) return -1;
-
-  if (offset < 0) return -1;
-
-  oggz->offset_data_begin = offset;
-
-  return 0;
-}
-
-static oggz_off_t
-oggz_tell_raw (OGGZ * oggz)
-{
-  oggz_off_t offset_at;
-
-  offset_at = oggz_io_tell (oggz);
-
-  return offset_at;
-}
-
-/*
- * seeks and syncs
- */
-static oggz_off_t
-oggz_seek_raw (OGGZ * oggz, oggz_off_t offset, int whence)
-{
-  OggzReader * reader = &oggz->x.reader;
-  oggz_off_t offset_at;
-
-  if (oggz_io_seek (oggz, offset, whence) == -1) {
-    return -1;
-  }
-
-  offset_at = oggz_io_tell (oggz);
-
-  oggz->offset = offset_at;
-
-  ogg_sync_reset (&reader->ogg_sync);
-
-  return offset_at;
-}
-
-static int
-oggz_stream_reset (void * data)
-{
-  oggz_stream_t * stream = (oggz_stream_t *) data;
-
-  if (stream->ogg_stream.serialno != -1) {
-    ogg_stream_reset (&stream->ogg_stream);
-  }
-
-  return 0;
-}
-
-static void
-oggz_reset_streams (OGGZ * oggz)
-{
-  oggz_vector_foreach (oggz->streams, oggz_stream_reset);
-}
-
-static long
-oggz_reset_seek (OGGZ * oggz, oggz_off_t offset, ogg_int64_t unit, int whence)
-{
-  OggzReader * reader = &oggz->x.reader;
-
-  oggz_off_t offset_at;
-
-  offset_at = oggz_seek_raw (oggz, offset, whence);
-  if (offset_at == -1) return -1;
-
-  oggz->offset = offset_at;
-
-#ifdef DEBUG
-  printf ("reset to %ld\n", offset_at);
-#endif
-
-  if (unit != -1) reader->current_unit = unit;
-
-  return offset_at;
-}
-
-static long
-oggz_reset (OGGZ * oggz, oggz_off_t offset, ogg_int64_t unit, int whence)
-{
-  oggz_reset_streams (oggz);
-  return oggz_reset_seek (oggz, offset, unit, whence);
-}
-
-int
-oggz_purge (OGGZ * oggz)
-{
-  if (oggz == NULL) return OGGZ_ERR_BAD_OGGZ;
-
-  if (oggz->flags & OGGZ_WRITE) {
-    return OGGZ_ERR_INVALID;
-  }
-
-  oggz_reset_streams (oggz);
-
-  if (oggz->file && oggz_reset (oggz, oggz->offset, -1, SEEK_SET) < 0) {
-    return OGGZ_ERR_SYSTEM;
-  }
-
-  return 0;
-}
-
-/*
- * oggz_get_next_page (oggz, og, do_read)
- *
- * retrieves the next page.
- * returns >= 0 if found; return value is offset of page start
- * returns -1 on error
- * returns -2 if EOF was encountered
- */
-static oggz_off_t
-oggz_get_next_page (OGGZ * oggz, ogg_page * og)
-{
-  OggzReader * reader = &oggz->x.reader;
-  char * buffer;
-  long bytes = 0, more;
-  oggz_off_t page_offset = 0, ret;
-  int found = 0;
-
-  do {
-    more = ogg_sync_pageseek (&reader->ogg_sync, og);
-
-    if (more == 0) {
-      page_offset = 0;
-
-      buffer = ogg_sync_buffer (&reader->ogg_sync, CHUNKSIZE);
-      if ((bytes = (long) oggz_io_read (oggz, buffer, CHUNKSIZE)) == 0) {
-	if (oggz->file && feof (oggz->file)) {
-#ifdef DEBUG_VERBOSE
-	  printf ("get_next_page: feof (oggz->file), returning -2\n");
-#endif
-	  clearerr (oggz->file);
-	  return -2;
-	}
-      }
-      if (bytes == OGGZ_ERR_SYSTEM) {
-	  /*oggz_set_error (oggz, OGGZ_ERR_SYSTEM);*/
-	  return -1;
-      }
-
-      if (bytes == 0) {
-#ifdef DEBUG_VERBOSE
-	printf ("get_next_page: bytes == 0, returning -2\n");
-#endif
-	return -2;
-#if 0
-      } else if (oggz->file && feof (oggz->file)) {
-#ifdef DEBUG_VERBOSE
-	printf ("get_next_page: feof (oggz->file), returning -2\n");
-#endif
-	clearerr (oggz->file);
-	return -2;
-#endif
-      }
-
-      ogg_sync_wrote(&reader->ogg_sync, bytes);
-
-    } else if (more < 0) {
-#ifdef DEBUG_VERBOSE
-      printf ("get_next_page: skipped %ld bytes\n", -more);
-#endif
-      page_offset -= more;
-    } else {
-#ifdef DEBUG_VERBOSE
-      printf ("get_next_page: page has %ld bytes\n", more);
-#endif
-      found = 1;
-    }
-
-  } while (!found);
-
-  /* Calculate the byte offset of the page which was found */
-  if (bytes > 0) {
-    oggz->offset = oggz_tell_raw (oggz) - bytes + page_offset;
-    ret = oggz->offset;
-  } else {
-    /* didn't need to do any reading -- accumulate the page_offset */
-    ret = oggz->offset + page_offset;
-    oggz->offset += page_offset + more;
-  }
-
-  return ret;
-}
-
-static oggz_off_t
-oggz_get_next_start_page (OGGZ * oggz, ogg_page * og)
-{
-  oggz_off_t page_offset;
-  int found = 0;
-
-  do {
-    page_offset = oggz_get_next_page (oggz, og);
-
-    /* Return this value if one of the following conditions is met:
-     *
-     *   page_offset < 0     : error or EOF
-     *   page_offset == 0    : start of stream
-     *   !ogg_page_continued : page contains start of a packet
-     *   ogg_page_packets > 1: page contains start of a packet
-     */
-    if (page_offset <= 0 || !ogg_page_continued (og) ||
-	ogg_page_packets (og) > 1)
-      found = 1;
-  }
-  while (!found);
-
-  return page_offset;
-}
-
-static oggz_off_t
-oggz_get_prev_start_page (OGGZ * oggz, ogg_page * og,
-			 ogg_int64_t * granule, long * serialno)
-{
-  oggz_off_t offset_at, offset_start;
-  oggz_off_t page_offset, prev_offset = 0;
-  ogg_int64_t unit_at;
-  long granule_at = -1;
-
-#if 0
-  offset_at = oggz_tell_raw (oggz);
-  if (offset_at == -1) return -1;
-#else
-  offset_at = oggz->offset;
-#endif
-
-  offset_start = offset_at;
-
-  do {
-
-    offset_start = offset_at - CHUNKSIZE;
-    if (offset_start < 0) offset_start = 0;
-
-    offset_start = oggz_seek_raw (oggz, offset_start, SEEK_SET);
-    if (offset_start == -1) return -1;
-
-#ifdef DEBUG
-
-    printf ("get_prev_start_page: [A] offset_at: @%ld\toffset_start: @%ld\n",
-	    offset_at, offset_start);
-
-    printf ("get_prev_start_page: seeked to %ld\n", offset_start);
-#endif
-
-    page_offset = 0;
-
-    do {
-      prev_offset = page_offset;
-
-      page_offset = oggz_get_next_start_page (oggz, og);
-      if (page_offset == -1) return -1;
-      if (page_offset == -2) {
-#ifdef DEBUG
-	printf ("*** get_prev_start_page: page_offset = -2\n");
-#endif
-	break;
-      }
-
-      granule_at = (long)ogg_page_granulepos (og);
-
-#ifdef DEBUG_VERBOSE
-      printf ("get_prev_start_page: GOT page (%ld) @%ld\tat @%ld\n",
-	      granule_at, page_offset, offset_at);
-#endif
-
-      /* Need to stash the granule and serialno of this page because og
-       * will be overwritten by the time we realise this was the desired
-       * prev page */
-      if (page_offset >= 0 && page_offset < offset_at) {
-	*granule = granule_at;
-	*serialno = ogg_page_serialno (og);
-      }
-
-    } while (page_offset >= 0 && page_offset < offset_at);
-
-#ifdef DEBUG
-    printf ("get_prev_start_page: [B] offset_at: @%ld\toffset_start: @%ld\n"
-	    "prev_offset: @%ld\tpage_offset: @%ld\n",
-	    offset_at, offset_start, prev_offset, page_offset);
-#endif
-    /* reset the file offset */
-    offset_at = offset_start;
-
-  } while (offset_at > 0 && prev_offset == 0);
-
-  unit_at = oggz_get_unit (oggz, *serialno, *granule);
-  offset_at = oggz_reset (oggz, prev_offset, unit_at, SEEK_SET);
-
-#ifdef DEBUG
-    printf ("get_prev_start_page: [C] offset_at: @%ld\t"
-	    "prev_offset: @%ld\tunit_at: %lld\n",
-	    offset_at, prev_offset, unit_at);
-#endif
-
-  if (offset_at == -1) return -1;
-
-  if (offset_at > 0)
-    return prev_offset;
-  else
-    return -1;
-}
-
-static oggz_off_t
-oggz_scan_for_page (OGGZ * oggz, ogg_page * og, ogg_int64_t unit_target,
-		   oggz_off_t offset_begin, oggz_off_t offset_end)
-{
-  oggz_off_t offset_at, offset_next;
-  oggz_off_t offset_prev = -1;
-  ogg_int64_t granule_at;
-  ogg_int64_t unit_at;
-  long serialno;
-
-#ifdef DEBUG
-  printf (" SCANNING from %ld...", offset_begin);
-#endif
-
-  for ( ; ; ) {
-    offset_at = oggz_seek_raw (oggz, offset_begin, SEEK_SET);
-    if (offset_at == -1) return -1;
-
-#ifdef DEBUG
-    printf (" scan @%ld\n", offset_at);
-#endif
-
-    offset_next = oggz_get_next_start_page (oggz, og);
-
-    if (offset_next < 0) {
-      return offset_next;
-    }
-
-    if (offset_next == 0 && offset_begin != 0) {
-#ifdef DEBUG
-      printf (" ... scanned past EOF\n");
-#endif
-      return -1;
-    }
-    if (offset_next > offset_end) {
-#ifdef DEBUG
-      printf (" ... scanned to page %ld\n", (long)ogg_page_granulepos (og));
-#endif
-      if (offset_prev != -1) {
-	offset_at = oggz_seek_raw (oggz, offset_prev, SEEK_SET);
-	if (offset_at == -1) return -1;
-
-	offset_next = oggz_get_next_start_page (oggz, og);
-	if (offset_next < 0) return offset_next;
-
-	serialno = ogg_page_serialno (og);
-	granule_at = ogg_page_granulepos (og);
-	unit_at = oggz_get_unit (oggz, serialno, granule_at);
-
-	return offset_at;
-      } else {
-	return -1;
-      }
-    }
-
-    offset_at = offset_next;
-
-    serialno = ogg_page_serialno (og);
-    granule_at = ogg_page_granulepos (og);
-    unit_at = oggz_get_unit (oggz, serialno, granule_at);
-
-    if (unit_at < unit_target) {
-#ifdef DEBUG
-      printf (" scan: (%lld) < (%lld)\n", unit_at, unit_target);
-#endif
-      offset_prev = offset_next;
-      offset_begin = offset_next+1;
-    } else if (unit_at > unit_target) {
-#ifdef DEBUG
-      printf (" scan: (%lld) > (%lld)\n", unit_at, unit_target);
-#endif
-#if 0
-      /* hole ? */
-      offset_at = oggz_seek_raw (oggz, offset_begin, SEEK_SET);
-      if (offset_at == -1) return -1;
-
-      offset_next = oggz_get_next_start_page (oggz, og);
-      if (offset_next < 0) return offset_next;
-
-      serialno = ogg_page_serialno (og);
-      granule_at = ogg_page_granulepos (og);
-      unit_at = oggz_get_unit (oggz, serialno, granule_at);
-
-      break;
-#else
-      return offset_at;
-#endif
-    } else if (unit_at == unit_target) {
-#ifdef DEBUG
-      printf (" scan: (%lld) == (%lld)\n", unit_at, unit_target);
-#endif
-      break;
-    }
-  }
-
-  return offset_at;
-}
-
-#define GUESS_MULTIPLIER (1<<16)
-
-static ogg_int64_t
-guess (ogg_int64_t unit_at, ogg_int64_t unit_target,
-       ogg_int64_t unit_begin, ogg_int64_t unit_end,
-       oggz_off_t offset_begin, oggz_off_t offset_end)
-{
-  ogg_int64_t guess_ratio;
-  oggz_off_t offset_guess;
-
-  if (unit_at == unit_begin) return offset_begin;
-
-  guess_ratio =
-    GUESS_MULTIPLIER * (unit_target - unit_begin) /
-    (unit_at - unit_begin);
-
-#ifdef DEBUG
-  printf ("oggz_seek::guess: guess_ratio %lld = (%lld - %lld) / (%lld - %lld)\n",
-	  guess_ratio, unit_target, unit_begin, unit_at, unit_begin);
-#endif
-  
-  offset_guess = offset_begin +
-    (oggz_off_t)(((offset_end - offset_begin) * guess_ratio) /
-		 GUESS_MULTIPLIER);
-  
-  return offset_guess;
-}
-
-static ogg_int64_t
-oggz_seek_set (OGGZ * oggz, ogg_int64_t unit_target)
-{
-  OggzReader * reader = &oggz->x.reader;
-  int fd;
-  struct stat statbuf;
-  oggz_off_t offset_orig, offset_at, offset_guess;
-  oggz_off_t offset_begin, offset_end = -1, offset_next;
-  ogg_int64_t granule_at;
-  ogg_int64_t unit_at, unit_begin = 0, unit_end = -1, unit_last_iter = -1;
-  long serialno;
-  ogg_page * og;
-  int looping = 0;
-
-  if (oggz == NULL) {
-    return -1;
-  }
-
-  if (unit_target > 0 && !oggz_has_metrics (oggz)) {
-#ifdef DEBUG
-    printf ("oggz_seek_set: No metric defined, FAIL\n");
-#endif
-    return -1;
-  }
-
-  if (oggz->file != NULL) {
-    if ((fd = fileno (oggz->file)) == -1) {
-      /*oggz_set_error (oggz, OGGZ_ERR_SYSTEM);*/
-      return -1;
-    }
-
-    if (fstat (fd, &statbuf) == -1) {
-      /*oggz_set_error (oggz, OGGZ_ERR_SYSTEM);*/
-      return -1;
-    }
-
-    if (oggz_stat_regular (statbuf.st_mode)) {
-      offset_end = statbuf.st_size;
-#ifdef DEBUG
-      printf ("oggz_seek_set: stat size %ld\n", offset_end);
-#endif
-    } else {
-      /*oggz_set_error (oggz, OGGZ_ERR_NOSEEK);*/
-
-      /* XXX: should be able to just carry on and guess, as per io */
-      /*return -1;*/
-    }
-  } else {
-    oggz_off_t offset_save;
-
-    if (oggz->io == NULL || oggz->io->seek == NULL) {
-      /* No file, and no io seek method */
-      return -1;
-    }
-
-    /* Get the offset of the end by querying the io seek method */
-    offset_save = oggz_io_tell (oggz);
-    if (oggz_io_seek (oggz, 0, SEEK_END) == -1) {
-      return -1;
-    }
-    offset_end = oggz_io_tell (oggz);
-    if (oggz_io_seek (oggz, offset_save, SEEK_SET) == -1) {
-      return -1; /* fubar */
-    }
-  }
-
-  if (unit_target == reader->current_unit) {
-    return (long)reader->current_unit;
-  }
-
-  if (unit_target == 0) {
-    offset_at = oggz_reset (oggz, oggz->offset_data_begin, 0, SEEK_SET);
-    if (offset_at == -1) return -1;
-    return 0;
-  }
-
-  offset_at = oggz_tell_raw (oggz);
-  if (offset_at == -1) return -1;
-
-  offset_orig = oggz->offset;
-
-  offset_begin = 0;
-
-  unit_at = reader->current_unit;
-  unit_begin = 0;
-  unit_end = -1;
-
-  og = &oggz->current_page;
-
-  for ( ; ; ) {
-
-    unit_last_iter = unit_at;
-
-#ifdef DEBUG
-    printf ("oggz_seek_set: [A] want u%lld: (u%lld - u%lld) [@%ld - @%ld]\n",
-	    unit_target, unit_begin, unit_end, offset_begin, offset_end);
-#endif
-
-    if (unit_end == -1) {
-      if (unit_at == unit_begin) {
-	offset_guess = offset_begin + (offset_end - offset_begin)/2;
-      } else {
-	offset_guess = guess (unit_at, unit_target, unit_begin, unit_end,
-			      offset_begin, offset_at);
-      }
-    } else if (unit_end == unit_begin) {
-#ifdef DEBUG
-      printf ("oggz_seek_set: unit_end == unit_begin (FOUND)\n");
-#endif
-      goto found;
-    } else if (unit_end <= unit_begin) {
-#ifdef DEBUG
-      printf ("oggz_seek_set: unit_end <= unit_begin (ERROR)\n");
-#endif
-      break;
-    } else {
-      offset_guess = guess (unit_at, unit_target, unit_begin, unit_end,
-			    offset_begin, offset_end);
-    }
-
-#ifdef DEBUG
-    printf ("oggz_seek_set: guessed %ld\n", offset_guess);
-#endif
-
-    if (offset_guess == offset_at) {
-      /* Already there, looping */
-      looping = 1;
-    }
-
-    offset_at = oggz_seek_raw (oggz, offset_guess, SEEK_SET);
-    if (offset_at == -1) {
-      goto notfound;
-    }
-
-    offset_next = oggz_get_next_start_page (oggz, og);
-
-#ifdef DEBUG
-    printf ("oggz_seek_set: offset_next %ld\n", offset_next);
-#endif
-
-    if (unit_end == -1 && offset_next == -2) { /* reached eof, backtrack */
-      offset_next = oggz_get_prev_start_page (oggz, og, &granule_at,
-					      &serialno);
-      unit_end = oggz_get_unit (oggz, serialno, granule_at);
-#ifdef DEBUG
-      printf ("oggz_seek_set: [C] offset_next @%ld, g%lld, (s%ld)\n",
-	      offset_next, granule_at, serialno);
-      printf ("oggz_seek_set: [c] u%lld\n",
-	      oggz_get_unit (oggz, serialno, granule_at));
-#endif
-    } else {
-      serialno = ogg_page_serialno (og);
-      granule_at = ogg_page_granulepos (og);
-    }
-
-    if (offset_next < 0) {
-      goto notfound;
-    }
-
-    if (offset_next > offset_end) {
-      offset_next =
-	oggz_scan_for_page (oggz, og, unit_target, offset_begin, offset_end);
-      if (offset_next < 0) goto notfound;
-
-      offset_at = offset_next;
-      serialno = ogg_page_serialno (og);
-      granule_at = ogg_page_granulepos (og);
-
-      unit_at = oggz_get_unit (oggz, serialno, granule_at);
-
-      goto found;
-    }
-
-    offset_at = offset_next;
-
-    unit_at = oggz_get_unit (oggz, serialno, granule_at);
-
-    if (unit_at == unit_last_iter) looping = 1;
-
-#ifdef DEBUG
-    printf ("oggz_seek_set: [D] want u%lld, got page u%lld @%ld g%lld\n",
-	    unit_target, unit_at, offset_at, granule_at);
-#endif
-
-    if (!looping && unit_at < unit_target) {
-      offset_begin = offset_at;
-      unit_begin = unit_at;
-    } else if (!looping && unit_at > unit_target) {
-      offset_end = offset_at-1;
-      unit_end = unit_at;
-    } else {
-      break;
-    }
-  }
-
- found:
-#ifdef DEBUG
-  printf ("oggz_seek_set: FOUND (%lld)\n", unit_at);
-#endif
-
-  offset_at = oggz_reset (oggz, offset_at, unit_at, SEEK_SET);
-  if (offset_at == -1) return -1;
-
-  return (long)reader->current_unit;
-
- notfound:
-#ifdef DEBUG
-  printf ("oggz_seek_set: NOT FOUND\n");
-#endif
-
-  oggz_reset (oggz, offset_orig, -1, SEEK_SET);
-
-  return -1;
-}
-
-static ogg_int64_t
-oggz_seek_end (OGGZ * oggz, ogg_int64_t unit_offset)
-{
-  oggz_off_t offset_orig, offset_at, offset_end;
-  ogg_int64_t granulepos;
-  ogg_int64_t unit_end;
-  long serialno;
-  ogg_page * og;
-
-  og = &oggz->current_page;
-
-  offset_orig = oggz->offset;
-
-  offset_at = oggz_seek_raw (oggz, 0, SEEK_END);
-  if (offset_at == -1) return -1;
-
-  offset_end = oggz_get_prev_start_page (oggz, og, &granulepos, &serialno);
-
-  unit_end = oggz_get_unit (oggz, serialno, granulepos);
-
-  if (offset_end < 0) {
-    oggz_reset (oggz, offset_orig, -1, SEEK_SET);
-    return -1;
-  }
-
-#ifdef DEBUG
-  printf ("*** oggz_seek_end: found packet (%ld) at @%ld [%ld]\n",
-	  unit_end, offset_end, granulepos);
-#endif
-
-  return oggz_seek_set (oggz, unit_end + unit_offset);
-}
-
-off_t
-oggz_seek (OGGZ * oggz, oggz_off_t offset, int whence)
-{
-  ogg_int64_t units = -1;
-
-  if (oggz == NULL) return -1;
-
-  if (oggz->flags & OGGZ_WRITE) {
-    return -1;
-  }
-
-  if (offset == 0) units = 0;
-
-  return (off_t)oggz_reset (oggz, offset, units, whence);
-}
-
-ogg_int64_t
-oggz_seek_units (OGGZ * oggz, ogg_int64_t units, int whence)
-{
-  OggzReader * reader = &oggz->x.reader;
-
-  if (oggz == NULL) {
-#ifdef DEBUG
-    printf ("oggz_seek_units: oggz NULL, FAIL\n");
-#endif
-    return -1;
-  }
-
-
-  if (oggz->flags & OGGZ_WRITE) {
-#ifdef DEBUG
-    printf ("oggz_seek_units: is OGGZ_WRITE, FAIL\n");
-#endif
-    return -1;
-  }
-
-  if (!oggz_has_metrics (oggz)) {
-#ifdef DEBUG
-    printf ("oggz_seek_units: !has_metrics, FAIL\n");
-#endif
-    return -1;
-  }
-
-  switch (whence) {
-  case SEEK_SET:
-    return oggz_seek_set (oggz, units);
-    break;
-  case SEEK_CUR:
-    units += reader->current_unit;
-    return oggz_seek_set (oggz, units);
-    break;
-  case SEEK_END:
-    return oggz_seek_end (oggz, units);
-    break;
-  default:
-    /*oggz_set_error (oggz, OGGZ_EINVALID);*/
-    return -1;
-    break;
-  }
-}
-
-long
-oggz_seek_byorder (OGGZ * oggz, void * target)
-{
-  return -1;
-}
-
-long
-oggz_seek_packets (OGGZ * oggz, long serialno, long packets, int whence)
-{
-  return -1;
-}
-
 #else /* OGGZ_CONFIG_READ */
 
 #include <ogg/ogg.h>
@@ -1302,28 +542,4 @@
   return OGGZ_ERR_DISABLED;
 }
 
-off_t
-oggz_seek (OGGZ * oggz, oggz_off_t offset, int whence)
-{
-  return OGGZ_ERR_DISABLED;
-}
-
-long
-oggz_seek_units (OGGZ * oggz, ogg_int64_t units, int whence)
-{
-  return OGGZ_ERR_DISABLED;
-}
-
-long
-oggz_seek_byorder (OGGZ * oggz, void * target)
-{
-  return OGGZ_ERR_DISABLED;
-}
-
-long
-oggz_seek_packets (OGGZ * oggz, long serialno, long packets, int whence)
-{
-  return OGGZ_ERR_DISABLED;
-}
-
 #endif

Added: liboggz/trunk/src/liboggz/oggz_seek.c
===================================================================
--- liboggz/trunk/src/liboggz/oggz_seek.c	2005-02-01 08:59:55 UTC (rev 805)
+++ liboggz/trunk/src/liboggz/oggz_seek.c	2005-02-01 09:34:52 UTC (rev 806)
@@ -0,0 +1,858 @@
+/*
+   Copyright (C) 2003 Commonwealth Scientific and Industrial Research
+   Organisation (CSIRO) Australia
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   - Neither the name of CSIRO Australia nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+   PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE ORGANISATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * oggz_seek.c
+ *
+ * Conrad Parker <conrad at annodex.net>
+ */
+
+#include "config.h"
+
+#if OGGZ_CONFIG_READ
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+
+#include <ogg/ogg.h>
+
+#include "oggz_compat.h"
+#include "oggz_private.h"
+
+/*#define DEBUG*/
+/*#define DEBUG_VERBOSE*/
+
+#define CHUNKSIZE 65536
+
+#define oggz_off_t long
+
+/*
+ * The typical usage is:
+ *
+ *   oggz_set_data_start (oggz, oggz_tell (oggz));
+ */
+int
+oggz_set_data_start (OGGZ * oggz, oggz_off_t offset)
+{
+  if (oggz == NULL) return -1;
+
+  if (offset < 0) return -1;
+
+  oggz->offset_data_begin = offset;
+
+  return 0;
+}
+
+static oggz_off_t
+oggz_tell_raw (OGGZ * oggz)
+{
+  oggz_off_t offset_at;
+
+  offset_at = oggz_io_tell (oggz);
+
+  return offset_at;
+}
+
+/*
+ * seeks and syncs
+ */
+static oggz_off_t
+oggz_seek_raw (OGGZ * oggz, oggz_off_t offset, int whence)
+{
+  OggzReader * reader = &oggz->x.reader;
+  oggz_off_t offset_at;
+
+  if (oggz_io_seek (oggz, offset, whence) == -1) {
+    return -1;
+  }
+
+  offset_at = oggz_io_tell (oggz);
+
+  oggz->offset = offset_at;
+
+  ogg_sync_reset (&reader->ogg_sync);
+
+  return offset_at;
+}
+
+static int
+oggz_stream_reset (void * data)
+{
+  oggz_stream_t * stream = (oggz_stream_t *) data;
+
+  if (stream->ogg_stream.serialno != -1) {
+    ogg_stream_reset (&stream->ogg_stream);
+  }
+
+  return 0;
+}
+
+static void
+oggz_reset_streams (OGGZ * oggz)
+{
+  oggz_vector_foreach (oggz->streams, oggz_stream_reset);
+}
+
+static long
+oggz_reset_seek (OGGZ * oggz, oggz_off_t offset, ogg_int64_t unit, int whence)
+{
+  OggzReader * reader = &oggz->x.reader;
+
+  oggz_off_t offset_at;
+
+  offset_at = oggz_seek_raw (oggz, offset, whence);
+  if (offset_at == -1) return -1;
+
+  oggz->offset = offset_at;
+
+#ifdef DEBUG
+  printf ("reset to %ld\n", offset_at);
+#endif
+
+  if (unit != -1) reader->current_unit = unit;
+
+  return offset_at;
+}
+
+static long
+oggz_reset (OGGZ * oggz, oggz_off_t offset, ogg_int64_t unit, int whence)
+{
+  oggz_reset_streams (oggz);
+  return oggz_reset_seek (oggz, offset, unit, whence);
+}
+
+int
+oggz_purge (OGGZ * oggz)
+{
+  if (oggz == NULL) return OGGZ_ERR_BAD_OGGZ;
+
+  if (oggz->flags & OGGZ_WRITE) {
+    return OGGZ_ERR_INVALID;
+  }
+
+  oggz_reset_streams (oggz);
+
+  if (oggz->file && oggz_reset (oggz, oggz->offset, -1, SEEK_SET) < 0) {
+    return OGGZ_ERR_SYSTEM;
+  }
+
+  return 0;
+}
+
+/*
+ * oggz_get_next_page (oggz, og, do_read)
+ *
+ * retrieves the next page.
+ * returns >= 0 if found; return value is offset of page start
+ * returns -1 on error
+ * returns -2 if EOF was encountered
+ */
+static oggz_off_t
+oggz_get_next_page (OGGZ * oggz, ogg_page * og)
+{
+  OggzReader * reader = &oggz->x.reader;
+  char * buffer;
+  long bytes = 0, more;
+  oggz_off_t page_offset = 0, ret;
+  int found = 0;
+
+  do {
+    more = ogg_sync_pageseek (&reader->ogg_sync, og);
+
+    if (more == 0) {
+      page_offset = 0;
+
+      buffer = ogg_sync_buffer (&reader->ogg_sync, CHUNKSIZE);
+      if ((bytes = (long) oggz_io_read (oggz, buffer, CHUNKSIZE)) == 0) {
+	if (oggz->file && feof (oggz->file)) {
+#ifdef DEBUG_VERBOSE
+	  printf ("get_next_page: feof (oggz->file), returning -2\n");
+#endif
+	  clearerr (oggz->file);
+	  return -2;
+	}
+      }
+      if (bytes == OGGZ_ERR_SYSTEM) {
+	  /*oggz_set_error (oggz, OGGZ_ERR_SYSTEM);*/
+	  return -1;
+      }
+
+      if (bytes == 0) {
+#ifdef DEBUG_VERBOSE
+	printf ("get_next_page: bytes == 0, returning -2\n");
+#endif
+	return -2;
+#if 0
+      } else if (oggz->file && feof (oggz->file)) {
+#ifdef DEBUG_VERBOSE
+	printf ("get_next_page: feof (oggz->file), returning -2\n");
+#endif
+	clearerr (oggz->file);
+	return -2;
+#endif
+      }
+
+      ogg_sync_wrote(&reader->ogg_sync, bytes);
+
+    } else if (more < 0) {
+#ifdef DEBUG_VERBOSE
+      printf ("get_next_page: skipped %ld bytes\n", -more);
+#endif
+      page_offset -= more;
+    } else {
+#ifdef DEBUG_VERBOSE
+      printf ("get_next_page: page has %ld bytes\n", more);
+#endif
+      found = 1;
+    }
+
+  } while (!found);
+
+  /* Calculate the byte offset of the page which was found */
+  if (bytes > 0) {
+    oggz->offset = oggz_tell_raw (oggz) - bytes + page_offset;
+    ret = oggz->offset;
+  } else {
+    /* didn't need to do any reading -- accumulate the page_offset */
+    ret = oggz->offset + page_offset;
+    oggz->offset += page_offset + more;
+  }
+
+  return ret;
+}
+
+static oggz_off_t
+oggz_get_next_start_page (OGGZ * oggz, ogg_page * og)
+{
+  oggz_off_t page_offset;
+  int found = 0;
+
+  do {
+    page_offset = oggz_get_next_page (oggz, og);
+
+    /* Return this value if one of the following conditions is met:
+     *
+     *   page_offset < 0     : error or EOF
+     *   page_offset == 0    : start of stream
+     *   !ogg_page_continued : page contains start of a packet
+     *   ogg_page_packets > 1: page contains start of a packet
+     */
+    if (page_offset <= 0 || !ogg_page_continued (og) ||
+	ogg_page_packets (og) > 1)
+      found = 1;
+  }
+  while (!found);
+
+  return page_offset;
+}
+
+static oggz_off_t
+oggz_get_prev_start_page (OGGZ * oggz, ogg_page * og,
+			 ogg_int64_t * granule, long * serialno)
+{
+  oggz_off_t offset_at, offset_start;
+  oggz_off_t page_offset, prev_offset = 0;
+  ogg_int64_t unit_at;
+  long granule_at = -1;
+
+#if 0
+  offset_at = oggz_tell_raw (oggz);
+  if (offset_at == -1) return -1;
+#else
+  offset_at = oggz->offset;
+#endif
+
+  offset_start = offset_at;
+
+  do {
+
+    offset_start = offset_at - CHUNKSIZE;
+    if (offset_start < 0) offset_start = 0;
+
+    offset_start = oggz_seek_raw (oggz, offset_start, SEEK_SET);
+    if (offset_start == -1) return -1;
+
+#ifdef DEBUG
+
+    printf ("get_prev_start_page: [A] offset_at: @%ld\toffset_start: @%ld\n",
+	    offset_at, offset_start);
+
+    printf ("get_prev_start_page: seeked to %ld\n", offset_start);
+#endif
+
+    page_offset = 0;
+
+    do {
+      prev_offset = page_offset;
+
+      page_offset = oggz_get_next_start_page (oggz, og);
+      if (page_offset == -1) return -1;
+      if (page_offset == -2) {
+#ifdef DEBUG
+	printf ("*** get_prev_start_page: page_offset = -2\n");
+#endif
+	break;
+      }
+
+      granule_at = (long)ogg_page_granulepos (og);
+
+#ifdef DEBUG_VERBOSE
+      printf ("get_prev_start_page: GOT page (%ld) @%ld\tat @%ld\n",
+	      granule_at, page_offset, offset_at);
+#endif
+
+      /* Need to stash the granule and serialno of this page because og
+       * will be overwritten by the time we realise this was the desired
+       * prev page */
+      if (page_offset >= 0 && page_offset < offset_at) {
+	*granule = granule_at;
+	*serialno = ogg_page_serialno (og);
+      }
+
+    } while (page_offset >= 0 && page_offset < offset_at);
+
+#ifdef DEBUG
+    printf ("get_prev_start_page: [B] offset_at: @%ld\toffset_start: @%ld\n"
+	    "prev_offset: @%ld\tpage_offset: @%ld\n",
+	    offset_at, offset_start, prev_offset, page_offset);
+#endif
+    /* reset the file offset */
+    offset_at = offset_start;
+
+  } while (offset_at > 0 && prev_offset == 0);
+
+  unit_at = oggz_get_unit (oggz, *serialno, *granule);
+  offset_at = oggz_reset (oggz, prev_offset, unit_at, SEEK_SET);
+
+#ifdef DEBUG
+    printf ("get_prev_start_page: [C] offset_at: @%ld\t"
+	    "prev_offset: @%ld\tunit_at: %lld\n",
+	    offset_at, prev_offset, unit_at);
+#endif
+
+  if (offset_at == -1) return -1;
+
+  if (offset_at > 0)
+    return prev_offset;
+  else
+    return -1;
+}
+
+static oggz_off_t
+oggz_scan_for_page (OGGZ * oggz, ogg_page * og, ogg_int64_t unit_target,
+		   oggz_off_t offset_begin, oggz_off_t offset_end)
+{
+  oggz_off_t offset_at, offset_next;
+  oggz_off_t offset_prev = -1;
+  ogg_int64_t granule_at;
+  ogg_int64_t unit_at;
+  long serialno;
+
+#ifdef DEBUG
+  printf (" SCANNING from %ld...", offset_begin);
+#endif
+
+  for ( ; ; ) {
+    offset_at = oggz_seek_raw (oggz, offset_begin, SEEK_SET);
+    if (offset_at == -1) return -1;
+
+#ifdef DEBUG
+    printf (" scan @%ld\n", offset_at);
+#endif
+
+    offset_next = oggz_get_next_start_page (oggz, og);
+
+    if (offset_next < 0) {
+      return offset_next;
+    }
+
+    if (offset_next == 0 && offset_begin != 0) {
+#ifdef DEBUG
+      printf (" ... scanned past EOF\n");
+#endif
+      return -1;
+    }
+    if (offset_next > offset_end) {
+#ifdef DEBUG
+      printf (" ... scanned to page %ld\n", (long)ogg_page_granulepos (og));
+#endif
+      if (offset_prev != -1) {
+	offset_at = oggz_seek_raw (oggz, offset_prev, SEEK_SET);
+	if (offset_at == -1) return -1;
+
+	offset_next = oggz_get_next_start_page (oggz, og);
+	if (offset_next < 0) return offset_next;
+
+	serialno = ogg_page_serialno (og);
+	granule_at = ogg_page_granulepos (og);
+	unit_at = oggz_get_unit (oggz, serialno, granule_at);
+
+	return offset_at;
+      } else {
+	return -1;
+      }
+    }
+
+    offset_at = offset_next;
+
+    serialno = ogg_page_serialno (og);
+    granule_at = ogg_page_granulepos (og);
+    unit_at = oggz_get_unit (oggz, serialno, granule_at);
+
+    if (unit_at < unit_target) {
+#ifdef DEBUG
+      printf (" scan: (%lld) < (%lld)\n", unit_at, unit_target);
+#endif
+      offset_prev = offset_next;
+      offset_begin = offset_next+1;
+    } else if (unit_at > unit_target) {
+#ifdef DEBUG
+      printf (" scan: (%lld) > (%lld)\n", unit_at, unit_target);
+#endif
+#if 0
+      /* hole ? */
+      offset_at = oggz_seek_raw (oggz, offset_begin, SEEK_SET);
+      if (offset_at == -1) return -1;
+
+      offset_next = oggz_get_next_start_page (oggz, og);
+      if (offset_next < 0) return offset_next;
+
+      serialno = ogg_page_serialno (og);
+      granule_at = ogg_page_granulepos (og);
+      unit_at = oggz_get_unit (oggz, serialno, granule_at);
+
+      break;
+#else
+      return offset_at;
+#endif
+    } else if (unit_at == unit_target) {
+#ifdef DEBUG
+      printf (" scan: (%lld) == (%lld)\n", unit_at, unit_target);
+#endif
+      break;
+    }
+  }
+
+  return offset_at;
+}
+
+#define GUESS_MULTIPLIER (1<<16)
+
+static ogg_int64_t
+guess (ogg_int64_t unit_at, ogg_int64_t unit_target,
+       ogg_int64_t unit_begin, ogg_int64_t unit_end,
+       oggz_off_t offset_begin, oggz_off_t offset_end)
+{
+  ogg_int64_t guess_ratio;
+  oggz_off_t offset_guess;
+
+  if (unit_at == unit_begin) return offset_begin;
+
+  guess_ratio =
+    GUESS_MULTIPLIER * (unit_target - unit_begin) /
+    (unit_at - unit_begin);
+
+#ifdef DEBUG
+  printf ("oggz_seek::guess: guess_ratio %lld = (%lld - %lld) / (%lld - %lld)\n",
+	  guess_ratio, unit_target, unit_begin, unit_at, unit_begin);
+#endif
+  
+  offset_guess = offset_begin +
+    (oggz_off_t)(((offset_end - offset_begin) * guess_ratio) /
+		 GUESS_MULTIPLIER);
+  
+  return offset_guess;
+}
+
+static ogg_int64_t
+oggz_seek_set (OGGZ * oggz, ogg_int64_t unit_target)
+{
+  OggzReader * reader = &oggz->x.reader;
+  int fd;
+  struct stat statbuf;
+  oggz_off_t offset_orig, offset_at, offset_guess;
+  oggz_off_t offset_begin, offset_end = -1, offset_next;
+  ogg_int64_t granule_at;
+  ogg_int64_t unit_at, unit_begin = 0, unit_end = -1, unit_last_iter = -1;
+  long serialno;
+  ogg_page * og;
+  int looping = 0;
+
+  if (oggz == NULL) {
+    return -1;
+  }
+
+  if (unit_target > 0 && !oggz_has_metrics (oggz)) {
+#ifdef DEBUG
+    printf ("oggz_seek_set: No metric defined, FAIL\n");
+#endif
+    return -1;
+  }
+
+  if (oggz->file != NULL) {
+    if ((fd = fileno (oggz->file)) == -1) {
+      /*oggz_set_error (oggz, OGGZ_ERR_SYSTEM);*/
+      return -1;
+    }
+
+    if (fstat (fd, &statbuf) == -1) {
+      /*oggz_set_error (oggz, OGGZ_ERR_SYSTEM);*/
+      return -1;
+    }
+
+    if (oggz_stat_regular (statbuf.st_mode)) {
+      offset_end = statbuf.st_size;
+#ifdef DEBUG
+      printf ("oggz_seek_set: stat size %ld\n", offset_end);
+#endif
+    } else {
+      /*oggz_set_error (oggz, OGGZ_ERR_NOSEEK);*/
+
+      /* XXX: should be able to just carry on and guess, as per io */
+      /*return -1;*/
+    }
+  } else {
+    oggz_off_t offset_save;
+
+    if (oggz->io == NULL || oggz->io->seek == NULL) {
+      /* No file, and no io seek method */
+      return -1;
+    }
+
+    /* Get the offset of the end by querying the io seek method */
+    offset_save = oggz_io_tell (oggz);
+    if (oggz_io_seek (oggz, 0, SEEK_END) == -1) {
+      return -1;
+    }
+    offset_end = oggz_io_tell (oggz);
+    if (oggz_io_seek (oggz, offset_save, SEEK_SET) == -1) {
+      return -1; /* fubar */
+    }
+  }
+
+  if (unit_target == reader->current_unit) {
+    return (long)reader->current_unit;
+  }
+
+  if (unit_target == 0) {
+    offset_at = oggz_reset (oggz, oggz->offset_data_begin, 0, SEEK_SET);
+    if (offset_at == -1) return -1;
+    return 0;
+  }
+
+  offset_at = oggz_tell_raw (oggz);
+  if (offset_at == -1) return -1;
+
+  offset_orig = oggz->offset;
+
+  offset_begin = 0;
+
+  unit_at = reader->current_unit;
+  unit_begin = 0;
+  unit_end = -1;
+
+  og = &oggz->current_page;
+
+  for ( ; ; ) {
+
+    unit_last_iter = unit_at;
+
+#ifdef DEBUG
+    printf ("oggz_seek_set: [A] want u%lld: (u%lld - u%lld) [@%ld - @%ld]\n",
+	    unit_target, unit_begin, unit_end, offset_begin, offset_end);
+#endif
+
+    if (unit_end == -1) {
+      if (unit_at == unit_begin) {
+	offset_guess = offset_begin + (offset_end - offset_begin)/2;
+      } else {
+	offset_guess = guess (unit_at, unit_target, unit_begin, unit_end,
+			      offset_begin, offset_at);
+      }
+    } else if (unit_end == unit_begin) {
+#ifdef DEBUG
+      printf ("oggz_seek_set: unit_end == unit_begin (FOUND)\n");
+#endif
+      goto found;
+    } else if (unit_end <= unit_begin) {
+#ifdef DEBUG
+      printf ("oggz_seek_set: unit_end <= unit_begin (ERROR)\n");
+#endif
+      break;
+    } else {
+      offset_guess = guess (unit_at, unit_target, unit_begin, unit_end,
+			    offset_begin, offset_end);
+    }
+
+#ifdef DEBUG
+    printf ("oggz_seek_set: guessed %ld\n", offset_guess);
+#endif
+
+    if (offset_guess == offset_at) {
+      /* Already there, looping */
+      looping = 1;
+    }
+
+    offset_at = oggz_seek_raw (oggz, offset_guess, SEEK_SET);
+    if (offset_at == -1) {
+      goto notfound;
+    }
+
+    offset_next = oggz_get_next_start_page (oggz, og);
+
+#ifdef DEBUG
+    printf ("oggz_seek_set: offset_next %ld\n", offset_next);
+#endif
+
+    if (unit_end == -1 && offset_next == -2) { /* reached eof, backtrack */
+      offset_next = oggz_get_prev_start_page (oggz, og, &granule_at,
+					      &serialno);
+      unit_end = oggz_get_unit (oggz, serialno, granule_at);
+#ifdef DEBUG
+      printf ("oggz_seek_set: [C] offset_next @%ld, g%lld, (s%ld)\n",
+	      offset_next, granule_at, serialno);
+      printf ("oggz_seek_set: [c] u%lld\n",
+	      oggz_get_unit (oggz, serialno, granule_at));
+#endif
+    } else {
+      serialno = ogg_page_serialno (og);
+      granule_at = ogg_page_granulepos (og);
+    }
+
+    if (offset_next < 0) {
+      goto notfound;
+    }
+
+    if (offset_next > offset_end) {
+      offset_next =
+	oggz_scan_for_page (oggz, og, unit_target, offset_begin, offset_end);
+      if (offset_next < 0) goto notfound;
+
+      offset_at = offset_next;
+      serialno = ogg_page_serialno (og);
+      granule_at = ogg_page_granulepos (og);
+
+      unit_at = oggz_get_unit (oggz, serialno, granule_at);
+
+      goto found;
+    }
+
+    offset_at = offset_next;
+
+    unit_at = oggz_get_unit (oggz, serialno, granule_at);
+
+    if (unit_at == unit_last_iter) looping = 1;
+
+#ifdef DEBUG
+    printf ("oggz_seek_set: [D] want u%lld, got page u%lld @%ld g%lld\n",
+	    unit_target, unit_at, offset_at, granule_at);
+#endif
+
+    if (!looping && unit_at < unit_target) {
+      offset_begin = offset_at;
+      unit_begin = unit_at;
+    } else if (!looping && unit_at > unit_target) {
+      offset_end = offset_at-1;
+      unit_end = unit_at;
+    } else {
+      break;
+    }
+  }
+
+ found:
+#ifdef DEBUG
+  printf ("oggz_seek_set: FOUND (%lld)\n", unit_at);
+#endif
+
+  offset_at = oggz_reset (oggz, offset_at, unit_at, SEEK_SET);
+  if (offset_at == -1) return -1;
+
+  return (long)reader->current_unit;
+
+ notfound:
+#ifdef DEBUG
+  printf ("oggz_seek_set: NOT FOUND\n");
+#endif
+
+  oggz_reset (oggz, offset_orig, -1, SEEK_SET);
+
+  return -1;
+}
+
+static ogg_int64_t
+oggz_seek_end (OGGZ * oggz, ogg_int64_t unit_offset)
+{
+  oggz_off_t offset_orig, offset_at, offset_end;
+  ogg_int64_t granulepos;
+  ogg_int64_t unit_end;
+  long serialno;
+  ogg_page * og;
+
+  og = &oggz->current_page;
+
+  offset_orig = oggz->offset;
+
+  offset_at = oggz_seek_raw (oggz, 0, SEEK_END);
+  if (offset_at == -1) return -1;
+
+  offset_end = oggz_get_prev_start_page (oggz, og, &granulepos, &serialno);
+
+  unit_end = oggz_get_unit (oggz, serialno, granulepos);
+
+  if (offset_end < 0) {
+    oggz_reset (oggz, offset_orig, -1, SEEK_SET);
+    return -1;
+  }
+
+#ifdef DEBUG
+  printf ("*** oggz_seek_end: found packet (%ld) at @%ld [%ld]\n",
+	  unit_end, offset_end, granulepos);
+#endif
+
+  return oggz_seek_set (oggz, unit_end + unit_offset);
+}
+
+off_t
+oggz_seek (OGGZ * oggz, oggz_off_t offset, int whence)
+{
+  ogg_int64_t units = -1;
+
+  if (oggz == NULL) return -1;
+
+  if (oggz->flags & OGGZ_WRITE) {
+    return -1;
+  }
+
+  if (offset == 0) units = 0;
+
+  return (off_t)oggz_reset (oggz, offset, units, whence);
+}
+
+ogg_int64_t
+oggz_seek_units (OGGZ * oggz, ogg_int64_t units, int whence)
+{
+  OggzReader * reader = &oggz->x.reader;
+
+  if (oggz == NULL) {
+#ifdef DEBUG
+    printf ("oggz_seek_units: oggz NULL, FAIL\n");
+#endif
+    return -1;
+  }
+
+
+  if (oggz->flags & OGGZ_WRITE) {
+#ifdef DEBUG
+    printf ("oggz_seek_units: is OGGZ_WRITE, FAIL\n");
+#endif
+    return -1;
+  }
+
+  if (!oggz_has_metrics (oggz)) {
+#ifdef DEBUG
+    printf ("oggz_seek_units: !has_metrics, FAIL\n");
+#endif
+    return -1;
+  }
+
+  switch (whence) {
+  case SEEK_SET:
+    return oggz_seek_set (oggz, units);
+    break;
+  case SEEK_CUR:
+    units += reader->current_unit;
+    return oggz_seek_set (oggz, units);
+    break;
+  case SEEK_END:
+    return oggz_seek_end (oggz, units);
+    break;
+  default:
+    /*oggz_set_error (oggz, OGGZ_EINVALID);*/
+    return -1;
+    break;
+  }
+}
+
+long
+oggz_seek_byorder (OGGZ * oggz, void * target)
+{
+  return -1;
+}
+
+long
+oggz_seek_packets (OGGZ * oggz, long serialno, long packets, int whence)
+{
+  return -1;
+}
+
+#else
+
+#include <ogg/ogg.h>
+#include "oggz_private.h"
+
+off_t
+oggz_seek (OGGZ * oggz, oggz_off_t offset, int whence)
+{
+  return OGGZ_ERR_DISABLED;
+}
+
+long
+oggz_seek_units (OGGZ * oggz, ogg_int64_t units, int whence)
+{
+  return OGGZ_ERR_DISABLED;
+}
+
+long
+oggz_seek_byorder (OGGZ * oggz, void * target)
+{
+  return OGGZ_ERR_DISABLED;
+}
+
+long
+oggz_seek_packets (OGGZ * oggz, long serialno, long packets, int whence)
+{
+  return OGGZ_ERR_DISABLED;
+}
+
+#endif


-- 
conrad



More information about the cvs-annodex mailing list