struct dvd_contents
{
- enum pgc_type { menu_pgc, title_pgc };
- typedef std::pair<pgc_type, int> pgc_ref;
+ enum pgc_type { unknown_pgc, menu_pgc, title_pgc };
+
+ struct pgc_ref
+ {
+ explicit pgc_ref(pgc_type type = unknown_pgc,
+ int index = -1,
+ int sub_index = 0)
+ : type(type), index(index), sub_index(sub_index)
+ {}
+ bool operator==(const pgc_ref & other) const
+ {
+ return type == other.type && index == other.index;
+ }
+ bool operator!=(const pgc_ref & other) const
+ {
+ return !(*this == other);
+ }
+
+ pgc_type type; // Menu or title reference?
+ unsigned index; // Menu or title index (within resp. vector)
+ unsigned sub_index; // Button or chapter number (1-based; 0 if
+ // unspecified; not compared!)
+ };
struct menu
{
std::cerr << ": " << e.what() << "\n";
Gtk::Main::quit();
}
+ catch (Glib::Exception & e)
+ {
+ std::cerr << "Fatal error";
+ if (!page_queue_.empty())
+ std::cerr << " while processing <" << page_queue_.front()
+ << ">";
+ std::cerr << ": " << e.what() << "\n";
+ Gtk::Main::quit();
+ }
}
}
temp_file links_temp;
- int link_num;
+ unsigned link_num;
link_iterator links_it, links_end;
rectangle link_rect;
0, 0, frame_params_.width, frame_params_.height
};
- int menu_num = resource_map_[page_queue_.front()].second;
+ unsigned menu_num = resource_map_[page_queue_.front()].index;
for (/* no initialisation */;
state->links_it != state->links_end;
{
nsCOMPtr<nsIDOMNode> node(*state->links_it);
- // Find the link URI.
+ // Find the link URI and separate any fragment from it.
nsCOMPtr<nsILink> link(do_QueryInterface(node));
assert(link);
- nsCOMPtr<nsIURI> uri;
- check(link->GetHrefURI(getter_AddRefs(uri)));
- std::string uri_string;
+ nsCOMPtr<nsIURI> uri_iface;
+ check(link->GetHrefURI(getter_AddRefs(uri_iface)));
+ std::string uri_and_fragment, uri, fragment;
{
- nsCString uri_ns_string;
- check(uri->GetSpec(uri_ns_string));
- uri_string.assign(uri_ns_string.BeginReading(),
- uri_ns_string.EndReading());
+ nsCString uri_and_fragment_ns;
+ check(uri_iface->GetSpec(uri_and_fragment_ns));
+ uri_and_fragment.assign(uri_and_fragment_ns.BeginReading(),
+ uri_and_fragment_ns.EndReading());
+
+ std::size_t hash_pos = uri_and_fragment.find('#');
+ uri.assign(uri_and_fragment, 0, hash_pos);
+ if (hash_pos != std::string::npos)
+ fragment.assign(uri_and_fragment,
+ hash_pos + 1, std::string::npos);
}
- std::string uri_sans_fragment(uri_string, 0, uri_string.find('#'));
// Is this a new link?
if (!state->link_changing)
if (state->link_rect.empty())
{
std::cerr << "Ignoring invisible link to "
- << uri_string << "\n";
+ << uri_and_fragment << "\n";
continue;
}
++state->link_num;
- if (state->link_num >= dvd::menu_buttons_max)
+ if (state->link_num >= unsigned(dvd::menu_buttons_max))
{
- if (state->link_num == dvd::menu_buttons_max)
+ if (state->link_num == unsigned(dvd::menu_buttons_max))
std::cerr << "No more than " << dvd::menu_buttons_max
<< " buttons can be placed on a menu\n";
- std::cerr << "Ignoring link to " << uri_string << "\n";
+ std::cerr << "Ignoring link to " << uri_and_fragment
+ << "\n";
continue;
}
// Check whether this is a link to a video or a page then
// add it to the known resources if not already seen; then
// add it to the menu entries.
- nsCString path;
- check(uri->GetPath(path));
- dvd_contents::pgc_ref dest_pgc;
+ dvd_contents::pgc_ref target;
// FIXME: This is a bit of a hack. Perhaps we could decide
// later based on the MIME type determined by Mozilla?
- if ((path.Length() > 4
- && std::strcmp(path.EndReading() - 4, ".vob") == 0)
- || (path.Length() > 8
- && std::strcmp(path.EndReading() - 8, ".voblist")
- == 0))
+ if ((uri.size() > 4
+ && uri.compare(uri.size() - 4, 4, ".vob") == 0)
+ || (uri.size() > 8
+ && uri.compare(uri.size() - 8, 8, ".voblist") == 0))
{
PRBool is_file;
- check(uri->SchemeIs("file", &is_file));
+ check(uri_iface->SchemeIs("file", &is_file));
if (!is_file)
{
std::cerr << "Links to video must use the file:"
<< " scheme\n";
continue;
}
- dest_pgc = add_title(uri_sans_fragment);
+ target = add_title(uri);
+ target.sub_index =
+ std::strtoul(fragment.c_str(), NULL, 10);
}
else
{
- dest_pgc = add_menu(uri_sans_fragment);
+ target = add_menu(uri);
+ // TODO: If there's a fragment, work out which button
+ // is closest and set target.sub_index.
}
- contents_.menus[menu_num].entries.push_back(dest_pgc);
+ contents_.menus[menu_num].entries.push_back(target);
nsCOMPtr<nsIContent> content(do_QueryInterface(node));
assert(content);
" <vmgm>\n"
" <menus>\n";
- for (std::size_t menu_num = 0;
+ for (unsigned menu_num = 0;
menu_num != contents.menus.size();
++menu_num)
{
" </pre>\n"
" <vob file='" << menu.vob_temp->get_name() << "'/>\n";
- for (std::size_t button_num = 0;
+ for (unsigned button_num = 0;
button_num != menu.entries.size();
++button_num)
{
+ const dvd_contents::pgc_ref & target =
+ menu.entries[button_num];
+
file << " <button> ";
- if (menu.entries[button_num].first == dvd_contents::menu_pgc)
+ if (target.type == dvd_contents::menu_pgc)
{
- int dest_menu_num = menu.entries[button_num].second;
-
- // Look for a button on the new menu that links
- // back to this one. If there is one, set that to
- // be the highlighted button; otherwise, use the
- // first button.
- const std::vector<dvd_contents::pgc_ref> &
- dest_menu_entries =
- contents.menus[dest_menu_num].entries;
- dvd_contents::pgc_ref this_pgc(
- dvd_contents::menu_pgc, menu_num);
- std::size_t dest_button_num = dest_menu_entries.size();
- while (dest_button_num != 0
- && dest_menu_entries[--dest_button_num] != this_pgc)
- ;
+ unsigned target_button_num;
+
+ if (target.sub_index)
+ {
+ target_button_num = target.sub_index;
+ }
+ else
+ {
+ // Look for a button on the new menu that links
+ // back to this one. If there is one, set that to
+ // be the highlighted button; otherwise, use the
+ // first button.
+ const std::vector<dvd_contents::pgc_ref> &
+ target_menu_entries =
+ contents.menus[target.index].entries;
+ dvd_contents::pgc_ref this_pgc(dvd_contents::menu_pgc,
+ menu_num);
+ target_button_num = target_menu_entries.size();
+ while (target_button_num != 0
+ && (target_menu_entries[--target_button_num]
+ != this_pgc))
+ ;
+ }
file << "g1 = "
- << (1 + dest_menu_num
- + (1 + dest_button_num) * button_mult)
- << "; jump menu " << 1 + dest_menu_num << ";";
+ << (1 + target.index
+ + (1 + target_button_num) * button_mult)
+ << "; jump menu " << 1 + target.index << ";";
}
else
{
- assert(menu.entries[button_num].first
- == dvd_contents::title_pgc);
+ assert(target.type == dvd_contents::title_pgc);
file << "g1 = "
<< 1 + menu_num + (1 + button_num) * button_mult
<< "; jump title "
- << 1 + menu.entries[button_num].second << ";";
+ << 1 + target.index;
+ if (target.sub_index)
+ file << " chapter " << target.sub_index;
+ file << ";";
}
file << " </button>\n";
// Generate a titleset for each title. This appears to make
// jumping to titles a whole lot simpler (but limits us to 99
// titles).
- for (std::size_t title_num = 0;
+ for (unsigned title_num = 0;
title_num != contents.titles.size();
++title_num)
{