fix up escaping of strings in TOC files (suggested by andreas ruge)
[ardour.git] / libs / ardour / export_handler.cc
index f34e8c326b498f5144316e10b47c59a3ef3ab9f0..0653185e877b6a7e9a088f6002720d822094d439 100644 (file)
@@ -237,6 +237,17 @@ void
 ExportHandler::finish_timespan ()
 {
        while (config_map.begin() != timespan_bounds.second) {
+
+               ExportFormatSpecPtr fmt = config_map.begin()->second.format;
+
+               if (fmt->with_cue()) {
+                       export_cd_marker_file (current_timespan, fmt, config_map.begin()->second.filename->get_path(fmt), CDMarkerCUE);
+               } 
+
+               if (fmt->with_toc()) {
+                       export_cd_marker_file (current_timespan, fmt, config_map.begin()->second.filename->get_path(fmt), CDMarkerTOC);
+               }
+
                config_map.erase (config_map.begin());
        }
 
@@ -255,13 +266,7 @@ void
 ExportHandler::export_cd_marker_file (ExportTimespanPtr timespan, ExportFormatSpecPtr file_format,
                                       std::string filename, CDMarkerFormat format)
 {
-       string filepath;
-       string basename = Glib::path_get_basename(filename);
-
-       size_t ext_pos = basename.rfind('.');
-       if (ext_pos != string::npos) {
-               basename = basename.substr(0, ext_pos); /* strip file extension, if there is one */
-       }
+       string filepath = get_cd_marker_filename(filename, format);
 
        void (ExportHandler::*header_func) (CDMarkerStatus &);
        void (ExportHandler::*track_func) (CDMarkerStatus &);
@@ -269,13 +274,11 @@ ExportHandler::export_cd_marker_file (ExportTimespanPtr timespan, ExportFormatSp
 
        switch (format) {
          case CDMarkerTOC:
-               filepath = Glib::build_filename(Glib::path_get_dirname(filename), basename + ".toc");
                header_func = &ExportHandler::write_toc_header;
                track_func = &ExportHandler::write_track_info_toc;
                index_func = &ExportHandler::write_index_info_toc;
                break;
          case CDMarkerCUE:
-               filepath = Glib::build_filename(Glib::path_get_dirname(filename), basename + ".cue");
                header_func = &ExportHandler::write_cue_header;
                track_func = &ExportHandler::write_track_info_cue;
                index_func = &ExportHandler::write_index_info_cue;
@@ -369,6 +372,24 @@ ExportHandler::export_cd_marker_file (ExportTimespanPtr timespan, ExportFormatSp
        }
 }
 
+string
+ExportHandler::get_cd_marker_filename(std::string filename, CDMarkerFormat format)
+{
+       /* do not strip file suffix because there may be more than one format, 
+          and we do not want the CD marker file from one format to overwrite
+          another (e.g. foo.wav.cue > foo.aiff.cue)
+       */
+
+       switch (format) {
+         case CDMarkerTOC:
+               return filename + ".toc";
+         case CDMarkerCUE:
+               return filename + ".cue";
+         default:
+               return filename + ".marker"; // Should not be reached when actually creating a file
+       }
+}
+
 void
 ExportHandler::write_cue_header (CDMarkerStatus & status)
 {
@@ -419,7 +440,8 @@ ExportHandler::write_toc_header (CDMarkerStatus & status)
 
        status.out << "CD_DA" << endl;
        status.out << "CD_TEXT {" << endl << "  LANGUAGE_MAP {" << endl << "    0 : EN" << endl << "  }" << endl;
-       status.out << "  LANGUAGE 0 {" << endl << "    TITLE \"" << title << "\"" << endl << "  }" << endl << "}" << endl;
+       status.out << "  LANGUAGE 0 {" << endl << "    TITLE " << toc_escape_string (title) << endl ;
+       status.out << "    PERFORMER \"\"" << endl << "  }" << endl << "}" << endl;
 }
 
 void
@@ -454,8 +476,8 @@ ExportHandler::write_track_info_cue (CDMarkerStatus & status)
                status.out << "    PERFORMER \"" <<  status.marker->cd_info["performer"] << "\"" << endl;
        }
 
-       if (status.marker->cd_info.find("string_composer") != status.marker->cd_info.end()) {
-               status.out << "    SONGWRITER \"" << status.marker->cd_info["string_composer"]  << "\"" << endl;
+       if (status.marker->cd_info.find("composer") != status.marker->cd_info.end()) {
+               status.out << "    SONGWRITER \"" << status.marker->cd_info["composer"]  << "\"" << endl;
        }
 
        if (status.track_position != status.track_start_frame) {
@@ -492,12 +514,17 @@ ExportHandler::write_track_info_toc (CDMarkerStatus & status)
                status.out << "ISRC \"" << status.marker->cd_info["isrc"] << "\"" << endl;
        }
 
-       status.out << "CD_TEXT {" << endl << "  LANGUAGE 0 {" << endl << "     TITLE \"" << status.marker->name() << "\"" << endl;
+       status.out << "CD_TEXT {" << endl << "  LANGUAGE 0 {" << endl << "     TITLE "
+                  << toc_escape_string (status.marker->name()) << endl;
+       
        if (status.marker->cd_info.find("performer") != status.marker->cd_info.end()) {
-               status.out << "     PERFORMER \"" << status.marker->cd_info["performer"]  << "\"" << endl;
+               status.out << "     PERFORMER " << toc_escape_string (status.marker->cd_info["performer"]);
+       } else {
+               status.out << "     PERFORMER \"\"";
        }
-       if (status.marker->cd_info.find("string_composer") != status.marker->cd_info.end()) {
-               status.out  << "     COMPOSER \"" << status.marker->cd_info["string_composer"] << "\"" << endl;
+       
+       if (status.marker->cd_info.find("composer") != status.marker->cd_info.end()) {
+               status.out  << "     COMPOSER " << toc_escape_string (status.marker->cd_info["composer"]) << endl;
        }
 
        if (status.marker->cd_info.find("isrc") != status.marker->cd_info.end()) {
@@ -511,7 +538,7 @@ ExportHandler::write_track_info_toc (CDMarkerStatus & status)
        status.out << "  }" << endl << "}" << endl;
 
        frames_to_cd_frames_string (buf, status.track_position);
-       status.out << "FILE \"" << status.filename << "\" " << buf;
+       status.out << "FILE " << toc_escape_string (status.filename) << ' ' << buf;
 
        frames_to_cd_frames_string (buf, status.track_duration);
        status.out << buf << endl;
@@ -557,4 +584,31 @@ ExportHandler::frames_to_cd_frames_string (char* buf, framepos_t when)
        sprintf (buf, " %02d:%02d:%02d", mins, secs, frames);
 }
 
+std::string
+ExportHandler::toc_escape_string (const std::string& txt)
+{
+       Glib::ustring utxt (txt);
+       Glib::ustring out;
+       char buf[5];
+
+       out = '"';
+
+       for (Glib::ustring::iterator c = utxt.begin(); c != utxt.end(); ++c) {
+
+               if ((*c) == '"') {
+                       out += "\\\"";
+               } else if (g_unichar_isprint (*c)) {
+                       out += *c;
+               } else {
+                       /* this isn't really correct */
+                       snprintf (buf, sizeof (buf), "\\%03o", *c);
+                       out += buf;
+               }
+       }
+       
+       out += '"';
+
+       return std::string (out);
+}
+
 } // namespace ARDOUR