package org.farng.mp3.filename; import java.util.Iterator; import org.farng.mp3.MP3File; import org.farng.mp3.TagException; import org.farng.mp3.TagOptionSingleton; import org.farng.mp3.TagUtility; import org.farng.mp3.id3.ID3v2_4; /** * This class builds a <code>FilenameTag</code>. The main method to call is <code>createFilenameTagFromMP3File</code>. * Other methods are public in order to update parts of the tag if needed. * * @author Eric Farng * @version $Revision: 2374 $ */ public class FilenameTagBuilder { private FilenameTagBuilder() { super(); } /** * Creates a FilenameComposite tree with the given string. It is parsed according to the different values that can * be set in <code>TagOptionSingleton</code> class * * @param token filename to parse * * @return FilenameComposite tree representing the given token. * * @throws TagException is thrown if there are unmatched parenthesis */ public static AbstractFilenameComposite createCompositeFromToken(final String token) throws TagException { String[] splitToken; AbstractFilenameComposite composite = null; final AbstractFilenameComposite beforeComposite; final AbstractFilenameComposite middleComposite; final AbstractFilenameComposite afterComposite; splitToken = parseParenthesis(token); if (splitToken != null) { composite = new FilenameParenthesis(); ((FilenameParenthesis) composite).setOpenDelimiter(splitToken[0]); beforeComposite = createCompositeFromToken(splitToken[2]); ((FilenameParenthesis) composite).setBeforeComposite(beforeComposite); middleComposite = createCompositeFromToken(splitToken[3]); ((FilenameParenthesis) composite).setMiddleComposite(middleComposite); afterComposite = createCompositeFromToken(splitToken[4]); ((FilenameParenthesis) composite).setAfterComposite(afterComposite); composite.setOriginalToken(token); return composite; } splitToken = parseDelimiter(token); if (splitToken != null) { composite = new FilenameDelimiter(); ((FilenameDelimiter) composite).setDelimiter(splitToken[0]); beforeComposite = createCompositeFromToken(splitToken[1]); ((FilenameDelimiter) composite).setBeforeComposite(beforeComposite); afterComposite = createCompositeFromToken(splitToken[2]); ((FilenameDelimiter) composite).setAfterComposite(afterComposite); composite.setOriginalToken(token); return composite; } splitToken = parseStartWordDelimiter(token); if (splitToken != null) { composite = new FilenameStartWordDelimiter(); ((FilenameDelimiter) composite).setDelimiter(splitToken[0]); beforeComposite = createCompositeFromToken(splitToken[1]); ((FilenameStartWordDelimiter) composite).setBeforeComposite(beforeComposite); afterComposite = createCompositeFromToken(splitToken[2]); ((FilenameStartWordDelimiter) composite).setAfterComposite(afterComposite); composite.setOriginalToken(token); return composite; } splitToken = parseEndWordDelimiter(token); if (splitToken != null) { composite = new FilenameEndWordDelimiter(); ((FilenameDelimiter) composite).setDelimiter(splitToken[0]); beforeComposite = createCompositeFromToken(splitToken[1]); ((FilenameEndWordDelimiter) composite).setBeforeComposite(beforeComposite); afterComposite = createCompositeFromToken(splitToken[2]); ((FilenameEndWordDelimiter) composite).setAfterComposite(afterComposite); composite.setOriginalToken(token); return composite; } if (token != null && token.trim().length() > 0) { composite = new FilenameToken(); ((FilenameToken) composite).setToken(token.trim()); composite.setOriginalToken(token); return composite; } return composite; } public static FilenameTag createEmptyFilenameTag() { final FilenameTag filenameTag = new FilenameTag(); filenameTag.setId3tag(new ID3v2_4()); return filenameTag; } /** * This method will create a complete FilenameTag from the given mp3File and from the options in * <code>TagOptionSingleton</code>. This will call all other necessary methods in this builder class. * * @param mp3File MP3 file to create the FilenameTag from. * * @return FilenameTag of the mp3File argument * * @throws Exception is thrown on any IO errors, or parsing errors such as unmatched parenthesis */ public static FilenameTag createFilenameTagFromMP3File(final MP3File mp3File) throws Exception { FilenameTag filenameTag = null; if (mp3File.getMp3file() != null) { filenameTag = new FilenameTag(); final AbstractFilenameComposite composite; final ID3v2_4 id3tag; String filename = mp3File.getMp3file().getName(); final int index = filename.lastIndexOf((int) '.'); if (index >= 0) { filenameTag.setExtension(filename.substring(index + 1)); filename = filename.substring(0, index); } // create composite composite = createCompositeFromToken(filename); updateCompositeFromAllTag(composite, mp3File); updateCompositeFromAllOption(composite); // create tag id3tag = composite.createId3Tag(); // assign values; filenameTag.setMp3file(mp3File); filenameTag.setComposite(composite); filenameTag.setId3tag(id3tag); } return filenameTag; } /** * Traverse the composite and set the class field to match keywords found in TagOptionSingleton. * * @param composite composite to update. */ public static void updateCompositeFromAllOption(final AbstractFilenameComposite composite) { final Iterator iterator = TagOptionSingleton.getInstance().getKeywordIterator(); while (iterator.hasNext()) { composite.matchAgainstKeyword((Class) iterator.next()); } } /** * Traverse the composite and set the class field to match frames from all three other tags that are already found * in the MP3 file. * * @param composite composite to update * @param mp3File mp3file to match all it's tags against. */ public static void updateCompositeFromAllTag(final AbstractFilenameComposite composite, final MP3File mp3File) { composite.matchAgainstTag(mp3File.getID3v1Tag()); composite.matchAgainstTag(mp3File.getID3v2Tag()); composite.matchAgainstTag(mp3File.getLyrics3Tag()); } /** * Parses the given token into two halves with the delimiters found in <code> TagOptionSingleton</code> * * @param token token to split * * @return index 0 is the delimiter. index 1 and 2 are the before and after tokens respectively. */ private static String[] parseDelimiter(final String token) { String[] tokenArray = null; if (token != null && token.length() > 0) { final Iterator iterator = TagOptionSingleton.getInstance().getFilenameDelimiterIterator(); int index; String delimiter; while (iterator.hasNext()) { delimiter = (String) iterator.next(); index = token.indexOf(delimiter); if (index >= 0) { tokenArray = new String[3]; tokenArray[0] = delimiter; tokenArray[1] = token.substring(0, index); tokenArray[2] = token.substring(index + delimiter.length()); } } } return tokenArray; } /** * Parses the given token into two halves with the delimiters found in <code> TagOptionSingleton</code> * * @param token token to split * * @return index 0 is the delimiter. index 1 and 2 are the before and after tokens respectively. */ private static String[] parseEndWordDelimiter(final String token) { String[] tokenArray = null; if (token != null && token.length() > 0) { final Iterator iterator = TagOptionSingleton.getInstance().getEndWordDelimiterIterator(); int index; String delimiter; while (iterator.hasNext()) { delimiter = (String) iterator.next(); if (token.endsWith(delimiter)) { index = token.substring(0, token.length() - delimiter.length()).indexOf(delimiter); } else { index = token.indexOf(delimiter); } if (index > 0) { tokenArray = new String[3]; tokenArray[0] = delimiter; tokenArray[1] = token.substring(0, index); tokenArray[2] = token.substring(index); } } } return tokenArray; } /** * Given a specific token, parse it into halves according to the <code>TagOptionSingleton</code> * * @param token token to split. * * @return index 0 and 1 are the parenthesis delimiters. index 2, 3, 4 are before, middle, and after respectively. */ private static String[] parseParenthesis(final String token) throws TagException { String[] tokenArray = null; if (token != null && token.length() > 0) { final TagOptionSingleton option = TagOptionSingleton.getInstance(); String tempOpen; String open = ""; final String close; int openIndex = token.length(); int tempIndex; final int closeIndex; final Iterator iterator = option.getOpenParenthesisIterator(); // find first parenthesis while (iterator.hasNext()) { tempOpen = (String) iterator.next(); tempIndex = token.indexOf(tempOpen); if (tempIndex >= 0 && tempIndex < openIndex) { openIndex = tempIndex; open = tempOpen; } } // we have a parenthesis if (openIndex >= 0 && openIndex < token.length()) { close = option.getCloseParenthesis(open); closeIndex = TagUtility.findMatchingParenthesis(token, openIndex); if (closeIndex < 0) { throw new TagException("Unmatched parenthesis in \"" + token + "\" at position : " + openIndex); } tokenArray = new String[5]; tokenArray[0] = open; tokenArray[1] = close; tokenArray[2] = token.substring(0, openIndex); tokenArray[3] = token.substring(openIndex + open.length(), closeIndex); tokenArray[4] = token.substring(closeIndex + close.length()); } } return tokenArray; } /** * Parses the given token into two halves with the delimiters found in <code> TagOptionSingleton</code> * * @param token token to split * * @return index 0 is the delimiter. index 1 and 2 are the before and after tokens respectively. */ private static String[] parseStartWordDelimiter(final String token) { String[] tokenArray = null; if (token != null && token.length() > 0) { final Iterator iterator = TagOptionSingleton.getInstance().getStartWordDelimiterIterator(); int index; String delimiter; while (iterator.hasNext()) { delimiter = (String) iterator.next(); if (token.startsWith(delimiter)) { index = token.indexOf(delimiter, delimiter.length()); } else { index = token.indexOf(delimiter); } if (index > 0) { tokenArray = new String[3]; tokenArray[0] = delimiter; tokenArray[1] = token.substring(0, index); tokenArray[2] = token.substring(index); } } } return tokenArray; } }