/* * Cuelib library for manipulating cue sheets. * Copyright (C) 2007-2008 Jan-Willem van den Broek * * This library 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.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package jwbroek.cuelib; import java.util.Set; import java.util.logging.Logger; /** * Class for serializing a {@link jwbroek.cuelib.CueSheet CueSheet} back to a string representation. Does the * inverse job of CueParser. * * @author jwbroek */ public class CueSheetSerializer { /** * Character sequence for a single indentation level. */ private String indentationValue = " "; /** * The logger for this class. */ private final static Logger logger = Logger.getLogger(CueSheetSerializer.class.getCanonicalName()); /** * Create a default CueSheetSerializer. */ public CueSheetSerializer() { CueSheetSerializer.logger.entering(CueSheetSerializer.class.getCanonicalName(), "CueSheetSerializer()"); CueSheetSerializer.logger.exiting(CueSheetSerializer.class.getCanonicalName(), "CueSheetSerializer()"); } /** * Create a CueSheetSerializer with the specified indentationValue. * * @param indentationValue This String will be used for indentation. */ public CueSheetSerializer(final String indentationValue) { CueSheetSerializer.logger.entering (CueSheetSerializer.class.getCanonicalName(), "CueSheetSerializer(String)", indentationValue); CueSheetSerializer.logger.config("Setting CueSheetSerializer indentation value to: '" + indentationValue + "'"); this.indentationValue = indentationValue; CueSheetSerializer.logger.exiting(CueSheetSerializer.class.getCanonicalName(), "CueSheetSerializer(String)"); } /** * Get a textual representation of the cue sheet. If the cue sheet was parsed, then the output * of this method is not necessarily identical to the parsed sheet, though it will contain the * same data. Fields may appear in a different order, whitespace may change, comments may be * gone, etc. * * @param cueSheet The CueSheet to serialize. * @return A textual representation of the cue sheet. */ public String serializeCueSheet(final CueSheet cueSheet) { CueSheetSerializer.logger.entering (CueSheetSerializer.class.getCanonicalName(), "serializeCueSheet(CueSheet)", cueSheet); StringBuilder builder = new StringBuilder(); serializeCueSheet(builder, cueSheet, ""); String result = builder.toString(); CueSheetSerializer.logger.exiting(CueSheetSerializer.class.getCanonicalName(), "serializeCueSheet(CueSheet)", result); return result; } /** * Serialize the CueSheet. * * @param builder The StringBuilder to serialize to. * @param cueSheet The CueSheet to serialize. * @param indentation The current indentation. */ private void serializeCueSheet(final StringBuilder builder, final CueSheet cueSheet, final String indentation) { CueSheetSerializer.logger.entering (CueSheetSerializer.class.getCanonicalName() , "serializeCueSheet(StringBuilder,CueSheet,String)" , new Object[]{builder, cueSheet, indentation} ); CueSheetSerializer.logger.fine("Serializing cue sheet to cue format."); addField(builder, "REM GENRE", indentation, cueSheet.getGenre()); addField(builder, "REM DATE", indentation, cueSheet.getYear()); addField(builder, "REM DISCID", indentation, cueSheet.getDiscid()); addField(builder, "REM COMMENT", indentation, cueSheet.getComment()); addField(builder, "CATALOG", indentation, cueSheet.getCatalog()); addField(builder, "PERFORMER", indentation, cueSheet.getPerformer()); addField(builder, "TITLE", indentation, cueSheet.getTitle()); addField(builder, "SONGWRITER", indentation, cueSheet.getSongwriter()); addField(builder, "CDTEXTFILE", indentation, cueSheet.getCdTextFile()); for (FileData fileData : cueSheet.getFileData()) { serializeFileData(builder, fileData, indentation); } CueSheetSerializer.logger.exiting (CueSheetSerializer.class.getCanonicalName(), "serializeCueSheet(StringBuilder,CueSheet,String)"); } /** * Serialize the FileData. * * @param builder The StringBuilder to serialize to. * @param fileData The FileData to serialize. * @param indentation The current indentation. */ private void serializeFileData(final StringBuilder builder, final FileData fileData, final String indentation) { CueSheetSerializer.logger.entering (CueSheetSerializer.class.getCanonicalName() , "serializeFileData(StringBuilder,FileData,String)" , new Object[]{builder, fileData, indentation} ); builder.append(indentation).append("FILE"); if (fileData.getFile() != null) { builder.append(' ').append(quoteIfNecessary(fileData.getFile())); } if (fileData.getFileType() != null) { builder.append(' ').append(quoteIfNecessary(fileData.getFileType())); } builder.append('\n'); for (TrackData trackData : fileData.getTrackData()) { serializeTrackData(builder, trackData, indentation + this.getIndentationValue()); } CueSheetSerializer.logger.exiting (CueSheetSerializer.class.getCanonicalName(), "serializeFileData(StringBuilder,FileData,String)"); } /** * Serialize the TrackData. * * @param builder The StringBuilder to serialize to. * @param trackData The TrackData to serialize. * @param indentation The current indentation. */ private void serializeTrackData(final StringBuilder builder , final TrackData trackData , final String indentation ) { CueSheetSerializer.logger.entering (CueSheetSerializer.class.getCanonicalName() , "serializeTrackData(StringBuilder,TrackData,String)" , new Object[]{builder, trackData, indentation} ); builder.append(indentation).append("TRACK"); if (trackData.getNumber() > -1) { builder.append(' ').append(String.format("%1$02d", trackData.getNumber())); } if (trackData.getDataType() != null) { builder.append(' ').append(quoteIfNecessary(trackData.getDataType())); } builder.append('\n'); String childIndentation = indentation + this.getIndentationValue(); addField(builder, "ISRC", childIndentation, trackData.getIsrcCode()); addField(builder, "PERFORMER", childIndentation, trackData.getPerformer()); addField(builder, "TITLE", childIndentation, trackData.getTitle()); addField(builder, "SONGWRITER", childIndentation, trackData.getSongwriter()); addField(builder, "PREGAP", childIndentation, trackData.getPregap()); addField(builder, "POSTGAP", childIndentation, trackData.getPostgap()); if (trackData.getFlags().size() > 0) { serializeFlags(builder, trackData.getFlags(), childIndentation); } for (Index index : trackData.getIndices()) { serializeIndex(builder, index, childIndentation); } CueSheetSerializer.logger.exiting (CueSheetSerializer.class.getCanonicalName() , "serializeTrackData(StringBuilder,TrackData,String)" ); } /** * Serialize the flags. * * @param builder The StringBuilder to serialize to. * @param flags The flags to serialize. * @param indentation The current indentation. */ private void serializeFlags(final StringBuilder builder, final Set<String> flags, final String indentation) { CueSheetSerializer.logger.entering (CueSheetSerializer.class.getCanonicalName() , "serializeFlags(StringBuilder,Set<String>,String)" , new Object[]{builder, flags, indentation} ); builder.append(indentation).append("FLAGS"); for (String flag : flags) { builder.append(' ').append(quoteIfNecessary(flag)); } builder.append('\n'); CueSheetSerializer.logger.exiting (CueSheetSerializer.class.getCanonicalName(), "serializeFlags(StringBuilder,Set<String>,String)"); } /** * Serialize the index. * * @param builder The StringBuilder to serialize to. * @param index The Index to serialize. * @param indentation The current indentation. */ private void serializeIndex(final StringBuilder builder, final Index index, final String indentation) { CueSheetSerializer.logger.entering (CueSheetSerializer.class.getCanonicalName() , "serializeIndex(StringBuilder,Index,String)" , new Object[]{builder, index, indentation} ); builder.append(indentation).append("INDEX"); if (index.getNumber() > -1) { builder.append(' ').append(String.format("%1$02d", index.getNumber())); } if (index.getPosition() != null) { builder.append(' ').append(formatPosition(index.getPosition())); } builder.append('\n'); CueSheetSerializer.logger.exiting (CueSheetSerializer.class.getCanonicalName(), "serializeIndex(StringBuilder,Index,String)"); } /** * Format the specified position. * * @param position * @return The formatted position. */ private String formatPosition(final Position position) { CueSheetSerializer.logger.entering(CueSheetSerializer.class.getCanonicalName(), "formatPosition(Position)", position); String result = String.format ("%1$02d:%2$02d:%3$02d", position.getMinutes(), position.getSeconds(), position.getFrames()); CueSheetSerializer.logger.exiting(CueSheetSerializer.class.getCanonicalName(), "formatPosition(Position)", result); return result; } /** * Add a field to the builder. The field is only added if the value is != null. * * @param cueBuilder * @param command The command to add. * @param value The value to add. Will be formatted as per formatPosition(Position). * @param indentation The indentation for this field. */ private void addField(final StringBuilder cueBuilder , final String command , final String indentation , final Position value ) { CueSheetSerializer.logger.entering (CueSheetSerializer.class.getCanonicalName() , "addField(StringBuilder,String,String,Position)" , new Object[]{cueBuilder, command, indentation, value} ); if (value != null) { cueBuilder.append(indentation) .append(command) .append(' ') .append(formatPosition(value)) .append('\n'); } CueSheetSerializer.logger.exiting (CueSheetSerializer.class.getCanonicalName() , "addField(StringBuilder,String,String,Position)" ); } /** * Add a field to the builder. The field is only added if the value is != null. * * @param cueBuilder * @param command The command to add. * @param value The value to add. * @param indentation The indentation for this field. */ private void addField(final StringBuilder cueBuilder , final String command , final String indentation , final String value ) { CueSheetSerializer.logger.entering (CueSheetSerializer.class.getCanonicalName() , "addField(StringBuilder,String,String,String)" , new Object[]{cueBuilder, command, indentation, value} ); if (value != null) { cueBuilder.append(indentation) .append(command) .append(' ') .append(quoteIfNecessary(value)) .append('\n'); } CueSheetSerializer.logger.exiting (CueSheetSerializer.class.getCanonicalName(), "addField(StringBuilder,String,String,String)"); } /** * Add a field to the builder. The field is only added if the value is > -1. * * @param cueBuilder * @param command The command to add. * @param value The value to add. * @param indentation The indentation for this field. */ private void addField(final StringBuilder cueBuilder , final String command , final String indentation , final int value ) { CueSheetSerializer.logger.entering (CueSheetSerializer.class.getCanonicalName() , "addField(StringBuilder,String,String,int)" , new Object[]{cueBuilder, command, indentation, value} ); if (value > -1) { cueBuilder.append(indentation) .append(command) .append(' ') .append("" + value) .append('\n'); } CueSheetSerializer.logger.exiting (CueSheetSerializer.class.getCanonicalName(), "addField(StringBuilder,String,String,int)"); } /** * Enclose the string in double quotes if it contains whitespace. * * @param input * @return The input string, which will be surrounded in double quotes if it contains any whitespace. */ private String quoteIfNecessary(final String input) { CueSheetSerializer.logger.entering(CueSheetSerializer.class.getCanonicalName(), "quoteIfNecessary(String)", input); // Search for whitespace for (int index = 0; index < input.length(); index++) { if (Character.isWhitespace(input.charAt(index))) { String result = '"' + input + '"'; logger.exiting(CueSheetSerializer.class.getCanonicalName(), "quoteIfNecessary(String)", result); return result; } } CueSheetSerializer.logger.exiting(CueSheetSerializer.class.getCanonicalName(), "quoteIfNecessary(String)", input); return input; } /** * Get the character sequence for a single indentation value. * * @return The character sequence for a single indentation value. */ public String getIndentationValue() { CueSheetSerializer.logger.entering(CueSheetSerializer.class.getCanonicalName(), "getIndentationValue()"); CueSheetSerializer.logger.exiting (CueSheetSerializer.class.getCanonicalName(), "getIndentationValue()", this.indentationValue); return this.indentationValue; } /** * Set the character sequence for a single indentation value. * * @param indentationValue The character sequence for a single indentation value. */ public void setIndentationValue(final String indentationValue) { CueSheetSerializer.logger.entering (CueSheetSerializer.class.getCanonicalName(), "setIndentationValue(String)", indentationValue); this.indentationValue = indentationValue; CueSheetSerializer.logger.exiting(CueSheetSerializer.class.getCanonicalName(), "setIndentationValue()"); } }