1 #include <string.h> // for mem* functions
11 static const char MVE_HEADER[] = "Interplay MVE File\x1A";
12 static const short MVE_HDRCONST1 = 0x001A;
13 static const short MVE_HDRCONST2 = 0x0100;
14 static const short MVE_HDRCONST3 = 0x1133;
17 mve_cb_Alloc mve_alloc;
19 mve_cb_ShowFrame mve_showframe;
20 mve_cb_SetPalette mve_setpalette;
23 * private utility functions
25 static short _mve_get_short(unsigned char *data);
26 static unsigned short _mve_get_ushort(unsigned char *data);
29 * private functions for mvefile
31 static MVEFILE *_mvefile_alloc(void);
32 static void _mvefile_free(MVEFILE *movie);
33 static int _mvefile_open(MVEFILE *movie, void *stream);
34 static void _mvefile_reset(MVEFILE *movie);
35 static int _mvefile_read_header(MVEFILE *movie);
36 static void _mvefile_set_buffer_size(MVEFILE *movie, int buf_size);
37 static int _mvefile_fetch_next_chunk(MVEFILE *movie);
40 * private functions for mvestream
42 static MVESTREAM *_mvestream_alloc(void);
43 static void _mvestream_free(MVESTREAM *movie);
44 static int _mvestream_open(MVESTREAM *movie, void *stream);
45 static void _mvestream_reset(MVESTREAM *movie);
47 /************************************************************
48 * public MVEFILE functions
49 ************************************************************/
54 MVEFILE *mvefile_open(void *stream)
59 file = _mvefile_alloc();
60 if (! _mvefile_open(file, stream))
66 /* initialize the file */
67 _mvefile_set_buffer_size(file, 1024);
69 /* verify the file's header */
70 if (! _mvefile_read_header(file))
76 /* now, prefetch the next chunk */
77 _mvefile_fetch_next_chunk(file);
85 void mvefile_close(MVEFILE *movie)
93 void mvefile_reset(MVEFILE *file)
97 /* initialize the file */
98 _mvefile_set_buffer_size(file, 1024);
100 /* verify the file's header */
101 if (! _mvefile_read_header(file))
107 /* now, prefetch the next chunk */
108 _mvefile_fetch_next_chunk(file);
112 * get the size of the next segment
114 int mvefile_get_next_segment_size(MVEFILE *movie)
116 /* if nothing is cached, fail */
117 if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill)
120 /* if we don't have enough data to get a segment, fail */
121 if (movie->cur_fill - movie->next_segment < 4)
124 /* otherwise, get the data length */
125 return _mve_get_short(movie->cur_chunk + movie->next_segment);
129 * get type of next segment in chunk (0xff if no more segments in chunk)
131 unsigned char mvefile_get_next_segment_major(MVEFILE *movie)
133 /* if nothing is cached, fail */
134 if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill)
137 /* if we don't have enough data to get a segment, fail */
138 if (movie->cur_fill - movie->next_segment < 4)
141 /* otherwise, get the data length */
142 return movie->cur_chunk[movie->next_segment + 2];
146 * get subtype (version) of next segment in chunk (0xff if no more segments in
149 unsigned char mvefile_get_next_segment_minor(MVEFILE *movie)
151 /* if nothing is cached, fail */
152 if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill)
155 /* if we don't have enough data to get a segment, fail */
156 if (movie->cur_fill - movie->next_segment < 4)
159 /* otherwise, get the data length */
160 return movie->cur_chunk[movie->next_segment + 3];
164 * see next segment (return NULL if no next segment)
166 unsigned char *mvefile_get_next_segment(MVEFILE *movie)
168 /* if nothing is cached, fail */
169 if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill)
172 /* if we don't have enough data to get a segment, fail */
173 if (movie->cur_fill - movie->next_segment < 4)
176 /* otherwise, get the data length */
177 return movie->cur_chunk + movie->next_segment + 4;
181 * advance to next segment
183 void mvefile_advance_segment(MVEFILE *movie)
185 /* if nothing is cached, fail */
186 if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill)
189 /* if we don't have enough data to get a segment, fail */
190 if (movie->cur_fill - movie->next_segment < 4)
193 /* else, advance to next segment */
194 movie->next_segment +=
195 (4 + _mve_get_ushort(movie->cur_chunk + movie->next_segment));
199 * fetch the next chunk (return 0 if at end of stream)
201 int mvefile_fetch_next_chunk(MVEFILE *movie)
203 return _mvefile_fetch_next_chunk(movie);
206 /************************************************************
207 * public MVESTREAM functions
208 ************************************************************/
213 MVESTREAM *mve_open(void *stream)
218 movie = _mvestream_alloc();
221 if (! _mvestream_open(movie, stream))
223 _mvestream_free(movie);
231 * close an MVE stream
233 void mve_close(MVESTREAM *movie)
235 _mvestream_free(movie);
239 * reset an MVE stream
241 void mve_reset(MVESTREAM *movie)
243 _mvestream_reset(movie);
247 * set segment type handler
249 void mve_set_handler(MVESTREAM *movie, unsigned char major, MVESEGMENTHANDLER handler)
252 movie->handlers[major] = handler;
256 * set segment handler context
258 void mve_set_handler_context(MVESTREAM *movie, void *context)
260 movie->context = context;
266 int mve_play_next_chunk(MVESTREAM *movie)
268 unsigned char major, minor;
272 /* loop over segments */
273 major = mvefile_get_next_segment_major(movie->movie);
274 while (major != 0xff)
276 /* check whether to handle the segment */
277 if (major < 32 && movie->handlers[major] != NULL)
279 minor = mvefile_get_next_segment_minor(movie->movie);
280 len = mvefile_get_next_segment_size(movie->movie);
281 data = mvefile_get_next_segment(movie->movie);
283 if (! movie->handlers[major](major, minor, data, len, movie->context))
287 /* advance to next segment */
288 mvefile_advance_segment(movie->movie);
289 major = mvefile_get_next_segment_major(movie->movie);
292 if (! mvefile_fetch_next_chunk(movie->movie))
299 /************************************************************
301 ************************************************************/
304 * allocate an MVEFILE
306 static MVEFILE *_mvefile_alloc(void)
308 MVEFILE *file = (MVEFILE *)mve_alloc(sizeof(MVEFILE));
310 file->cur_chunk = NULL;
313 file->next_segment = 0;
321 static void _mvefile_free(MVEFILE *movie)
323 /* free the stream */
324 movie->stream = NULL;
326 /* free the buffer */
327 if (movie->cur_chunk)
328 mve_free(movie->cur_chunk);
329 movie->cur_chunk = NULL;
331 /* not strictly necessary */
334 movie->next_segment = 0;
336 /* free the struct */
341 * open the file stream in thie object
343 static int _mvefile_open(MVEFILE *file, void *stream)
345 file->stream = stream;
353 * allocate an MVEFILE
355 static void _mvefile_reset(MVEFILE *file)
358 file->cur_chunk = NULL;
361 file->next_segment = 0;
366 * read and verify the header of the recently opened file
368 static int _mvefile_read_header(MVEFILE *movie)
370 unsigned char buffer[26];
372 /* check the file is open */
376 /* check the file is long enough */
377 if (! mve_read(movie->stream, buffer, 26))
380 /* check the signature */
381 if (memcmp(buffer, MVE_HEADER, 20))
384 /* check the hard-coded constants */
385 if (_mve_get_short(buffer+20) != MVE_HDRCONST1)
387 if (_mve_get_short(buffer+22) != MVE_HDRCONST2)
389 if (_mve_get_short(buffer+24) != MVE_HDRCONST3)
395 static void _mvefile_set_buffer_size(MVEFILE *movie, int buf_size)
397 unsigned char *new_buffer;
400 /* check if this would be a redundant operation */
401 if (buf_size <= movie->buf_size)
404 /* allocate new buffer */
405 new_len = 100 + buf_size;
406 new_buffer = (unsigned char *)mve_alloc(new_len);
409 if (movie->cur_chunk && movie->cur_fill)
410 memcpy(new_buffer, movie->cur_chunk, movie->cur_fill);
412 /* free old buffer */
413 if (movie->cur_chunk)
415 mve_free(movie->cur_chunk);
416 movie->cur_chunk = 0;
419 /* install new buffer */
420 movie->cur_chunk = new_buffer;
421 movie->buf_size = new_len;
424 static int _mvefile_fetch_next_chunk(MVEFILE *movie)
426 unsigned char buffer[4];
427 unsigned short length;
429 /* fail if not open */
433 /* fail if we can't read the next segment descriptor */
434 if (! mve_read(movie->stream, buffer, 4))
437 /* pull out the next length */
438 length = _mve_get_short(buffer);
440 /* make sure we've got sufficient space */
441 _mvefile_set_buffer_size(movie, length);
444 if (! mve_read(movie->stream, movie->cur_chunk, length))
446 movie->cur_fill = length;
447 movie->next_segment = 0;
452 static short _mve_get_short(unsigned char *data)
455 value = data[0] | (data[1] << 8);
459 static unsigned short _mve_get_ushort(unsigned char *data)
461 unsigned short value;
462 value = data[0] | (data[1] << 8);
467 * allocate an MVESTREAM
469 static MVESTREAM *_mvestream_alloc(void)
473 /* allocate and zero-initialize everything */
474 movie = (MVESTREAM *)mve_alloc(sizeof(MVESTREAM));
477 memset(movie->handlers, 0, sizeof(movie->handlers));
485 static void _mvestream_free(MVESTREAM *movie)
489 mvefile_close(movie->movie);
492 /* clear context and handlers */
493 movie->context = NULL;
494 memset(movie->handlers, 0, sizeof(movie->handlers));
496 /* free the struct */
501 * open an MVESTREAM object
503 static int _mvestream_open(MVESTREAM *movie, void *stream)
505 movie->movie = mvefile_open(stream);
507 return (movie->movie == NULL) ? 0 : 1;
513 static void _mvestream_reset(MVESTREAM *movie)
515 mvefile_reset(movie->movie);