void TTXTSubtitleFormat::ReadFile(AssFile *target, agi::fs::path const& filename, std::string const& encoding) const {
	target->LoadDefault(false);

	// Load XML document
	wxXmlDocument doc;
	if (!doc.Load(filename.wstring())) throw TTXTParseError("Failed loading TTXT XML file.", nullptr);

	// Check root node name
	if (doc.GetRoot()->GetName() != "TextStream") throw TTXTParseError("Invalid TTXT file.", nullptr);

	// Check version
	wxString verStr = doc.GetRoot()->GetAttribute("version", "");
	int version = -1;
	if (verStr == "1.0")
		version = 0;
	else if (verStr == "1.1")
		version = 1;
	else
		throw TTXTParseError("Unknown TTXT version: " + from_wx(verStr), nullptr);

	// Get children
	AssDialogue *diag = nullptr;
	int lines = 0;
	for (wxXmlNode *child = doc.GetRoot()->GetChildren(); child; child = child->GetNext()) {
		// Line
		if (child->GetName() == "TextSample") {
			if ((diag = ProcessLine(child, diag, version))) {
				lines++;
				target->Line.push_back(*diag);
			}
		}
		// Header
		else if (child->GetName() == "TextStreamHeader") {
			ProcessHeader(child);
		}
	}

	// No lines?
	if (lines == 0)
		target->Line.push_back(*new AssDialogue);
}
void TTXTSubtitleFormat::WriteFile(const AssFile *src, agi::fs::path const& filename, std::string const& encoding) const {
	// Convert to TTXT
	AssFile copy(*src);
	ConvertToTTXT(copy);

	// Create XML structure
	wxXmlDocument doc;
	wxXmlNode *root = new wxXmlNode(nullptr, wxXML_ELEMENT_NODE, "TextStream");
	root->AddAttribute("version", "1.1");
	doc.SetRoot(root);

	// Create header
	WriteHeader(root);

	// Create lines
	const AssDialogue *prev = nullptr;
	for (auto current : copy.Line | agi::of_type<AssDialogue>()) {
		WriteLine(root, prev, current);
		prev = current;
	}

	// Save XML
	doc.Save(filename.wstring());
}
Esempio n. 3
0
void SubsController::Load(agi::fs::path const& filename, std::string charset) {
	try {
		if (charset.empty())
			charset = CharSetDetect::GetEncoding(filename);
	}
	catch (agi::UserCancelException const&) {
		return;
	}

	// Make sure that file isn't actually a timecode file
	if (charset != "binary") {
		try {
			TextFileReader testSubs(filename, charset);
			std::string cur = testSubs.ReadLineFromFile();
			if (boost::starts_with(cur, "# timecode")) {
				context->videoController->LoadTimecodes(filename);
				return;
			}
		}
		catch (...) {
			// if trying to load the file as timecodes fails it's fairly
			// safe to assume that it is in fact not a timecode file
		}
	}

	const SubtitleFormat *reader = SubtitleFormat::GetReader(filename);

	try {
		AssFile temp;
		reader->ReadFile(&temp, filename, charset);

		bool found_style = false;
		bool found_dialogue = false;

		// Check if the file has at least one style and at least one dialogue line
		for (auto const& line : temp.Line) {
			AssEntryGroup type = line.Group();
			if (type == AssEntryGroup::STYLE) found_style = true;
			if (type == AssEntryGroup::DIALOGUE) found_dialogue = true;
			if (found_style && found_dialogue) break;
		}

		// And if it doesn't add defaults for each
		if (!found_style)
			temp.InsertLine(new AssStyle);
		if (!found_dialogue)
			temp.InsertLine(new AssDialogue);

		context->ass->swap(temp);
	}
	catch (agi::UserCancelException const&) {
		return;
	}
	catch (agi::fs::FileNotFound const&) {
		wxMessageBox(filename.wstring() + " not found.", "Error", wxOK | wxICON_ERROR | wxCENTER, context->parent);
		config::mru->Remove("Subtitle", filename);
		return;
	}
	catch (agi::Exception const& err) {
		wxMessageBox(to_wx(err.GetChainedMessage()), "Error", wxOK | wxICON_ERROR | wxCENTER, context->parent);
		return;
	}
	catch (std::exception const& err) {
		wxMessageBox(to_wx(err.what()), "Error", wxOK | wxICON_ERROR | wxCENTER, context->parent);
		return;
	}
	catch (...) {
		wxMessageBox("Unknown error", "Error", wxOK | wxICON_ERROR | wxCENTER, context->parent);
		return;
	}

	SetFileName(filename);

	// Push the initial state of the file onto the undo stack
	undo_stack.clear();
	redo_stack.clear();
	autosaved_commit_id = saved_commit_id = commit_id + 1;
	context->ass->Commit("", AssFile::COMMIT_NEW);

	// Save backup of file
	if (CanSave() && OPT_GET("App/Auto/Backup")->GetBool()) {
		auto path_str = OPT_GET("Path/Auto/Backup")->GetString();
		agi::fs::path path;
		if (path_str.empty())
			path = filename.parent_path();
		else
			path = config::path->Decode(path_str);
		agi::fs::CreateDirectory(path);
		agi::fs::Copy(filename, path/(filename.stem().string() + ".ORIGINAL" + filename.extension().string()));
	}

	FileOpen(filename);
}