1 #include <string.h> // for mem* functions
9 static const char MVE_HEADER[] = "Interplay MVE File\x1A";
10 static const short MVE_HDRCONST1 = 0x001A;
11 static const short MVE_HDRCONST2 = 0x0100;
12 static const short MVE_HDRCONST3 = 0x1133;
15 * private utility functions
17 static short _mve_get_short(unsigned char *data);
18 static unsigned short _mve_get_ushort(unsigned char *data);
21 * private functions for mvefile
23 static MVEFILE *_mvefile_alloc(void);
24 static void _mvefile_free(MVEFILE *movie);
25 static void _mvefile_free_filehandle(MVEFILE *movie);
26 static int _mvefile_open(MVEFILE *movie, const char *filename);
27 static int _mvefile_open_filehandle(MVEFILE *movie, int filehandle);
28 static void _mvefile_reset(MVEFILE *movie);
29 static int _mvefile_read_header(MVEFILE *movie);
30 static void _mvefile_set_buffer_size(MVEFILE *movie, int buf_size);
31 static int _mvefile_fetch_next_chunk(MVEFILE *movie);
34 * private functions for mvestream
36 static MVESTREAM *_mvestream_alloc(void);
37 static void _mvestream_free(MVESTREAM *movie);
38 static void _mvestream_free_filehandle(MVESTREAM *movie);
39 static int _mvestream_open(MVESTREAM *movie, const char *filename);
40 static int _mvestream_open_filehandle(MVESTREAM *movie, int filehandle);
41 static void _mvestream_reset(MVESTREAM *movie);
43 /************************************************************
44 * public MVEFILE functions
45 ************************************************************/
50 MVEFILE *mvefile_open(const char *filename)
55 file = _mvefile_alloc();
56 if (! _mvefile_open(file, filename))
62 /* initialize the file */
63 _mvefile_set_buffer_size(file, 1024);
65 /* verify the file's header */
66 if (! _mvefile_read_header(file))
72 /* now, prefetch the next chunk */
73 _mvefile_fetch_next_chunk(file);
78 MVEFILE *mvefile_open_filehandle(int filehandle)
83 file = _mvefile_alloc();
84 if (! _mvefile_open_filehandle(file, filehandle))
86 _mvefile_free_filehandle(file);
90 /* initialize the file */
91 _mvefile_set_buffer_size(file, 1024);
93 /* verify the file's header */
94 if (! _mvefile_read_header(file))
96 _mvefile_free_filehandle(file);
100 /* now, prefetch the next chunk */
101 _mvefile_fetch_next_chunk(file);
109 void mvefile_close(MVEFILE *movie)
111 _mvefile_free(movie);
114 void mvefile_close_filehandle(MVEFILE *movie)
116 _mvefile_free_filehandle(movie);
122 void mvefile_reset(MVEFILE *file)
124 _mvefile_reset(file);
126 /* initialize the file */
127 _mvefile_set_buffer_size(file, 1024);
129 /* verify the file's header */
130 if (! _mvefile_read_header(file))
132 _mvefile_free_filehandle(file);
136 /* now, prefetch the next chunk */
137 _mvefile_fetch_next_chunk(file);
141 * get the size of the next segment
143 int mvefile_get_next_segment_size(MVEFILE *movie)
145 /* if nothing is cached, fail */
146 if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill)
149 /* if we don't have enough data to get a segment, fail */
150 if (movie->cur_fill - movie->next_segment < 4)
153 /* otherwise, get the data length */
154 return _mve_get_short(movie->cur_chunk + movie->next_segment);
158 * get type of next segment in chunk (0xff if no more segments in chunk)
160 unsigned char mvefile_get_next_segment_major(MVEFILE *movie)
162 /* if nothing is cached, fail */
163 if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill)
166 /* if we don't have enough data to get a segment, fail */
167 if (movie->cur_fill - movie->next_segment < 4)
170 /* otherwise, get the data length */
171 return movie->cur_chunk[movie->next_segment + 2];
175 * get subtype (version) of next segment in chunk (0xff if no more segments in
178 unsigned char mvefile_get_next_segment_minor(MVEFILE *movie)
180 /* if nothing is cached, fail */
181 if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill)
184 /* if we don't have enough data to get a segment, fail */
185 if (movie->cur_fill - movie->next_segment < 4)
188 /* otherwise, get the data length */
189 return movie->cur_chunk[movie->next_segment + 3];
193 * see next segment (return NULL if no next segment)
195 unsigned char *mvefile_get_next_segment(MVEFILE *movie)
197 /* if nothing is cached, fail */
198 if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill)
201 /* if we don't have enough data to get a segment, fail */
202 if (movie->cur_fill - movie->next_segment < 4)
205 /* otherwise, get the data length */
206 return movie->cur_chunk + movie->next_segment + 4;
210 * advance to next segment
212 void mvefile_advance_segment(MVEFILE *movie)
214 /* if nothing is cached, fail */
215 if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill)
218 /* if we don't have enough data to get a segment, fail */
219 if (movie->cur_fill - movie->next_segment < 4)
222 /* else, advance to next segment */
223 movie->next_segment +=
224 (4 + _mve_get_ushort(movie->cur_chunk + movie->next_segment));
228 * fetch the next chunk (return 0 if at end of stream)
230 int mvefile_fetch_next_chunk(MVEFILE *movie)
232 return _mvefile_fetch_next_chunk(movie);
235 /************************************************************
236 * public MVESTREAM functions
237 ************************************************************/
242 MVESTREAM *mve_open(const char *filename)
247 movie = _mvestream_alloc();
250 if (! _mvestream_open(movie, filename))
252 _mvestream_free(movie);
259 MVESTREAM *mve_open_filehandle(int filehandle)
264 movie = _mvestream_alloc();
267 if (! _mvestream_open_filehandle(movie, filehandle))
269 _mvestream_free_filehandle(movie);
277 * close an MVE stream
279 void mve_close(MVESTREAM *movie)
281 _mvestream_free(movie);
284 void mve_close_filehandle(MVESTREAM *movie)
286 _mvestream_free_filehandle(movie);
290 * reset an MVE stream
292 void mve_reset(MVESTREAM *movie)
294 _mvestream_reset(movie);
298 * set segment type handler
300 void mve_set_handler(MVESTREAM *movie, unsigned char major, MVESEGMENTHANDLER handler)
303 movie->handlers[major] = handler;
307 * set segment handler context
309 void mve_set_handler_context(MVESTREAM *movie, void *context)
311 movie->context = context;
317 int mve_play_next_chunk(MVESTREAM *movie)
319 unsigned char major, minor;
323 /* loop over segments */
324 major = mvefile_get_next_segment_major(movie->movie);
325 while (major != 0xff)
327 /* check whether to handle the segment */
328 if (major < 32 && movie->handlers[major] != NULL)
330 minor = mvefile_get_next_segment_minor(movie->movie);
331 len = mvefile_get_next_segment_size(movie->movie);
332 data = mvefile_get_next_segment(movie->movie);
334 if (! movie->handlers[major](major, minor, data, len, movie->context))
338 /* advance to next segment */
339 mvefile_advance_segment(movie->movie);
340 major = mvefile_get_next_segment_major(movie->movie);
343 if (! mvefile_fetch_next_chunk(movie->movie))
350 /************************************************************
352 ************************************************************/
355 * allocate an MVEFILE
357 static MVEFILE *_mvefile_alloc(void)
359 MVEFILE *file = (MVEFILE *)malloc(sizeof(MVEFILE));
361 file->cur_chunk = NULL;
364 file->next_segment = 0;
372 static void _mvefile_free(MVEFILE *movie)
374 /* free the stream */
375 if (movie->stream != -1)
376 close(movie->stream);
379 /* free the buffer */
380 if (movie->cur_chunk)
381 free(movie->cur_chunk);
382 movie->cur_chunk = NULL;
384 /* not strictly necessary */
387 movie->next_segment = 0;
389 /* free the struct */
393 static void _mvefile_free_filehandle(MVEFILE *movie)
395 /* free the stream */
398 /* free the buffer */
399 if (movie->cur_chunk)
400 free(movie->cur_chunk);
401 movie->cur_chunk = NULL;
403 /* not strictly necessary */
406 movie->next_segment = 0;
408 /* free the struct */
413 * open the file stream in thie object
415 static int _mvefile_open(MVEFILE *file, const char *filename)
418 file->stream = open(filename, O_RDONLY | O_BINARY);
420 file->stream = open(filename, O_RDONLY);
422 if (file->stream == -1)
428 static int _mvefile_open_filehandle(MVEFILE *file, int filehandle)
430 file->stream = filehandle;
431 if (file->stream == -1)
438 * allocate an MVEFILE
440 static void _mvefile_reset(MVEFILE *file)
443 file->cur_chunk = NULL;
446 file->next_segment = 0;
451 * read and verify the header of the recently opened file
453 static int _mvefile_read_header(MVEFILE *movie)
455 unsigned char buffer[26];
457 /* check the file is open */
458 if (movie->stream == -1)
461 /* check the file is long enough */
462 if (read(movie->stream, buffer, 26) < 26)
465 /* check the signature */
466 if (memcmp(buffer, MVE_HEADER, 20))
469 /* check the hard-coded constants */
470 if (_mve_get_short(buffer+20) != MVE_HDRCONST1)
472 if (_mve_get_short(buffer+22) != MVE_HDRCONST2)
474 if (_mve_get_short(buffer+24) != MVE_HDRCONST3)
480 static void _mvefile_set_buffer_size(MVEFILE *movie, int buf_size)
482 unsigned char *new_buffer;
485 /* check if this would be a redundant operation */
486 if (buf_size <= movie->buf_size)
489 /* allocate new buffer */
490 new_len = 100 + buf_size;
491 new_buffer = (unsigned char *)malloc(new_len);
494 if (movie->cur_chunk && movie->cur_fill)
495 memcpy(new_buffer, movie->cur_chunk, movie->cur_fill);
497 /* free old buffer */
498 if (movie->cur_chunk)
500 free(movie->cur_chunk);
501 movie->cur_chunk = 0;
504 /* install new buffer */
505 movie->cur_chunk = new_buffer;
506 movie->buf_size = new_len;
509 static int _mvefile_fetch_next_chunk(MVEFILE *movie)
511 unsigned char buffer[4];
512 unsigned short length;
514 /* fail if not open */
515 if (movie->stream == -1)
518 /* fail if we can't read the next segment descriptor */
519 if (read(movie->stream, buffer, 4) < 4)
522 /* pull out the next length */
523 length = _mve_get_short(buffer);
525 /* make sure we've got sufficient space */
526 _mvefile_set_buffer_size(movie, length);
529 if (read(movie->stream, movie->cur_chunk, length) < length)
531 movie->cur_fill = length;
532 movie->next_segment = 0;
537 static short _mve_get_short(unsigned char *data)
540 value = data[0] | (data[1] << 8);
544 static unsigned short _mve_get_ushort(unsigned char *data)
546 unsigned short value;
547 value = data[0] | (data[1] << 8);
552 * allocate an MVESTREAM
554 static MVESTREAM *_mvestream_alloc(void)
558 /* allocate and zero-initialize everything */
559 movie = (MVESTREAM *)malloc(sizeof(MVESTREAM));
562 memset(movie->handlers, 0, sizeof(movie->handlers));
570 static void _mvestream_free(MVESTREAM *movie)
574 mvefile_close(movie->movie);
577 /* clear context and handlers */
578 movie->context = NULL;
579 memset(movie->handlers, 0, sizeof(movie->handlers));
582 static void _mvestream_free_filehandle(MVESTREAM *movie)
586 mvefile_close_filehandle(movie->movie);
589 /* clear context and handlers */
590 movie->context = NULL;
591 memset(movie->handlers, 0, sizeof(movie->handlers));
595 * open an MVESTREAM object
597 static int _mvestream_open(MVESTREAM *movie, const char *filename)
599 movie->movie = mvefile_open(filename);
601 return (movie->movie == NULL) ? 0 : 1;
604 static int _mvestream_open_filehandle(MVESTREAM *movie, int filehandle)
606 movie->movie = mvefile_open_filehandle(filehandle);
608 return (movie->movie == NULL) ? 0 : 1;
614 static void _mvestream_reset(MVESTREAM *movie)
616 mvefile_reset(movie->movie);