vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / media / plugins / asf_reader / libasf / asf.c
blobee2deed542202452b0f9bf68a95fff0afadfee34
1 /* libasf - An Advanced Systems Format media file parser
2 * Copyright (C) 2006-2010 Juho Vähä-Herttua
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 #include <stdlib.h>
20 #include <stdio.h>
22 #include "asf.h"
23 #include "asfint.h"
24 #include "byteio.h"
25 #include "header.h"
26 #include "parse.h"
27 #include "data.h"
28 #include "debug.h"
31 static int
32 asf_fileio_read_cb(void *stream, void *buffer, int size)
34 int ret;
36 ret = fread(buffer, 1, size, stream);
37 if (!ret && !feof(stream))
38 return -1;
40 return ret;
43 static int64_t
44 asf_fileio_seek_cb(void *stream, int64_t offset)
46 return fseek(stream, offset, SEEK_SET);
49 asf_file_t *
50 asf_open_file(const char *filename)
52 asf_file_t *file;
53 asf_iostream_t stream;
54 FILE *fstream;
56 fstream = fopen(filename, "rb");
57 if (!fstream)
58 return NULL;
60 stream.read = asf_fileio_read_cb;
61 stream.write = NULL;
62 stream.seek = asf_fileio_seek_cb;
63 stream.opaque = fstream;
65 file = asf_open_cb(&stream);
66 if (!file)
67 return NULL;
69 file->filename = filename;
71 return file;
74 asf_file_t *
75 asf_open_cb(asf_iostream_t *iostream)
77 asf_file_t *file;
78 int i;
80 if (!iostream)
81 return NULL;
83 file = calloc(1, sizeof(asf_file_t));
84 if (!file)
85 return NULL;
87 file->filename = NULL;
88 file->iostream.read = iostream->read;
89 file->iostream.write = iostream->write;
90 file->iostream.seek = iostream->seek;
91 file->iostream.opaque = iostream->opaque;
93 file->header = NULL;
94 file->data = NULL;
95 file->index = NULL;
97 for (i=0; i < ASF_MAX_STREAMS; i++) {
98 file->streams[i].type = ASF_STREAM_TYPE_NONE;
99 file->streams[i].flags = ASF_STREAM_FLAG_NONE;
100 file->streams[i].properties = NULL;
101 file->streams[i].extended_properties = NULL;
104 return file;
108 asf_init(asf_file_t *file)
110 int tmp;
112 if (!file)
113 return ASF_ERROR_INTERNAL;
115 tmp = asf_parse_header(file);
116 if (tmp < 0) {
117 debug_printf("error parsing header: %d", tmp);
118 return tmp;
120 file->position += tmp;
121 file->data_position = file->position;
123 tmp = asf_parse_data(file);
124 if (tmp < 0) {
125 debug_printf("error parsing data object: %d", tmp);
126 return tmp;
128 file->position += tmp;
130 if (file->flags & ASF_FLAG_SEEKABLE && file->iostream.seek) {
131 int64_t seek_position;
133 file->index_position = file->data_position +
134 file->data->size;
136 seek_position = file->iostream.seek(file->iostream.opaque,
137 file->index_position);
139 /* if first seek fails, we can try to recover and just ignore seeking */
140 if (seek_position >= 0) {
141 while (seek_position == file->index_position &&
142 file->index_position < file->file_size && !file->index) {
143 tmp = asf_parse_index(file);
144 if (tmp < 0) {
145 debug_printf("Error finding index object! %d", tmp);
146 break;
149 /* The object read was something else than index */
150 if (!file->index)
151 file->index_position += tmp;
153 seek_position = file->iostream.seek(file->iostream.opaque,
154 file->index_position);
157 if (!file->index) {
158 debug_printf("Couldn't find an index object");
159 file->index_position = 0;
162 seek_position = file->iostream.seek(file->iostream.opaque,
163 file->data->packets_position);
164 if (seek_position != file->data->packets_position) {
165 /* Couldn't seek back to packets position, this is fatal! */
166 return ASF_ERROR_SEEK;
171 for (tmp = 0; tmp < ASF_MAX_STREAMS; tmp++) {
172 if (file->streams[tmp].type != ASF_STREAM_TYPE_NONE) {
173 debug_printf("stream %d of type %d found!", tmp, file->streams[tmp].type);
177 return 0;
180 void
181 asf_close(asf_file_t *file)
183 if (file) {
184 int i;
186 asf_free_header(file->header);
187 free(file->data);
188 if (file->index)
189 free(file->index->entries);
190 free(file->index);
192 if (file->filename)
193 fclose(file->iostream.opaque);
195 for (i=0; i < ASF_MAX_STREAMS; i++) {
196 free(file->streams[i].properties);
197 free(file->streams[i].extended_properties);
200 free(file);
204 asf_packet_t *
205 asf_packet_create()
207 asf_packet_t *ret;
209 ret = malloc(sizeof(asf_packet_t));
210 if (!ret)
211 return NULL;
213 asf_data_init_packet(ret);
215 return ret;
219 asf_get_packet(asf_file_t *file, asf_packet_t *packet)
221 int tmp;
223 if (!file || !packet)
224 return ASF_ERROR_INTERNAL;
226 if (file->packet >= file->data_packets_count) {
227 return 0;
230 tmp = asf_data_get_packet(packet, file);
231 if (tmp < 0) {
232 return tmp;
235 file->position += tmp;
236 file->packet++;
238 return tmp;
241 void
242 asf_packet_destroy(asf_packet_t *packet)
244 asf_data_free_packet(packet);
245 free(packet);
248 int64_t
249 asf_seek_to_msec(asf_file_t *file, int64_t msec)
251 uint64_t packet;
252 uint64_t new_position;
253 uint64_t new_msec;
254 int64_t seek_position;
256 if (!file)
257 return ASF_ERROR_INTERNAL;
259 if (!(file->flags & ASF_FLAG_SEEKABLE) || !file->iostream.seek) {
260 return ASF_ERROR_SEEKABLE;
263 /* Index structure is missing, check if we can still seek */
264 // DLM we can always seek to 0
265 if (file->index == NULL && msec > 0) {
266 int i, audiocount;
268 audiocount = 0;
269 for (i=0; i<ASF_MAX_STREAMS; i++) {
270 if (file->streams[i].type == ASF_STREAM_TYPE_NONE)
271 continue;
273 /* Non-audio files are not seekable without index */
274 if (file->streams[i].type != ASF_STREAM_TYPE_AUDIO)
275 return ASF_ERROR_SEEKABLE;
276 else
277 audiocount++;
280 /* Audio files with more than one audio track are not seekable
281 * without index */
282 if (audiocount != 1)
283 return ASF_ERROR_SEEKABLE;
286 if (msec > (file->play_duration / 10000)) {
287 return ASF_ERROR_SEEK;
290 if (file->index && file->index->entry_count == 0) {
291 // Some sort of Constant packet size?
293 /* Calculate current packet from index header */
294 packet = msec * 10000 / file->index->entry_time_interval;
295 new_msec = msec;
297 } else if (file->index && file->index->entry_count > 0) {
298 uint32_t index_entry;
300 /* Fetch current packet from index entry structure */
301 index_entry = msec * 10000 / file->index->entry_time_interval;
302 if (index_entry >= file->index->entry_count) {
303 return ASF_ERROR_SEEK;
305 packet = file->index->entries[index_entry].packet_index;
307 /* the correct msec time isn't known before reading the packet */
308 new_msec = msec;
309 } else {
310 /* convert msec into bytes per second and divide with packet_size */
311 packet = msec * file->max_bitrate / 8000 / file->packet_size;
313 /* calculate the resulting position in the audio stream */
314 new_msec = packet * file->packet_size * 8000 / file->max_bitrate;
317 /* calculate new position to be in the beginning of the current frame */
318 new_position = file->data->packets_position + packet * file->packet_size;
320 seek_position = file->iostream.seek(file->iostream.opaque, new_position);
321 if (seek_position < 0 || seek_position != new_position) {
322 return ASF_ERROR_SEEK;
325 /* update current file position information */
326 file->position = new_position;
327 file->packet = packet;
329 return new_msec;
332 asf_metadata_t *
333 asf_header_get_metadata(asf_file_t *file)
335 if (!file || !file->header)
336 return NULL;
338 return asf_header_metadata(file->header);
341 void
342 asf_header_destroy(asf_file_t *file)
344 if (!file)
345 return;
347 asf_free_header(file->header);
348 file->header = NULL;
351 void
352 asf_metadata_destroy(asf_metadata_t *metadata)
354 asf_header_free_metadata(metadata);
357 uint8_t
358 asf_get_stream_count(asf_file_t *file)
360 uint8_t ret = 0;
361 int i;
363 for (i = 0; i < ASF_MAX_STREAMS; i++) {
364 if (file->streams[i].type != ASF_STREAM_TYPE_NONE)
365 ret = i;
368 return ret;
372 asf_is_broadcast(asf_file_t *file) {
373 return (file->flags & ASF_FLAG_BROADCAST);
377 asf_is_seekable(asf_file_t *file) {
378 return (file->flags & ASF_FLAG_SEEKABLE);
381 asf_stream_t *
382 asf_get_stream(asf_file_t *file, uint8_t track)
384 if (!file || track >= ASF_MAX_STREAMS)
385 return NULL;
387 return &file->streams[track];
390 uint64_t
391 asf_get_file_size(asf_file_t *file)
393 if (!file)
394 return 0;
396 return file->file_size;
399 uint64_t
400 asf_get_creation_date(asf_file_t *file)
402 if (!file)
403 return 0;
405 return file->creation_date;
408 uint64_t
409 asf_get_data_packets(asf_file_t *file)
411 if (!file)
412 return 0;
414 return file->data_packets_count;
417 uint64_t
418 asf_get_duration(asf_file_t *file)
420 if (!file)
421 return 0;
423 return file->play_duration;
426 uint32_t
427 asf_get_max_bitrate(asf_file_t *file)
429 if (!file)
430 return 0;
432 return file->max_bitrate;