File Coverage

blib/lib/MPEG/Audio/Frame.pm
Criterion Covered Total %
statement 173 197 87.8
branch 52 80 65.0
condition 21 41 51.2
subroutine 50 60 83.3
pod 45 48 93.7
total 341 426 80.0


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -w
2              
3             package MPEG::Audio::Frame;
4              
5             # BLECH! With 5.005_04 compatibility the pretty 0b000101001 notation went away,
6             # and now we're stuck using hex. Phooey!
7              
8 31     31   1338783 use strict;
  31         86  
  31         1535  
9             #use warnings;
10 31     31   9213 use integer;
  31         143  
  31         207  
11              
12             # fields::new is not used because it is very costly in such a tight loop. about 1/4th of the time, according to DProf
13             #use fields qw/
14             # headhash
15             # binhead
16             # header
17             # content
18             # length
19             # bitrate
20             # sample
21             # offset
22             # crc_sum
23             # calculated_sum
24             # broken
25             #/;
26              
27 31     31   106900 use overload '""' => \&asbin;
  31         77295  
  31         304  
28              
29 31     31   3458 use vars qw/$VERSION $free_bitrate $lax $mpeg25/;
  31         67  
  31         4839  
30             $VERSION = 0.09;
31              
32             $mpeg25 = 1; # normally support it
33              
34             # constants and tables
35              
36             BEGIN {
37 31 50   31   248 if ($] <= 5.006){
38 31         168 require Fcntl; Fcntl->import(qw/SEEK_CUR/);
  31         26658  
39             } else {
40 0         0 require POSIX; POSIX->import(qw/SEEK_CUR/);
  0         0  
41             }
42             }
43              
44             my @version = (
45             1, # 0b00 MPEG 2.5
46             undef, # 0b01 is reserved
47             1, # 0b10 MPEG 2
48             0, # 0b11 MPEG 1
49             );
50              
51             my @layer = (
52             undef, # 0b00 is reserved
53             2, # 0b01 Layer III
54             1, # 0b10 Layer II
55             0, # 0b11 Layer I
56             );
57              
58             my @bitrates = (
59             # 0/free 1 10 11 100 101 110 111 1000 1001 1010 1011 1100 1101 1110 # bits
60             [ # mpeg 1
61             [ undef, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448 ], # l1
62             [ undef, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384 ], # l2
63             [ undef, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320 ], # l3
64             ],
65             [ # mpeg 2
66             [ undef, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256 ], # l1
67             [ undef, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 ], # l3
68             [ undef, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 ], # l3
69             ],
70             );
71              
72             my @samples = (
73             [ # MPEG 2.5
74             11025, # 0b00
75             12000, # 0b01
76             8000, # 0b10
77             undef, # 0b11 is reserved
78             ],
79             undef, # version 0b01 is reserved
80             [ # MPEG 2
81             22050, # 0b00
82             24000, # 0b01
83             16000, # 0b10
84             undef, # 0b11 is reserved
85             ],
86             [ # MPEG 1
87             44100, # 0b00
88             48000, # 0b01
89             32000, # 0b10
90             undef, # 0b11 is reserved
91             ],
92             );
93              
94              
95             # stolen from libmad, bin.c
96             my @crc_table = (
97             0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011,
98             0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022,
99             0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072,
100             0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041,
101             0x80c3, 0x00c6, 0x00cc, 0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2,
102             0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1,
103             0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1,
104             0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087, 0x0082,
105              
106             0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192,
107             0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1,
108             0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1,
109             0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2,
110             0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151,
111             0x8173, 0x0176, 0x017c, 0x8179, 0x0168, 0x816d, 0x8167, 0x0162,
112             0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132,
113             0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101,
114              
115             0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317, 0x0312,
116             0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321,
117             0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371,
118             0x8353, 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342,
119             0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1,
120             0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2,
121             0x83a3, 0x03a6, 0x03ac, 0x83a9, 0x03b8, 0x83bd, 0x83b7, 0x03b2,
122             0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381,
123              
124             0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291,
125             0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7, 0x02a2,
126             0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2,
127             0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1,
128             0x8243, 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252,
129             0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261,
130             0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231,
131             0x8213, 0x0216, 0x021c, 0x8219, 0x0208, 0x820d, 0x8207, 0x0202
132             );
133              
134             sub CRC_POLY () { 0x8005 }
135              
136             ###
137              
138             my @protbits = (
139             [ 128, 256 ], # layer one
140             undef,
141             [ 136, 256 ], # layer three
142             );
143              
144              
145             my @consts;
146 403 100   403 0 28718 sub B ($) { $_[0] == 12 ? 3 : (1 + ($_[0] / 4)) }
147             sub M ($) {
148 403     403 0 618 my $s = 0;
149 403         2264 $s += $consts[$_][1] for (0 .. $_[0]-1);
150 403         871 $s%=8;
151 403         498 my $v = '';
152 403         3734 vec($v,8-$_,1) = 1 for $s+1 .. $s+$consts[$_[0]][1];
153 403         16671 "0x" . unpack("H*", $v);
154             }
155             sub R ($) {
156 403     403 0 509 my $i = 0;
157 403         45381 my $m = eval "M_$consts[$_[0]][0]()";
158 403         9792 $i++ until (($m >> $i) & 1);
159 403         22207 $i;
160             }
161              
162             BEGIN {
163 31     31   446 @consts = (
164             # [ $name, $width ]
165             [ SYNC => 3 ],
166             [ VERSION => 2 ],
167             [ LAYER => 2 ],
168             [ CRC => 1 ],
169             [ BITRATE => 4 ],
170             [ SAMPLE => 2 ],
171             [ PAD => 1 ],
172             [ PRIVATE => 1 ],
173             [ CHANMODE => 2 ],
174             [ MODEXT => 2 ],
175             [ COPY => 1 ],
176             [ HOME => 1 ],
177             [ EMPH => 2 ],
178             );
179 31         104 my $i = 0;
180 31         103 foreach my $c (@consts){
181 403         748 my $CONST = $c->[0];
182 403         17128 eval "sub $CONST () { $i }"; # offset in $self->{header}
183 403         1737 eval "sub M_$CONST () { " . M($i) ." }"; # bit mask
184 403         1659 eval "sub B_$CONST () { " . B($i) . " }"; # offset in read()'s @hb
185 403         1647 eval "sub R_$CONST () { " . R($i) . " }"; # amount to right shift
186 403         100368 $i++;
187             }
188             }
189              
190              
191             # constructor and work horse
192             sub read {
193 2033   50 2033 1 947295 my $pkg = shift || return undef;
194 2033   50     12772 my $fh = shift || return undef;
195            
196 2032         16077 local $/ = "\xff"; # get readline to find 8 bits of sync.
197            
198 2032         3299 my $offset; # where in the handle
199             my $header; # the binary header data... what a fabulous pun.
200 0         0 my @hr; # an array of integer
201              
202             OUTER: {
203 2032         3531 while (defined(<$fh>)){ # readline, readline, find me a header, make me a header, catch me a header. somewhate wasteful, perhaps. But I don't want to seek.
  2032         14552  
204 2128         3880 $header = "\xff";
205 2128 100 100     13812 (read $fh, $header, 3, 1 or return undef) == 3 or return undef; # read the rest of the header
206              
207 2099         12652 my @hb = unpack("CCCC",$header); # an array of 4 integers for convenient access, each representing a byte of the header
208             # I wish vec could take non powers of 2 for the bit width param... *sigh*
209             # make sure there are no illegal values in the header
210 2099 100       14456 ($hr[SYNC] = ($hb[B_SYNC] & M_SYNC) >> R_SYNC) != 0x07 and next; # see if the sync remains
211 2026 100 50     6786 ($hr[VERSION] = ($hb[B_VERSION] & M_VERSION) >> R_VERSION) == 0x00 and ($mpeg25 or next);
212 2026 100       4899 ($hr[VERSION]) == 0x01 and next;
213 2025 100       5761 ($hr[LAYER] = ($hb[B_LAYER] & M_LAYER) >> R_LAYER) == 0x00 and next;
214 2023 100       7703 ($hr[BITRATE] = ($hb[B_BITRATE] & M_BITRATE) >> R_BITRATE) == 0x0f and next;
215 2016 100       7770 ($hr[SAMPLE] = ($hb[B_SAMPLE] & M_SAMPLE) >> R_SAMPLE) == 0x03 and next;
216 2012 100 100     7022 ($hr[EMPH] = ($hb[B_EMPH] & M_EMPH) >> R_EMPH) == 0x02 and ($lax or next);
217             # and drink up all that we don't bother verifying
218 2002         4516 $hr[CRC] = ($hb[B_CRC] & M_CRC) >> R_CRC;
219 2002         3776 $hr[PAD] = ($hb[B_PAD] & M_PAD) >> R_PAD;
220 2002         3749 $hr[PRIVATE] = ($hb[B_PRIVATE] & M_PRIVATE) >> R_PRIVATE;
221 2002         7439 $hr[CHANMODE] = ($hb[B_CHANMODE] & M_CHANMODE) >> R_CHANMODE;
222 2002         3622 $hr[MODEXT] = ($hb[B_MODEXT] & M_MODEXT) >> R_MODEXT;
223 2002         3113 $hr[COPY] = ($hb[B_COPY] & M_COPY) >> R_COPY;
224 2002         3154 $hr[HOME] = ($hb[B_HOME] & M_HOME) >> R_HOME;
225              
226             # record the offset
227 2002         4184 $offset = tell($fh) - 4;
228              
229 2002         5366 last OUTER; # were done reading for the header
230             }
231 1         7 seek $fh, -3, SEEK_CUR;
232 1         10 return undef;
233             }
234              
235            
236 2002         3131 my $sum = '';
237 2002 100       5454 if (!$hr[CRC]){
238 607 50 50     3982 (read $fh, $sum, 2 or return undef) == 2 or return undef;
239             }
240              
241 2002 50 66     11890 my $bitrate = $bitrates[$version[$hr[VERSION]]][$layer[$hr[LAYER]]][$hr[BITRATE]] || $free_bitrate or return undef;
242 2002         4110 my $sample = $samples[$hr[VERSION]][$hr[SAMPLE]];
243              
244 2002   100     14555 my $use_smaller = $hr[VERSION] == 2 || $hr[VERSION] == 0; # FIXME VERSION == 2 means no support for MPEG2 multichannel
245 2002 100       13472 my $length = $layer[$hr[LAYER]]
    50          
    100          
246             ? (($use_smaller ? 72 : 144) * ($bitrate * 1000) / $sample + $hr[PAD]) # layers 2 & 3
247             : ((($use_smaller ? 6 : 12 ) * ($bitrate * 1000) / $sample + $hr[PAD]) * 4); # layer 1
248            
249 2002 100       4939 my $clength = $length - 4 - ($hr[CRC] ? 0 : 2);
250 2002 100 50     15039 (read $fh, my($content), $clength or return undef) == $clength or return undef; # appearantly header length is included... learned this the hard way.
251            
252 1988         8250 my $self = bless {}, $pkg;
253            
254 1988         22667 %$self = (
255             binhead => $header, # binary header
256             header => \@hr, # array of integer header records
257             content => $content, # the actuaol content of the frame, excluding the header and crc
258             length => $length, # the length of the header + content == length($frame->content()) + 4 + ($frame->crc() ? 2 : 0);
259             bitrate => $bitrate, # the bitrate, in kilobits
260             sample => $sample, # the sample rate, in Hz
261             offset => $offset, # the offset where the header was found in the handle, based on tell
262             crc_sum => $sum, # the bytes of the network order short that is the crc sum
263             );
264              
265 1988         30951 $self;
266             }
267              
268             # methods
269              
270             sub asbin { # binary representation of the frame
271 110     110 1 561 my $self = shift;
272 110         1010 $self->{binhead} . $self->{crc_sum} . $self->{content}
273             }
274              
275             sub content { # byte content of frame, no header, no CRC sum
276 0     0 1 0 my $self = shift;
277 0         0 $self->{content}
278             }
279              
280             sub header { # array of records in list context, binary header in scalar context
281 0     0 1 0 my $self = shift;
282             wantarray
283 0 0       0 ? @{ $self->{header} }
  0         0  
284             : $self->{binhead}
285             }
286              
287             sub crc { # the actual sum bytes
288 3     3 1 6 my $self = shift;
289 3         19 $self->{crc_sum}
290             }
291              
292             sub has_crc { # does a crc exist?
293 2664     2664 1 4717 my $self = shift;
294 2664         22404 not $self->{header}[CRC];
295             }
296              
297             sub length { # length of frame in bytes, including header and header CRC
298 112     112 1 201 my $self = shift;
299 112         548 $self->{length}
300             }
301              
302             sub bitrate { # symbolic bit rate
303 1666     1666 1 3152 my $self = shift;
304 1666         13699 $self->{bitrate}
305             }
306              
307             sub free_bitrate {
308 68     68 1 6670 my $self = shift;
309 68         678 $self->{header}[BITRATE] == 0;
310             }
311              
312             sub sample { # symbolic sample rate
313 2087     2087 1 4621 my $self = shift;
314 2087         10143 $self->{sample}
315             }
316              
317             sub channels { # the data we want is the data in the header in this case
318 2251     2251 1 3727 my $self = shift;
319 2251         16926 $self->{header}[CHANMODE]
320             }
321              
322             sub stereo {
323 524     524 1 995 my $self = shift;
324 524         1267 $self->channels == 0;
325             }
326              
327             sub joint_stereo {
328 551     551 1 909 my $self = shift;
329 551         1262 $self->channels == 1;
330             }
331              
332             sub dual_channel {
333 75     75 1 211 my $self = shift;
334 75         178 $self->channels == 2;
335             }
336              
337             sub mono {
338 1052     1052 1 1927 my $self = shift;
339 1052         2747 $self->channels == 3;
340             }
341              
342             sub modext {
343 307     307 1 1773 my $self = shift;
344 307         2808 $self->{header}[MODEXT];
345             }
346              
347             sub _jmodes {
348 240     240   358 my $self = shift;
349 240 50       404 $self->layer3 || die "Joint stereo modes only make sense with layer III"
350             }
351              
352             sub normal_joint_stereo {
353 10     10 1 49 my $self = shift;
354 10 50 33     24 $self->_jmodes && $self->joint_stereo && !$self->intensity_stereo && !$self->ms_stereo;
      33        
355             }
356              
357             sub intensity_stereo {
358 80     80 1 1578 my $self = shift;
359 80 50 33     160 $self->_jmodes and $self->joint_stereo and $self->modext % 2 == 1;
360             }
361              
362             sub intensity_stereo_only {
363 30     30 1 304 my $self = shift;
364 30 50 33     78 $self->_jmodes && $self->intensity_stereo && !$self->ms_stereo;
365             }
366              
367             sub ms_stereo {
368 80     80 1 112 my $self = shift;
369 80 50 33     150 $self->_jmodes and $self->joint_stereo and $self->modext > 1;
370             }
371              
372             sub ms_stereo_only {
373 10     10 1 45 my $self = shift;
374 10 50 33     27 $self->_jmodes and $self->ms_stereo && !$self->intensity_stereo;
375             }
376              
377             sub ms_and_intensity_stereo {
378 30     30 1 139 my $self = shift;
379 30 50 33     79 $self->_jmodes and $self->ms_stereo && $self->intensity_stereo;
380             }
381             *intensity_and_ms_stereo = \&ms_and_intensity_stereo;
382              
383             sub _bands {
384 0     0   0 my $self = shift;
385 0 0       0 !$self->layer3 || die "Intensity stereo bands only make sense with layers I I";
386             }
387              
388             sub band_4 {
389 0     0 1 0 my $self = shift;
390 0 0       0 $self->_bands and $self->modext == 0;
391             }
392              
393             sub band_8 {
394 0     0 1 0 my $self = shift;
395 0 0       0 $self->_bands and $self->modext == 1;
396             }
397              
398             sub band_12 {
399 0     0 1 0 my $self = shift;
400 0 0       0 $self->_bands and $self->modext == 2;
401             }
402              
403             sub band_16 {
404 0     0 1 0 my $self = shift;
405 0 0       0 $self->_bands and $self->modext == 3;
406             }
407              
408             sub any_stereo {
409 147     147 1 506 my $self = shift;
410 147 100       332 $self->stereo or $self->joint_stereo;
411             }
412              
413             sub seconds { # duration in floating point seconds
414 104     104 1 1140 my $self = shift;
415              
416 31     31   413 no integer;
  31         81  
  31         488  
417 104 100       839 $layer[$self->{header}[LAYER]]
    0          
    50          
418             ? (($version[$self->{header}[VERSION]] == 0 ? 1152 : 576) / $self->sample())
419             : (($version[$self->{header}[VERSION]] == 0 ? 384 : 192) / $self->sample())
420             }
421              
422             sub framerate {
423 31     31   4398 no integer;
  31         69  
  31         244  
424 0     0 1 0 1 / $_[0]->seconds();
425             }
426              
427             sub pad {
428 0     0 1 0 my $self = shift;
429 0         0 $self->{header}[PAD];
430             }
431              
432             sub home {
433 30     30 1 13144 my $self = shift;
434 30         106 $self->{header}[HOME];
435             }
436              
437             sub copyright {
438 30     30 1 21228 my $self = shift;
439 30         110 $self->{header}[COPY];
440             }
441              
442             sub private {
443 30     30 1 54 my $self = shift;
444 30         112 $self->{header}[PRIVATE];
445             }
446              
447             sub version {
448 1978     1978 1 3220 my $self = shift;
449 1978         10603 $self->{header}[VERSION];
450             }
451              
452             sub mpeg1 {
453 1919     1919 1 3548 my $self = shift;
454 1919         9121 $self->version == 3;
455             }
456              
457             sub mpeg2 {
458 40     40 1 61 my $self = shift;
459 40         88 $self->version == 2;
460             }
461              
462             sub mpeg25 {
463 19     19 1 27 my $self = shift;
464 19         44 $self->version == 0;
465             }
466              
467             sub layer {
468 2218     2218 1 3084 my $self = shift;
469 2218         25658 $self->{header}[LAYER];
470             }
471              
472             sub layer1 {
473 405     405 1 670 my $self = shift;
474 405         897 $self->layer == 3;
475             }
476              
477             sub layer2 {
478 320     320 1 768 my $self = shift;
479 320         909 $self->layer == 2;
480             }
481              
482             sub layer3 {
483 1493     1493 1 2553 my $self = shift;
484 1493         8085 $self->layer == 1;
485             }
486              
487             sub emph {
488 30     30 1 15512 my $self = shift;
489 30         202 $self->{header}[EMPH];
490             }
491             *emphasize = \&emph;
492             *emphasise = \&emph;
493             *emphasis = \&emph;
494              
495             sub offset { # the position in the handle where the frame was found
496 3     3 1 7 my $self = shift;
497 3         36 $self->{offset}
498             }
499              
500             sub crc_ok {
501 0     0 1 0 not shift->broken;
502             }
503              
504             sub broken { # was the crc broken?
505 1935     1935 1 30211 my $self = shift;
506 1935 50       10188 if (not defined $self->{broken}){
507 1935 100       4961 return $self->{broken} = 0 unless $self->has_crc; # we assume it's OK if we have no CRC at all
508 607 100       4948 return $self->{broken} = 0 unless (($self->{header}[LAYER] & 0x02) == 0x00); # can't sum
509              
510 29 50       156 my $bits = $protbits[$layer[$self->{header}[LAYER]]][$self->{header}[CHANMODE] == 0x03 ? 0 : 1 ];
511 29         45 my $i;
512            
513 29         51 my $c = 0xffff;
514            
515 29         137 $c = ($c << 8) ^ $crc_table[(($c >> 8) ^ ord((substr($self->{binhead},2,1)))) & 0xff];
516 29         89 $c = ($c << 8) ^ $crc_table[(($c >> 8) ^ ord((substr($self->{binhead},3,1)))) & 0xff];
517              
518 29         106 for ($i = 0; $bits >= 32; do { $bits-=32; $i+=4 }){
  232         339  
  232         475  
519 232         530 my $data = unpack("N",substr($self->{content},$i,4));
520            
521 232         501 $c = ($c << 8) ^ $crc_table[(($c >> 8) ^ ($data >> 24)) & 0xff];
522 232         340 $c = ($c << 8) ^ $crc_table[(($c >> 8) ^ ($data >> 16)) & 0xff];
523 232         347 $c = ($c << 8) ^ $crc_table[(($c >> 8) ^ ($data >> 8)) & 0xff];
524 232         406 $c = ($c << 8) ^ $crc_table[(($c >> 8) ^ ($data >> 0)) & 0xff];
525            
526             }
527 29         95 while ($bits >= 8){
528 0         0 $c = ($c << 8) ^ $crc_table[(($c >> 8) ^ (ord(substr($self->{content},$i++,1)))) & 0xff];
529 0         0 } continue { $bits -= 8 }
530 29 100       162 $self->{broken} = (( $c & 0xffff ) != unpack("n",$self->{crc_sum})) ? 1 : 0;
531             }
532              
533 29         156 return $self->{broken};
534             }
535              
536              
537             # tie hack
538              
539 1     1   16 sub TIEHANDLE { bless \$_[1],$_[0] } # encapsulate the handle to save on unblessing and stuff
540 1     1   9 sub READLINE { (ref $_[0])->read(${$_[0]}) } # read from the encapsulated handle
  1         56  
541              
542             1; # keep your mother happy
543              
544             __END__