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