DOSBox-X
|
00001 /* 00002 * Copyright (C) 2018-2020 Jon Campbell 00003 * 00004 * This program is free software; you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation; either version 2 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License along 00015 * with this program; if not, write to the Free Software Foundation, Inc., 00016 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 */ 00018 00019 /* Shut up! */ 00020 #define _CRT_NONSTDC_NO_DEPRECATE 00021 00022 #include "rawint.h" 00023 #include "riff.h" 00024 #include <unistd.h> 00025 #include <stdlib.h> 00026 #include <string.h> 00027 #include <assert.h> 00028 #ifdef _MSC_VER 00029 # include <io.h> 00030 #endif 00031 00032 int riff_std_read(void *a,void *b,size_t c) { 00033 riff_stack *rs; 00034 int rd; 00035 00036 rs = (riff_stack*)a; 00037 if (rs->fd < 0) return -1; 00038 if (rs->trk_file_pointer < (int64_t)0) return -1; 00039 rd = (int)read(rs->fd,b,(unsigned int)c); 00040 00041 if (rd < 0) rs->trk_file_pointer = -1LL; 00042 else rs->trk_file_pointer += rd; 00043 00044 return rd; 00045 } 00046 00047 int riff_std_write(void *a,const void *b,size_t c) { 00048 riff_stack *rs; 00049 int rd; 00050 00051 rs = (riff_stack*)a; 00052 if (rs->fd < 0) return -1; 00053 if (rs->trk_file_pointer < (int64_t)0) return -1; 00054 rd = (int)write(rs->fd,b,(unsigned int)c); 00055 00056 if (rd < 0) rs->trk_file_pointer = -1LL; 00057 else rs->trk_file_pointer += rd; 00058 00059 return rd; 00060 } 00061 00062 int64_t riff_std_seek(void *a,int64_t offset) { 00063 riff_stack *rs = (riff_stack*)a; 00064 if (rs->fd < 0) return -1; 00065 if (!rs->always_lseek && offset == rs->trk_file_pointer) return offset; 00066 #if defined(_MSC_VER) 00067 rs->trk_file_pointer = _lseeki64(rs->fd, offset, SEEK_SET); 00068 #else 00069 rs->trk_file_pointer = lseek(rs->fd, offset, SEEK_SET); 00070 #endif 00071 return rs->trk_file_pointer; 00072 } 00073 00074 int riff_buf_read(void *a,void *b,size_t c) { 00075 riff_stack *rs = (riff_stack*)a; 00076 if (rs->buffer == NULL) return -1; 00077 if (rs->bufofs >= rs->buflen) return 0; 00078 if ((rs->bufofs+c) > rs->buflen) c = (size_t)(rs->buflen - rs->bufofs); 00079 memcpy(b,(char*)rs->buffer+rs->bufofs,c); 00080 rs->bufofs += (size_t)c; 00081 return (int)c; 00082 } 00083 00084 int riff_buf_write(void *a,const void *b,size_t c) { 00085 riff_stack *rs = (riff_stack*)a; 00086 if (rs->buffer == NULL) return -1; 00087 if (rs->bufofs >= rs->buflen) return 0; 00088 if ((rs->bufofs+c) > rs->buflen) c = (size_t)(rs->buflen - rs->bufofs); 00089 memcpy((char*)rs->buffer+rs->bufofs,b,c); 00090 rs->bufofs += (size_t)c; 00091 return (int)c; 00092 } 00093 00094 int64_t riff_buf_seek(void *a,int64_t offset) { 00095 riff_stack *rs = (riff_stack*)a; 00096 if (rs->buffer == NULL) return -1; 00097 if (offset < 0LL) offset = 0LL; 00098 else if (offset > (int64_t)(rs->buflen)) offset = (int64_t)(rs->buflen); 00099 rs->bufofs = (size_t)offset; 00100 return (int64_t)rs->bufofs; 00101 } 00102 00103 /* NTS: By design, this code focuses only on closing the file descriptor. 00104 * If you forgot to write sync headers or pop all off the stack, 00105 * then the incomplete and invalid RIFF structure is your problem. */ 00106 void riff_stack_close_source(riff_stack *s) { 00107 if (s->fd >= 0 && s->fd_owner) { 00108 close(s->fd); 00109 s->fd = -1; 00110 } 00111 } 00112 00113 /* NTS: By default, does NOT take ownership of the file descriptor. 00114 * If you want the RIFF stack to take ownership, and automatically 00115 * free the descriptor on destruction/close, then you would call 00116 * this function then call riff_stack_assign_fd_ownershop() */ 00117 int riff_stack_assign_fd(riff_stack *s,int fd) { 00118 if (fd != s->fd) { 00119 riff_stack_close_source(s); 00120 s->fd_owner = 0; 00121 s->fd = fd; 00122 } 00123 s->buffer = NULL; 00124 s->read = riff_std_read; 00125 s->seek = riff_std_seek; 00126 s->write = riff_std_write; 00127 s->trk_file_pointer = -1LL; 00128 return 1; 00129 } 00130 00131 int riff_stack_assign_fd_ownership(riff_stack *s) { 00132 s->fd_owner = 1; 00133 return 1; 00134 } 00135 00136 int riff_stack_assign_buffer(riff_stack *s,void *buffer,size_t len) { 00137 s->fd = -1; 00138 s->buflen = len; 00139 s->buffer = buffer; 00140 s->bufofs = (size_t)(0UL); 00141 s->read = riff_buf_read; 00142 s->seek = riff_buf_seek; 00143 s->write = riff_buf_write; 00144 s->trk_file_pointer = -1LL; 00145 return 1; 00146 } 00147 00148 riff_stack *riff_stack_create(int depth) { 00149 riff_stack *s = (riff_stack*)malloc(sizeof(riff_stack)); 00150 if (!s) return NULL; 00151 memset(s,0,sizeof(*s)); 00152 00153 if (depth == 0) depth = 32; 00154 else if (depth < 16) depth = 16; 00155 else if (depth > 512) depth = 512; 00156 00157 s->fd = -1; 00158 s->current = -1; 00159 s->depth = depth; 00160 s->stack = (riff_chunk*)malloc(sizeof(riff_chunk)*(unsigned int)depth); 00161 if (!s->stack) { 00162 free(s); 00163 return NULL; 00164 } 00165 memset(s->stack,0,sizeof(riff_chunk)*(unsigned int)depth); 00166 return s; 00167 } 00168 00169 riff_stack *riff_stack_destroy(riff_stack *s) { 00170 if (s) { 00171 riff_stack_close_source(s); 00172 if (s->stack) free(s->stack); 00173 free(s); 00174 } 00175 return NULL; 00176 } 00177 00178 int riff_stack_is_empty(riff_stack *s) { 00179 return (s->current == -1); 00180 } 00181 00182 int riff_stack_empty(riff_stack *s) { 00183 s->current = -1; 00184 s->next_read = 0; 00185 s->next_write = 0; 00186 s->top = NULL; 00187 s->eof = 0; 00188 return 1; 00189 } 00190 00191 riff_chunk *riff_stack_top(riff_stack *s) { 00192 if (!s) return NULL; 00193 if (s->current == -1) return NULL; 00194 return (s->top = (s->stack + s->current)); 00195 } 00196 00197 riff_chunk *riff_stack_pop(riff_stack *s) { 00198 riff_chunk *pc,*c; 00199 00200 if (!s) return NULL; 00201 if (s->current == -1) return NULL; 00202 00203 c = s->top; 00204 s->current--; 00205 if (s->current == -1) { 00206 if (s->wmode) { 00207 if (!c->disable_sync) riff_stack_header_sync(s,c); 00208 if (c->data_length < (int64_t)c->write_offset) 00209 c->data_length = (uint32_t)c->write_offset; 00210 00211 c->absolute_data_length = (c->data_length + 1) & (~1UL); 00212 s->next_write = c->absolute_data_offset + c->absolute_data_length; 00213 } 00214 s->top = NULL; 00215 return NULL; 00216 } 00217 s->top = (s->stack + s->current); 00218 00219 /* if we're writing a RIFF structure, we need to make sure 00220 * the parent chunk's data offsets are properly set up. 00221 * the above conditions ensure we don't get here unless 00222 * there was a parent chunk involved */ 00223 if (s->wmode) { 00224 unsigned char no_sync = c->disable_sync; 00225 00226 if (c->placeholder) { 00227 c->placeholder = 0; /* caller pops a chunk off the stack to complete it, therefore the placeholder must be rewritten */ 00228 c->disable_sync = 0; /* it MUST be rewritten, disabling sync is no longer an option */ 00229 no_sync = 0; /* <--- ditto */ 00230 } 00231 00232 if (!no_sync) riff_stack_header_sync(s,c); 00233 pc = s->top; 00234 while (pc && c) { 00235 if ((c->absolute_data_offset + c->absolute_data_length) > 00236 (pc->absolute_data_offset + pc->data_length)) { 00237 pc->data_length = (uint32_t)((c->absolute_data_offset + c->absolute_data_length) - 00238 pc->absolute_data_offset); 00239 pc->absolute_data_length = pc->data_length; /* FIXME: right? */ 00240 } 00241 00242 if (c->absolute_data_offset >= pc->absolute_data_offset) { 00243 int64_t limit = c->absolute_data_offset + c->absolute_data_length - 00244 pc->absolute_data_offset; 00245 00246 if (pc->write_offset < limit) 00247 pc->write_offset = limit; 00248 } 00249 00250 if (pc == s->stack) 00251 break; 00252 00253 c = pc--; /* NTS: remember pc = s->top = s->stack + <index> */ 00254 } 00255 if (!no_sync) riff_stack_header_sync(s,s->top); 00256 } 00257 00258 return s->top; 00259 } 00260 00261 int riff_stack_push(riff_stack *s,riff_chunk *c) { 00262 riff_chunk *to; 00263 if (s == NULL || c == NULL) return 0; 00264 if (s->current < -1) return 0; 00265 if ((s->current+1) >= s->depth) return 0; 00266 to = s->stack + (++s->current); 00267 memcpy(to,c,sizeof(riff_chunk)); 00268 s->top = to; 00269 return 1; 00270 } 00271 00272 int64_t riff_stack_current_chunk_offset(riff_stack *s) { 00273 int64_t o; 00274 if (s == NULL) return -1LL; 00275 if (s->top->read_offset > (s->top->data_length-8LL)) return -1LL; 00276 o = s->top->absolute_data_offset+s->top->read_offset; 00277 return o; 00278 } 00279 00280 int64_t riff_stack_seek(riff_stack *s,riff_chunk *c,int64_t of) { 00281 if (c) { 00282 if (of > c->data_length) of = c->data_length; 00283 else if (of < 0) of = 0; 00284 c->read_offset = c->write_offset = of; 00285 } 00286 else { 00287 if (of < 0) of = 0; 00288 s->next_write = s->next_read = of; 00289 } 00290 00291 return of; 00292 } 00293 00294 int riff_stack_streamwrite(riff_stack *s,riff_chunk *c,const void *buf,size_t len) { 00295 if (s->write == NULL) 00296 return -1; 00297 00298 if (c) { 00299 if (!c->wmode) 00300 return -1; 00301 00302 /* once the data is written, you are not allowed to write any more */ 00303 if (c->write_offset != 0) 00304 return -1; 00305 00306 /* AVI chunks are limited to 2GB or less */ 00307 if (((unsigned long long)c->write_offset+len) >= 0x80000000ULL) 00308 return -1; 00309 00310 /* assume the write will complete and setup pointers now */ 00311 c->read_offset = c->write_offset = (int64_t)len; 00312 c->data_length = (uint32_t)c->write_offset; 00313 c->absolute_data_length = (c->data_length + 1UL) & (~1UL); 00314 00315 /* write the header NOW */ 00316 riff_stack_header_sync(s,c); 00317 00318 /* then write the data. 00319 * the consequence of this design is that unlike riff_stack_write() the 00320 * call is considered an absolute failure IF we were not able to write all 00321 * the data to disk. We have to, the design of this code bets on it! 00322 * 00323 * NTS: We allow the caller to streamwrite NULL-length packets with buf=NULL and len=0 */ 00324 if (buf != NULL) { 00325 int rd; 00326 00327 if (s->seek(s,c->absolute_data_offset) != c->absolute_data_offset) return 0; 00328 rd = s->write(s,buf,len); 00329 00330 /* if we were not able to write all data, well, too bad. update the header */ 00331 if (rd < (int)len) { 00332 if (rd < 0) rd = 0; 00333 c->read_offset = c->write_offset = rd; 00334 c->data_length = (uint32_t)c->write_offset; 00335 c->absolute_data_length = (c->data_length + 1UL) & (~1UL); 00336 00337 /* write the header NOW */ 00338 riff_stack_header_sync(s,c); 00339 00340 /* fail */ 00341 return -1; 00342 } 00343 } 00344 00345 /* we already wrote the header, and the caller is SUPPOSED to 00346 * use this function ONCE for a RIFF chunk. Don't let riff_stack_pop() 00347 * waste it's time lseek()'ing back to rewrite the header */ 00348 c->disable_sync = 1; 00349 } 00350 else { 00351 abort(); /* TODO */ 00352 } 00353 00354 return (int)len; 00355 } 00356 00357 int riff_stack_write(riff_stack *s,riff_chunk *c,const void *buf,size_t len) { 00358 int rd; 00359 00360 if (s->write == NULL) 00361 return -1; 00362 00363 if (c) { 00364 if (!c->wmode) 00365 return -1; 00366 if (c->absolute_data_offset == ((int64_t)(-1))) 00367 return -1; 00368 00369 /* AVI chunks are limited to 2GB or less */ 00370 if (((unsigned long long)c->write_offset+len) >= 0x80000000ULL) 00371 return -1; 00372 00373 if (s->seek(s,c->absolute_data_offset+c->write_offset) != 00374 (c->absolute_data_offset+c->write_offset)) return 0; 00375 rd = s->write(s,buf,len); 00376 if (rd > 0) c->read_offset = (c->write_offset += rd); 00377 if (c->data_length < (int64_t)c->write_offset) 00378 c->data_length = (uint32_t)c->write_offset; 00379 c->absolute_data_length = (c->data_length + 1UL) & (~1UL); 00380 } 00381 else { 00382 if (s->seek(s,s->next_write) != s->next_write) return 0; 00383 rd = s->write(s,buf,len); 00384 if (rd > 0) s->next_read = (s->next_write += rd); 00385 } 00386 00387 return rd; 00388 } 00389 00390 int riff_stack_read(riff_stack *s,riff_chunk *c,void *buf,size_t len) { 00391 int rd; 00392 00393 if (c) { 00394 int64_t rem = c->data_length - c->read_offset; 00395 if (rem > (int64_t)len) rem = (int64_t)len; 00396 len = (size_t)rem; 00397 if (len == 0) return 0; 00398 if (c->absolute_data_offset == ((int64_t)(-1))) return 0; 00399 if (s->seek(s,c->absolute_data_offset+c->read_offset) != (c->absolute_data_offset+c->read_offset)) return 0; 00400 rd = s->read(s,buf,len); 00401 if (rd > 0) c->write_offset = (c->read_offset += rd); 00402 } 00403 else { 00404 if (s->seek(s,s->next_read) != s->next_read) return 0; 00405 rd = s->read(s,buf,len); 00406 if (rd > 0) s->next_write = (s->next_read += rd); 00407 } 00408 00409 return rd; 00410 } 00411 00412 /* given a chunk (pc), read a subchunk. 00413 * to read at the top (file) level, set pc == NULL. 00414 * 00415 * if a subchunk is present, function returns 1 and the subchunk in (c). 00416 * else, (c) is not changed and function returns 0. 00417 * 00418 * The function needs the stack object to read, but does not automatically 00419 * push the chunk to the top of the stack. if you want to enter the 00420 * chunk to examine it, then you must push it to the stack yourself. 00421 * 00422 * this function DOES NOT check for you whether the chunk you are reading 00423 * should have subchunks. YOU are responsible for using 00424 * riff_stack_chunk_contains_subchunks() to determine that first. if you 00425 * use this function on a chunk that contains only data, you will get 00426 * garbage chunks and that's your fault. 00427 * 00428 * Anatomy of an AVI chunk (data only, always little endian): 00429 * 00430 * Offset size / type contents 00431 * ------------------------------------- 00432 * +0x00 +0 4 / DWORD FOURCC (4-byte ASCII identifying the chunk) 00433 * +0x04 +4 4 / DWORD data length (not including header) 00434 * =0x08 +8 8 00435 * 00436 * Anatomy of an AVI chunk (list chunk containing subchunks): 00437 * 00438 * Offset size / type contents 00439 * ------------------------------------- 00440 * +0x00 +0 4 / DWORD FOURCC ("RIFF" or "LIST") 00441 * +0x04 +4 4 / DWORD data length (not including header but including 4-byte subchunk header that follows) 00442 * +0x08 +8 4 / DWORD FOURCC (4-byte ASCII identifying the subchunk) 00443 * =0x0C +12 12 00444 * 00445 * A word of caution about top-level chunks: Most RIFF formats are based on the top level 00446 * containing one major top-level chunk, and most (all) chunks are within that top level 00447 * chunk. If the file extends past 2GB, then the file at the top level is a series of 00448 * very large top-level RIFF chunks. It is very unlikely that you'll ever get a non-list 00449 * chunk at top level, so if this function returns one at toplevel, it's probably unrelated 00450 * junk at the end of the file. 00451 * 00452 * In most cases, your code should simply read the one chunk at the start of the file and 00453 * generally stay within the chunk, unless for example OpenDML AVI 2.0, in which you must 00454 * make sure you read the series of RIFF:AVI and RIFF:AVIX chunks until you reach the end 00455 * of the file or encounter any other chunk. Again, this code will NOT prevent you from 00456 * reading junk at the end of the file as an AVI chunk! 00457 */ 00458 int riff_stack_readchunk(riff_stack *s,riff_chunk *pc,riff_chunk *c) { 00459 unsigned char buf[8]; 00460 00461 if (s == NULL) return 0; /* caller must provide (s) stack */ 00462 if (c == NULL) return 0; /* caller must provide (c) chunk structure to fill in */ 00463 if (s->wmode) return 0; /* no reading chunks while writing RIFF */ 00464 00465 if (pc != NULL) { 00466 /* if parent chunk provided, read new chunk from parent chunk */ 00467 if (c->absolute_data_offset == ((int64_t)(-1))) return 0; 00468 if ((pc->read_offset+8) > pc->data_length) return 0; 00469 if (s->seek(s,pc->absolute_data_offset+pc->read_offset) != (pc->absolute_data_offset+pc->read_offset)) return 0; 00470 c->absolute_header_offset = pc->absolute_data_offset+pc->read_offset; 00471 } 00472 else { 00473 /* if parent chunk NOT provided, read from read pointer in file. 00474 * return now if read pointer has signalled eof. 00475 * signal eof and return if seek fails. */ 00476 if (s->eof) return 0; 00477 if (s->seek(s,s->next_read) != s->next_read) { 00478 s->eof = 1; 00479 return 0; 00480 } 00481 c->absolute_header_offset = s->next_read; 00482 } 00483 00484 /* read 8 bytes corresponding to the FOURCC and data length. 00485 * failure to read is the end of the chunk. 00486 * signal eof if the failure is at the top level. */ 00487 if (s->read(s,buf,8) < 8) { 00488 if (pc == NULL) s->eof = 1; 00489 return 0; 00490 } 00491 00492 c->wmode = 0; 00493 c->read_offset = 0; 00494 c->write_offset = 0; 00495 c->absolute_data_offset = c->absolute_header_offset + 8LL; 00496 c->list_fourcc = (riff_fourcc_t)(0UL); 00497 c->fourcc = __le_u32(buf+0); 00498 c->data_length = __le_u32(buf+4); /* <-- NOTE this is why AVI files have a 2GB limit */ 00499 c->absolute_data_length = (c->data_length + 1ULL) & (~1ULL); /* <-- RIFF chunks are WORD aligned */ 00500 c->absolute_offset_next_chunk = c->absolute_data_offset + c->absolute_data_length; 00501 00502 /* consider it the end of the chunks if we read in a NULL fourcc, and mark EOF */ 00503 if (c->fourcc == 0UL) { 00504 if (pc) pc->read_offset = pc->write_offset = pc->data_length; 00505 else s->eof = 1; 00506 return 0; 00507 } 00508 00509 /* some chunks like 'RIFF' or 'LIST' are actually 12 byte headers, with the real FOURCC 00510 * following the length, then subchunks follow in the data area. */ 00511 if (c->fourcc == riff_RIFF || c->fourcc == riff_LIST) { 00512 c->list_fourcc = c->fourcc; 00513 if (c->data_length >= 4) { 00514 if (s->read(s,buf,4) < 4) return 0; 00515 c->fourcc = __le_u32(buf+0); 00516 c->absolute_data_offset += 4; 00517 c->absolute_data_length -= 4; 00518 c->data_length -= 4; 00519 } 00520 else { 00521 memset(buf,0,4); 00522 if ((int)s->read(s,buf,c->absolute_data_length) < (int)c->absolute_data_length) return 0; 00523 c->fourcc = __le_u32(buf+0); 00524 c->absolute_data_offset += c->absolute_data_length; 00525 c->absolute_data_length = 0; 00526 c->data_length = 0; 00527 } 00528 } 00529 00530 if (pc) pc->read_offset = pc->write_offset = c->absolute_offset_next_chunk - pc->absolute_data_offset; 00531 else s->next_read = s->next_write = c->absolute_offset_next_chunk; 00532 return 1; 00533 } 00534 00535 int riff_stack_chunk_contains_subchunks(riff_chunk *c) { 00536 if (c == NULL) return 0; 00537 if (c->list_fourcc == riff_RIFF) return 1; 00538 if (c->list_fourcc == riff_LIST) return 1; 00539 return 0; 00540 } 00541 00542 void riff_stack_fourcc_to_str(riff_fourcc_t t,char *tmp) { 00543 tmp[0] = (char)((t >> 0) & 0xFF); 00544 tmp[1] = (char)((t >> 8) & 0xFF); 00545 tmp[2] = (char)((t >> 16) & 0xFF); 00546 tmp[3] = (char)((t >> 24) & 0xFF); 00547 tmp[4] = (char)0; 00548 } 00549 00550 void riff_stack_debug_print_indent(FILE *fp,int level) { 00551 while (level-- > 0) fprintf(fp," "); 00552 } 00553 00554 void riff_stack_debug_print(FILE *fp,int level,riff_chunk *chunk) { 00555 char tmp[8]; 00556 00557 riff_stack_debug_print_indent(fp,level); 00558 fprintf(fp,"[%d] ",level); 00559 if (riff_stack_chunk_contains_subchunks(chunk)) { 00560 riff_stack_fourcc_to_str(chunk->list_fourcc,tmp); 00561 fprintf(fp,"'%s:",tmp); 00562 riff_stack_fourcc_to_str(chunk->fourcc,tmp); 00563 fprintf(fp,"%s' ",tmp); 00564 } 00565 else { 00566 riff_stack_fourcc_to_str(chunk->fourcc,tmp); 00567 fprintf(fp,"'%s' ",tmp); 00568 } 00569 fprintf(fp,"hdr=%llu data=%llu len=%lu data-end=%llu", 00570 (unsigned long long)(chunk->absolute_header_offset), 00571 (unsigned long long)(chunk->absolute_data_offset), 00572 (unsigned long)(chunk->data_length), 00573 (unsigned long long)(chunk->absolute_data_offset+chunk->data_length)); 00574 fprintf(fp,"\n"); 00575 } 00576 00577 void riff_stack_debug_chunk_dump(FILE *fp,riff_stack *riff,riff_chunk *chunk) { 00578 unsigned char tmp[64]; 00579 int rd,i,col=0,o; 00580 00581 if (riff_stack_seek(riff,chunk,0LL) != 0LL) 00582 return; 00583 00584 rd = (int)riff_stack_read(riff,chunk,tmp,sizeof(tmp)); 00585 for (i=0;i < ((rd+15)&(~15));) { 00586 if (col == 0) fprintf(fp," "); 00587 00588 col++; 00589 if (i < rd) fprintf(fp,"%02X ",tmp[i]); 00590 else fprintf(fp," "); 00591 i++; 00592 00593 if (col >= 16 || i == ((rd+15)&(~15))) { 00594 for (col=0;col < 16;col++) { 00595 o = i+col-16; 00596 if (o >= rd) 00597 fwrite(" ",1,1,fp); 00598 else if (tmp[o] >= 32 && tmp[o] < 127) 00599 fwrite(tmp+o,1,1,fp); 00600 else 00601 fwrite(".",1,1,fp); 00602 } 00603 00604 col = 0; 00605 fprintf(fp,"\n"); 00606 } 00607 } 00608 } 00609 00610 int riff_stack_eof(riff_stack *r) { 00611 if (r == NULL) return 0; 00612 if (r->current == -1) return r->eof; 00613 return 0; 00614 } 00615 00616 void riff_chunk_improvise(riff_chunk *c,uint64_t ofs,uint32_t size) { 00617 c->absolute_header_offset = (int64_t)ofs; 00618 c->absolute_data_offset = (int64_t)ofs; 00619 c->absolute_offset_next_chunk = (int64_t)(ofs + size); 00620 c->fourcc = 0U; 00621 c->data_length = size; 00622 c->absolute_data_length = size; 00623 c->list_fourcc = 0U; 00624 c->read_offset = 0ULL; 00625 c->write_offset = 0ULL; 00626 c->wmode = 0; 00627 } 00628 00629 int riff_stack_prepare_for_writing(riff_stack *r,int wmode) { 00630 if (r == NULL) return 0; 00631 if (r->wmode == wmode) return 1; 00632 00633 /* no state changes while anything is stacked on */ 00634 if (r->current >= 0) return 0; 00635 00636 /* no state changes while reading an AVI chunk */ 00637 if (r->next_read != 0LL && !r->eof) return 0; 00638 00639 r->wmode = wmode > 0 ? 1 : 0; 00640 return 1; 00641 } 00642 00643 int riff_stack_begin_new_chunk_here(riff_stack *s,riff_chunk *c) { 00644 riff_chunk *p = riff_stack_top(s); 00645 00646 /* you can't begin new chunks if you're not writing the file */ 00647 if (!s->wmode) 00648 return 0; 00649 00650 /* sanity check. 00651 * if we're currently in a subchunk, make sure the subchunk allows for subchunks within. 00652 * you can't just put chunks inside data. */ 00653 if (p != NULL) { 00654 if (!riff_stack_chunk_contains_subchunks(p)) { 00655 fprintf(stderr,"BUG: riff_stack_begin_new_chunk_here() caller attempting to start new RIFF chunks inside a chunk that does not contain subchunks\n"); 00656 return 0; 00657 } 00658 } 00659 00660 /* zero the chunk and pick the header offset. 00661 * for debugging purposes, we do not assign the data offset until the 00662 * host program calls set_chunk_list_type/set_chunk_data_type. 00663 * the chunk itself must also remember that it's in write mode. */ 00664 memset(c,0,sizeof(*c)); 00665 if (p != NULL) 00666 c->absolute_header_offset = p->absolute_data_offset + p->write_offset; 00667 else 00668 c->absolute_header_offset = s->next_write; 00669 00670 c->absolute_data_offset = (int64_t)(-1LL); 00671 c->wmode = 1; 00672 return 1; 00673 } 00674 00675 int riff_stack_header_sync(riff_stack *s,riff_chunk *c) { 00676 unsigned char tmp[12]; 00677 00678 if (!c->wmode || !s->wmode) 00679 return 0; 00680 00681 if (s->seek(s,c->absolute_header_offset) != c->absolute_header_offset) 00682 return 0; 00683 00684 /* NTS: A placeholder value of 0xFFFFFFFF would technically violate the AVI standard 00685 * because it is well known older programs treat the length as signed. We use 00686 * 0x7FFFFFFF instead. */ 00687 if (c->list_fourcc != (riff_fourcc_t)0) { 00688 __w_le_u32(tmp+0,c->list_fourcc); 00689 if (c->placeholder) 00690 __w_le_u32(tmp+4,0x7FFFFFFFUL); 00691 else 00692 __w_le_u32(tmp+4,c->data_length + 4UL); /* for some reason the length covers the fourcc */ 00693 __w_le_u32(tmp+8,c->fourcc); 00694 if (s->write(s,tmp,12) < 12) 00695 return 0; 00696 } 00697 else { 00698 __w_le_u32(tmp+0,c->fourcc); 00699 if (c->placeholder) 00700 __w_le_u32(tmp+4,0x7FFFFFFFUL); 00701 else 00702 __w_le_u32(tmp+4,c->data_length); 00703 if (s->write(s,tmp,8) < 8) 00704 return 0; 00705 } 00706 00707 return 1; 00708 } 00709 00710 int riff_stack_header_sync_all(riff_stack *s) { 00711 int i = s->current; 00712 00713 while (i >= 0) { 00714 riff_chunk *c = s->stack + (i--); 00715 if (!riff_stack_header_sync(s,c)) 00716 return 0; 00717 } 00718 00719 return 1; 00720 } 00721 00722 /* start a data chunk (no subchunks) with FOURCC (fcc) */ 00723 int riff_stack_set_chunk_data_type(riff_chunk *c,riff_fourcc_t fcc) { 00724 if (!c->wmode) 00725 return 0; 00726 if (c->write_offset != 0LL) { 00727 fprintf(stderr,"BUG: riff_stack_set_chunk_data_type() caller attempted to set type after writing data!\n"); 00728 return 0; 00729 } 00730 00731 c->fourcc = fcc; 00732 c->list_fourcc = (riff_fourcc_t)0; 00733 c->absolute_data_offset = c->absolute_header_offset + 8LL; /* <fourcc> <len> */ 00734 return 1; 00735 } 00736 00737 /* start a list chunk (with subchunks) with list type (list) usually "RIFF" and "LIST" and FOURCC (fcc). 00738 * For example: RIFF:AVI would be list = "RIFF" fcc = "AVI " */ 00739 int riff_stack_set_chunk_list_type(riff_chunk *c,riff_fourcc_t list,riff_fourcc_t fcc) { 00740 if (!c->wmode) 00741 return 0; 00742 if (c->write_offset != 0LL) { 00743 fprintf(stderr,"BUG: riff_stack_set_chunk_list_type() caller attempted to set type after writing data!\n"); 00744 return 0; 00745 } 00746 00747 c->fourcc = fcc; 00748 c->list_fourcc = list; 00749 c->absolute_data_offset = c->absolute_header_offset + 12LL; /* RIFF <len> <fourcc> */ 00750 return 1; 00751 } 00752 00753 void riff_stack_writing_sync(riff_stack *s) { 00754 int64_t noffset = 0; 00755 00756 while (s->current >= 0) { 00757 /* the caller uses this function when all chunks are to be completed, 00758 * and the writing process may or may not be done. the AVI writer 00759 * may uses this for instance when writing the next 'AVIX' chunk 00760 * in an OpenDML file which requires all chunks to be completed. 00761 * 00762 * as part of the process we must clear all disable_sync and 00763 * placeholder markings so the true state can be written back */ 00764 riff_chunk *t = riff_stack_top(s); 00765 t->disable_sync = 0; 00766 t->placeholder = 0; 00767 riff_stack_header_sync_all(s); 00768 assert(s->top->absolute_data_offset >= (int64_t)0); 00769 int64_t x = s->top->absolute_data_offset + s->top->absolute_data_length; 00770 if (noffset < x) noffset = x; 00771 riff_stack_pop(s); 00772 } 00773 00774 s->next_write = noffset; 00775 } 00776 00777 /* if I wrote "len" bytes, would I hit or cross the AVI 2GB chunk limit at any level? */ 00778 /* if so, the caller must pop down all AVI chunks, emptying the stack, and then create 00779 * new chunks to continue on */ 00780 int riff_stack_chunk_limit(riff_stack *s,int len) { 00781 riff_chunk *lowest,*highest; 00782 unsigned long long base; 00783 00784 if (s->current < 0) return 0; 00785 00786 lowest = s->stack; 00787 assert(lowest->absolute_data_offset >= (int64_t)0); 00788 highest = riff_stack_top(s); 00789 assert(highest != NULL); 00790 assert(highest->absolute_data_offset >= (int64_t)0); 00791 base = (unsigned long long)lowest->absolute_data_offset; 00792 00793 for (;highest >= lowest;highest--) { 00794 signed long long rel = (signed long long)((unsigned long long)highest->absolute_data_offset - base); 00795 /* subchunks should not be all over the place---sanity check! */ 00796 assert(rel >= 0); 00797 00798 if ((rel + highest->write_offset + len) >= 0x40000000LL) /* 1GB mark */ 00799 return 1; 00800 } 00801 00802 return 0; 00803 } 00804 00805 int riff_stack_enable_placeholder(riff_stack *s,riff_chunk *c) { 00806 if (s == NULL) return 0; 00807 if (c == NULL) return 0; 00808 c->placeholder = 1; 00809 return 1; 00810 } 00811