X-Git-Url: https://git.decadent.org.uk/gitweb/?a=blobdiff_plain;f=webdvd.cpp;h=31ad122776a154586a14ea9baf4e7642331dcd5a;hb=86602dfc3c0f036cc061277b70607e2631b50229;hp=e3c02e90f271e757283ddf4f667d5ab8e5296193;hpb=cdd14ea76afc16f91e09323362468eaf5d0bcf9e;p=videolink.git diff --git a/webdvd.cpp b/webdvd.cpp index e3c02e9..31ad122 100644 --- a/webdvd.cpp +++ b/webdvd.cpp @@ -142,6 +142,36 @@ namespace return result; } + + std::string xml_escape(const std::string & str) + { + std::string result; + std::size_t begin = 0; + + for (;;) + { + std::size_t end = str.find_first_of("\"&'<>", begin); + result.append(str, begin, end - begin); + if (end == std::string::npos) + return result; + + const char * entity = NULL; + switch (str[end]) + { + case '"': entity = """; break; + case '&': entity = "&"; break; + case '\'': entity = "'"; break; + case '<': entity = "<"; break; + case '>': entity = ">"; break; + } + assert(entity); + result.append(entity); + + begin = end + 1; + } + } + + struct dvd_contents { enum pgc_type { menu_pgc, title_pgc }; @@ -280,8 +310,7 @@ namespace filename + " is missing or not a regular file"); vob_list .append("\n"); } else @@ -765,9 +794,6 @@ namespace } } - void generate_menu_dispatch(std::ostream &, int indent, - int first_menu, int last_menu); - void webdvd_window::generate_dvd() { temp_file temp("webdvd-dvdauthor-"); @@ -776,10 +802,9 @@ namespace // We generate code that uses registers in the following way: // - // g0: button destination (when jumping to menu 1), then scratch + // g0: scratch // g1: current location - // g2-g11: location history (g2 = most recent) - // g12: location that last linked to a video + // g12: location that last jumped to a video // // All locations are divided into two bitfields: the least // significant 10 bits are a page/menu number and the most @@ -790,7 +815,6 @@ namespace static const int button_mult = dvd::reg_s8_button_mult; static const int menu_mask = button_mult - 1; static const int button_mask = (1 << dvd::reg_bits) - button_mult; - static const int location_bias = button_mult + 1; file << "\n" @@ -805,93 +829,102 @@ namespace if (menu_num == 0) { - // This is the first (title) menu, which needs to include - // initialisation and dispatch code. - + // This is the first (title) menu, displayed when the + // disc is first played. file << " \n" "
\n"
-		    // Has the location been set yet?
+		    // Initialise the current location if it is not set
+		    // (all general registers are initially 0).
 		    "          if (g1 eq 0)\n"
-		    "          {\n"
-		    // Initialise the current location to first button on
-		    // this menu.
-		    "            g1 = " << location_bias << ";\n"
-		    "          }\n"
-		    "          else\n"
-		    "          {\n"
-		    // Has the user selected a link?
-		    "            if (g0 ne 0)\n"
-		    "            {\n"
-		    // First update the history.
-                    // Does link go to the last page in the history?
-		    "              if (((g0 ^ g2) & " << menu_mask
-		     << ") == 0)\n"
-                    // It does; we treat this as going back and pop the old
-		    // location off the history stack into the current
-		    // location.  Clear the free stack slot.
-		    "              {\n"
-		    "                g1 = g2; g2 = g3; g3 = g4; g4 = g5;\n"
-		    "                g5 = g6; g6 = g7; g7 = g8; g8 = g9;\n"
-		    "                g9 = g10; g10 = g11; g11 = 0;\n"
-	            "              }\n"
-                    "              else\n"
-		    // Link goes to some other page, so push current
-		    // location onto the history stack and set the current
-		    // location to be exactly the target location.
-		    "              {\n"
-		    "                g11 = g10; g10 = g9; g9 = g8; g8 = g7;\n"
-		    "                g7 = g6; g6 = g5; g5 = g4; g4 = g3;\n"
-		    "                g3 = g2; g2 = g1; g1 = g0;\n"
-	            "              }\n"
-		    "            }\n"
-		    // Find the target page number.
-		    "            g0 = g1 & " << menu_mask << ";\n";
-		// There seems to be no way to perform a computed jump,
-		// so we generate all possible jumps and a binary search
-		// to select the correct one.
-		generate_menu_dispatch(file, 12,
-				       0, contents_.menus.size() - 1);
-		file <<
-		    "          }\n";
+		    "            g1 = " << 1 + button_mult << ";\n";
 	    }
-	    else // menu_num != 0
+	    else
 	    {
 		file <<
 		    "      \n"
 		    "        
\n";
 	    }
 
+	    // When a title finishes or the user presses the menu
+	    // button, this always jumps to the titleset's root menu.
+	    // We want to return the user to the last menu they used.
+	    // So we arrange for each titleset's root menu to return
+	    // to the vmgm title menu and then dispatch from there to
+	    // whatever the correct menu is.  We determine the correct
+	    // menu by looking at the menu part of g1.
+
+	    file << "          g0 = g1 & " << menu_mask << ";\n";
+
+	    // There is a limit of 128 VM instructions in each PGC.
+	    // Therefore in each menu's 
 section we generate
+	    // jumps to menus with numbers greater by 512, 256, 128,
+	    // ..., 1 where (a) such a menu exists, (b) this menu
+	    // number is divisible by twice that increment and (c) the
+	    // correct menu is that or a later menu.  Thus each menu
+	    // has at most 10 such conditional jumps and is reachable
+	    // by at most 10 jumps from the title menu.  This chain of
+	    // jumps might take too long on some players; this has yet
+	    // to be investigated.
+	    
+	    for (std::size_t menu_incr = (menu_mask + 1) / 2;
+		 menu_incr != 0;
+		 menu_incr /= 2)
+	    {
+		if (menu_num + menu_incr < contents_.menus.size()
+		    && (menu_num & (menu_incr * 2 - 1)) == 0)
+		{
+		    file <<
+			"          if (g0 ge " << 1 + menu_num + menu_incr
+					       << ")\n"
+			"            jump menu " << 1 + menu_num + menu_incr
+					       << ";\n";
+		}
+	    }
+
 	    file <<
-		// Clear link indicator and highlight the
-		// appropriate link/button.
-		"          g0 = 0; s8 = g1 & " << button_mask << ";\n"
+		// Highlight the appropriate button.
+		"          s8 = g1 & " << button_mask << ";\n"
 		"        
\n" - " \n"; + " \n"; for (std::size_t button_num = 0; button_num != menu.entries.size(); ++button_num) { - file << "