! Copyright (C) 2009 Tim Wawrzynczak ! See http://factorcode.org/license.txt for BSD license. USING: sequences io io.encodings.binary io.files io.pathnames strings kernel math io.mmap io.mmap.uchar accessors syntax combinators math.ranges unicode.categories byte-arrays prettyprint make ; IN: id3 ! tuples TUPLE: header version flags size ; TUPLE: frame frame-id flags size data ; :
( -- object ) header new ; : ( -- object ) frame new ; ! utility words : id3v2? ( mmap -- ? ) "ID3" head? ; : id3v1? ( mmap -- ? ) 128 tail-slice* "TAG" head? ; : >28bitword ( seq -- int ) 0 [ swap 7 shift bitor ] reduce ; ! frame details stuff : valid-frame-id? ( id -- ? ) [ [ digit? ] [ LETTER? ] bi or ] all? ; : read-frame-id ( mmap -- id ) 4 head-slice ; : read-frame-size ( mmap -- size ) [ 4 8 ] dip subseq ; : read-frame-flags ( mmap -- flags ) [ 8 10 ] dip subseq ; : read-frame-data ( frame mmap -- frame data ) over size>> 10 + 10 swap rot ; ! read whole frames : (read-frame) ( mmap -- frame ) [ ] dip { [ read-frame-id >string >>frame-id ] [ read-frame-flags >byte-array >>flags ] [ read-frame-size >28bitword >>size ] [ read-frame-data >string >>data ] } cleave ; : read-frame ( mmap -- frame/f ) dup read-frame-id valid-frame-id? [ (read-frame) ] [ drop f ] if ; : (read-frames) ( mmap -- mmap ) dup read-frame [ [ , ] [ size>> 10 + ] bi tail-slice (read-frames) ] when* ; : read-frames ( mmap -- seq ) [ (read-frames) ] { } make nip ; ! header stuff : read-header-supported-version? ( mmap -- ? ) 3 tail-slice [ { 4 } head? ] [ { 3 } head? ] bi or ; : read-header-flags ( mmap -- flags ) 5 swap nth ; : read-header-size ( mmap -- size ) 6 10 rot >28bitword ; : read-v2-header ( mmap -- id3header ) [
] dip { [ read-header-supported-version? >>version ] [ read-header-flags >>flags ] [ read-header-size >>size ] } cleave ; : drop-header ( mmap -- seq1 seq2 ) dup 10 tail-slice swap ; ! main stuff : read-v2-tag-data ( seq -- header frames ) drop-header read-v2-header swap read-frames ; : id3stuff ( path -- header/f frame/str ) [ { { [ dup id3v2? ] [ read-v2-tag-data ] } { [ dup id3v1? ] [ drop f "id3v1" ] } [ drop f "none" ] } cond ] with-mapped-uchar-file ; ! end