5 static const char MVE_HEADER[] = "Interplay MVE File\x1A";
6 static const short MVE_HDRCONST1 = 0x001A;
7 static const short MVE_HDRCONST2 = 0x0100;
8 static const short MVE_HDRCONST3 = 0x1133;
11 * private utility functions
13 static short _mve_get_short(unsigned char *data);
16 * private functions for mvefile
18 static MVEFILE *_mvefile_alloc(void);
19 static void _mvefile_free(MVEFILE *movie);
20 static int _mvefile_open(MVEFILE *movie, int filehandle);
21 static int _mvefile_read_header(MVEFILE *movie);
22 static void _mvefile_set_buffer_size(MVEFILE *movie, int buf_size);
23 static int _mvefile_fetch_next_chunk(MVEFILE *movie);
26 * private functions for mvestream
28 static MVESTREAM *_mvestream_alloc(void);
29 static void _mvestream_free(MVESTREAM *movie);
30 static int _mvestream_open(MVESTREAM *movie, int filehandle);
32 /************************************************************
33 * public MVEFILE functions
34 ************************************************************/
39 MVEFILE *mvefile_open(filehandle)
44 file = _mvefile_alloc();
45 if (! _mvefile_open(file, filehandle))
51 /* initialize the file */
52 _mvefile_set_buffer_size(file, 1024);
54 /* verify the file's header */
55 if (! _mvefile_read_header(file))
61 /* now, prefetch the next chunk */
62 _mvefile_fetch_next_chunk(file);
70 void mvefile_close(MVEFILE *movie)
76 * get the size of the next segment
78 int mvefile_get_next_segment_size(MVEFILE *movie)
80 /* if nothing is cached, fail */
81 if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill)
84 /* if we don't have enough data to get a segment, fail */
85 if (movie->cur_fill - movie->next_segment < 4)
88 /* otherwise, get the data length */
89 return _mve_get_short(movie->cur_chunk + movie->next_segment);
93 * get type of next segment in chunk (0xff if no more segments in chunk)
95 unsigned char mvefile_get_next_segment_major(MVEFILE *movie)
97 /* if nothing is cached, fail */
98 if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill)
101 /* if we don't have enough data to get a segment, fail */
102 if (movie->cur_fill - movie->next_segment < 4)
105 /* otherwise, get the data length */
106 return movie->cur_chunk[movie->next_segment + 2];
110 * get subtype (version) of next segment in chunk (0xff if no more segments in
113 unsigned char mvefile_get_next_segment_minor(MVEFILE *movie)
115 /* if nothing is cached, fail */
116 if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill)
119 /* if we don't have enough data to get a segment, fail */
120 if (movie->cur_fill - movie->next_segment < 4)
123 /* otherwise, get the data length */
124 return movie->cur_chunk[movie->next_segment + 3];
128 * see next segment (return NULL if no next segment)
130 unsigned char *mvefile_get_next_segment(MVEFILE *movie)
132 /* if nothing is cached, fail */
133 if (movie->cur_chunk == NULL || movie->next_segment >= movie->cur_fill)
136 /* if we don't have enough data to get a segment, fail */
137 if (movie->cur_fill - movie->next_segment < 4)
140 /* otherwise, get the data length */
141 return movie->cur_chunk + movie->next_segment + 4;
145 * advance to next segment
147 void mvefile_advance_segment(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 /* else, advance to next segment */
158 movie->next_segment +=
159 (4 + _mve_get_short(movie->cur_chunk + movie->next_segment));
163 * fetch the next chunk (return 0 if at end of stream)
165 int mvefile_fetch_next_chunk(MVEFILE *movie)
167 return _mvefile_fetch_next_chunk(movie);
170 /************************************************************
171 * public MVESTREAM functions
172 ************************************************************/
177 MVESTREAM *mve_open(int filehandle)
182 movie = _mvestream_alloc();
185 if (! _mvestream_open(movie, filehandle))
187 _mvestream_free(movie);
195 * close an MVE stream
197 void mve_close(MVESTREAM *movie)
199 _mvestream_free(movie);
203 * set segment type handler
205 void mve_set_handler(MVESTREAM *movie, unsigned char major, MVESEGMENTHANDLER handler)
208 movie->handlers[major] = handler;
212 * set segment handler context
214 void mve_set_handler_context(MVESTREAM *movie, void *context)
216 movie->context = context;
222 int mve_play_next_chunk(MVESTREAM *movie)
224 unsigned char major, minor;
228 /* loop over segments */
229 major = mvefile_get_next_segment_major(movie->movie);
230 while (major != 0xff)
232 /* check whether to handle the segment */
233 if (major < 32 && movie->handlers[major] != NULL)
235 minor = mvefile_get_next_segment_minor(movie->movie);
236 len = mvefile_get_next_segment_size(movie->movie);
237 data = mvefile_get_next_segment(movie->movie);
239 if (! movie->handlers[major](major, minor, data, len, movie->context))
243 /* advance to next segment */
244 mvefile_advance_segment(movie->movie);
245 major = mvefile_get_next_segment_major(movie->movie);
248 if (! mvefile_fetch_next_chunk(movie->movie))
255 /************************************************************
257 ************************************************************/
260 * allocate an MVEFILE
262 static MVEFILE *_mvefile_alloc(void)
264 MVEFILE *file = (MVEFILE *)malloc(sizeof(MVEFILE));
266 file->cur_chunk = NULL;
269 file->next_segment = 0;
277 static void _mvefile_free(MVEFILE *movie)
279 /* free the stream */
282 /* free the buffer */
283 if (movie->cur_chunk)
284 free(movie->cur_chunk);
285 movie->cur_chunk = NULL;
287 /* not strictly necessary */
290 movie->next_segment = 0;
292 /* free the struct */
297 * open the file stream in thie object
299 static int _mvefile_open(MVEFILE *file, int filehandle)
301 file->stream = filehandle;
307 * read and verify the header of the recently opened file
309 static int _mvefile_read_header(MVEFILE *movie)
311 unsigned char buffer[26];
313 /* check the file is open */
314 if (movie->stream == 0)
317 /* check the file is long enough */
318 if (read(movie->stream, buffer, 26) < 26)
321 /* check the signature */
322 if (memcmp(buffer, MVE_HEADER, 20))
325 /* check the hard-coded constants */
326 if (_mve_get_short(buffer+20) != MVE_HDRCONST1)
328 if (_mve_get_short(buffer+22) != MVE_HDRCONST2)
330 if (_mve_get_short(buffer+24) != MVE_HDRCONST3)
336 static void _mvefile_set_buffer_size(MVEFILE *movie, int buf_size)
338 unsigned char *new_buffer;
341 /* check if this would be a redundant operation */
342 if (buf_size <= movie->buf_size)
345 /* allocate new buffer */
346 new_len = 100 + buf_size;
347 new_buffer = malloc(new_len);
350 if (movie->cur_chunk && movie->cur_fill)
351 memcpy(new_buffer, movie->cur_chunk, movie->cur_fill);
353 /* free old buffer */
354 if (movie->cur_chunk)
356 free(movie->cur_chunk);
357 movie->cur_chunk = 0;
360 /* install new buffer */
361 movie->cur_chunk = new_buffer;
362 movie->buf_size = new_len;
365 static int _mvefile_fetch_next_chunk(MVEFILE *movie)
367 unsigned char buffer[4];
368 unsigned short length;
370 /* fail if not open */
371 if (movie->stream == 0)
374 /* fail if we can't read the next segment descriptor */
375 if (read(movie->stream, buffer, 4) < 4)
378 /* pull out the next length */
379 length = _mve_get_short(buffer);
381 /* make sure we've got sufficient space */
382 _mvefile_set_buffer_size(movie, length);
385 if (read(movie->stream, movie->cur_chunk, length) < length)
387 movie->cur_fill = length;
388 movie->next_segment = 0;
393 static short _mve_get_short(unsigned char *data)
396 value = data[0] | (data[1] << 8);
401 * allocate an MVESTREAM
403 static MVESTREAM *_mvestream_alloc(void)
407 /* allocate and zero-initialize everything */
408 movie = (MVESTREAM *)malloc(sizeof(MVESTREAM));
411 memset(movie->handlers, 0, sizeof(movie->handlers));
419 static void _mvestream_free(MVESTREAM *movie)
423 mvefile_close(movie->movie);
426 /* clear context and handlers */
427 movie->context = NULL;
428 memset(movie->handlers, 0, sizeof(movie->handlers));
432 * open an MVESTREAM object
434 static int _mvestream_open(MVESTREAM *movie, int filehandle)
436 movie->movie = mvefile_open(filehandle);
438 return (movie->movie == NULL) ? 0 : 1;