Paste: id3 parser in joy

Author: inforichland
Mode: factor
Date: Mon, 6 Jul 2009 00:33:53
Plain Text |
(* id3lib.joy *) 

"seqlib" libload . (* for reverse *)

LIBRA

	_id3lib == true ;

HIDE

	(* helper functions *)
	open-read == "r" fopen ;
	seek-end == 2 fseek pop ; (* pop off the 'false' *)
	synchsafe == 0 [ [ 7 bitlshift ] dip bitor ] fold ;
	from-take == [drop] dip take ;
	chars-string == "" swap [swap cons] step reverse ;
	intlist-to-string == [0 = not] filter [chr] map chars-string ;

	(* constants *)
	v1-tag-place == -128 ;
	tag-header-ident-length == 3 ;
	v2-tag-header-length == 10 ;
	v2-tag-header-version-length == 2 ;
	v2-tag-header-flags-length == 1 ;
	v2-tag-header-size-length == 4 ;
	frame-header-length == 10 ;
	frame-id-length == 4 ;
	frame-size-length == 4 ;
	frame-flags-length == 2 ;

	(* file-type indicators *)
	v1-tag-header == ['T 'A 'G] ;
	v2-tag-header == ['I 'D '3] ;
	
	(* v2 functions *)
	read-ident == tag-header-ident-length fread ;
	read-version == v2-tag-header-version-length fread ;
	read-flags == v2-tag-header-flags-length fread ;
	read-size == v2-tag-header-size-length fread ;

	(* v1 functions *)
	read-title == 30 fread intlist-to-string ;
	read-artist == 30 fread intlist-to-string ;
	read-album == 30 fread intlist-to-string ;
	read-year == 4 fread intlist-to-string ;
	read-comment == 30 fread intlist-to-string ;
	read-genre == 1 fread ;
	(* ... n -- seq *)
	mklist == [] swap [cons] times ;

	(* quotations *)
	read-header == [[read-ident]
			[read-version]
			[read-flags]
			[read-size]] ;
	frame-header-quot == 
		[frame-header-length take]
		[[0 frame-id-length from-take]
		 [4 frame-size-length from-take]
		 [8 frame-flags-length from-take]] ;
	v1-data == [[read-title]
		    [read-artist]
		    [read-album]
		    [read-year]
		    [read-comment]
		    [read-genre]] ;

	(* fobj frsize -- fobj fsz all-data *)
	read-id3-data == dup [fread] dip swap ;

	(* seq -- seq frame-header *)
	read-frame-header == 
		frame-header-quot
		construct
		3 mklist ;

	(* x -- [x] *)
	quote == [] cons ;

	(* seq frame-header -- new-seq frame-header *)
	drop-header == [10 drop] dip ;

	(* seq header -- seq header frsz *)
	extract-frame-size == dup rest first synchsafe ;

	(* seq at -- seq1 seq2 *)
	split-at == dupd dup [take] dip swap [drop] dip ;

	(* data frame sz -- data *)
	read-frame-data == [split-at] dip cons 2 take reverse ;

	(* data frame sz -- new-data frame *)
	drop-frame-data == quote [drop] concat dip ;

	(* int-seq-seq -- char-seq-seq *)
	to-char-list == [[chr] map] map ;

	(* frame is, e.g. [ [TALB] [data] ] *)
	(* fsz all-data -- fsz rest-data frame *)
	read-frame == 
		read-frame-header 
		drop-header
		extract-frame-size swap (* sz data fsz frame *)
		read-frame-data 
		to-char-list
		[chars-string] map ;

	(* [[seq]] -- [[seq]] *)
	map-chars-to-strings ==
		[[chars-string] map] map ;

	(* filename -- header *)
	id3v2-header ==
		open-read dup (* fobj fobj *)
		[dup] (* save the file onto the temp stack *)
		read-header
		construct (* run 4 quotations *)
		4 mklist (* cons them up *)	
		3 at synchsafe read-id3-data
		[fclose] dipd ;

IN

	(* filename -- t/f *)
	is-id3v1 == 
		open-read (* fobj *)
		[v1-tag-place seek-end] (* fobj *)
		[tag-header-ident-length fread] (* fobj arr *)
		cleave 
		v1-tag-header equal (* arr header *)
		[fclose] dip ;

	(* fobj -- [v1-data] *)
	read-v1-data == open-read
		v1-tag-place 3 + seek-end
		[dup]
		v1-data
		construct
		6 mklist
		[fclose] dip ;

	(* filename -- t/f *)
	is-id3v2 ==
		open-read dup (* fobj fobj *)
		tag-header-ident-length fread
		v2-tag-header equal
		[fclose] dip ;

	(* sz data -- frames *)
	read-v2-frames == id3v2-header []
		[[[small] [first 0 =] cleave or] dip swap]
		[popd popd] (* remove extra crap and sz *)
		[[read-frame] dip cons]
		tailrec .

New Annotation

Summary:
Author:
Mode:
Body: