Credit Andrew R for finding the direct copy mods for exr and ppm sequences
[goodguy/cinelerra.git] / cinelerra-5.1 / libzmpeg3 / zio.C
1 #include "libzmpeg3.h"
2 #if defined(__TERMUX__)
3 #include "bthread.h"
4 #endif
5
6 #ifdef USE_FUTEX
7 typedef zmpeg3_t::zloc_t zzloc_t;
8
9 int zzloc_t::
10 zyield()
11 {
12   return syscall(SYS_sched_yield);
13 }
14
15 int zzloc_t::
16 zgettid()
17 {
18   return syscall(SYS_gettid);
19 }
20
21 int zzloc_t::
22 zwake(int nwakeups)
23 {
24   int ret;
25   while( (ret=zfutex(FUTEX_WAKE, nwakeups)) < 0 );
26   return ret;
27 }
28
29 int zzloc_t::
30 zwait(int val)
31 {
32   return zfutex(FUTEX_WAIT, val);
33 }
34
35 int zzlock_t::
36 zemsg1()
37 {
38   fprintf(stderr,"unlocking and not locked\n");
39   return -1;
40 }
41
42 int zzlock_t::
43 zlock(int v)
44 {
45   if( v || zxchg(1,loc) >= 0 ) do {
46     zwait(1);
47   } while ( zxchg(1,loc) >= 0 );
48   return 1;
49 }
50
51 int zzlock_t::
52 zunlock(int nwakeups)
53 {
54   loc = -1;
55   return zwake(1);
56 }
57
58 void zzrwlock_t::
59 zenter()
60 {
61   zdecr(loc); lk.lock();
62   zincr(loc); lk.unlock();
63 }
64
65 void zzrwlock_t::
66 zleave()
67 {
68   if( lk.loc >= 0 )
69     zwake(1);
70 }
71
72 void zzrwlock_t::
73 zwrite_enter(int r)
74 {
75   lk.lock();
76   if( r < 0 ) zdecr(loc);
77   int v;  while( (v=loc) >= 0 ) zwait(v);
78 }
79
80 void zzrwlock_t::
81 zwrite_leave(int r)
82 {
83   if( r < 0 ) zincr(loc);
84   lk.unlock();
85 }
86
87 #else
88
89 void zzrwlock_t::
90 enter()
91 {
92   lock();
93   while( blocking ) { unlock(); lk.lock(); lk.unlock(); lock(); }
94   ++users;
95   unlock();
96 }
97
98 void zzrwlock_t::
99 leave()
100 {
101   lock();
102   if( !--users && blocking ) wake();
103   unlock();
104 }
105
106 void zzrwlock_t::
107 zwrite_enter(int r)
108 {
109   lk.lock();
110   blocking = pthread_self();
111   lock();
112   if( r < 0 ) --users;
113   while( users ) { unlock(); wait(); lock(); }
114   unlock();
115 }
116
117 void zzrwlock_t::
118 zwrite_leave(int r)
119 {
120   if( r < 0 ) ++users;
121   blocking = 0; lk.unlock();
122 }
123
124 #endif
125
126 zbuffer_t::
127 buffer_t(zmpeg3_t *zsrc, int access)
128 {
129   src = zsrc;
130   access_type = access;
131   alloc = !(access_type & io_SEQUENTIAL) ? IO_SIZE : SEQ_IO_SIZE;
132   reader_done = -1;
133   writer_done = -1;
134   ref_count = 1;
135   fd = -1;
136   reset();
137   owner = pthread_self();
138 }
139
140 zbuffer_t::
141 ~buffer_t()
142 {
143   if( (access_type & io_THREADED) )
144     stop_reader();
145   if( data ) delete [] data;
146 }
147
148 void zbuffer_t::
149 unblock()
150 {
151   io_lock.unlock();
152   io_block.unblock();
153   ::sched_yield();
154   io_lock.lock();
155 }
156
157 void zbuffer_t::
158 block()
159 {
160   io_block.block();
161 }
162
163 void zbuffer_t::
164 reader()
165 {
166   pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,0);
167   pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,0);
168   lock();
169   while( !reader_done ) {
170     if( do_restart ) {
171       do_restart = 0;
172       restart(0);
173       restarted = 1;
174     }
175     if( size+MAX_IO_SIZE > alloc )
176       size = alloc - MAX_IO_SIZE;
177     unlock();
178     int64_t count = read_in(zmpeg3_t::MAX_IO_SIZE);
179     lock();
180     if( count > 0 ) {
181       file_pos += count;
182       fin = in;
183       if( (size+=count) > alloc )
184         size = alloc;
185       if( src->recd_fd >= 0 && the_writer )
186         write_lock.unblock();
187     }
188     unblock();
189   }
190   unlock();
191   reader_done = -1;
192 }
193
194 void *zbuffer_t::
195 reader(void *the_buffer)
196 {
197   buffer_t *b = (buffer_t *)the_buffer;
198   b->reader();
199   return 0;
200 }
201
202 void zbuffer_t::
203 writer()
204 {
205   const int mx_blksz = 0x100000;
206
207   while( !writer_done ) {
208     write_record(mx_blksz,0xfff);
209     if( file_pos - write_pos < mx_blksz )
210       write_lock.block();
211     else
212       sched_yield();
213   }
214
215   write_record(INT_MAX, 0);
216   writer_done = -1;
217 }
218
219 void *zbuffer_t::
220 writer(void *the_buffer)
221 {
222   buffer_t *b = (buffer_t *)the_buffer;
223   b->writer();
224   return 0;
225 }
226
227 int zbuffer_t::
228 open_file(char *path)
229 {
230 //zmsgs("1 %s\n", path);
231   if( !open_count ) {
232     if( (access_type & io_THREADED) )
233       access_type |= io_SINGLE_ACCESS + io_SEQUENTIAL;
234     if( !(access_type & io_UNBUFFERED) ) {
235       if( fp == 0 ) {
236         if( !(fp=::fopen(path, "rb")) ) {
237           perrs("%s",path);
238           return 1;
239         }
240       }
241     }
242     else {
243       if( fd < 0 ) {
244         int mode = (access_type & io_NONBLOCK) ? O_RDONLY+O_NONBLOCK : O_RDONLY;
245         if( (fd=::open(path, mode)) < 0 ) {
246           perrs("%s",path);
247           return 1;
248         }
249       }
250     }
251     if( (access_type & io_THREADED) )
252       start_reader();
253     else
254       restart();
255   }
256   ++open_count;
257   return 0;
258 }
259
260 void zbuffer_t::
261 reset()
262 {
263   in = fin = out = size = 0;
264   file_pos = out_pos = file_nudge = 0;
265 }
266
267 void zbuffer_t::
268 restart(int lk)
269 {
270   if( lk ) lock();
271   reset();
272   if( !(access_type & io_SEQUENTIAL) ) {
273     if( !(access_type & io_UNBUFFERED) ) {
274       if( ::fseek(fp,0,SEEK_SET) < 0 )
275         perrs("fseek %jd", file_pos);
276     }
277     else {
278       if( ::lseek(fd,0,SEEK_SET) < 0 )
279         perrs("lseek %jd", file_pos);
280     }
281   }
282   if( lk ) unlock();
283 }
284
285 void zbuffer_t::
286 start_reader()
287 {
288   restart();
289   reader_done = 0;
290   pthread_create(&the_reader,0,reader,this);
291 }
292
293 void zbuffer_t::
294 stop_reader()
295 {
296   if( reader_done || !the_reader ) return;
297   reader_done = 1;
298   io_block.unblock();
299   int tmo = 10;
300   while( reader_done >= 0 && --tmo >= 0 ) usleep(100000);
301   if( tmo < 0 ) pthread_cancel(the_reader);
302   the_reader = 0;
303   stop_record();
304 }
305
306 int zbuffer_t::
307 start_record()
308 {
309   writer_done = 0;
310   pthread_create(&the_writer,0,writer,this);
311   return 0;
312 }
313
314 int zbuffer_t::
315 stop_record()
316 {
317   if( writer_done || !the_writer ) return 1;
318   writer_done = 1;
319   write_lock.unblock();
320   pthread_join(the_writer,0);
321   int tmo = 10;
322   while( writer_done >= 0 && --tmo >= 0 ) usleep(100000);
323   if( tmo < 0 ) pthread_cancel(the_writer);
324   the_writer = 0;
325   return 0;
326 }
327
328 int zbuffer_t::
329 write_align(int sz)
330 {
331   int isz = 2*src->packet_size;
332   if( sz > isz ) isz = sz;
333   uint8_t *pat = 0;
334   int psz = 0;
335   if( src->is_program_stream() ) {
336     static uint8_t pack_start[4] = { 0x00, 0x00, 0x01, 0xba };
337     pat = pack_start;  psz = sizeof(pack_start);
338   }
339   else if( src->is_transport_stream() ) {
340     static uint8_t sync_start[1] = { 0x47 };
341     pat = sync_start;  psz = sizeof(sync_start);
342   }
343   if( isz > out_pos ) isz = out_pos;
344   int64_t bsz = file_pos - out_pos;
345   int i = bsz>alloc ? 0 : alloc-bsz;
346   if( isz > i ) isz = i;
347   i = out - isz;
348   if( i < 0 ) i += alloc;
349   uint8_t *bfr = &data[i];
350   uint8_t *lmt = &data[alloc];
351   int64_t len = isz + bsz;
352   i = 0;
353   if( pat ) {
354     while( --len >= 0 ) {
355       if( *bfr++ != pat[i] ) { i = 0; }
356       else if( ++i >= psz ) break;
357       if( bfr >= lmt ) bfr = &data[0];
358     }
359   }
360   if( len < 0 ) return 1;
361   len += psz;
362   if( (bfr-=psz) < &data[0] ) bfr += alloc;
363   wout = bfr - data;
364   write_pos = file_pos - len;
365   return 0;
366 }
367
368 // write blocks of (mask+1) bytes of data at data+wout, update wout
369 //   only write full blocks, fragments cause disk thrashing
370 void zbuffer_t::
371 write_record(int sz, int mask)
372 {
373   int isz = file_pos - write_pos;
374   if( isz > sz ) isz = sz;
375   if( !(isz &= ~mask) ) return;
376 //zmsgs(" isz=%d, file_pos=%ld, write_pos=%ld\n", isz, file_pos, write_pos);
377   write_pos += isz;
378   int len = isz;
379   int n = alloc - wout;
380   if( n > len ) n = len;
381   if( n > 0 ) {
382     src->write_record(&data[wout],n);
383     len -= n;
384   }
385   if( len > 0 )
386     src->write_record(&data[0],wout=len);
387   else
388     wout += n;
389 }
390
391 void zbuffer_t::
392 close_file()
393 {
394   if( open_count > 0 && --open_count == 0 ) {
395     if( (access_type & io_THREADED) )
396       stop_reader();
397     if( !src || !src->iopened ) {
398       if( !(access_type & io_UNBUFFERED) ) {
399         if( fp != 0 ) { fclose(fp); fp = 0; }
400       }
401       else {
402         if( fd >= 0 ) { close(fd); fd = -1; }
403       }
404     }
405   }
406 }
407
408 /* sole user of in ptr (except restart) */
409 int64_t zbuffer_t::
410 read_in(int64_t len)
411 {
412   int64_t count = 0;
413   while( count < len ) {
414     int xfr = len - count;
415     int avl = alloc - in;
416     if( avl < xfr ) xfr = avl;
417     if( access_type & io_UNBUFFERED ) {
418       if( access_type & io_NONBLOCK ) {
419         avl = -1;
420         for( int i=10; avl<0 && --i>=0; ) { // 10 retries, 2 seconds
421           struct timeval tv;  tv.tv_sec = 0;  tv.tv_usec = 200000;
422           fd_set rd_fd;  FD_ZERO(&rd_fd);  FD_SET(fd, &rd_fd);
423           int ret = select(fd+1, &rd_fd, 0, 0, &tv);
424           if( !ret ) continue;
425           if( ret < 0 ) break;
426           if( !FD_ISSET(fd, &rd_fd) ) continue;
427           if( (ret=::read(fd, &data[in], xfr)) > 0 ) avl = ret;
428         }
429       }
430       else
431         avl = ::read(fd, &data[in], xfr);
432     }
433     else {
434       avl = ::fread(&data[in], 1, xfr, fp);
435       if( !avl && ferror(fp) ) avl = -1;
436     }
437     if( avl < 0 ) {
438       if( errno == EOVERFLOW ) {
439         zerr("Overflow\n");
440         continue;
441       }
442       ++errs;
443       if( !(access_type & io_ERRFAIL) ) {
444         if( errs < IO_ERR_LIMIT && xfr > ERR_PACKET_SIZE )
445           xfr = ERR_PACKET_SIZE;
446         memset(&data[in],0,xfr);
447         if( !(access_type & io_THREADED) ) {
448           int64_t pos = file_pos + count + xfr;
449           if( (access_type & io_UNBUFFERED) ) {
450             if( ::lseek(fd,pos,SEEK_SET) < 0 )
451               perrs("lseek pos %jx",pos);
452           }
453           else {
454             if( ::fseek(fp,pos,SEEK_SET) < 0 )
455               perrs("fseek pos %jx",pos);
456           }
457         }
458         avl = xfr;
459       }
460       else {
461         perrs("read pos %jx",file_pos + count);
462         avl = 0;
463       }
464     }
465     else
466       errs = 0;
467     if( avl == 0 ) break;
468     if( paused ) continue;
469     count += avl;
470     in += avl;
471     if( (avl=in-alloc) >= 0 ) in = avl;
472   }
473   return count;
474 }
475
476 int zbuffer_t::
477 wait_in(int64_t pos)
478 {
479   int result = 0;
480   if( (access_type & io_THREADED) && !restarted ) {
481     while( !reader_done && !restarted && file_pos <= pos ) {
482       io_lock.unlock();
483       io_block.block();
484       io_lock.lock();
485     }
486   }
487   if( reader_done || restarted ) result = 1;
488   restarted = 0;
489   return result;
490 }
491
492 int zbuffer_t::
493 seek_in(int64_t pos)
494 {
495   int result = 0;
496   if( file_pos != pos ) {
497     if( !(access_type & io_SEQUENTIAL) ) {
498       result = (access_type & io_UNBUFFERED) ?
499         (lseek64(fd, pos, SEEK_SET) >= 0 ? 0 : 1) :
500         (fseeko(fp, pos, SEEK_SET) == 0 ? 0 : 1) ;
501     }
502     else if( pos != 0 ) {
503       if( (access_type & io_THREADED) )
504         src->restart();
505       zerrs("seek on sequential from %jd to %jd\n", file_pos, pos);
506       result = 1;
507     }
508     else {
509       restart(0);
510       result = 1;
511     }
512   }
513   return result;
514 }
515
516 int zbuffer_t::
517 read_fin(int64_t len)
518 {
519   int64_t count = read_in(len);
520   /* must already be locked */
521   fin = in;
522   file_pos += count;
523   if( (size+=count) > alloc )
524     size = alloc;
525   return len && count ? 0 : 1;
526 }
527
528 int zbuffer_t::
529 seek_to(int64_t pos, int64_t len)
530 {
531 //zmsgs(" pos=%ld, len=%ld\n", pos, len);
532   int result = seek_in(pos);
533   if( !result ) {
534     file_pos = out_pos = pos;
535     in = size = 0;
536     result = read_fin(len);
537   }
538   return result;
539 }
540
541 int zbuffer_t::
542 read_to(int64_t pos)
543 {
544 //zmsgs(" pos=%ld\n", pos);
545   int result = 0;
546   int64_t len = pos - file_pos;
547   if( len < 0 ) {
548     zerrs("reversed seq read (%jd < %jd)\n", pos, file_pos);
549     result = 1;
550   }
551   else
552     result = read_fin(len);
553   return result;
554 }
555
556 int zbuffer_t::
557 sync(int64_t pos)
558 {
559   int result = 1;
560   pos += file_nudge;
561   int64_t start_pos = file_pos - size;
562   if( pos < start_pos ) { /* before buffer */
563     if( (access_type & io_THREADED) ) {
564       if( pos ) {
565         zerrs("threaded sync before buffer %jd < %jd\n", pos, start_pos);
566         int64_t mid_pos = start_pos + size/2;
567         file_nudge += mid_pos - pos;
568         pos = mid_pos;
569       }
570       else {
571         restart(0);  /* allow fake seek to start */
572         result = -1;
573       }
574     }
575     else
576       result = -1;
577   }
578   else
579     result = pos < file_pos ? 0 : /* in buffer */
580       (access_type & io_THREADED) ?
581         wait_in(pos) : -1; /* after buffer */
582   if( result < 0 ) { /* out of buffer */
583 //zmsgs("out of buffer pos=%ld, start_pos=%ld, file_pos=%ld, out_pos=%ld\n",
584 //  pos, start_pos, file_pos, out_pos);
585     int64_t seek_pos = pos - alloc/2;
586     int64_t end_pos = seek_pos + alloc;
587     if( seek_pos < 0 ) seek_pos = 0;
588     result = (access_type & io_SEQUENTIAL) ||
589         (seek_pos < file_pos && end_pos >= file_pos) ?
590       read_to(end_pos) : seek_to(seek_pos, alloc);
591   }
592   if( !result ) {
593     int64_t offset = file_pos - pos;
594     if( offset >= 0 && offset <= size ) {
595       if( (offset=fin-offset) < 0 ) offset += alloc;
596       out = offset;  out_pos = pos;
597     }
598     else
599       result = 1;
600   }
601   return result;
602 }
603
604 int zbuffer_t::
605 read_out(uint8_t *bfr,int len)
606 {
607   int count = 0;
608   while( count < len ) {
609     int avail = file_pos - out_pos;
610     if( avail <= 0 ) break;
611     int fragment_size = alloc - out;
612     if( fragment_size > avail ) fragment_size = avail;
613     avail = len - count;
614     if( fragment_size > avail ) fragment_size = avail;
615     memcpy(bfr, &data[out], fragment_size);
616     bfr += fragment_size;
617     out += fragment_size;
618     if( out >= alloc ) out = 0;
619     out_pos += fragment_size;
620     count += fragment_size;
621   }
622   return count;
623 }
624
625 static int fd_name(int fd,char *nm,int sz)
626 {
627   char pfn[PATH_MAX];
628   snprintf(&pfn[0],sizeof(pfn),"/proc/self/fd/%d",fd);
629   return readlink(&pfn[0],nm,sz);
630 }
631
632 zfs_t::
633 fs_t(zmpeg3_t *zsrc, const char *fpath, int access)
634 {
635   src = zsrc;
636   strcpy(path, fpath);
637   buffer = new buffer_t(src, access);
638   if( (access & io_SINGLE_ACCESS) )
639     open_file();
640 }
641
642 zfs_t::
643 fs_t(zmpeg3_t *zsrc, int fd, int access)
644 {
645   src = zsrc;
646   access |= io_UNBUFFERED;
647   access |= io_SINGLE_ACCESS;
648   if( (access & io_THREADED) ) access |= io_SEQUENTIAL;
649   buffer = new buffer_t(src, access);
650   if( !fd_name(fd,&path[0],sizeof(path)) )
651     css.get_keys(&path[0]);
652   is_open = 1;
653   buffer->fd = fd;
654   buffer->open_count = 1;
655   get_total_bytes();
656   if( (buffer->access_type & io_THREADED) )
657     buffer->start_reader();
658 }
659
660 zfs_t::
661 fs_t(zmpeg3_t *zsrc, FILE *fp, int access)
662 {
663   src = zsrc;
664   access &= ~io_UNBUFFERED;
665   access |= io_SINGLE_ACCESS;
666   if( (access & io_THREADED) ) access |= io_SEQUENTIAL;
667   buffer = new buffer_t(src, access);
668   int fd = fileno(fp);
669   if( !fd_name(fd,&path[0],sizeof(path)) )
670     css.get_keys(&path[0]);
671   is_open = 1;
672   buffer->fp = fp;
673   buffer->open_count = 1;
674   get_total_bytes();
675   if( (buffer->access_type & io_THREADED) )
676     buffer->start_reader();
677 }
678
679 zfs_t::
680 ~fs_t()
681 {
682   close_file();
683   close_buffer();
684 }
685
686 zfs_t::
687 fs_t(zfs_t &fs)
688 {
689   src = fs.src;
690   strcpy(path, fs.path);
691   total_bytes = fs.total_bytes;
692   css = fs.css;
693   if( !fs.buffer ) return;
694   int access = fs.buffer->access_type;
695   if( (access & io_SINGLE_ACCESS) ) {
696     buffer = fs.buffer;
697     ++buffer->ref_count;
698     is_open = fs.is_open;
699     if( is_open )
700       ++buffer->open_count;
701   }
702   else
703     buffer = new buffer_t(src, access);
704 }
705
706 uint8_t zfs_t::
707 next_char()
708 {
709   enter();
710   uint32_t ret = buffer->next_byte();
711   leave();
712   return ret;
713 }
714
715 uint8_t zfs_t::
716 read_char()
717 {
718   enter();
719   uint32_t result = buffer->get_byte();
720   ++current_byte;
721   leave();
722   return result;
723 }
724
725 uint32_t zfs_t::
726 read_uint16()
727 {
728   uint32_t a, b;
729   enter();
730   if( current_byte+2 < buffer->file_tell() ) {
731     b = buffer->get_byte();
732     a = buffer->get_byte();
733     current_byte += 2;
734   }
735   else {
736     b = buffer->get_byte(); chk_next();
737     a = buffer->get_byte(); ++current_byte;
738   }
739   leave();
740   uint32_t result = (b << 8) | (a);
741   return result;
742 }
743
744 uint32_t zfs_t::
745 read_uint24()
746 {
747   uint32_t a, b, c;
748   enter();
749   if( current_byte+3 < buffer->file_tell() ) {
750     c = buffer->get_byte();
751     b = buffer->get_byte();
752     a = buffer->get_byte();
753     current_byte += 3;
754   }
755   else {
756     c = buffer->get_byte(); chk_next();
757     b = buffer->get_byte(); chk_next();
758     a = buffer->get_byte(); ++current_byte;
759   }
760   leave();
761   uint32_t result = (c << 16) | (b << 8) | (a);
762   return result;
763 }
764
765 uint32_t zfs_t::
766 read_uint32()
767 {
768   uint32_t a, b, c, d;
769   enter();
770   if( current_byte+4 < buffer->file_tell() ) {
771     d = buffer->get_byte();
772     c = buffer->get_byte();
773     b = buffer->get_byte();
774     a = buffer->get_byte();
775     current_byte += 4;
776   }
777   else {
778     d = buffer->get_byte(); chk_next();
779     c = buffer->get_byte(); chk_next();
780     b = buffer->get_byte(); chk_next();
781     a = buffer->get_byte(); ++current_byte;
782   }
783   leave();
784   uint32_t result = (d << 24) | (c << 16) | (b << 8) | (a);
785   return result;
786 }
787
788 uint64_t zfs_t::
789 read_uint64()
790 {
791   uint32_t a, b, c, d;
792   uint64_t result;
793   enter();
794   if( current_byte+8 < buffer->file_tell() ) {
795     d = buffer->get_byte();
796     c = buffer->get_byte();
797     b = buffer->get_byte();
798     a = buffer->get_byte();
799     result = (d << 24) | (c << 16) | (b << 8) | (a);
800     d = buffer->get_byte();
801     c = buffer->get_byte();
802     b = buffer->get_byte();
803     a = buffer->get_byte();
804     current_byte += 8;
805   }
806   else {
807     d = buffer->get_byte(); chk_next();
808     c = buffer->get_byte(); chk_next();
809     b = buffer->get_byte(); chk_next();
810     a = buffer->get_byte(); chk_next();
811     result = (d << 24) | (c << 16) | (b << 8) | (a);
812     d = buffer->get_byte(); chk_next();
813     c = buffer->get_byte(); chk_next();
814     b = buffer->get_byte(); chk_next();
815     a = buffer->get_byte(); ++current_byte;
816   }
817   result = (result <<32 ) | (d << 24) | (c << 16) | (b << 8) | (a);
818   leave();
819   return result;
820 }
821
822 int64_t zfs_t::
823 get_total_bytes()
824 {
825   total_bytes = (buffer->access_type & io_SEQUENTIAL) ?
826     INT64_MAX : path_total_bytes(path);
827   return total_bytes;
828 }
829
830 int zfs_t::
831 open_file()
832 {
833   /* Need to perform authentication before reading a single byte. */
834 //zmsgs("1 %s\n", path);
835   if( !is_open ) {
836     css.get_keys(path);
837     if( buffer->open_file(path) ) return 1; 
838     if( !get_total_bytes() ) {
839       buffer->close_file();
840       return 1;
841     }
842     current_byte = 0;
843     is_open = 1;
844   } 
845   return 0;
846 }
847
848 void zfs_t::
849 close_file()
850 {
851   if( is_open ) {
852     if( buffer ) 
853       buffer->close_file();
854     is_open = 0;
855   }
856 }
857
858 int zfs_t::
859 read_data(uint8_t *bfr, int64_t len)
860 {
861   int64_t n, count = 0;
862 //zmsgs("1 %d\n", len);
863   int result = enter();
864   if( !result ) do {
865     n = buffer->read_out(&bfr[count],len-count);
866     current_byte += n;  count += n;
867   } while( n > 0 && count < len && !(result=sync()) );
868   leave();
869
870 //zmsgs("100 %d %d\n", result, count);
871   return (result && count < len) ? 1 : 0;
872 }
873
874 int zfs_t::
875 seek(int64_t byte)
876 {
877 //zmsgs("1 %jd\n", byte);
878   current_byte = byte;
879   int result = (current_byte < 0) || (current_byte > total_bytes);
880   return result;
881 }
882
883 int zfs_t::
884 seek_relative(int64_t bytes)
885 {
886 //zmsgs("1 %jd\n", bytes);
887   current_byte += bytes;
888   int result = (current_byte < 0) || (current_byte > total_bytes);
889   return result;
890 }
891
892 void zfs_t::restart()
893 {
894   if( !buffer ) return;
895   if( !(buffer->access_type & io_SINGLE_ACCESS) ) return;
896   if( (buffer->access_type & io_THREADED) )
897     buffer->do_restart = 1;
898   else
899     buffer->restart();
900 }
901
902 int zfs_t::
903 pause_reader(int v)
904 {
905   if( !buffer ) return 1;
906   buffer->paused = v;
907   return 0;
908 }
909
910 int zfs_t::
911 start_record(int bsz)
912 {
913   if( !buffer ) return -1;
914   buffer->write_align(bsz);
915   return buffer->start_record();
916 }
917
918 int zfs_t::
919 stop_record()
920 {
921   return buffer ? buffer->stop_record() : -1;
922 }
923
924 void zfs_t::
925 close_buffer()
926 {
927   if( !buffer || --buffer->ref_count > 0 ) return;
928   delete buffer;  buffer = 0;
929 }
930