123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330(*
* Copyright 2007-2011 Romain Beauxis
*
* This file is part of ocaml-taglib.
*
* ocaml-taglib is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* ocaml-taglib 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 Lesser General Public License
* along with ocaml-taglib; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* As a special exception to the GNU Library General Public License, you may
* link, statically or dynamically, a "work that uses the Library" with a publicly
* distributed version of the Library to produce an executable file containing
* portions of the Library, and distribute that executable file under terms of
* your choice, without any of the additional requirements listed in clause 6
* of the GNU Library General Public License.
* By "a publicly distributed version of the Library", we mean either the unmodified
* Library as distributed by The Savonet Team, or a modified version of the Library that is
* distributed under the conditions defined in clause 3 of the GNU Library General
* Public License. This exception does not however invalidate any other reasons why
* the executable file might be covered by the GNU Library General Public License.
*
*)(* @author Romain Beauxis *)externalinit:unit->unit="caml_taglib_init"let()=Callback.register_exception"taglib_exn_not_found"Not_found;init()typetagtype'at='a*('a->tag)externalversion:unit->string="caml_taglib_version"letversion=version()moduleFile=structtypetaglib_filetypeaudiopropertiestypefile_type=[`Autodetect|`Mpeg|`OggVorbis|`OggOpus|`Flac|`Mpc|`OggFlac|`WavPack|`Speex|`TrueAudio|`Mp4|`Asf]type'afileref={file_type:'a;mutabletaglib_file:taglib_fileoption;}constraint'a=[<file_type](** Type for a file. *)type'afile_tag='afilereftype'afile='afilereftexceptionInvalid_fileexceptionClosedexceptionNot_implementedlet_=Callback.register_exception"taglib_exn_invalid_file"Invalid_file;Callback.register_exception"taglib_exn_not_implemented"Not_implementedexternalopen_file:file_type->string->taglib_file="caml_taglib_file_new"externalclose_file:taglib_file->unit="caml_taglib_file_free"letclose_file(d,_)=matchdwith|{taglib_file=None;_}->()|{taglib_file=Somef;_}->close_filef;d.taglib_file<-Noneexternalfile_tag:taglib_file->tag="caml_taglib_file_tag"externalfile_audioproperties:taglib_file->audioproperties="caml_taglib_file_audioproperties"letget_taglib_filef=matchfwith|{taglib_file=None;_}->raiseClosed|{taglib_file=Somef;_}->fexternalfile_save:taglib_file->bool="caml_taglib_file_save"letfile_save(f,_)=file_save(get_taglib_filef)letfile_type(d,_)=matchdwith{taglib_file=None;_}->raiseClosed|_->d.file_typeletopen_filefile_typename=(* Test whether file exist to avoid library issue.
See: http://bugs.debian.org/454732 *)begintryignore(Unix.statname)with_->raiseNot_foundend;letf=open_filefile_typenameinletfile={taglib_file=Somef;file_type}inletfile=(file,funf->matchfwith|{taglib_file=None;_}->raiseClosed|{taglib_file=Somef;_}->file_tagf)inGc.finaliseclose_filefile;fileexternalproperties:taglib_file->(string->string->unit)->unit="caml_taglib_file_get_properties"letproperties(f,_)=letf=get_taglib_filefinletprops=Hashtbl.create5inletfnkeyvalue=letvalues=tryHashtbl.findpropskeywithNot_found->[]inHashtbl.replacepropskey(value::values)inpropertiesffn;propsexternalset_properties:taglib_file->(string*stringarray)array->unit="caml_taglib_file_set_properties"letset_properties(f,_)props=letf=get_taglib_filefinletprops=Hashtbl.fold(funkeyvaluesprops->(key,Array.of_listvalues)::props)props[]inset_propertiesf(Array.of_listprops)externalaudioproperties_get_int:audioproperties->string->int="caml_taglib_audioproperties_get_int"letaudioproperties_get_int(f,_)s=letf=get_taglib_filefinaudioproperties_get_int(file_audiopropertiesf)sletaudioproperties_lengthp=audioproperties_get_intp"length"letaudioproperties_bitratep=audioproperties_get_intp"bitrate"letaudioproperties_sampleratep=audioproperties_get_intp"samplerate"letaudioproperties_channelsp=audioproperties_get_intp"channels"endlettag_extract(x,f)=fxexternaltag_get_string:tag->string->string="caml_taglib_tag_get_string"lettag_get_stringds=tag_get_string(tag_extractd)slettag_titlet=tag_get_stringt"title"lettag_artistt=tag_get_stringt"artist"lettag_albumt=tag_get_stringt"album"lettag_commentt=tag_get_stringt"comment"lettag_genret=tag_get_stringt"genre"externaltag_get_int:tag->string->int="caml_taglib_tag_get_int"lettag_get_intds=tag_get_int(tag_extractd)slettag_yeart=tag_get_intt"year"lettag_trackt=tag_get_intt"track"externaltag_set_string:tag->string->string->unit="caml_taglib_tag_set_string"lettag_set_stringtsv=tag_set_string(tag_extractt)svlettag_set_titlet=tag_set_stringt"title"lettag_set_artistt=tag_set_stringt"artist"lettag_set_albumt=tag_set_stringt"album"lettag_set_commentt=tag_set_stringt"comment"lettag_set_genret=tag_set_stringt"genre"externaltag_set_int:tag->string->int->unit="caml_taglib_tag_set_int"lettag_set_inttsv=tag_set_int(tag_extractt)svlettag_set_yeart=tag_set_intt"year"lettag_set_trackt=tag_set_intt"track"moduleInline=structmoduleId3v2=structtypestate=[`Invalid|`Parsed|`Valid]type'aid3v2_tag=unitconstraint'a=[<state]type'aid3v2='aid3v2_tagttypeframe_type=stringtypeframe_text=stringexternalinit:unit->tag="caml_taglib_id3v2_init"letinit()=lett=init()in((),fun()->t)externalheader_size:unit->int="caml_taglib_id3v2_header_len"letheader_size=header_size()letgrab_tag((),f)=f()externalparse_header:tag->string->unit="caml_taglib_id3v2_parse_header"externaltag_size:tag->int="caml_taglib_id3v2_tag_size"lettag_sizet=tag_size(grab_tagt)letparse_headerth=ifString.lengthh<header_sizethenfailwith"header string too short.";parse_header(grab_tagt)h;iftag_sizet<=header_sizethenfailwith"invalid header";texternalparse_tag:tag->string->unit="caml_taglib_id3v2_parse_tag"letparse_tagth=ifString.lengthh<tag_sizetthenfailwith"tag data too short.";parse_tag(grab_tagt)h;texternalrender:tag->bytes="caml_taglib_id3v2_render"letrendert=Bytes.unsafe_to_string(render(grab_tagt))externalattach_frame:tag->string->string->unit="caml_taglib_id3v2_attach_frame"letattach_frametlc=attach_frame(grab_tagt)lc;tlettag_set_titlets=tag_set_titlets;tlettag_set_artistts=tag_set_artistts;tlettag_set_albumts=tag_set_albumts;tlettag_set_commentts=tag_set_commentts;tlettag_set_genrets=tag_set_genrets;tlettag_set_yearts=tag_set_yearts;tlettag_set_trackts=tag_set_trackts;tendendtypefile_type=|Mpeg|OggVorbis|OggOpus|Flac|Mpc|OggFlac|WavPack|Speex|TrueAudio|Mp4|AsfexceptionClosedexceptionNot_implementedletset_strings_unicode_=()letopen_file?file_typef=letfx=File.open_filexfinmatchfile_typewith|None->f`Autodetect|Somet->(matchtwith|Mpeg->f`Mpeg|OggVorbis->f`OggVorbis|OggOpus->f`OggOpus|Flac->f`Flac|Mpc->f`Mpc|OggFlac->f`OggFlac|WavPack->f`WavPack|Speex->f`Speex|TrueAudio->f`TrueAudio|Mp4->f`Mp4|Asf->f`Asf)letwft=tryftwith|File.Closed->raiseClosed|File.Not_implemented->raiseNot_implementedletaudioproperties_length=wFile.audioproperties_lengthletaudioproperties_bitrate=wFile.audioproperties_bitrateletaudioproperties_samplerate=wFile.audioproperties_samplerateletaudioproperties_channels=wFile.audioproperties_channelsletclose_file=wFile.close_fileletfile_save=wFile.file_save