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 int _mvefile_read_header(MVEFILE *movie);
29 static void _mvefile_set_buffer_size(MVEFILE *movie, int buf_size);
30 static int _mvefile_fetch_next_chunk(MVEFILE *movie);
33 * private functions for mvestream
35 static MVESTREAM *_mvestream_alloc(void);
36 static void _mvestream_free(MVESTREAM *movie);
37 static void _mvestream_free_filehandle(MVESTREAM *movie);
38 static int _mvestream_open(MVESTREAM *movie, const char *filename);
39 static int _mvestream_open_filehandle(MVESTREAM *movie, int filehandle);
41 /************************************************************
42 * public MVEFILE functions
43 ************************************************************/
48 MVEFILE *mvefile_open(const char *filename)
53 file = _mvefile_alloc();
54 if (! _mvefile_open(file, filename))
60 /* initialize the file */
61 _mvefile_set_buffer_size(file, 1024);
63 /* verify the file's header */
64 if (! _mvefile_read_header(file))
70 /* now, prefetch the next chunk */
71 _mvefile_fetch_next_chunk(file);
76 MVEFILE *mvefile_open_filehandle(int filehandle)
81 file = _mvefile_alloc();
82 if (! _mvefile_open_filehandle(file, filehandle))
84 _mvefile_free_filehandle(file);
88 /* initialize the file */
89 _mvefile_set_buffer_size(file, 1024);
91 /* verify the file's header */
92 if (! _mvefile_read_header(file))
94 _mvefile_free_filehandle(file);
98 /* now, prefetch the next chunk */
99 _mvefile_fetch_next_chunk(file);
107 void mvefile_close(MVEFILE *movie)
109 _mvefile_free(movie);
112 void mvefile_close_filehandle(MVEFILE *movie)
114 _mvefile_free_filehandle(movie);
118 * get the size of the next segment
120 int mvefile_get_next_segment_size(MVEFILE *movie)
122 /* if nothing is cached, fail */
123 if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill)
126 /* if we don't have enough data to get a segment, fail */
127 if (movie->cur_fill - movie->next_segment < 4)
130 /* otherwise, get the data length */
131 return _mve_get_short(movie->cur_chunk + movie->next_segment);
135 * get type of next segment in chunk (0xff if no more segments in chunk)
137 unsigned char mvefile_get_next_segment_major(MVEFILE *movie)
139 /* if nothing is cached, fail */
140 if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill)
143 /* if we don't have enough data to get a segment, fail */
144 if (movie->cur_fill - movie->next_segment < 4)
147 /* otherwise, get the data length */
148 return movie->cur_chunk[movie->next_segment + 2];
152 * get subtype (version) of next segment in chunk (0xff if no more segments in
155 unsigned char mvefile_get_next_segment_minor(MVEFILE *movie)
157 /* if nothing is cached, fail */
158 if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill)
161 /* if we don't have enough data to get a segment, fail */
162 if (movie->cur_fill - movie->next_segment < 4)
165 /* otherwise, get the data length */
166 return movie->cur_chunk[movie->next_segment + 3];
170 * see next segment (return NULL if no next segment)
172 unsigned char *mvefile_get_next_segment(MVEFILE *movie)
174 /* if nothing is cached, fail */
175 if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill)
178 /* if we don't have enough data to get a segment, fail */
179 if (movie->cur_fill - movie->next_segment < 4)
182 /* otherwise, get the data length */
183 return movie->cur_chunk + movie->next_segment + 4;
187 * advance to next segment
189 void mvefile_advance_segment(MVEFILE *movie)
191 /* if nothing is cached, fail */
192 if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill)
195 /* if we don't have enough data to get a segment, fail */
196 if (movie->cur_fill - movie->next_segment < 4)
199 /* else, advance to next segment */
200 movie->next_segment +=
201 (4 + _mve_get_ushort(movie->cur_chunk + movie->next_segment));
205 * fetch the next chunk (return 0 if at end of stream)
207 int mvefile_fetch_next_chunk(MVEFILE *movie)
209 return _mvefile_fetch_next_chunk(movie);
212 /************************************************************
213 * public MVESTREAM functions
214 ************************************************************/
219 MVESTREAM *mve_open(const char *filename)
224 movie = _mvestream_alloc();
227 if (! _mvestream_open(movie, filename))
229 _mvestream_free(movie);
236 MVESTREAM *mve_open_filehandle(int filehandle)
241 movie = _mvestream_alloc();
244 if (! _mvestream_open_filehandle(movie, filehandle))
246 _mvestream_free_filehandle(movie);
254 * close an MVE stream
256 void mve_close(MVESTREAM *movie)
258 _mvestream_free(movie);
261 void mve_close_filehandle(MVESTREAM *movie)
263 _mvestream_free_filehandle(movie);
267 * set segment type handler
269 void mve_set_handler(MVESTREAM *movie, unsigned char major, MVESEGMENTHANDLER handler)
272 movie->handlers[major] = handler;
276 * set segment handler context
278 void mve_set_handler_context(MVESTREAM *movie, void *context)
280 movie->context = context;
286 int mve_play_next_chunk(MVESTREAM *movie)
288 unsigned char major, minor;
292 /* loop over segments */
293 major = mvefile_get_next_segment_major(movie->movie);
294 while (major != 0xff)
296 /* check whether to handle the segment */
297 if (major < 32 && movie->handlers[major] != NULL)
299 minor = mvefile_get_next_segment_minor(movie->movie);
300 len = mvefile_get_next_segment_size(movie->movie);
301 data = mvefile_get_next_segment(movie->movie);
303 if (! movie->handlers[major](major, minor, data, len, movie->context))
307 /* advance to next segment */
308 mvefile_advance_segment(movie->movie);
309 major = mvefile_get_next_segment_major(movie->movie);
312 if (! mvefile_fetch_next_chunk(movie->movie))
319 /************************************************************
321 ************************************************************/
324 * allocate an MVEFILE
326 static MVEFILE *_mvefile_alloc(void)
328 MVEFILE *file = (MVEFILE *)malloc(sizeof(MVEFILE));
330 file->cur_chunk = NULL;
333 file->next_segment = 0;
341 static void _mvefile_free(MVEFILE *movie)
343 /* free the stream */
344 if (movie->stream != -1)
345 close(movie->stream);
348 /* free the buffer */
349 if (movie->cur_chunk)
350 free(movie->cur_chunk);
351 movie->cur_chunk = NULL;
353 /* not strictly necessary */
356 movie->next_segment = 0;
358 /* free the struct */
362 static void _mvefile_free_filehandle(MVEFILE *movie)
364 /* free the stream */
367 /* free the buffer */
368 if (movie->cur_chunk)
369 free(movie->cur_chunk);
370 movie->cur_chunk = NULL;
372 /* not strictly necessary */
375 movie->next_segment = 0;
377 /* free the struct */
382 * open the file stream in thie object
384 static int _mvefile_open(MVEFILE *file, const char *filename)
386 file->stream = open(filename, O_RDONLY);
387 if (file->stream == -1)
393 static int _mvefile_open_filehandle(MVEFILE *file, int filehandle)
395 file->stream = filehandle;
396 if (file->stream == -1)
403 * read and verify the header of the recently opened file
405 static int _mvefile_read_header(MVEFILE *movie)
407 unsigned char buffer[26];
409 /* check the file is open */
410 if (movie->stream == -1)
413 /* check the file is long enough */
414 if (read(movie->stream, buffer, 26) < 26)
417 /* check the signature */
418 if (memcmp(buffer, MVE_HEADER, 20))
421 /* check the hard-coded constants */
422 if (_mve_get_short(buffer+20) != MVE_HDRCONST1)
424 if (_mve_get_short(buffer+22) != MVE_HDRCONST2)
426 if (_mve_get_short(buffer+24) != MVE_HDRCONST3)
432 static void _mvefile_set_buffer_size(MVEFILE *movie, int buf_size)
434 unsigned char *new_buffer;
437 /* check if this would be a redundant operation */
438 if (buf_size <= movie->buf_size)
441 /* allocate new buffer */
442 new_len = 100 + buf_size;
443 new_buffer = (unsigned char *)malloc(new_len);
446 if (movie->cur_chunk && movie->cur_fill)
447 memcpy(new_buffer, movie->cur_chunk, movie->cur_fill);
449 /* free old buffer */
450 if (movie->cur_chunk)
452 free(movie->cur_chunk);
453 movie->cur_chunk = 0;
456 /* install new buffer */
457 movie->cur_chunk = new_buffer;
458 movie->buf_size = new_len;
461 static int _mvefile_fetch_next_chunk(MVEFILE *movie)
463 unsigned char buffer[4];
464 unsigned short length;
466 /* fail if not open */
467 if (movie->stream == -1)
470 /* fail if we can't read the next segment descriptor */
471 if (read(movie->stream, buffer, 4) < 4)
474 /* pull out the next length */
475 length = _mve_get_short(buffer);
477 /* make sure we've got sufficient space */
478 _mvefile_set_buffer_size(movie, length);
481 if (read(movie->stream, movie->cur_chunk, length) < length)
483 movie->cur_fill = length;
484 movie->next_segment = 0;
489 static short _mve_get_short(unsigned char *data)
492 value = data[0] | (data[1] << 8);
496 static unsigned short _mve_get_ushort(unsigned char *data)
498 unsigned short value;
499 value = data[0] | (data[1] << 8);
504 * allocate an MVESTREAM
506 static MVESTREAM *_mvestream_alloc(void)
510 /* allocate and zero-initialize everything */
511 movie = (MVESTREAM *)malloc(sizeof(MVESTREAM));
514 memset(movie->handlers, 0, sizeof(movie->handlers));
522 static void _mvestream_free(MVESTREAM *movie)
526 mvefile_close(movie->movie);
529 /* clear context and handlers */
530 movie->context = NULL;
531 memset(movie->handlers, 0, sizeof(movie->handlers));
534 static void _mvestream_free_filehandle(MVESTREAM *movie)
538 mvefile_close_filehandle(movie->movie);
541 /* clear context and handlers */
542 movie->context = NULL;
543 memset(movie->handlers, 0, sizeof(movie->handlers));
547 * open an MVESTREAM object
549 static int _mvestream_open(MVESTREAM *movie, const char *filename)
551 movie->movie = mvefile_open(filename);
553 return (movie->movie == NULL) ? 0 : 1;
556 static int _mvestream_open_filehandle(MVESTREAM *movie, int filehandle)
558 movie->movie = mvefile_open_filehandle(filehandle);
560 return (movie->movie == NULL) ? 0 : 1;