1 // Copyright 2006 Ben Hutchings <ben@decadentplace.org.uk>.
2 // See the file "COPYING" for licence details.
13 #include <glibmm/fileutils.h>
14 #include <glibmm/miscutils.h>
16 #include "auto_fd.hpp"
17 #include "auto_handle.hpp"
18 #include "vob_list.hpp"
22 struct xml_parser_closer
24 void operator()(XML_Parser parser) const
27 XML_ParserFree(parser);
31 struct xml_parser_factory
33 XML_Parser operator()() const
39 typedef auto_handle<XML_Parser, xml_parser_closer, xml_parser_factory>
44 parse_context(XML_Parser parser,
45 const std::string & list_path,
49 base_path(Glib::path_get_dirname(list_path)),
54 const std::string & list_path;
55 std::string base_path;
57 std::auto_ptr<xml_error> parse_error;
61 void start_element_handler(void * user_data,
63 const char ** attributes)
65 parse_context & context = *static_cast<parse_context *>(user_data);
67 if (context.level == 0 && std::strcmp(name, "vob-list") == 0)
69 // We don't expect (and will ignore) any attributes.
71 else if (context.level == 1 && std::strcmp(name, "vob") == 0)
75 while (attributes[0] != NULL)
77 if (std::strcmp(attributes[0], "file") == 0)
79 ref.file = attributes[1];
80 if (!Glib::path_is_absolute(ref.file))
81 ref.file = Glib::build_filename(context.base_path,
84 else if (std::strcmp(attributes[0], "chapters") == 0)
86 ref.chapters = attributes[1];
88 else if (std::strcmp(attributes[0], "pause") == 0)
90 ref.pause = attributes[1];
98 context.parse_error.reset(
101 XML_GetCurrentLineNumber(context.parser),
102 "<vob> element missing file attribute"));
106 context.list.push_back(ref);
109 else // not root <vob-list> or child <vob>
111 context.parse_error.reset(
114 XML_GetCurrentLineNumber(context.parser),
115 std::string("unexpected element: <").append(name)
122 void end_element_handler(void * user_data,
125 parse_context & context = *static_cast<parse_context *>(user_data);
130 vob_list read_vob_list(const std::string & path)
134 auto_fd fd(open(path.c_str(), O_RDONLY, 0));
136 // FIXME: look up proper error code
137 throw Glib::FileError(Glib::FileError::FAILED,
138 std::strerror(errno));
140 auto_xml_parser parser(XML_ParserCreate(NULL));
141 if (parser.get() == NULL)
142 throw std::bad_alloc(); // any other reason?
144 parse_context context(parser.get(), path, result);
145 XML_SetUserData(parser.get(), &context);
146 XML_SetStartElementHandler(parser.get(), start_element_handler);
147 XML_SetEndElementHandler(parser.get(), end_element_handler);
151 static const int buffer_size = 1024;
152 void * buffer = XML_GetBuffer(parser.get(), buffer_size);
154 throw std::bad_alloc();
155 int read_size = read(fd.get(), buffer, buffer_size);
157 // FIXME: look up proper error code
158 throw Glib::FileError(Glib::FileError::FAILED,
159 std::strerror(errno));
160 bool is_final = read_size < buffer_size;
161 if (XML_ParseBuffer(parser.get(), read_size, is_final)
163 throw xml_error(path,
164 XML_GetCurrentLineNumber(parser.get()),
165 XML_ErrorString(XML_GetErrorCode(parser.get())));
166 if (context.parse_error.get())
167 throw *context.parse_error;
177 std::string make_xml_error_message(const std::string & path, int line,
178 const std::string & message)
180 std::ostringstream os;
181 os << path << ":" << line << ": " << message;
186 xml_error::xml_error(const std::string & path, int line,
187 const std::string & message)
188 : std::runtime_error(make_xml_error_message(path, line, message))