Ogg-Vorbis-Header-PurePerl-1.05/0000755000175000017500000000000013763201440014757 5ustar davedaveOgg-Vorbis-Header-PurePerl-1.05/META.json0000664000175000017500000000273013763201440016404 0ustar davedave{ "abstract" : "access Ogg Vorbis info and comment fields", "author" : [ "Dan Sully " ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 7.46, CPAN::Meta::Converter version 2.150010", "license" : [ "open_source" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "Ogg-Vorbis-Header-PurePerl", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "6.3" } }, "runtime" : { "requires" : { "constant" : "0", "perl" : "5.006", "strict" : "0", "warnings" : "0" } }, "test" : { "requires" : { "Test::More" : "0.88" } } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "https://github.com/davorg/perl-ogg-vorbis-header-pureperl/issues" }, "repository" : { "type" : "git", "url" : "https://github.com/davorg/perl-ogg-vorbis-header-pureperl.git", "web" : "https://github.com/davorg/perl-ogg-vorbis-header-pureperl" } }, "version" : "1.05", "x_serialization_backend" : "JSON::PP version 4.04" } Ogg-Vorbis-Header-PurePerl-1.05/LICENSE.GPL0000644000175000017500000004313113751016137016413 0ustar davedave GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. Ogg-Vorbis-Header-PurePerl-1.05/MANIFEST0000644000175000017500000000051513763201440016111 0ustar davedaveChanges Makefile.PL MANIFEST lib/Ogg/Vorbis/Header/PurePerl.pm README t/01-require.t t/02-basic.t t/04-files.t t/test.ogg t/test.mp3 examples/ogginfo.pl LICENSE.GPL META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) Ogg-Vorbis-Header-PurePerl-1.05/examples/0000755000175000017500000000000013763201437016603 5ustar davedaveOgg-Vorbis-Header-PurePerl-1.05/examples/ogginfo.pl0000755000175000017500000000061713751016137020575 0ustar davedave#!/usr/bin/perl -w use strict; use Ogg::Vorbis::Header::PurePerl; if (!$ARGV[0]) { print "Usage: ogginfo.pl filename\n"; exit; } my $fn = $ARGV[0]; my $ogg = Ogg::Vorbis::Header::PurePerl->new($fn); foreach my $k (keys %{$ogg->info}) { print $k, '=', $ogg->info->{$k}, "\n"; } foreach my $k ($ogg->comment_tags) { foreach my $cmmt ($ogg->comment($k)) { print $k, '=', $cmmt, "\n"; } } Ogg-Vorbis-Header-PurePerl-1.05/lib/0000755000175000017500000000000013763201437015533 5ustar davedaveOgg-Vorbis-Header-PurePerl-1.05/lib/Ogg/0000755000175000017500000000000013763201437016247 5ustar davedaveOgg-Vorbis-Header-PurePerl-1.05/lib/Ogg/Vorbis/0000755000175000017500000000000013763201437017513 5ustar davedaveOgg-Vorbis-Header-PurePerl-1.05/lib/Ogg/Vorbis/Header/0000755000175000017500000000000013763201437020703 5ustar davedaveOgg-Vorbis-Header-PurePerl-1.05/lib/Ogg/Vorbis/Header/PurePerl.pm0000644000175000017500000003534013763201376023006 0ustar davedavepackage Ogg::Vorbis::Header::PurePerl; use 5.006; use strict; use warnings; # First four bytes of stream are always OggS use constant OGGHEADERFLAG => 'OggS'; our $VERSION = '1.05'; sub new { my $class = shift; my $file = shift; my %data = (); if (ref $file) { binmode $file; %data = ( 'filesize' => -s $file, 'fileHandle' => $file, ); } else { open my $fh, '<', $file or do { warn "$class: File $file does not exist or cannot be read: $!"; return undef; }; # make sure dos-type systems can handle it... binmode $fh; %data = ( 'filename' => $file, 'filesize' => -s $file, 'fileHandle' => $fh, ); } if ( _init(\%data) ) { _load_info(\%data); _load_comments(\%data); _calculate_track_length(\%data); } undef $data{'fileHandle'}; return bless \%data, $class; } sub info { my $self = shift; my $key = shift; # if the user did not supply a key, return the entire hash return $self->{'INFO'} unless $key; # otherwise, return the value for the given key return $self->{'INFO'}{lc $key}; } sub comment_tags { my $self = shift; my %keys = (); return grep { !$keys{$_}++ } @{$self->{'COMMENT_KEYS'}}; } sub comment { my $self = shift; my $key = shift; # if the user supplied key does not exist, return undef return undef unless($self->{'COMMENTS'}{lc $key}); return wantarray ? @{$self->{'COMMENTS'}{lc $key}} : $self->{'COMMENTS'}{lc $key}->[0]; } sub path { my $self = shift; return $self->{'filename'}; } # "private" methods sub _init { my $data = shift; # check the header to make sure this is actually an Ogg-Vorbis file $data->{'startInfoHeader'} = _check_header($data) || return undef; return 1; } sub _skip_id3_header { my $fh = shift; read $fh, my $buffer, 3; my $byte_count = 3; if ($buffer eq 'ID3') { while (read $fh, $buffer, 4096) { my $found; if (($found = index($buffer, OGGHEADERFLAG)) >= 0) { $byte_count += $found; seek $fh, $byte_count, 0; last; } else { $byte_count += 4096; } } } else { seek $fh, 0, 0; } return tell($fh); } sub _check_header { my $data = shift; my $fh = $data->{'fileHandle'}; my $buffer; my $page_seg_count; # stores how far into the file we've read, so later reads into the file can # skip right past all of the header stuff my $byte_count = _skip_id3_header($fh); # Remember the start of the Ogg data $data->{startHeader} = $byte_count; # check that the first four bytes are 'OggS' read($fh, $buffer, 27); if (substr($buffer, 0, 4) ne OGGHEADERFLAG) { warn "This is not an Ogg bitstream (no OggS header)."; return undef; } $byte_count += 4; # check the stream structure version (1 byte, should be 0x00) if (ord(substr($buffer, 4, 1)) != 0x00) { warn "This is not an Ogg bitstream (invalid structure version)."; return undef; } $byte_count += 1; # check the header type flag # This is a bitfield, so technically we should check all of the bits # that could potentially be set. However, the only value this should # possibly have at the beginning of a proper Ogg-Vorbis file is 0x02, # so we just check for that. If it's not that, we go on anyway, but # give a warning (this behavior may (should?) be modified in the future. if (ord(substr($buffer, 5, 1)) != 0x02) { warn "Invalid header type flag (trying to go ahead anyway)."; } $byte_count += 1; # read the number of page segments $page_seg_count = ord(substr($buffer, 26, 1)); $byte_count += 21; # read $page_seg_count bytes, then throw 'em out seek($fh, $page_seg_count, 1); $byte_count += $page_seg_count; # check packet type. Should be 0x01 (for indentification header) read($fh, $buffer, 7); if (ord(substr($buffer, 0, 1)) != 0x01) { warn "Wrong vorbis header type, giving up."; return undef; } $byte_count += 1; # check that the packet identifies itself as 'vorbis' if (substr($buffer, 1, 6) ne 'vorbis') { warn "This does not appear to be a vorbis stream, giving up."; return undef; } $byte_count += 6; # at this point, we assume the bitstream is valid return $byte_count; } sub _load_info { my $data = shift; my $start = $data->{'startInfoHeader'}; my $fh = $data->{'fileHandle'}; my $byte_count = $start + 23; my %info = (); seek($fh, $start, 0); # read the vorbis version read($fh, my $buffer, 23); $info{'version'} = _decode_int(substr($buffer, 0, 4, '')); # read the number of audio channels $info{'channels'} = ord(substr($buffer, 0, 1, '')); # read the sample rate $info{'rate'} = _decode_int(substr($buffer, 0, 4, '')); # read the bitrate maximum $info{'bitrate_upper'} = _decode_int(substr($buffer, 0, 4, '')); # read the bitrate nominal $info{'bitrate_nominal'} = _decode_int(substr($buffer, 0, 4, '')); # read the bitrate minimal $info{'bitrate_lower'} = _decode_int(substr($buffer, 0, 4, '')); # read the blocksize_0 and blocksize_1 # these are each 4 bit fields, whose actual value is 2 to the power # of the value of the field my $blocksize = substr($buffer, 0, 1, ''); $info{'blocksize_0'} = 2 << ((ord($blocksize) & 0xF0) >> 4); $info{'blocksize_1'} = 2 << (ord($blocksize) & 0x0F); # read the framing_flag $info{'framing_flag'} = ord(substr($buffer, 0, 1, '')); # bitrate_window is -1 in the current version of vorbisfile $info{'bitrate_window'} = -1; $data->{'startCommentHeader'} = $byte_count; $data->{'INFO'} = \%info; } sub _load_comments { my $data = shift; my $fh = $data->{'fileHandle'}; my $start = $data->{'startHeader'}; $data->{COMMENT_KEYS} = []; # Comment parsing code based on Image::ExifTool::Vorbis my $MAX_PACKETS = 2; my $done; my ($page, $packets, $streams) = (0,0,0,0); my ($buff, $flag, $stream, %val); seek $fh, $start, 0; while (1) { if (!$done && read( $fh, $buff, 28 ) == 28) { # validate magic number unless ( $buff =~ /^OggS/ ) { warn "No comment header?"; last; } $flag = get8u(\$buff, 5); # page flag $stream = get32u(\$buff, 14); # stream serial number ++$streams if $flag & 0x02; # count start-of-stream pages ++$packets unless $flag & 0x01; # keep track of packet count } else { # all done unless we have to process our last packet last unless %val; ($stream) = sort keys %val; # take a stream $flag = 0; # no continuation $done = 1; # flag for done reading } # can finally process previous packet from this stream # unless this is a continuation page if (defined $val{$stream} and not $flag & 0x01) { _process_comments( $data, \$val{$stream} ); delete $val{$stream}; # only read the first $MAX_PACKETS packets from each stream if ($packets > $MAX_PACKETS * $streams) { # all done (success!) last unless %val; # process remaining stream(s) next; } } # stop processing Ogg Vorbis if we have scanned enough packets last if $packets > $MAX_PACKETS * $streams and not %val; # continue processing the current page # page sequence number my $page_num = get32u(\$buff, 18); # number of segments my $nseg = get8u(\$buff, 26); # calculate total data length my $data_len = get8u(\$buff, 27); if ($nseg) { read( $fh, $buff, $nseg-1 ) == $nseg-1 or last; my @segs = unpack('C*', $buff); # could check that all these (but the last) are 255... foreach (@segs) { $data_len += $_ } } if (defined $page) { if ($page == $page_num) { ++$page; } else { warn "Missing page(s) in Ogg file\n"; undef $page; } } # read page data read($fh, $buff, $data_len) == $data_len or last; if (defined $val{$stream}) { # add this continuation page $val{$stream} .= $buff; } elsif (not $flag & 0x01) { # ignore remaining pages of a continued packet # ignore the first page of any packet we aren't parsing if ($buff =~ /^(.)vorbis/s and ord($1) == 3) { # save this page, it has comments $val{$stream} = $buff; } } if (defined $val{$stream} and $flag & 0x04) { # process Ogg Vorbis packet now if end-of-stream bit is set _process_comments($data, \$val{$stream}); delete $val{$stream}; } } $data->{'INFO'}{offset} = tell $fh; } sub _process_comments { my ( $data, $data_pt ) = @_; my $pos = 7; my $end = length $$data_pt; my $num; my %comments; while (1) { last if $pos + 4 > $end; my $len = get32u($data_pt, $pos); last if $pos + 4 + $len > $end; my $start = $pos + 4; my $buff = substr($$data_pt, $start, $len); $pos = $start + $len; my ($tag, $val); if (defined $num) { $buff =~ /(.*?)=(.*)/s or last; ($tag, $val) = ($1, $2); } else { $tag = 'vendor'; $val = $buff; $num = ($pos + 4 < $end) ? get32u($data_pt, $pos) : 0; $pos += 4; } my $lctag = lc $tag; push @{$comments{$lctag}}, $val; push @{$data->{COMMENT_KEYS}}, $lctag; # all done if this was our last tag if ( !$num-- ) { $data->{COMMENTS} = \%comments; return 1; } } warn "format error in Vorbis comments\n"; return 0; } sub get8u { return unpack( "x$_[1] C", ${$_[0]} ); } sub get32u { return unpack( "x$_[1] V", ${$_[0]} ); } sub _calculate_track_length { my $data = shift; my $fh = $data->{'fileHandle'}; # The original author was doing something pretty lame, and was walking the # entire file to find the last granule_position. Instead, let's seek to # the end of the file - blocksize_0, and read from there. my $len = 0; # Bug 1155 - Seek further back to get the granule_position. # However, for short tracks, don't seek that far back. if (($data->{'filesize'} - $data->{'INFO'}{'offset'}) > ($data->{'INFO'}{'blocksize_0'} * 2)) { $len = $data->{'INFO'}{'blocksize_0'} * 2; } elsif ($data->{'filesize'} < $data->{'INFO'}{'blocksize_0'}) { $len = $data->{'filesize'}; } else { $len = $data->{'INFO'}{'blocksize_0'}; } if ($data->{'INFO'}{'blocksize_0'} == 0) { print "Ogg::Vorbis::Header::PurePerl:\n"; warn "blocksize_0 is 0! Should be a power of 2! http://www.xiph.org/ogg/vorbis/doc/vorbis-spec-ref.html\n"; return; } seek($fh, -$len, 2); my $buf = ''; my $found_header = 0; my $block = $len; SEEK: while ($found_header == 0 && read($fh, $buf, $len)) { # search the last read $block bytes for Ogg header flag # the search is conducted backwards so that the last flag # is found first for (my $i = $block; $i >= 0; $i--) { if (substr($buf, $i, 4) eq OGGHEADERFLAG) { substr($buf, 0, ($i+4), ''); $found_header = 1; last SEEK; } } # already read the whole file? last if $len == $data->{'filesize'}; $len += $block; $len = $data->{'filesize'} if $len > $data->{'filesize'}; seek($fh, -$len, 2); } unless ($found_header) { warn "Ogg::Vorbis::Header::PurePerl: Didn't find an ogg header - invalid file?\n"; return; } # stream structure version - must be 0x00 if (ord(substr($buf, 0, 1, '')) != 0x00) { warn "Ogg::Vorbis::Header::PurePerl: Invalid stream structure version: " . sprintf("%x", ord($buf)); return; } # absolute granule position - this is what we need! substr($buf, 0, 1, ''); my $granule_position = _decode_int(substr($buf, 0, 8, '')); if ($granule_position && $data->{'INFO'}{'rate'}) { $data->{'INFO'}{'length'} = int($granule_position / $data->{'INFO'}{'rate'}); if ($data->{'INFO'}{'length'}) { $data->{'INFO'}{'bitrate_average'} = sprintf( "%d", ( $data->{'filesize'} * 8 ) / $data->{'INFO'}{'length'} ); } else { $data->{'INFO'}{'bitrate_average'} = 0; } } else { $data->{'INFO'}{'length'} = 0; } } sub _decode_int { my $bytes = shift; my $num_bytes = length($bytes); my $num = 0; my $mult = 1; for (my $i = 0; $i < $num_bytes; $i ++) { $num += ord(substr($bytes, 0, 1, '')) * $mult; $mult *= 256; } return $num; } 1; __END__ =head1 NAME Ogg::Vorbis::Header::PurePerl - access Ogg Vorbis info and comment fields =head1 SYNOPSIS use Ogg::Vorbis::Header::PurePerl; my $ogg = Ogg::Vorbis::Header::PurePerl->new("song.ogg"); while (my ($k, $v) = each %{$ogg->info}) { print "$k: $v\n"; } foreach my $com ($ogg->comment_tags) { print "$com: $_\n" foreach $ogg->comment($com); } =head1 DESCRIPTION This module is intended to be a drop in replacement for Ogg::Vorbis::Header, implemented entirely in Perl. It provides an object-oriented interface to Ogg Vorbis information and comment fields. (NOTE: This module currently supports only read operations). Unlike Ogg::Vorbis::Header, this module will go ahead and fill in all of the information fields as soon as you construct the object. =head1 CONSTRUCTORS =head2 C Opens an Ogg Vorbis file, ensuring that it exists and is actually an Ogg Vorbis stream. This method does not actually read any of the information or comment fields, and closes the file immediately. =head1 INSTANCE METHODS =head2 C Returns a hashref containing information about the Ogg Vorbis file from the file's information header. Hash fields are: version, channels, rate, bitrate_upper, bitrate_nominal, bitrate_lower, bitrate_window, and length. The bitrate_window value is not currently used by the vorbis codec, and will always be -1. The optional parameter, key, allows you to retrieve a single value from the object's hash. Returns C if the key is not found. =head2 C Returns an array containing the key values for the comment fields. These values can then be passed to C to retrieve their values. =head2 C Returns an array of comment values associated with the given key. =head2 C Unimplemented. =head2 C Unimplemented. =head2 C Unimplemented. =head2 C Unimplemented. =head2 C Unimplemented. =head2 C Returns the path/filename of the file the object represents. =head1 SEE ALSO L - module for decoding Ogg Vorbis files. Requires a C compiler. L - another module for accessing Ogg Vorbis header info. L - a perl interface to the L library, for decoding and manipulating Vorbis audio streams. =head1 REPOSITORY L =head1 AUTHOR Andrew Molloy Eamolloy@kaizolabs.comE Dan Sully Edaniel | at | cpan.orgE =head1 COPYRIGHT Copyright (c) 2003, Andrew Molloy. All Rights Reserved. Copyright (c) 2005-2009, Dan Sully. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. A copy of this license is included with this module (LICENSE.GPL). =head1 SEE ALSO L, L =cut Ogg-Vorbis-Header-PurePerl-1.05/t/0000755000175000017500000000000013763201437015230 5ustar davedaveOgg-Vorbis-Header-PurePerl-1.05/t/01-require.t0000644000175000017500000000016213751016137017304 0ustar davedave#!perl use strict; use warnings; use Test::More; require_ok('Ogg::Vorbis::Header::PurePerl'); done_testing(); Ogg-Vorbis-Header-PurePerl-1.05/t/test.mp30000755000175000017500000014417713751016137016647 0ustar davedaveID3hTIT2testTPE1davorgTALBnoneTRCK0TYER2003TCON nonsense -< cKuL"A^S r,*pj0\AРx7xxx@8 |;)4d|U3;Z}i|.o-9n/g_ ӧ71Яe"Q:Q_T<NQab$zzc K Ngia,~)A~HEP,SGgs}v߼dv?!A[t(4" A6+%S@ځY)?^Ҟq.$wNg@11򸃭])ns}gk5Cy ;>mIRM=͕MiYЯ 63*pR+Y"m *LJHMec*-AӍ`fct<KCG6ծ y2*pR+Y"m *LJHMec*&h X&P)nrd` ge<8\;-<%tPΆdNE@(#8C2iJircm)]0bn 9K4f:3o-V 4БXY,s$G[X>toչ.Wv)UmEԭeofCE#A*ddF7xWp@#(Gm^5tU[03y\U2"Dgs"X}XoIw"+&4#"T3JNFF wlݟ  S5Ah,&轑EGm2s]_+o@Q3nqK鐓g: ~LƉ![#uFiu)yX?ucC3 zQܨٮݛ_Wו/-nU!**;2yYgrʯk1&Lc`so#hi)zXF="] xS5nꦰH$!"EW7|ZiR #adi\62k/gݟɧBwK*VDi7_V&tI9k[\mi#FmHR.yU|' ߍ iT@ATv1[c>}9TX%<dk>yOL7j '$Ae4 wcajbx17/C A.!18@3S8;Å/Ypa{QmWﲂB!tK..&0~hBpa+d8*VM8GobRfu75}nH]p XXV0b L,a)_wgl$fwTIQ ^qE(]AZ ֊*D5Lr"ݗLigꊧReJ,-O׶EWBB;$(hH8.v-lum]E"9H"ݗΟM,QTU\+m2H%BGCb)wJqyk8f>%NI91*b(K]olt:uЂ1$i`ViYYzNۯjxmD" l# q& ӊ AP(jf,UE9*9ʼn-_ `&%,̃b`X(]=] 9MGKm),`Bh TM7yki2͢aJi呠8&VcZԜ[8#ULmgjoGݴ8̙ fg?v@05 F\Mvco3'(ޱx1S(RG{Wm wt*^jFUFJZXKmQ<`5`g<<5), V}_taţ/uZYgeAȇSQ9%N"Q ng&IC X $.rxj=)<{b$K*)mfvu}1_hLqe{3k/y^Je9 ܍GLaAw=(@L dCy6$aQ|5:J[ ɠb$?| HN9r2!z sNǿ>Ox OA-ؓeFYHd ve)l/&7h ˴,X:"2v,~?opT%Q@ Iܦ4Ea!)-!)`jBz%nXv!SFtȎX-j֍I`)LoB%kzUXiڳҘ і:%%`6,H\~P¾$:Kl,W{~o{\w9dg:%7 psl\:,U.2+9qe *g=:͜eMwno]nk;QDJ·{ILy؎2f";zP`Z'c/J -+KKph,@ed?j4_Q)".+%Iŕ(茐s@-˷L/0Z;i]͊@>'%??ҭxu,]( +(C%YQjL1YqX*MwMf,}F7Ddn]ax߸޳Jlk.!l6|"N&JGL6Y힭V$X\ RzJu19S/ij?_!ݔFf{F$x Z.Y /(=MF o %rSΟXd`)rGQ,$MYSCG(Q|^,BHR /$ѧ.%QjX]C1K xGG aZ,z-n  _z͖ "`!c$HS{)%3 h`e%ڟeڵڔ@Iey+3ΰl{}$%A<#4AK\}aU1 1_:\sd) oe$o"_A 5L$S.ԵTZE$dzho5^{wwܙNۺٲ!׭LϹQ]Qԇ{*WH50*{t@iaL=PƬGzxySԉ"ȇhZ[K].rBgJW]GڪmJ32VJTFL%(U1ށ)b㗩 Ǖ=H-'hB-,ءS2N}[+}!W%#s")i+Ȭy5+rE cȾhkraV*Jتjfڈ+-7IZ(D$ ,'r!l|8b@CC09Ayޥq9&5n\#)hejHw: s"ebdlC) 5=)C!DXw`鉹Nz2L*0K+߶)h4Pm5WR-+gufg+RLKqH;zZȇ ;سnDPS17)FW)n@{&bY]tts~>92엙*NWM)ru: 8D#?Ox!hiz` `nJ9Mxf  s᝽ԷG&$2Q52\Oc/pm!.U;s)"B2ȮIvb)U;Rx/@64LJU[/_bh]T1JW&wbEvcҬ}_ӹ"!]KK#*LLo2^JisE.(3JT壺`a ,x^1 ٿ=:4߇nV\NϘ#3=ЧiuB[] ^{#i _F$, RUtg}IQSͥ?ʥ-U],Y UpS!Μw-RcQ]3JVs-Z*0hr`cdotZq 3@ teTJcVEks%̩"t_]%[u1(e)i2fD9Ԛ%Ѵ)P5@aEOk_JmEIFY55^b5/|szO_*~tS idΦhdHY9_p(Ohir_ 0BnKџ5Mɕg o|fQ+O~&k;譳#jGtb uBȆ2R}HGI2snZTW^*Ρ@RlYLhg^%PF-Ly["ϔHsጦ-wH?rs*ބHG fdTyI FLay9SȣgbʱJHT aDo6/GbUr5qh1Ի\ACg䭎_uw?겟TZEe6z۳슷EG;"kE *`%G* +qџGb:?Wp܍h)KNЕ]9jW&OvԵsD\.^GM=wB gMQreLɪC {UFaCWʎjUe9fC/n.ni̻S /_`] !<(c'+Bc עB%\N HYdP,FPu0FAn̡9egc}JZhfviz!c~wS"Y#ʭdTKkXD(܃M"$.R%e b+֠jTòuCSحy?ק9o^T7Jy޲nE*o*BWrRCI!b,ȞH3gQrU9<^Ly3GM~g}-ZVa7e3TK"̧~˴9Ʉe{yt~r6YdžP!OM4؈%#lxG؁)AIC,zoSzX4tޛTuZ mLm_5}MQJW/þwvo?,9 ,f5.P~=zuVmㇸM+irU%]ݴ [#23w.s;R`MuH(,xZhZmƇxAY\s~ֆ:6cd4J?)[eҶ#-@)LX{8ӫ!j^r2Rn;l͖RG4i]<"nL5GMv.选b@7!g"Bxw;k}*lp<_w/h_][~{ߋ:S`'P: ۬ٸ7!3f81|F "S ?!̑ٿ'4srw}K4mNreM\F%j9Ԛg|G‘lD2&V;BǴpˮ!AngqO3fqt{j"gJv[r]W.yIiG!M'"C7M7Xυrx=ƚe 3,vkVnmʖ7sKXE> Hޫy̵3yBNg)ƽ|j]AT~z$7}.hNiXI!@*tߴ fʵYgc9)Ba#9}0D[չy̢V2_ O/F763aMXYSL2J^_g)hi!re0enKA5Me4f` o," Od#I?GgTSVEJs=tW29G -BE3!̭gP,LGu Jjmˎv:XD+ivW[3$BW Uk1{+*[^+5TBc#3239(aV#Ty^4Q՘vF!PȍF醘whB֔͘$Rnz{1EE#mvb1{]ݔ39;P!sYgY;zfJ-=9Ԍ4%*ffBЅKHFsE)?st, %˹pN:Ǔ&A;e)gV;DOM;fRjj&n &k=hi+r^Mm0cnK3MɊ4f|J6IXb]7k^˙T*"ՍѴ-SB*bBy +є:NS,S*˫ޕZݬ"U&2pOwitUצQ=a9}>U TLoJF9tE|R׼|7ug+rdFbHfIj'Biq_~o3xnBa0ڢ5s1*Fķ(u vMG9n_[̔(#%^rЈS([c4!D5˝'ILywQQfp (D1*\O%HeUu r%]TնBv9Jt$gWQG 3o)=aE: FA]X +k edHw, :ևBܯV`ŝJP(2/*] G#<PYxpH?*]]=%] Qa~*4,[C8m:tqhaq6~ya h"BEZDJew'wy9m)NEq̠P|2~(n5T-:oQҴΎ-L2N:o3L$h"BEZDJew'{ײ\q.A0|. VMCJss5m @$h q"2*FصȻLV/n_۲ﯻVy_򢠰L!A9jkBD:'ء#Eb 1.s)X24m[̋QTEi{mv^j6+k}%k/JXdiK xQ=iaj),oX`c$@A!Pf°(vrzClޜ@6(MNM.lhQ++K)ꓼEdzgTdk֯ԅA鷬((͔0A+ $7K1iZ%lޜ!^dXڬ^ ^s-7߱o]Sd^tZ+WgTYHXFzĀط9E٨2HOHYU]/?8mvM $ԞTsbWj,w D ZB`oXe^&8 .AJB|ZEʨ2xkh&Û nPhԱl@Gr *Em1 Q'&>R9*]G?\ Q=)*4ǥ0J 05ż5H*(Iķl-{2\%,cA4W+2BO"i0:<cDNM`kyZZTQ験o l-{33?rtoذ,ΌV;ANw!'ѿؐ~8(=Z=HvԧtQޱW?TJюܗRz^~%*vn $i0×uL' %GʠY'4|}}@%tQޱW> CҲc%Ա}Eޗ J?@x[4uI.D 0]f QyIM }}f ,>bb]m ,] i+"-41%tX{k}W^mܦC\vae9}jSNUJ5רjofzֹͩt@`>1|nIXM /Ik]=9ԍZ~ 4"49,u,͗h!o31Sn0AOR -*HN*T2ٙ!xT/k( D8KU_f.}UC]K$eMfa6GzuX{m&PTeS{Q}AN j׫P.>h.^2 N .V}g Uu,ڎ²EM5֕ !cgD_L-i&2`\m$L 9 |(0 5$[zxRُ^抵 ļ(K9P 7P0r NrH<4Ҝ[B[w[ 'd]<"`$S  5$ջzxRُ^抵 ļ(K9P 7P2$J:"Jqo%y~adXl]'rŅR( 6DcQAƌ5)E39w <;S0!9U0c(ջٸfmk g, oubWB ,v&4aJ()ĝ˸_nژhʩF6V5U{k_\Ed&bq'U[.`~}W-4bReD{6`W\Te[}0Bd*&Vw޸ߑf'u85ofGrn=J*[T\)   D9EЍǶc?3L|clLf5֎O,)-|O}1Oޭ_Z~lU@Sid>5d\.; vG_uoB Y^VeF8!`K,!7:\\X({yPiT-Rݐ0<:ujf`WHRpE^}7ݚo=GMY ek#s@ 0.*ZDP4O5#!RV]ԧ־^>zk!tsQ-ݕWfj)TQK$R 0F*_j=_ CftuHnk!&jz, A^rbFّ~2[]( N#g|*:2RqۘCQ[}mfnSc@ݐg!'+YF'L3_yɋfEIHu†6ۣzC*;2jH^Qq/lwf3LI :Irk< $4SPbVn>jMQp 7?WUoKIߦ~I}gO/o@{Ehi+ze kq(r#Um'1-C:OKglu9嶌ק*! QW\k#+te! c<8A~\USTKqD RO,.u,ѡwlݪVSwE?o=:2J]EKI#9ʔ* q H3omgM]`<(\ Kӕ϶f@I Vy>ȮޯFy݈g2V{[D:}Spm.#*P]$z=eK CM}4ht*w7F;f?+o[̥(er:-uη(`"eGi6D2e( `F`^'Zui`},-:H3@8=Ui[6$x hwegMuܣ@{?܉gx"}<8hҁu! .㠘3@З`BQ0V$u6AZ"8@I"~9"sz"wAoٖ[)F{Y*c٦T&ƫ_g1@&= Drn±%HөOUhL!}UiAf̽v;ݑuJr*#- h:U5ճe.͖K!ܨA[6:̬y(D>̽4,?7t12 '$dz"͖7Ev^sXjk- oAhi;zbM cļ5j}M5&t*'@oYE%0oz!*ԩn%F>δKWGфgA'TsPnh+zb  `oK CM鐴h5qұwĠ dJ p_g)0F1=amdTٝʓ]H۩z蔞D&vVG;rYXl.{zT?2 t DX#"UD(txES's{mUu*QYF9N;EFK,dB5YZB,L{}/* \s+CPwZjwUAO~"v#e}fG3,sԒ#ףvT<٭a LI+evc}D"8CdW/G];ج~?͡s(R)) W)R:9Odvj=ee V4]ƚ=]L%;Mm4gu XoEQFTJs4?DLj>VAkv1X߯m~ͩ~O 並{ޢ.Š7gH @TsƮS +\Z+֩r _1џbv߫f2Ne/ka}W%}Ez{DxF$ 2P("]".F0w;(dm:ag&t#e2^U[joԖ#-JU%Qi.ՖrV(Jz$IT@ePDxZyFc&fl!!7gE)כDd:eEgIklj~vE= aa\KCGKhtuL!$V%G^T/r*1 z.QW*e>V+R\eqq]IAe^iIu)z_eX.`u+(O8|DԚQ{Njv_}wo6vȗCStw!o/u,x'BRW%hb=C(?I,GOTz2ֆT X#k\rqs+ݿ-u^'_N3%Vmℝ I\&A"$t񾊝FZʝA+kire\6%J@ɕm_}d˽O k0aY`bnKЋCL@iau,YR W4! fNČkP]6`k gg݊EB4*O:(KrL!P*o[]G]RLm{NHeTM?ϝ/=Zί]əg9ٙl۵9S=;-GHw$gOa!XX$ID 78%QZiHEP*9ˤrFK*aew3(N @o4 L &B F0<:h^TJt/ 70~F{BKU4DL6W qXyaPX 1rś|! 2Xe*a] ,D,|(,-tSHB@c@x1/V.[I<^ 4"_`U~ܲB}ΗdZ$ TA&4j^],H¡PT}_E[7IS&ЕlLDkA u?ZjWGzǑg A@OY:pUFXMԦÎ]wl g)L"jl{jPTƳABa7t*&!ء .<ܸ+l`7Jal8vaA6WZ̝"I/'1z^obO?hj?W"5aBL3cJ.Դ$CA4$M;UJt<ћ cz#a_ IL|@Ң[zTW.(B>R:WdgbK KMl롂i%,i ŊD [YQ]N7&, Dl:LGL]VG#+a0(@9Eaj@Ԃ$wrtL[+ˊ@F! iһ"7& z4Z_?>Ua FF&8y7gt6ФIsvЊ u"#Ɉ3)&<Ƈ%o¬ R{׺ɶ|QT ?VMD9&Mѧ]gdО 0 T<|q98IYTHRN &fWUĴRK̈́ԋ&ڃb\nEgdږh$JXXĚzc)K Jm)Ahi]( oY60] .[O5 YG(; aTgZ%z]&*k@VJ۫_Ԙ y wRP.„HȄ'bc; aTgZC3?LTZ c(k1s  Z]6$YL ˆ1Q@_4"1Qǒ_\'jUCu[S9;_uMDt'rEGeKG!'Q?Cx'4YTBj db94@m/">dCi*.LAa^nȌeuVAmbʔSZBVJ Qr@:C@#Dd d:] ̸E.#Wc\rK vArQf]U kjSmN6BU0$ߠ.DcUS_%BX^DmgIJ ȓKi)Ai5%(*iU1'$**PP~(Htj7rT1ܖ !V 80y7?]Bh1h`Vj 8| 93">afS\=X]s8#̹C0kL@#۽K,j_#$2Q.yT-GV Ct"YXTΐD4>h:;sI1Gvb$mH5kʧ_.[1QAd Nx(tDڃ $JX_}cIK hGL Ah()]e) n88]'ힳx>UxY,zf"񍙼L oł,iq+/ sA%c깙JBi|*J{g:Ͻ^,VnfK)qF%:١Ȯcfo(Dn8[`p)y+G݀E JΥ0SyG"uў ŒKTˑnm .LBT9ֻkEVY*^JhBa[`5Q3Y.g 5Idۈ|3 շZWgF`*eCXֻkU6B[$~yk#PW_-[n!kBPUYc8 =L(4h4FC'J BcpjQA^I;o֧ Wfפw@* P'Pqg?1k5?FڎPk GS`;Q.uW?S426$j_^Ѐ T6,[VcSTn@H߂{CM2+k %aE:/hrcm=CnL ?mn4htkɻ gf) iϫ#QΡSΔG'16j _}&t眜TCr)k -(UM<3#:IXу8?@; %(A!"ϫ#QβkQ(S<)^뛼+i̓;ԕnƵ^,"/)UQҟEy`L4ܐ·#˙`9zϻcTiPt_Гor"kۡŲQ2Rz[q5ʒz*i?$3>HيϠ?NKs٪tJ:%Pz{/fgO+e1Ҫb)bq 9'[&WZ1غ5V  hz` n 3Fev)S9]OI}duR0\*m%bRq5ڳy%2(Ϥ5ZrտγεC jSWw92fPJ&y݇Z|V&,[:yB'o={}&eo6l-;xt62/\ʘYYǢ!5s:TIsd` 򌺖Ag e [KwSC#:bs%;+ sS/Ȇw9PvgAb:p࡭ƹO" SXB4Y|=lLDK_Χ/".C8!T?νMbyJ+)KwbB Vrb k\|<@ uZ0lE_]PٍUyVSw:V=߅fs(L[U,2v ʤ&c22*#AXB 4_*<#oL%=m4gt hKYa 2F^rW#~Sg>Uި@߿ϳGk!6#N=k=Y9a?5H8MpP61Vڴ$/`F_"F>1vhdU5jvD*FtQ(ab>aS8e:d@$"!vo&띵s5zYZS#v?x2+]W!?r ɾP܋mF)!<&Jm(Ѡ_$\ҕur0V*1lX~us3 7y ? d` U8ٷԖk %kӭ }߅ą6hzaMOHhrdm`EnL%=b4g4iuObZۈH$B/qL_?ЩE8~Ǒ ZRT3=̘5,ʒkJJ]- 7$F*:k]ݗ#f[::^5_-LV53LbԊC1=:#39QQ.!b*auVwuy.WQ5ga~g8 T@bes!8D=he= 㕚,[wAubtb 5 %k#OvB5"jOpo@>2J ڽ G8PT5l%Mh+rZ  #nK7mxfS Ž2*\S,;;CQIno)/ć "#P滜u#Riβw"MScd1S9B1@%dz_&BMDClN6DYegי6q~Eٯ S^zJp4+B3gM:R/ D;Lo{yU;ozk,=5l!_f #2Ǧʦu^Ѝj}=gMuJ_]IFoA_K]:گdM] CPdR;&v3;W(>W@34Ƣ.hr`$EnK5 Mɂfk㭯dW]}-JO5^tY3Kh-&lR{ivN<([Z#[WȒO$;3'~!@iU l=y'Ze/v>W\E5ܩd~-cRD2NtuL{!ը)&"wJ!YPHc"a:y3TVgAL2}x\4my8ǩfѽwFVCZWO$fKțfC!ڨd!#DSLq4$FhM :S7jt42#?gc;u?}|ge.f|1R9йZ$ֶXQVKEP"hy#+rd]$enKT_S!ZjvRl%GJ!65">nsrsUC#Q1H}Ψd6fYuqŐ-eKiXKF/ըiFr8 *%S`q ufjK< ӏok2T5J撪琣l)ʆ2ي]d>sc+t+!ʇsPFfS/FA]2}_W^phW_a@FY@@6b298 Sz|O ׉eo{!$\FrQPH#h, aj1e/.PA(N| S|N/ ח jq>_=Q #X<c ǔLA` e,_PCuBÎ" =ZYX9F^(~f2!=Oy`2=v7 j ?ߟ,3EljD S{# Ҵ.rbٯDUޯ_A$ Wc,3x1U#Fp@Pb{*+yw(r0kf?ͽh?NvU_@ U#If)lƘd\eW (!3Enaț1Y$WUfm&YWYYAVo=b* 8Oiaziǭ,EU븱^+n{e\B0,8iY]jz0i&5הR3CUZEeJ^0L BMޭh`f` VQiz,l,50۵l *E5ZjbW~ZL&5הR3CZZEeJe-Ia(KSպ)EH̽i+iև[f(D2yVjTseð ]1i9HV ]¡v.`p G+!HkC3"`<+5*|9LMqNKa]p\$*7\Ȍ;ZJ V$ZXYz]=_ GK!tH3n=Z&BBqHي+s;YY x4{']pmqiW?.h& 'gDtʭZ_LM# #f+h4gfv"dߍ+?ƭ!Wj:>ʦI4=d[~N[E]5 CxcDyMQ`)j=_ i%O JI,^wya9G8b*Pl)OH֙]SlB&tϿb "?J}fNs)| .#RL&O}f (WeaAankQe)8ҩT'/F&iJS5WTGw];{I~c'HSW⪍a9 !S$*ht241*NT[J"KQV_# w6 8ϭkR)Www/ok y2Uc{~ K|*CI8SGZ:FL;Qn+>cH1E:\T`ӕd˺Y` MB)BR[\ą/p=s0wE#)ٜڥcU4v> w#L@jl o8 ]T9JKkx|cg8UsWWB(Hvg6D}Md:3)do)J@yGS:`Hc] #SGKm$*htS.ʑ]K{NPxLe=?*&' U:K"⟓WUY{=ZY&TJPũMimuHϦSۃxdrjIdQSjJPU{=Z%f)SJ %ŒMOops;&Iras\U4X.id:D66Pqͳve B= re2W*d,S3 .b'`11.^1nk,rG@5F&׎9zER d#Щ'_Z#VȅrAU2Bz{$ G*c) za] iQ=!$i|uG!$LPE+ϒjz 䫲#kưa0WoO CTC# i +0R*, \8qG,)_|T[PH%]O'ܱmqcL8rzb{ڎc}/P:d*!*pҕ-@aNRWfc# (9ՙ^+[Su i5"`!F7 H" "|(h$ 8l@0JͽN!\2S#VB*`?#ٙK=m})W!T``5E K;/]wa_ #QL6a_"to`g֊іE^G;^"+ L}%"s*c*R'K.Eg2 5$]itn YDe0QbPGUf̐e^>.'k};00USڗi1m(0aek}7uUoC#<}?l _5RByx@fк ' U?mpn2.]fw_*# d鳫hv;{oLGk^(a] Q[ڍ=] i#Q8F `^pp%)G<^:z;>[W[3_pguE}^qgedzĐ,AoPMw wXl=GRD+$|ndh+lw/k7".WWcW3;+^omFkcza] HWL=g!#i)tR4HҪGe/`FaWwWc=&㬽xD:(%7#:?fT!B]/bX S(ItU )o$U(tT`\TAo߰ MGt_ hਇފC^ٕtd 0K݊b0V%ˡ* =,>n$ cDor&Kҹrrl7$a5RN2MlہF D+xym#:Ik^#P,e="i |IF$V>z #~Y]-ٟ*"*ӡFTm:5r +l+#f{(e3gQ=3coG{yB#%jXYj=K @giA͇(#3keRhj>Y|j((e:A=$A(f|@pPlk:-o$iS_3o(Py) ^}?98B (QLFܮ5'qblTϔ(dZ<$uzKS\sU} ? ^9esYVE'rO3c)(cg榭d?xԴMZ,*Ωwy+{gk"Z1J4bo!VXߵ49uדSk]ٝoӓ3*9RVX4X: W.{;IC^ 1(%9BP`=J aYIM^)t |jzݘĔ-COkt&hK]%Y:٬9a \`yw,C iN ^  ToKOyCP$I_eifTn}$EuAcTc4;ښ*/ʬgDܾtz*@JW2O9' /TR,*b]1^ `KiAot(+% ,?3i4RtWz;$#+>iEG/p"HgM6k#[٬RVC҇QS,;T'C)r-6E/Mrԩ N})YN(B9|L@ d'WK3Y b}YWu%d=(qE1þA{Vq[ZqBׇNUInZa0g)?_'bV谔аT21c,㤷'e? r-՜8:*I}o3-Qi)\Wk؍eBCȊDF%~CIQa:==^ gE'ht-(iSR:f6frG=}R.jxWuEK͘EbPΥ_m{++R.nw`l!c|W ji&g+ Ԝw8CEٯ3#mOj2f(gQG#ؔ3W[|VWj `^ڵڭv[XYNʝU]B$⡖^}:A#dlJ]BΛ+uJ!s6Keg2cݙ9|9{,ˏձ6U倇J8vY;ɄE`/΍bBK[}q s%" P 5]?ߧFL%U0$.5)?.]$ؽn_?f/LYɱӐՉ0+EtWE,6FBIv}{ʂ 2Pm' RMH->ltX b.ďIcY1J mC M4h g~zvxKDopox8QI֢S9 %vt +PdY#=q[(kz$#w,e=9dHo L;L֤imA:#2UTM׵Oi* fOdzaBUzEv7&} ͚@$+'9, L(tjQF̵\ӷo01Igj!(Pd)!NSvMۇnI|+R0,jRZj2;G}rdt6տ0"n"#Љ[HSe=Tej9j]՟Nfi/1_ =nLY?Mx4g 0pP  *ja$iX_# h;}Ti:= WhK%@T:qUb+ 9UI6J(7ɣ$Åf/P'М_۩R_^OzZ%ngFB^viOdݴ<ߦHJӅj.\0o :LʇNR8T4?q}ETѩ!n>jș@C;2ٞV n!*6%j.\0.bJia Bۻ.yTz5 ;FwsU엃'$[!>K9UBz=8 S`K#u tPap%~2[ =Nbv|,U2f_6tQ"so1c {mUfn\qy^3 ] h 0S& D x(C yNLbhŃG"7 g6]vxu_qUHf'(H5D#gbɅRCyѻ||t9:7BeuޝpnDqwr\˚S 5C$U$j[3 Yo$n3ڱ^yɅRCyѻ||t9:7BeuSTBr 3Y)dFQ.E?j%o0E":1s&EƈJ"RJ rzS^f \}ۨ VB)tGUi^=]L)#SKj4t.dd"P mc"_\0rB\s>y qgf+bcrQ&#* $ۼ!4b 8e8@*;\N}p v r2Gŝʤw;kv_d e*ܯ]Q_Zk v c9"'XO2sr-+OkPcBXt1 9W?[y=0R(Lmg c4 Z JD"DžB`7ZyF\b(HQ\Iz=_ 1#QK$j4| u9,crxFXP Sއlě-r'DjH2צwDok7=lӪ>ZyG 60%`<*>c148izH>_leFYBUB]tf#+P^!NEb^~)H)1DRKVVȧu;ZOQA"t;"=}2#,*ġ]tf;쌮}AzL89zڝ{┥ @UMJu-ZoWu;ZDΩ$A"r}HX :=_L]'SIDW-mFIM.Mȷf]Û0.7{K.E2M5C%21a+wt5x %U/ 荂1NS8QOI὏}>r!Q3).޻-WtV9)O9 s [^GR:aڍ=] XIGA(q9?r$gxi&$,bFz(|0%'!+ T*gSF!J4̷9ڮ^gjg__hөNHkxhFN-)[i\C݇c <'%XE0jvd&F/O2i{1 c/ 8AԠmM(yr`h╦ԓd8ҞָR6kE{ 61[Ћ>Px <$#'/NX#J.Yr`hݱ ĉ)3&!z8ƴۉ* Li&FTGΦδ~ѯgVua(m޹֔(SiZX[m=kK LGGAh( o9g-˓Dʌ\N# s" " a]AsMN]x嬭,$c/R_?sރe y6`;yFLtW2$k>: s" " a]AsM ]x嬨)T-+,栰@&Euv|mzE*nw&-u*t8,bOF L-en؟kyc껋yj !Ƌ}풡8Ds`bazLW;OQS5-7ƿߺ:_q1v'iUΖ2lOY3U[ Po4Xm'j ؝3H.\zoFi*]%-=J EGA{=( l&zެ]B`|[ubEWHs<W#N8f$"Ly~8suKnd{8CzV ͅv/ZՋLr~X.ApTh'*4V"Pd1{7Q}` spY+/=ܮ5~MʼndZZU@smywsGw=D^gMBT̼Y!Vm_{0#%|=T9\V^{7rx֑4W%jS+`?UiU͵}X[{5R6Y!Vz[{ #ZP_y=J =GiAgu&iXgmxĺ6 Ul3 Em0OZio]N"*.A*8?@R.bosD@[{͞&iXgmxĺ6 Ul3H̵E3H[{r/r]l' ?8{q60kne#S"9I]'1/!F*0V*)p,ΩTCudlk'W>HB K$6kϊRzFP36XydfDo֝g<(TVgaLq«189:]Ha,k-F/.Ch}Ec3Μήv+3W'樦9< "V)\qg'A]MYiD~{x^Ξu$s:Έu-;9e`ft~\xhire0enKU;Mɋ4g<•pfT͜ʄP|cZ{/Z3Ir*UM-d_J*5klUD9o.iw|$=CK(Ҵ繘KLfǔ78i5tTr-nmyvEW3QfRU if-rrE;-*w[W(W \+zQVm>Z&ZIGoYRؒo,)i>֧bVw* !D t.V9W̏d~u2[yzzJR2JDԆOgf"Y1QMWήZU +) x P/h"+zZm$CoL9mo4h<Ģ`X&M;UvEܭvUݫSQNS!HƺCR^SMGٖceR+)D*%vΣЍ7B!AٷeG!MWMs:p甥y_!_!/e"Hl:lp<}ŔD*9LIWKG~&{dFшg DB˙~Q7G\Vyni)t϶3˙ Ϟ"fd`Ldww0mNjח}>/62#Do=#"WM:-MU*v%]]snCvAu9ctg @n @h"rc$#nKQ7䈭ɀ4g< )jB! ̎tU+OI/.gSYJFdZJZJFV3̱hh'M@~DkPe=>PH |;nRyHw.dy>g6gig%d6Z4jͅ3HP*Me0"e "&Dceg`Z#辛ˡgz=;Unf7M&vݯ~M-V"NvaV!Uhf2Ɓ9%1-?59j4,ܙ6Llȅ%Pzte茛4çoo" gfcuC^Nwf]Nڞ{+Em0rhi!re͈\9loB.볳t'].,;ior~`iydY–_=Ԅ#=LVM#ޱH[ErF6ođ`DԭV]-\dc$6xdjd0ߑ|5e=a/%.L:Hu!E6l9VCr]s(1 CwtWGL"-v3\2K Q\)eɛt>J/V<48lܚ"%R-p"~ѵdyh#rW-$"nL5m_g4a q ~MUSYrR.<5g"GHe^վf:*1H9ݓwiQTQVR#v{:gXO@A15me TDxFLMHyP٤ϔ͗e=Uwv!/UG(FgmURwc:h/ 6vgۜHգEKnvo7jܗH_w81^Ӓc:تtYJŽY\ȦIw Mz ϔVkfo32DJˣ\g"[T 󼠰ŔQLϹŃ{:>߱n4hief%\ AKh4l pD1dsD#F9s!D'+!%~뛤6d{@`B;YkY*t#3o ]<%VGDFkgG3ʪEʶ̙("Xj2HdIpq쬼dfQn{T>% M*i-Zvj%RkC8af`>.NPt$Ђ|xJ yǤQ-"]1*@lr3vmIK4)M ڏIZcfnT@(i鿛Rqb륫sV *A|'$Tحn -"/TAGtestdavorgnone2003Ogg-Vorbis-Header-PurePerl-1.05/t/02-basic.t0000644000175000017500000000247113751016137016717 0ustar davedave# much of this test code is blatently ripped out of the test code from # Ogg::Vorbis::Header. # This is in part due to laziness and in part to try to ensure the # two modules share the same API. ######################### # change 'tests => 1' to 'tests => last_test_to_print'; use strict; use warnings; use Test::More; use Ogg::Vorbis::Header::PurePerl; ######################### # See if partial load works ok(my $ogg = Ogg::Vorbis::Header::PurePerl->new('t/test.ogg')); # Try all the routines is($ogg->info->{'rate'}, 44_100, 'Got rate from hash'); is($ogg->info('rate'), 44_100, 'Got rate from subroutine'); ok($ogg->comment_tags, 'Got comment tags'); is($ogg->comment('artist'), 'maloi', 'Got artist'); is($ogg->path, 't/test.ogg', 'Got path'); my @artists = $ogg->comment('artist'); is(@artists, 1, 'Correct number of artists'); is($artists[0], 'maloi', 'Correct artist'); $ogg = 0; # See if full load works ok($ogg = Ogg::Vorbis::Header::PurePerl->new('t/test.ogg'), 'Got an object'); isa_ok($ogg, 'Ogg::Vorbis::Header::PurePerl'); is($ogg->comment('artist'), 'maloi', 'Got artist again'); # and see if we can get comments including the '=' character is($ogg->comment('album'), 'this=that', 'Got title'); # Make sure we're getting the right track length is($ogg->info->{'length'}, 0, 'Got length'); done_testing(); Ogg-Vorbis-Header-PurePerl-1.05/t/04-files.t0000644000175000017500000000121713751016137016737 0ustar davedaveuse warnings; use strict; use Test::More; use Ogg::Vorbis::Header::PurePerl; open my $ogg_fh, '<', 't/test.ogg'; my $ogg = Ogg::Vorbis::Header::PurePerl->new($ogg_fh); ok($ogg, 'Create object from a filehandle'); isa_ok($ogg, 'Ogg::Vorbis::Header::PurePerl'); my $warn; $SIG{__WARN__} = sub { $warn = "@_"; }; ok(! defined Ogg::Vorbis::Header::PurePerl->new('not-there.ogg'), 'Fail on a non-existent file'); like($warn, qr/does not exist/, 'Correct warning'); ok(defined Ogg::Vorbis::Header::PurePerl->new('t/test.mp3'), 'Fail to fail on wrong file type'); like($warn, qr/^This is not an Ogg/, 'Correct warning though'); done_testing(); Ogg-Vorbis-Header-PurePerl-1.05/t/test.ogg0000644000175000017500000000771313751016137016713 0ustar davedaveOggS'FvorbisDOggS'FmYPvorbisXiph.Org libVorbis I 20030909 ARTIST=maloiALBUM=this=thatvorbis%BCV@$sZ2fs{BB{ALBk!càBcАU@g{˽{Fg{i{Ƚ{ʽ{{{%g{H{G{{eW{({{{G{{'zĬ{7 {{^{{{{$W{({W{h{꽗{{ 4d((  @Qqɑɱ  YHXX%Y%Y%Iy뺮뺮. HPQp YdHh \CTLǕ\5]u]u]UUUUUUUUUUUU Y@i0#BCV0ŀАU@IN(9) YLJ9)G1yTA)RJ)RJ) YJ9)(Y*5)G9yR=)RJ)RJ))yҒA)(iВM=)(EI)RJ)RJ)J RJ)=֓RJ)1J RJ)RJ)RJ) 4dgr(:g(gBiB&9JJ&s9O9' Y@!RH!RH!b!r *J**,2,2,:ꨳB()Z[I[sI)RJs BCV BdQF!b)J*АU Q2Q$Q-53E4]UveYmvuYuٷ}[m׍88888 4d BH!RH)s:! YPGqɑ$I$,M4MDOLO\Qm\mTOTQ5U5]u]U]UVe׶m۶m۶m۶m۶m[BCV:#)")8#I@h*@@(H%Y&iɞ.@h*@h舖(((((((((((((yyy$t$Gr,R$ER,rАU 1$Er,˲4M 0, 'warnings' => 0, 'constant' => 0, ); my @TEST_REQUIRES = ( 'Test::More' => 0.88, ); push(@REQUIRES, @TEST_REQUIRES) if $mm_ver < 6.64; WriteMakefile( 'NAME' => 'Ogg::Vorbis::Header::PurePerl', 'VERSION_FROM' => 'lib/Ogg/Vorbis/Header/PurePerl.pm', 'PREREQ_PM' => { @REQUIRES }, ($mm_ver >= 6.64 ? (TEST_REQUIRES => { @TEST_REQUIRES }) : () ), ($mm_ver >= 6.52 ? (CONFIGURE_REQUIRES => { 'ExtUtils::MakeMaker' => 6.30, }) : () ), ($] >= 5.005 ? (ABSTRACT_FROM => 'lib/Ogg/Vorbis/Header/PurePerl.pm', AUTHOR => 'Dan Sully ') : ()), ($mm_ver >= 6.31 ? (LICENSE => 'gpl') : () ), ($mm_ver >= 6.48 ? (MIN_PERL_VERSION => 5.006) : () ), ($mm_ver <= 6.45 ? () : (META_MERGE => { 'meta-spec' => { version => 2 }, resources => { repository => { type => 'git', web => 'https://github.com/davorg/perl-ogg-vorbis-header-pureperl', url => 'https://github.com/davorg/perl-ogg-vorbis-header-pureperl.git', }, bugtracker => { web => 'https://github.com/davorg/perl-ogg-vorbis-header-pureperl/issues', }, }, }) ), ); Ogg-Vorbis-Header-PurePerl-1.05/META.yml0000664000175000017500000000146213763201437016243 0ustar davedave--- abstract: 'access Ogg Vorbis info and comment fields' author: - 'Dan Sully ' build_requires: ExtUtils::MakeMaker: '0' Test::More: '0.88' configure_requires: ExtUtils::MakeMaker: '6.3' dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 7.46, CPAN::Meta::Converter version 2.150010' license: open_source meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Ogg-Vorbis-Header-PurePerl no_index: directory: - t - inc requires: constant: '0' perl: '5.006' strict: '0' warnings: '0' resources: bugtracker: https://github.com/davorg/perl-ogg-vorbis-header-pureperl/issues repository: https://github.com/davorg/perl-ogg-vorbis-header-pureperl.git version: '1.05' x_serialization_backend: 'CPAN::Meta::YAML version 0.018' Ogg-Vorbis-Header-PurePerl-1.05/Changes0000644000175000017500000000450313763201426016260 0ustar davedaveRevision history for Perl module Ogg::Vorbis::Header::PurePerl. 1.05 2020-12-06 DAVECROSS - Fix division by zero error (RT #88374) - Add bugtracker info 1.03 2020-07-20 DAVECROSS - Give track length a default value of zero - Merge patch about track length from Debian Perl group 1.02 2020-07-16 DAVECROSS - Point to new Github repo - Fix some perlcritic recommendations 1.01 2020-07-13 DAVECROSS (releasing work by NEILB) - Moved PurePerl.pm to lib/Ogg/Vorbis/Header/PurePerl.pm - Refactored test.pl as two tests in t/ - Moved ogginfo.pl into examples/ - Deleted META.yml from repo, as it's generated by EUMM. - Reformatted this file as per CPAN::Changes::Spec - Changed abstract (=head1 NAME) section to follow convention - Specified license type (GPL) in metadata, to match doc. - Added github repo to dist metadata and doc - Changed min perl version in code from 5.005 to 5.006, as "our ..." requires 5.006 - Setting PREREQ_PM, TEST_REQUIRES and CONFIGURE_REQUIRES as/if supported by local version of ExtUtils::MakeMaker - Add basic SEE ALSO section to doc - Min perl version added to dist metadata 1.0 2008-11-09 DANIEL - Massive refactoring for improved performance. http://svn.slimdevices.com/trunk/server/CPAN/Ogg/Vorbis/Header/PurePerl.pm?rev=2564&view=rev - Allow multiple comment keys of the same type for Vorbis comments. - Skip ID3 tags if they exist. - Ogg tag parser was badly broken and would fail if the amount of tag data was > 8K or exceeded one page. Rewrote the comment parsing routine based on code from Image::ExifTool::Vorbis. Also fixed the cover art code as it was also broken: from Andy Grundman 0.05 2004-01-08 AMOLLOY - Fixed "load" method to be more compatible with Ogg::Vorbis::Header - Added some actual tests. - Actually added a copy of the GPL License to the package (as promised in the POD documentation). 0.04 2004-01-07 AMOLLOY - Applied patch from Dan Sully to make "startMainData" accessible from the Info interface. 0.03 2003-12-09 AMOLLOY - Added fix from Robert Moser II for problems with files with no comments. 0.01 2003-01-20 AMOLLOY - original version; created by h2xs 1.21 with options -XA -n Ogg::Vorbis::Header::PurePerl Ogg-Vorbis-Header-PurePerl-1.05/README0000644000175000017500000000212113751016137015637 0ustar davedaveOgg/Vorbis/Header/PurePerl version 1.0 ======================================= Ogg::Vorbis::Header::PurePerl - An object-oriented interface to Ogg Vorbis information and comment fields, implemented entirely in Perl. Intended to be a drop in replacement for Ogg::Vobis::Header. This module is intended to be a drop in replacement for Ogg::Vorbis::Header, implemented entirely in Perl. It provides an object-oriented interface to Ogg Vorbis information and comment fields. (NOTE: This module currently supports only read operations). INSTALLATION To install this module type the following: perl Makefile.PL make make test make install COPYRIGHT AND LICENCE Copyright (c) 2003, Andrew Molloy. All Rights Reserved. Copyright (c) 2005-2008, Dan Sully. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. A copy of this license is included with this module (LICENSE.GPL).