File Coverage

blib/lib/MPEG/Audio/Frame.pm
Criterion Covered Total %
statement 178 201 88.5
branch 52 80 65.0
condition 21 41 51.2
subroutine 51 61 83.6
pod 45 48 93.7
total 347 431 80.5


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