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 mve_cb_Alloc mve_alloc;
17 mve_cb_ShowFrame mve_showframe;
18 mve_cb_SetPalette mve_setpalette;
21 * private utility functions
23 static short _mve_get_short(unsigned char *data);
24 static unsigned short _mve_get_ushort(unsigned char *data);
27 * private functions for mvefile
29 static MVEFILE *_mvefile_alloc(void);
30 static void _mvefile_free(MVEFILE *movie);
31 static int _mvefile_open(MVEFILE *movie, void *stream);
32 static void _mvefile_reset(MVEFILE *movie);
33 static int _mvefile_read_header(MVEFILE *movie);
34 static void _mvefile_set_buffer_size(MVEFILE *movie, int buf_size);
35 static int _mvefile_fetch_next_chunk(MVEFILE *movie);
38 * private functions for mvestream
40 static MVESTREAM *_mvestream_alloc(void);
41 static void _mvestream_free(MVESTREAM *movie);
42 static int _mvestream_open(MVESTREAM *movie, void *stream);
43 static void _mvestream_reset(MVESTREAM *movie);
45 /************************************************************
46 * public MVEFILE functions
47 ************************************************************/
52 MVEFILE *mvefile_open(void *stream)
57 file = _mvefile_alloc();
58 if (! _mvefile_open(file, stream))
64 /* initialize the file */
65 _mvefile_set_buffer_size(file, 1024);
67 /* verify the file's header */
68 if (! _mvefile_read_header(file))
74 /* now, prefetch the next chunk */
75 _mvefile_fetch_next_chunk(file);
83 void mvefile_close(MVEFILE *movie)
91 void mvefile_reset(MVEFILE *file)
95 /* initialize the file */
96 _mvefile_set_buffer_size(file, 1024);
98 /* verify the file's header */
99 if (! _mvefile_read_header(file))
105 /* now, prefetch the next chunk */
106 _mvefile_fetch_next_chunk(file);
110 * get the size of the next segment
112 int mvefile_get_next_segment_size(MVEFILE *movie)
114 /* if nothing is cached, fail */
115 if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill)
118 /* if we don't have enough data to get a segment, fail */
119 if (movie->cur_fill - movie->next_segment < 4)
122 /* otherwise, get the data length */
123 return _mve_get_short(movie->cur_chunk + movie->next_segment);
127 * get type of next segment in chunk (0xff if no more segments in chunk)
129 unsigned char mvefile_get_next_segment_major(MVEFILE *movie)
131 /* if nothing is cached, fail */
132 if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill)
135 /* if we don't have enough data to get a segment, fail */
136 if (movie->cur_fill - movie->next_segment < 4)
139 /* otherwise, get the data length */
140 return movie->cur_chunk[movie->next_segment + 2];
144 * get subtype (version) of next segment in chunk (0xff if no more segments in
147 unsigned char mvefile_get_next_segment_minor(MVEFILE *movie)
149 /* if nothing is cached, fail */
150 if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill)
153 /* if we don't have enough data to get a segment, fail */
154 if (movie->cur_fill - movie->next_segment < 4)
157 /* otherwise, get the data length */
158 return movie->cur_chunk[movie->next_segment + 3];
162 * see next segment (return NULL if no next segment)
164 unsigned char *mvefile_get_next_segment(MVEFILE *movie)
166 /* if nothing is cached, fail */
167 if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill)
170 /* if we don't have enough data to get a segment, fail */
171 if (movie->cur_fill - movie->next_segment < 4)
174 /* otherwise, get the data length */
175 return movie->cur_chunk + movie->next_segment + 4;
179 * advance to next segment
181 void mvefile_advance_segment(MVEFILE *movie)
183 /* if nothing is cached, fail */
184 if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill)
187 /* if we don't have enough data to get a segment, fail */
188 if (movie->cur_fill - movie->next_segment < 4)
191 /* else, advance to next segment */
192 movie->next_segment +=
193 (4 + _mve_get_ushort(movie->cur_chunk + movie->next_segment));
197 * fetch the next chunk (return 0 if at end of stream)
199 int mvefile_fetch_next_chunk(MVEFILE *movie)
201 return _mvefile_fetch_next_chunk(movie);
204 /************************************************************
205 * public MVESTREAM functions
206 ************************************************************/
211 MVESTREAM *mve_open(void *stream)
216 movie = _mvestream_alloc();
219 if (! _mvestream_open(movie, stream))
221 _mvestream_free(movie);
229 * close an MVE stream
231 void mve_close(MVESTREAM *movie)
233 _mvestream_free(movie);
237 * reset an MVE stream
239 void mve_reset(MVESTREAM *movie)
241 _mvestream_reset(movie);
245 * set segment type handler
247 void mve_set_handler(MVESTREAM *movie, unsigned char major, MVESEGMENTHANDLER handler)
250 movie->handlers[major] = handler;
254 * set segment handler context
256 void mve_set_handler_context(MVESTREAM *movie, void *context)
258 movie->context = context;
264 int mve_play_next_chunk(MVESTREAM *movie)
266 unsigned char major, minor;
270 /* loop over segments */
271 major = mvefile_get_next_segment_major(movie->movie);
272 while (major != 0xff)
274 /* check whether to handle the segment */
275 if (major < 32 && movie->handlers[major] != NULL)
277 minor = mvefile_get_next_segment_minor(movie->movie);
278 len = mvefile_get_next_segment_size(movie->movie);
279 data = mvefile_get_next_segment(movie->movie);
281 if (! movie->handlers[major](major, minor, data, len, movie->context))
285 /* advance to next segment */
286 mvefile_advance_segment(movie->movie);
287 major = mvefile_get_next_segment_major(movie->movie);
290 if (! mvefile_fetch_next_chunk(movie->movie))
297 /************************************************************
299 ************************************************************/
302 * allocate an MVEFILE
304 static MVEFILE *_mvefile_alloc(void)
306 MVEFILE *file = (MVEFILE *)mve_alloc(sizeof(MVEFILE));
308 file->cur_chunk = NULL;
311 file->next_segment = 0;
319 static void _mvefile_free(MVEFILE *movie)
321 /* free the stream */
322 movie->stream = NULL;
324 /* free the buffer */
325 if (movie->cur_chunk)
326 mve_free(movie->cur_chunk);
327 movie->cur_chunk = NULL;
329 /* not strictly necessary */
332 movie->next_segment = 0;
334 /* free the struct */
339 * open the file stream in thie object
341 static int _mvefile_open(MVEFILE *file, void *stream)
343 file->stream = stream;
351 * allocate an MVEFILE
353 static void _mvefile_reset(MVEFILE *file)
356 file->cur_chunk = NULL;
359 file->next_segment = 0;
364 * read and verify the header of the recently opened file
366 static int _mvefile_read_header(MVEFILE *movie)
368 unsigned char buffer[26];
370 /* check the file is open */
374 /* check the file is long enough */
375 if (! mve_read(movie->stream, buffer, 26))
378 /* check the signature */
379 if (memcmp(buffer, MVE_HEADER, 20))
382 /* check the hard-coded constants */
383 if (_mve_get_short(buffer+20) != MVE_HDRCONST1)
385 if (_mve_get_short(buffer+22) != MVE_HDRCONST2)
387 if (_mve_get_short(buffer+24) != MVE_HDRCONST3)
393 static void _mvefile_set_buffer_size(MVEFILE *movie, int buf_size)
395 unsigned char *new_buffer;
398 /* check if this would be a redundant operation */
399 if (buf_size <= movie->buf_size)
402 /* allocate new buffer */
403 new_len = 100 + buf_size;
404 new_buffer = (unsigned char *)mve_alloc(new_len);
407 if (movie->cur_chunk && movie->cur_fill)
408 memcpy(new_buffer, movie->cur_chunk, movie->cur_fill);
410 /* free old buffer */
411 if (movie->cur_chunk)
413 mve_free(movie->cur_chunk);
414 movie->cur_chunk = 0;
417 /* install new buffer */
418 movie->cur_chunk = new_buffer;
419 movie->buf_size = new_len;
422 static int _mvefile_fetch_next_chunk(MVEFILE *movie)
424 unsigned char buffer[4];
425 unsigned short length;
427 /* fail if not open */
431 /* fail if we can't read the next segment descriptor */
432 if (! mve_read(movie->stream, buffer, 4))
435 /* pull out the next length */
436 length = _mve_get_short(buffer);
438 /* make sure we've got sufficient space */
439 _mvefile_set_buffer_size(movie, length);
442 if (! mve_read(movie->stream, movie->cur_chunk, length))
444 movie->cur_fill = length;
445 movie->next_segment = 0;
450 static short _mve_get_short(unsigned char *data)
453 value = data[0] | (data[1] << 8);
457 static unsigned short _mve_get_ushort(unsigned char *data)
459 unsigned short value;
460 value = data[0] | (data[1] << 8);
465 * allocate an MVESTREAM
467 static MVESTREAM *_mvestream_alloc(void)
471 /* allocate and zero-initialize everything */
472 movie = (MVESTREAM *)mve_alloc(sizeof(MVESTREAM));
475 memset(movie->handlers, 0, sizeof(movie->handlers));
483 static void _mvestream_free(MVESTREAM *movie)
487 mvefile_close(movie->movie);
490 /* clear context and handlers */
491 movie->context = NULL;
492 memset(movie->handlers, 0, sizeof(movie->handlers));
494 /* free the struct */
499 * open an MVESTREAM object
501 static int _mvestream_open(MVESTREAM *movie, void *stream)
503 movie->movie = mvefile_open(stream);
505 return (movie->movie == NULL) ? 0 : 1;
511 static void _mvestream_reset(MVESTREAM *movie)
513 mvefile_reset(movie->movie);