5 #include <string.h> // for mem* functions
6 #if !defined(_WIN32) && !defined(macintosh)
15 static const char MVE_HEADER[] = "Interplay MVE File\x1A";
16 static const short MVE_HDRCONST1 = 0x001A;
17 static const short MVE_HDRCONST2 = 0x0100;
18 static const short MVE_HDRCONST3 = 0x1133;
21 mve_cb_Alloc mve_alloc;
23 mve_cb_ShowFrame mve_showframe;
24 mve_cb_SetPalette mve_setpalette;
27 * private utility functions
29 static short _mve_get_short(unsigned char *data);
30 static unsigned short _mve_get_ushort(unsigned char *data);
33 * private functions for mvefile
35 static MVEFILE *_mvefile_alloc(void);
36 static void _mvefile_free(MVEFILE *movie);
37 static int _mvefile_open(MVEFILE *movie, void *stream);
38 static void _mvefile_reset(MVEFILE *movie);
39 static int _mvefile_read_header(MVEFILE *movie);
40 static void _mvefile_set_buffer_size(MVEFILE *movie, int buf_size);
41 static int _mvefile_fetch_next_chunk(MVEFILE *movie);
44 * private functions for mvestream
46 static MVESTREAM *_mvestream_alloc(void);
47 static void _mvestream_free(MVESTREAM *movie);
48 static int _mvestream_open(MVESTREAM *movie, void *stream);
49 static void _mvestream_reset(MVESTREAM *movie);
51 /************************************************************
52 * public MVEFILE functions
53 ************************************************************/
58 MVEFILE *mvefile_open(void *stream)
63 file = _mvefile_alloc();
64 if (! _mvefile_open(file, stream))
70 /* initialize the file */
71 _mvefile_set_buffer_size(file, 1024);
73 /* verify the file's header */
74 if (! _mvefile_read_header(file))
80 /* now, prefetch the next chunk */
81 _mvefile_fetch_next_chunk(file);
89 void mvefile_close(MVEFILE *movie)
97 void mvefile_reset(MVEFILE *file)
101 /* initialize the file */
102 _mvefile_set_buffer_size(file, 1024);
104 /* verify the file's header */
105 if (! _mvefile_read_header(file))
111 /* now, prefetch the next chunk */
112 _mvefile_fetch_next_chunk(file);
116 * get the size of the next segment
118 int mvefile_get_next_segment_size(MVEFILE *movie)
120 /* if nothing is cached, fail */
121 if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill)
124 /* if we don't have enough data to get a segment, fail */
125 if (movie->cur_fill - movie->next_segment < 4)
128 /* otherwise, get the data length */
129 return _mve_get_short(movie->cur_chunk + movie->next_segment);
133 * get type of next segment in chunk (0xff if no more segments in chunk)
135 unsigned char mvefile_get_next_segment_major(MVEFILE *movie)
137 /* if nothing is cached, fail */
138 if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill)
141 /* if we don't have enough data to get a segment, fail */
142 if (movie->cur_fill - movie->next_segment < 4)
145 /* otherwise, get the data length */
146 return movie->cur_chunk[movie->next_segment + 2];
150 * get subtype (version) of next segment in chunk (0xff if no more segments in
153 unsigned char mvefile_get_next_segment_minor(MVEFILE *movie)
155 /* if nothing is cached, fail */
156 if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill)
159 /* if we don't have enough data to get a segment, fail */
160 if (movie->cur_fill - movie->next_segment < 4)
163 /* otherwise, get the data length */
164 return movie->cur_chunk[movie->next_segment + 3];
168 * see next segment (return NULL if no next segment)
170 unsigned char *mvefile_get_next_segment(MVEFILE *movie)
172 /* if nothing is cached, fail */
173 if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill)
176 /* if we don't have enough data to get a segment, fail */
177 if (movie->cur_fill - movie->next_segment < 4)
180 /* otherwise, get the data length */
181 return movie->cur_chunk + movie->next_segment + 4;
185 * advance to next segment
187 void mvefile_advance_segment(MVEFILE *movie)
189 /* if nothing is cached, fail */
190 if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill)
193 /* if we don't have enough data to get a segment, fail */
194 if (movie->cur_fill - movie->next_segment < 4)
197 /* else, advance to next segment */
198 movie->next_segment +=
199 (4 + _mve_get_ushort(movie->cur_chunk + movie->next_segment));
203 * fetch the next chunk (return 0 if at end of stream)
205 int mvefile_fetch_next_chunk(MVEFILE *movie)
207 return _mvefile_fetch_next_chunk(movie);
210 /************************************************************
211 * public MVESTREAM functions
212 ************************************************************/
217 MVESTREAM *mve_open(void *stream)
222 movie = _mvestream_alloc();
225 if (! _mvestream_open(movie, stream))
227 _mvestream_free(movie);
235 * close an MVE stream
237 void mve_close(MVESTREAM *movie)
239 _mvestream_free(movie);
243 * reset an MVE stream
245 void mve_reset(MVESTREAM *movie)
247 _mvestream_reset(movie);
251 * set segment type handler
253 void mve_set_handler(MVESTREAM *movie, unsigned char major, MVESEGMENTHANDLER handler)
256 movie->handlers[major] = handler;
260 * set segment handler context
262 void mve_set_handler_context(MVESTREAM *movie, void *context)
264 movie->context = context;
270 int mve_play_next_chunk(MVESTREAM *movie)
272 unsigned char major, minor;
276 /* loop over segments */
277 major = mvefile_get_next_segment_major(movie->movie);
278 while (major != 0xff)
280 /* check whether to handle the segment */
281 if (major < 32 && movie->handlers[major] != NULL)
283 minor = mvefile_get_next_segment_minor(movie->movie);
284 len = mvefile_get_next_segment_size(movie->movie);
285 data = mvefile_get_next_segment(movie->movie);
287 if (! movie->handlers[major](major, minor, data, len, movie->context))
291 /* advance to next segment */
292 mvefile_advance_segment(movie->movie);
293 major = mvefile_get_next_segment_major(movie->movie);
296 if (! mvefile_fetch_next_chunk(movie->movie))
303 /************************************************************
305 ************************************************************/
308 * allocate an MVEFILE
310 static MVEFILE *_mvefile_alloc(void)
312 MVEFILE *file = (MVEFILE *)mve_alloc(sizeof(MVEFILE));
314 file->cur_chunk = NULL;
317 file->next_segment = 0;
325 static void _mvefile_free(MVEFILE *movie)
327 /* free the stream */
328 movie->stream = NULL;
330 /* free the buffer */
331 if (movie->cur_chunk)
332 mve_free(movie->cur_chunk);
333 movie->cur_chunk = NULL;
335 /* not strictly necessary */
338 movie->next_segment = 0;
340 /* free the struct */
345 * open the file stream in thie object
347 static int _mvefile_open(MVEFILE *file, void *stream)
349 file->stream = stream;
357 * allocate an MVEFILE
359 static void _mvefile_reset(MVEFILE *file)
362 file->cur_chunk = NULL;
365 file->next_segment = 0;
370 * read and verify the header of the recently opened file
372 static int _mvefile_read_header(MVEFILE *movie)
374 unsigned char buffer[26];
376 /* check the file is open */
380 /* check the file is long enough */
381 if (! mve_read(movie->stream, buffer, 26))
384 /* check the signature */
385 if (memcmp(buffer, MVE_HEADER, 20))
388 /* check the hard-coded constants */
389 if (_mve_get_short(buffer+20) != MVE_HDRCONST1)
391 if (_mve_get_short(buffer+22) != MVE_HDRCONST2)
393 if (_mve_get_short(buffer+24) != MVE_HDRCONST3)
399 static void _mvefile_set_buffer_size(MVEFILE *movie, int buf_size)
401 unsigned char *new_buffer;
404 /* check if this would be a redundant operation */
405 if (buf_size <= movie->buf_size)
408 /* allocate new buffer */
409 new_len = 100 + buf_size;
410 new_buffer = (unsigned char *)mve_alloc(new_len);
413 if (movie->cur_chunk && movie->cur_fill)
414 memcpy(new_buffer, movie->cur_chunk, movie->cur_fill);
416 /* free old buffer */
417 if (movie->cur_chunk)
419 mve_free(movie->cur_chunk);
420 movie->cur_chunk = 0;
423 /* install new buffer */
424 movie->cur_chunk = new_buffer;
425 movie->buf_size = new_len;
428 static int _mvefile_fetch_next_chunk(MVEFILE *movie)
430 unsigned char buffer[4];
431 unsigned short length;
433 /* fail if not open */
437 /* fail if we can't read the next segment descriptor */
438 if (! mve_read(movie->stream, buffer, 4))
441 /* pull out the next length */
442 length = _mve_get_short(buffer);
444 /* make sure we've got sufficient space */
445 _mvefile_set_buffer_size(movie, length);
448 if (! mve_read(movie->stream, movie->cur_chunk, length))
450 movie->cur_fill = length;
451 movie->next_segment = 0;
456 static short _mve_get_short(unsigned char *data)
459 value = data[0] | (data[1] << 8);
463 static unsigned short _mve_get_ushort(unsigned char *data)
465 unsigned short value;
466 value = data[0] | (data[1] << 8);
471 * allocate an MVESTREAM
473 static MVESTREAM *_mvestream_alloc(void)
477 /* allocate and zero-initialize everything */
478 movie = (MVESTREAM *)mve_alloc(sizeof(MVESTREAM));
481 memset(movie->handlers, 0, sizeof(movie->handlers));
489 static void _mvestream_free(MVESTREAM *movie)
493 mvefile_close(movie->movie);
496 /* clear context and handlers */
497 movie->context = NULL;
498 memset(movie->handlers, 0, sizeof(movie->handlers));
500 /* free the struct */
505 * open an MVESTREAM object
507 static int _mvestream_open(MVESTREAM *movie, void *stream)
509 movie->movie = mvefile_open(stream);
511 return (movie->movie == NULL) ? 0 : 1;
517 static void _mvestream_reset(MVESTREAM *movie)
519 mvefile_reset(movie->movie);