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 if (! (file->stream = filehandle))
308 * read and verify the header of the recently opened file
310 static int _mvefile_read_header(MVEFILE *movie)
312 unsigned char buffer[26];
314 /* check the file is open */
315 if (movie->stream == 0)
318 /* check the file is long enough */
319 if (read(movie->stream, buffer, 26) < 26)
322 /* check the signature */
323 if (memcmp(buffer, MVE_HEADER, 20))
326 /* check the hard-coded constants */
327 if (_mve_get_short(buffer+20) != MVE_HDRCONST1)
329 if (_mve_get_short(buffer+22) != MVE_HDRCONST2)
331 if (_mve_get_short(buffer+24) != MVE_HDRCONST3)
337 static void _mvefile_set_buffer_size(MVEFILE *movie, int buf_size)
339 unsigned char *new_buffer;
342 /* check if this would be a redundant operation */
343 if (buf_size <= movie->buf_size)
346 /* allocate new buffer */
347 new_len = 100 + buf_size;
348 new_buffer = malloc(new_len);
351 if (movie->cur_chunk && movie->cur_fill)
352 memcpy(new_buffer, movie->cur_chunk, movie->cur_fill);
354 /* free old buffer */
355 if (movie->cur_chunk)
357 free(movie->cur_chunk);
358 movie->cur_chunk = 0;
361 /* install new buffer */
362 movie->cur_chunk = new_buffer;
363 movie->buf_size = new_len;
366 static int _mvefile_fetch_next_chunk(MVEFILE *movie)
368 unsigned char buffer[4];
369 unsigned short length;
371 /* fail if not open */
372 if (movie->stream == 0)
375 /* fail if we can't read the next segment descriptor */
376 if (read(movie->stream, buffer, 4) < 4)
379 /* pull out the next length */
380 length = _mve_get_short(buffer);
382 /* make sure we've got sufficient space */
383 _mvefile_set_buffer_size(movie, length);
386 if (read(movie->stream, movie->cur_chunk, length) < length)
388 movie->cur_fill = length;
389 movie->next_segment = 0;
394 static short _mve_get_short(unsigned char *data)
397 value = data[0] | (data[1] << 8);
402 * allocate an MVESTREAM
404 static MVESTREAM *_mvestream_alloc(void)
408 /* allocate and zero-initialize everything */
409 movie = (MVESTREAM *)malloc(sizeof(MVESTREAM));
412 memset(movie->handlers, 0, sizeof(movie->handlers));
420 static void _mvestream_free(MVESTREAM *movie)
424 mvefile_close(movie->movie);
427 /* clear context and handlers */
428 movie->context = NULL;
429 memset(movie->handlers, 0, sizeof(movie->handlers));
433 * open an MVESTREAM object
435 static int _mvestream_open(MVESTREAM *movie, int filehandle)
437 movie->movie = mvefile_open(filehandle);
439 return (movie->movie == NULL) ? 0 : 1;