Però è una classe scritta in C#, dovrei convertirla di nuovo in java, o creare un binding.
Da questa pagina ho consultato come è formato l'header dei file flac, dunque con delle operazioni sui file binari bit a bit sono riuscito a creare questa classe che attualmente legge bene i file, modifica bene anche i file che hanno già una sezione vorbis comment, ma ancora non ho testato la modifica dei file che non hanno la suddetta sezione, e quindi sarà la caratteristica che implementerò al prossimo commit su git.
La pagina git è questa: https://github.com/standuptall/Flacreader, con due branch, uno quello principale (la classe è Flacreader.cs) e un'altro branch (grafica) che include una piccola interfaccia grafica. Anche se con git devo prenderci ancora la mano.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO; namespace it.albe { public class FlacReader { public static string vendor_string; public static Int32 user_comment_list_length; private string filepath; private bool data_written = false; private class _metadata { public struct _streaminfo { public bool presente; public const int code = 0x0; public bool ultimo; } public struct _padding { public bool presente; public const int code = 0x1; public bool ultimo; } public struct _application { public bool presente; public const int code = 0x2; public bool ultimo; } public struct _seektable { public bool presente; public const int code = 0x3; public bool ultimo; } public struct _vorbis_comment { public bool presente; public const int code = 0x4; public bool ultimo; } public struct _cuesheet { public bool presente; public const int code = 0x5; public bool ultimo; } public struct _picture { public bool presente; public const int code = 0x6; public bool ultimo; } public _streaminfo streaminfo; public _padding padding; public _application application; public _seektable seektable; public _vorbis_comment vorbis_comment; public _cuesheet cuesheet; public _picture picture; public const int ending_metadata_code = 0xF0; const int NUM_METADATA = 7; public _metadata() { streaminfo.presente = false; streaminfo.ultimo = false; padding.presente = false; padding.ultimo = false; application.presente = false; application.ultimo = false; seektable.presente = false; seektable.ultimo = false; vorbis_comment.presente = false; vorbis_comment.ultimo = false; cuesheet.presente = false; cuesheet.ultimo = false; picture.presente = false; picture.ultimo = false; } public void setMetadata(int code) { switch ((code<<1)>>1) //tolgo il bit più significativo { case _streaminfo.code: streaminfo.presente = true; break; case _padding.code: padding.presente = true; break; case _application.code: application.presente = true; break; case _seektable.code: seektable.presente = true; break; case _vorbis_comment.code: vorbis_comment.presente = true; break; case _cuesheet.code: cuesheet.presente = true; break; case _picture.code: picture.presente = true; break; } } public int getFlag(int flag) //devo controllare se è l'ultimo, così setto il bit più significativo a 1 { flag = ((flag << 1) >> 1); //tolgo il bit più significtivo if (picture.presente) picture.ultimo = true; else if (cuesheet.presente) cuesheet.ultimo = true; else if (vorbis_comment.presente) vorbis_comment.ultimo = true; else if (seektable.presente) seektable.ultimo = true; else if (application.presente) application.ultimo = true; else if (padding.presente) padding.ultimo = true; else if (streaminfo.presente) streaminfo.ultimo = true; switch (flag) { case _streaminfo.code: if (streaminfo.presente) flag += ending_metadata_code; break; case _padding.code: if (streaminfo.presente) flag += ending_metadata_code; break; case _application.code: if (streaminfo.presente) flag += ending_metadata_code; break; case _seektable.code: if (streaminfo.presente) flag += ending_metadata_code; break; case _vorbis_comment.code: if (streaminfo.presente) flag += ending_metadata_code; break; case _cuesheet.code: if (streaminfo.presente) flag += ending_metadata_code; break; case _picture.code: if (streaminfo.presente) flag += ending_metadata_code; break; } return flag; } } ; _metadata metadata; private int metadata_comments_length; public Dictionarycomments; public FlacReader(string filepath) { metadata_comments_length = 0; metadata = new _metadata(); comments = new Dictionary (); this.filepath = filepath; user_comment_list_length = 0; FileStream stream; stream = File.OpenRead(filepath); if (stream == null) throw new FileNotFoundException("Il file non esiste"); byte[] array = {0,0,0,0}; stream.Read(array,0,4); if (!((array[0]==0x66)&&(array[1]==0x4C)&&(array[2]==0x61)&&(array[3]==0x43))) //fLaC throw new Exception("Il file non è un file flac!"); byte flag; do { stream.Read(array,0,1); //mi sposto di 1 byte flag = array[0]; metadata.setMetadata(flag); stream.Read(array, 0, 3); //leggo tre byte per la lunghezza del metadata Int32 metadata_length = array[0] * 65536 + array[1] * 256 + array[2]; if (flag == 4 || flag == 132) //se è un vorbis comment cioè 00000100 oppure 10000100 { metadata_comments_length = metadata_length; caricaCommenti(stream); } else stream.Seek(metadata_length, SeekOrigin.Current); //mi sposto della lunghezza del metadata } while (!((flag>>7)==0x1)); //se il bit più significativo è uguale a uno vuol dire ch enon ci sono più metadata stream.Close(); } public void setVendor(string vendorName) { int vendor_string_length_old = vendor_string.Length; metadata_comments_length -= vendor_string_length_old;//tolgo la lunghezza iniziale vendor_string = vendorName; metadata_comments_length += vendor_string.Length; //e metto la nuova lunghezza del vendor string } public string getVendor() { return vendor_string; } public void addComment(string field, string value) { try { if (comments[field] != null) //se il commento già esiste { string val = comments[field]; metadata_comments_length -= (field.Length + val.Length + 1); //tolgo la lunghezza originaria metadata_comments_length -= 4; } } catch(KeyNotFoundException e) { comments[field] = value; user_comment_list_length++; metadata_comments_length += 4; //aggiungo 4 byte per memorizzare la lunghezza del comment sul file metadata_comments_length += field.Length + value.Length + 1; //aggiungo la lunghezza del commento più il simbolo uguale } } public void writeAll() //file esistente quindi riverso il contenuto su un file _temp { FileStream stream,streamWrite; stream = File.OpenRead(filepath); streamWrite = File.OpenWrite(filepath + "_temp"); byte[] array = { 0, 0, 0, 0 }; stream.Read(array, 0, 4); streamWrite.Write(array, 0, 4); byte flag; do { stream.Read(array, 0, 1); //mi sposto di 1 byte streamWrite.Write(array, 0, 1); //mi sposto di 1 byte flag = array[0]; stream.Read(array, 0, 3); //leggo tre byte per la lunghezza del metadata Int32 metadata_length = array[0] * 65536 + array[1] * 256 + array[2]; if (flag == 4 || flag == 132) //se è un vorbis comment cioè 00000100 oppure 10000100 { stream.Seek(metadata_length, SeekOrigin.Current); //mi sposto sul lettore della lunghezza del metadata array[0] = (byte) (metadata_comments_length >> 16); array[1] = (byte) (metadata_comments_length >> 8); array[2] = (byte)(metadata_comments_length); streamWrite.Write(array, 0, 3); //scrivo la nuova lunghezza del metadata scriviCommenti(streamWrite); } else { streamWrite.Write(array, 0, 3); //scrivo la lunghezza del metadata int i = 0; for (i = 0; (i+4)< metadata_length; i+=4) { stream.Read(array, 0, 4); streamWrite.Write(array, 0, 4); } /* scrivo i byte rimanenti */ stream.Read(array, 0, metadata_length-i); streamWrite.Write(array, 0, metadata_length -i); } } while (!((flag >> 7) == 0x1)); //se il bit più significativo è uguale a uno vuol dire ch enon ci sono più metadata /* scrivo tutto il rimanente */ byte[] chunk = new byte[10240]; int num = 0; while (true) { num = stream.Read(chunk, 0, 10240); streamWrite.Write(chunk, 0, num); if (num < 10240) { stream.Close(); streamWrite.Close(); return; } } } public void writeAll(String filename) //nuovo file { } private void caricaCommenti(Stream stream) { byte[] array = { 0, 0, 0, 0 }; stream.Read(array, 0, 4); uint vendor_length = (uint)((array[0])); //non capisco perché ma conta solo il primo byte byte[] stringa = new byte[1024]; stream.Read(stringa, 0, (int)vendor_length); vendor_string = System.Text.Encoding.UTF8.GetString(stringa,0,(int)vendor_length); stream.Read(array, 0, 4); //leggo il numero dei commenti uint number_of_comments = (uint)array[0]; for (uint i = 0; i < number_of_comments; i++) { stream.Read(array, 0, 4); //leggo il numero di caratteri da leggere uint comment_length = (uint)array[0]; stream.Read(stringa, 0, (int)comment_length); String comment = System.Text.Encoding.UTF8.GetString(stringa, 0,(int) comment_length); comments[comment.Split('=')[0]] = comment.Split('=')[1]; Array.Clear(stringa, 0, stringa.Length); } } private void scriviCommenti(Stream stream) { Int32 length = vendor_string.Length; byte[] array = { 0, 0, 0, 0 }; array[0] = (byte)(length); array[1] = 0; array[2] = 0; array[3] = 0; stream.Write(array, 0, 4); byte[] arrayName = System.Text.Encoding.UTF8.GetBytes(vendor_string.ToCharArray()); stream.Write(arrayName, 0, length); byte numcommenti = (byte)comments.Count; array[0] = (byte)(numcommenti); stream.Write(array, 0, 4); /* scrivo i commenti */ foreach (KeyValuePair entry in comments) { string comment = entry.Key + "=" + entry.Value; length = comment.Length; arrayName = System.Text.Encoding.UTF8.GetBytes(comment.ToCharArray()); array[0] = (byte)length; array[1] = 0; array[2] = 0; array[3] = 0; stream.Write(array, 0, 4); stream.Write(arrayName, 0, length); } data_written = true; } } }