1 // Copyright 2006 Ben Hutchings <ben@decadent.org.uk>.
2 // See the file "COPYING" for licence details.
14 #include <glibmm/fileutils.h>
15 #include <glibmm/miscutils.h>
17 #include "auto_fd.hpp"
18 #include "auto_handle.hpp"
19 #include "vob_list.hpp"
23 struct xml_parser_closer
25 void operator()(XML_Parser parser) const
28 XML_ParserFree(parser);
32 struct xml_parser_factory
34 XML_Parser operator()() const
40 typedef auto_handle<XML_Parser, xml_parser_closer, xml_parser_factory>
45 parse_context(XML_Parser parser,
46 const std::string & list_path,
50 base_path(Glib::path_get_dirname(list_path)),
55 const std::string & list_path;
56 std::string base_path;
58 std::auto_ptr<xml_error> parse_error;
62 void start_element_handler(void * user_data,
64 const char ** attributes)
66 parse_context & context = *static_cast<parse_context *>(user_data);
68 if (context.level == 0 && std::strcmp(name, "vob-list") == 0)
70 // We don't expect (and will ignore) any attributes.
72 else if (context.level == 1 && std::strcmp(name, "vob") == 0)
76 while (attributes[0] != NULL)
78 if (std::strcmp(attributes[0], "file") == 0)
80 ref.file = attributes[1];
81 if (!Glib::path_is_absolute(ref.file))
82 ref.file = Glib::build_filename(context.base_path,
85 else if (std::strcmp(attributes[0], "chapters") == 0)
87 ref.chapters = attributes[1];
89 else if (std::strcmp(attributes[0], "pause") == 0)
91 ref.pause = attributes[1];
99 context.parse_error.reset(
102 XML_GetCurrentLineNumber(context.parser),
103 "<vob> element missing file attribute"));
107 context.list.push_back(ref);
110 else // not root <vob-list> or child <vob>
112 context.parse_error.reset(
115 XML_GetCurrentLineNumber(context.parser),
116 std::string("unexpected element: <").append(name)
123 void end_element_handler(void * user_data,
124 const char * /*name*/)
126 parse_context & context = *static_cast<parse_context *>(user_data);
131 vob_list read_vob_list(const std::string & path)
135 auto_fd fd(open(path.c_str(), O_RDONLY, 0));
137 // FIXME: look up proper error code
138 throw Glib::FileError(Glib::FileError::FAILED,
139 std::strerror(errno));
141 auto_xml_parser parser(XML_ParserCreate(NULL));
142 if (parser.get() == NULL)
143 throw std::bad_alloc(); // any other reason?
145 parse_context context(parser.get(), path, result);
146 XML_SetUserData(parser.get(), &context);
147 XML_SetStartElementHandler(parser.get(), start_element_handler);
148 XML_SetEndElementHandler(parser.get(), end_element_handler);
152 static const int buffer_size = 1024;
153 void * buffer = XML_GetBuffer(parser.get(), buffer_size);
155 throw std::bad_alloc();
156 int read_size = read(fd.get(), buffer, buffer_size);
158 // FIXME: look up proper error code
159 throw Glib::FileError(Glib::FileError::FAILED,
160 std::strerror(errno));
161 bool is_final = read_size < buffer_size;
162 if (XML_ParseBuffer(parser.get(), read_size, is_final)
164 throw xml_error(path,
165 XML_GetCurrentLineNumber(parser.get()),
166 XML_ErrorString(XML_GetErrorCode(parser.get())));
167 if (context.parse_error.get())
168 throw *context.parse_error;
178 std::string make_xml_error_message(const std::string & path, int line,
179 const std::string & message)
181 std::ostringstream os;
182 os << path << ":" << line << ": " << message;
187 xml_error::xml_error(const std::string & path, int line,
188 const std::string & message)
189 : std::runtime_error(make_xml_error_message(path, line, message))