-static OggVorbis_File *oggvorbis_file;
-static FILE *infile;
-static int header_len, inbuf_size, vi_channels;
-static char *header, *inbuf;
-static ssize_t *chunk_table, max_chunk_len, num_chunks;
-static struct audio_format_handler *af;
-static long vi_sampling_rate, vi_bitrate, vi_bitrate_nominal;
+/** describes a memory-mapped ogg vorbis file */
+struct ogg_datasource {
+ /** the memory mapping */
+ char *map;
+ /** this size of the mapping */
+ off_t numbytes;
+ /** the current position in the mapping */
+ off_t fpos;
+};
+
+static size_t cb_read(void *buf, size_t size, size_t nmemb, void *datasource)
+{
+ struct ogg_datasource *ods = datasource;
+ size_t copy = PARA_MIN(ods->numbytes - ods->fpos, size * nmemb),
+ ret = copy / size;
+ if (!ret)
+ return 0;
+ memcpy(buf, ods->map + ods->fpos, copy);
+// PARA_INFO_LOG("size: %zd, nmemb: %zd, ret: %zd\n", size, nmemb, ret);
+ ods->fpos += ret * size;
+ return ret;
+}
+
+static int cb_seek(void *datasource, ogg_int64_t offset,
+ int whence)
+{
+ struct ogg_datasource *ods = datasource;
+ switch (whence) {
+ case SEEK_SET:
+ if (offset >= 0 && offset <= ods->numbytes) {
+ ods->fpos = offset;
+ return 0;
+ }
+ errno = EINVAL;
+ return -1;
+ break;
+ case SEEK_END:
+ if (offset <= 0 && -offset <= ods->numbytes) {
+ ods->fpos = ods->numbytes + offset;
+ return 0;
+ }
+ errno = EINVAL;
+ return -1;
+ break;
+ case SEEK_CUR:
+ if ((offset >= 0 && offset + ods->fpos > ods->numbytes) ||
+ (offset < 0 && offset + ods->fpos < 0)) {
+ errno = EINVAL;
+ return -1;
+ }
+ ods->fpos += offset;
+ return 0;
+ }
+ errno = EINVAL;
+ return -1;
+}
+
+/* don't do anything as vss still needs the open filehandle */
+static int cb_close(__a_unused void *datasource)
+{
+ return 0;
+}