Added full source code

This commit is contained in:
Emmanuel BENOîT 2016-01-10 11:01:49 +01:00
commit 33f8586698
1377 changed files with 123808 additions and 0 deletions

View file

@ -0,0 +1,66 @@
<?php
class main_manual_library {
var $index = array(
'getFirstPage',
'getNavLinks',
'getPageId',
'getSectionsIn',
'getStructure',
'readXMLFile',
'search',
'updateSections'
);
function main_manual_library($lib) {
$this->lib = $lib;
$this->db = $this->lib->game->db;
$this->version = $this->lib->game->version->id;
}
function getPage($pageId) {
$section = $this->readSectionRecord($pageId);
$tree = $this->lib->call('getSectionsIn', $pageId, 0);
$this->readSubSections($pageId, $section, $tree);
return $section;
}
function getSectionId($lang, $name) {
$q = $this->db->query("SELECT id FROM man_section WHERE version='{$this->version}' AND lang='$lang' AND name='" . addslashes($name) . "'");
if (!($q && dbCount($q) == 1)) {
return null;
}
list($secId) = dbFetchArray($q);
return $secId;
}
function readSectionRecord($sectionId) {
$q = dbQuery("SELECT name,title,contents,link_to FROM man_section WHERE id=$sectionId");
if (!($q && dbCount($q) == 1)) {
return null;
}
list($name,$title,$contents,$linkto) = dbFetchArray($q);
return array(
"id" => $sectionId,
"name" => $name,
"title" => $title,
"contents" => $contents,
"linkto" => $linkto,
"subsections" => array()
);
}
function readSubSections($sectionId, &$section, &$subList) {
foreach ($subList as $secId => $sData) {
$nSec = $this->readSectionRecord($secId);
$this->readSubSections($secId, $nSec, $subList[$secId]['subs']);
array_push($section['subsections'], $nSec);
}
}
}
?>

View file

@ -0,0 +1,30 @@
<?php
class main_manual_getFirstPage {
function __construct($lib) {
$this->lib = $lib;
$this->db = $this->lib->game->db;
$this->version = $this->lib->mainClass->version;
}
function run($lang) {
// Get the manual's root node identifier
$q = $this->db->query("SELECT id FROM man_section WHERE version='{$this->version}' AND lang='$lang' AND in_section IS NULL");
if (!($q && dbCount($q) == 1)) {
return null;
}
list($rootId) = dbFetchArray($q);
// Get the root node's first page
$q = $this->db->query("SELECT id FROM man_section WHERE in_section=$rootId AND after_section=$rootId AND is_page");
if (!($q && dbCount($q) == 1)) {
return null;
}
list($fPage) = dbFetchArray($q);
return $fPage;
}
}
?>

View file

@ -0,0 +1,67 @@
<?php
class main_manual_getNavLinks {
function main_manual_getNavLinks($lib) {
$this->lib = $lib;
$this->db = $this->lib->game->db;
}
function run($pageId) {
// Get the version, language and parent section for the page
$q = $this->db->query("SELECT version,lang,in_section,after_section FROM man_section WHERE id=$pageId");
if (!($q && dbCount($q) == 1)) {
return null;
}
list($version,$lang,$parent,$after) = dbFetchArray($q);
// Get the manual's root node identifier
$q = $this->db->query("SELECT id FROM man_section WHERE version='$version' AND lang='$lang' AND in_section IS NULL");
if (!($q && dbCount($q) == 1)) {
return null;
}
list($rootId) = dbFetchArray($q);
// Get the root node's first page
$q = $this->db->query("SELECT id FROM man_section WHERE in_section=$rootId AND after_section=$rootId AND is_page");
if (!($q && dbCount($q) == 1)) {
return null;
}
list($fPage) = dbFetchArray($q);
// Get identifiers
$rv = array($pageId == $fPage ? null : $fPage);
$rv[1] = ($parent == $rootId) ? (is_null($rv[0]) ? null : $rv[0]) : $parent;
$rv[2] = ($after == $rootId) ? null : $after;
$q = $this->db->query("SELECT id FROM man_section WHERE is_page AND after_section=$pageId");
if ($q && dbCount($q) == 1) {
list($rv[3]) = dbFetchArray($q);
} else {
$rv[3] = null;
}
// Get names
$nnl = array();
for ($i=0;$i<4;$i++) {
if (!is_null($rv[$i])) {
array_push($nnl, $rv[$i]);
}
}
if (count($nnl)) {
$q = $this->db->query("SELECT id,name FROM man_section WHERE id IN (" . join(',', array_unique($nnl)) . ")");
$l = array();
while ($r = dbFetchArray($q)) {
$l[$r[0]] = $r[1];
}
for ($i=0;$i<4;$i++) {
if (!is_null($rv[$i])) {
$rv[$i] = $l[$rv[$i]];
}
}
}
return $rv;
}
}
?>

View file

@ -0,0 +1,31 @@
<?php
class main_manual_getPageId {
function main_manual_getPageId($lib) {
$this->lib = $lib;
$this->db = $this->lib->game->db;
}
function run($secId) {
// Find the section itself
$q = $this->db->query("SELECT is_page,in_section FROM man_section WHERE id=$secId");
if (!($q && dbCount($q) == 1)) {
return null;
}
list($isPage, $parentId) = dbFetchArray($q);
// Find the page in which the section is
while ($isPage != 't') {
$q = $this->db->query("SELECT id,is_page,in_section FROM man_section WHERE id=$parentId");
if (!($q && dbCount($q) == 1)) {
return null;
}
list($secId, $isPage, $parentId) = dbFetchArray($q);
}
return $secId;
}
}
?>

View file

@ -0,0 +1,35 @@
<?php
class main_manual_getSectionsIn {
function main_manual_getSectionsIn($lib) {
$this->lib = $lib;
$this->db = $this->lib->game->db;
}
function run($rootId, $type = 1) {
$qs = ($type > 0) ? (" AND is_page" . ($type == 2 ? " AND in_menu" : "")) : " AND NOT is_page";
$q = $this->db->query("SELECT id,name,title,after_section FROM man_section WHERE in_section=$rootId$qs");
$sl = array();
$as = array();
while ($r = dbFetchArray($q)) {
$sl[$r[0]] = array(
"name" => $r[1],
"title" => $r[2]
);
$as[$r[3]] = $r[0];
}
$cid = $rootId;
$nl = array();
while (!is_null($as[$cid])) {
$cid = $as[$cid];
$nl[$cid] = $sl[$cid];
$nl[$cid]['subs'] = $this->run($cid, $type);
}
return $nl;
}
}
?>

View file

@ -0,0 +1,24 @@
<?php
class main_manual_getStructure {
function main_manual_getStructure($lib) {
$this->lib = $lib;
$this->db = $this->lib->game->db;
$this->version = $this->lib->mainClass->version;
}
function run($lang) {
// Get the manual's root node identifier
$q = $this->db->query("SELECT id FROM man_section WHERE version='{$this->version}' AND lang='$lang' AND in_section IS NULL");
if (!($q && dbCount($q) == 1)) {
return array();
}
list($rootId) = dbFetchArray($q);
// List sections
return $this->lib->call('getSectionsIn', $rootId, 2);
}
}
?>

View file

@ -0,0 +1,158 @@
<?php
class main_manual_readXMLFile {
function main_manual_readXMLFile($lib) {
$this->lib = $lib;
$this->db = $this->lib->game->db;
}
function run($path) {
logText("manual/readXMLFile: extracting XML file '$path'", LOG_DEBUG);
// Get the section's name from the path
$section = basename($path, ".lwdoc");
// Open the file
$file = @file_get_contents($path);
if ($file === FALSE) {
logText("manual/readXMLFile: failed to read file '$path'", LOG_DEBUG);
return 1;
}
$file = utf8_encode($file);
// Parse it
$doc = new DOMDocument();
if (!$doc->loadXML($file)) {
logText("manual/readXMLFile: failed to parse file '$path'", LOG_DEBUG);
return 2;
}
$root = $doc->documentElement;
$node = $root->firstChild;
$version = $title = $lang = "";
// Extract the version, language and title
for ($i=0;$i<3;$i++) {
while ($node && $node->nodeType != XML_ELEMENT_NODE) {
$node = $node->nextSibling;
}
$name = $node->nodeName;
$val = $node->textContent;
if ($name == "version") {
$version = $val;
} elseif ($name == "language") {
$language = $val;
} elseif ($name == "title") {
$title = $val;
} else {
logText("manual/readXMLFile('$path'): unexpected tag '$name'", LOG_DEBUG);
return 3;
}
$node = $node->nextSibling;
}
if (!$node || $version == "" || $language == "" || $title == "") {
logText("manual/readXMLFile('$path'): incomplete file header", LOG_DEBUG);
return 4;
}
// Generate the main section
$sections = array(
$section => array(
"language" => $language,
"version" => $version,
"in_section" => null,
"is_page" => true,
"in_menu" => ($root->getAttribute('hide') !== "1"),
"title" => $title,
"contents" => "",
"subs" => array()
)
);
// Read the sections
$stack = array();
while ($node) {
$cs = empty($stack) ? $section : $stack[count($stack)-1][1];
if ($node->nodeType == XML_ELEMENT_NODE && $node->nodeName == "section") {
$nFile = $node->getAttribute('file');
if ($nFile != '') {
// This subsection must be read from another file
if ($nFile{0} != "/")
$nFile = dirname($path) . "/$nFile";
$a = $this->run($nFile);
if (!is_array($a)) {
logText("manual/readXMLFile('$path'): error $a in sub-file '$nFile'", LOG_DEBUG);
return $a;
}
$id = basename($nFile, '.lwdoc');
$a[$id]['in_section'] = $cs;
$sections = array_merge($sections, $a);
array_push($sections[$cs]['subs'], $id);
$node = $node->nextSibling;
} else {
// Inline subsection
$id = $node->getAttribute('id');
array_push($sections[$cs]['subs'], $id);
$sections[$id] = array(
"language" => $language,
"version" => $version,
"in_section" => $cs,
"is_page" => false,
"title" => $node->getAttribute('title'),
"linkto" => $node->getAttribute('linkto'),
"contents" => $this->getEmbeddedXHTML($node),
"subs" => array()
);
array_push($stack, array($node, $id));
$node = $node->firstChild;
}
} else {
$node = $node->nextSibling;
if (!empty($stack)) {
do {
if (!$node) {
$x = array_pop($stack);
$node = $x[0]->nextSibling;
}
} while (!$node && !empty($stack));
}
}
}
return $sections;
}
function getEmbeddedXHTML($node) {
if (!$node->hasChildNodes()) {
return $node->textContent;
}
$st = "";
for ($i=0;$i<$node->childNodes->length;$i++) {
$cnode = $node->childNodes->item($i);
if ($cnode->nodeType == XML_TEXT_NODE) {
$st .= $cnode->nodeValue;
} elseif ($cnode->nodeType == XML_ELEMENT_NODE && $cnode->nodeName != 'section') {
$st .= "<" . $cnode->nodeName;
if ($attribnodes = $cnode->attributes) {
$st .= " ";
foreach ($attribnodes as $anode) {
$st .= $anode->nodeName . "='" . $anode->nodeValue . "'";
}
}
$nodeText = $this->getEmbeddedXHTML($cnode);
if (empty($nodeText) && !$attribnodes) {
$st .= " />"; // unary
} else {
$st .= ">" . $nodeText . "</" . $cnode->nodeName . ">";
}
}
}
return $st;
}
}
?>

View file

@ -0,0 +1,229 @@
<?php
class main_manual_search {
function main_manual_search($lib) {
$this->lib = $lib;
$this->db = $this->lib->game->db;
}
function run($text, $lang) {
$version = "'{$this->lib->mainClass->version}'";
$text = preg_replace('/\s+/', ' ', trim($text));
// Read the banned words list
$banList = array();
$q = $this->db->query("SELECT word FROM man_index_ban WHERE lang='$lang'");
while ($r = dbFetchArray($q)) {
array_push($banList, $r[0]);
}
// Generate the three lists: required, excluded and normal words
$required = $excluded = $normal = array();
$tl = explode(' ', $text);
foreach ($tl as $word) {
if ($word{0} == '+' || $word{0} == '-') {
$qual = $word{0};
$word = substr($word, 1);
} else {
$qual = '';
}
$word = preg_replace('/["\s\.,;:!\(\)<>&]+/', ' ', $word);
$rwl = explode(' ', $word);
foreach ($rwl as $rword) {
$rword = strtolower($rword);
if (in_array($rword, $banList)) {
continue;
}
$rword = addslashes($rword);
if ($qual == '') {
array_push($normal, $rword);
} elseif ($qual == '+') {
array_push($required, $rword);
} else {
array_push($excluded, $rword);
}
}
}
$required = array_unique($required);
$excluded = array_unique($excluded);
$normal = array_unique($normal);
// Read the index for each list
$words = array($required, $normal, $excluded);
$lists = array(array(), array(), array());
for ($i=0;$i<count($words);$i++) {
if (empty($words[$i])) {
continue;
}
$q = $this->db->query("SELECT i.word,i.wcount,i.section"
. " FROM man_index i,man_section s "
. "WHERE i.lang='$lang' AND s.id=i.section AND s.version=$version "
. "AND word in ('" . join("','", $words[$i]) . "')");
while ($r = dbFetchArray($q)) {
if (!is_array($lists[$i][$r[0]])) {
$lists[$i][$r[0]] = array();
}
$lists[$i][$r[0]][$r[2]] = $r[1];
}
}
if (count($words[0])) {
// Look for sections that have all required words
$secReq = array();
foreach ($required as $word) {
if (!is_array($lists[0][$word])) {
continue;
}
foreach (array_keys($lists[0][$word]) as $s) {
$secReq[$s] ++;
}
}
$secOk = array();
foreach ($secReq as $s => $n) {
if ($n == count($words[0]) && !in_array($s, $secOk)) {
array_push($secOk, $s);
}
}
} else {
// Look for sections that have these words
$secOk = array();
if (count($words[1])) {
foreach ($lists[1] as $word => $sections) {
foreach (array_keys($sections) as $section) {
if (!in_array($section, $secOk)) {
array_push($secOk, $section);
}
}
}
}
}
// Remove sections that have excluded words
if (count($words[2])) {
// Generate a list of banned sections
$bannedSections = array();
foreach ($lists[2] as $word => $sections) {
foreach ($sections as $s => $c) {
if (!in_array($s, $bannedSections)) {
array_push($bannedSections, $s);
}
}
}
// Remove banned sections from the list
$newList = array();
foreach ($secOk as $s) {
if (!in_array($s, $bannedSections)) {
array_push($newList, $s);
}
}
$secOk = $newList;
}
/*
* For each section in the generated list, find out:
* - how many occurences of each required or normal word it
* has,
* - the maximum amount of occurences a section has of each
* required or normal word.
*/
// Initialise the word list
$sWords = array_unique(array_merge($words[0], $words[1]));
$mWords = array();
foreach ($sWords as $word) {
$mWords[$word] = 0;
}
// Generate the section list and update maximum counts
$wPerSec = array();
foreach ($secOk as $section) {
$wPerSec[$section] = array();
foreach ($sWords as $word) {
$count = $lists[is_null($lists[0][$word]) ? 1 : 0][$word][$section];
if (!is_null($count)) {
$wPerSec[$section][$word] = $count;
if ($count > $mWords[$word]) {
$mWords[$word] = $count;
}
} else {
$wPerSec[$section][$word] = 0;
}
}
}
/* Now we assign a "distance" from the optimal value to
* each section by using each word as a dimension; the closer
* a section to the optimal value, the higher it will be in
* the displayed results.
*/
// Eliminate words that are not on any section
$nWords = array();
foreach ($sWords as $word) {
if ($mWords[$word] > 0) {
array_push($nWords, $word);
}
}
// Compute the maximum distance
$sum = 0;
foreach ($nWords as $word) {
$d = $mWords[$word];
$sum += $d * $d;
}
$dMax = sqrt($sum);
// Compute the revelance of each section
$dSec = array();
foreach ($secOk as $section) {
$sum = 0;
foreach ($nWords as $word) {
$d = $mWords[$word] - $wPerSec[$section][$word];
$sum += $d * $d;
}
$dSec[$section] = 1 - (sqrt($sum) / $dMax);
}
// Find out the page for each section
$pages = array();
$nSecs = array();
foreach ($secOk as $section) {
$pageId = $this->lib->call('getPageId', $section);
if (is_null($pageId)) {
continue;
}
$pages[$pageId] += $dSec[$section];
$nSecs[$pageId] += 1;
}
// Sort the pages according to their points
$pts = array();
foreach (array_keys($pages) as $p) {
$pp = sprintf("%.2f", $pages[$p] / $nSecs[$pageId]);
if (!is_array($pts[$pp])) {
$pts[$pp] = array();
}
array_push($pts[$pp], $p);
}
$k = array_keys($pts);
sort($k);
// Return the results
$results = array();
foreach (array_reverse($k) as $points) {
foreach ($pts[$points] as $p) {
array_push($results, $p);
}
}
return $results;
}
}
?>

View file

@ -0,0 +1,107 @@
<?php
class main_manual_updateSections {
function main_manual_updateSections($lib) {
$this->lib = $lib;
$this->db = $this->lib->game->db;
}
function run($sections) {
$versions = array();
foreach ($sections as $sName => $sData) {
if (is_null($versions[$sData['version']])) {
$versions[$sData['version']] = "'" . addslashes($sData['version']) . "'";
}
$this->db->query("DELETE FROM man_section WHERE name='" . addslashes($sName)
. "' AND version=" . $versions[$sData['version']]
. " AND lang='" . addslashes($sData['language']) . "'");
}
// Insert the data itself
$now = time();
foreach ($sections as $sName => $sData) {
if (is_null($versions[$sData['version']])) {
continue;
}
$this->db->query("INSERT INTO man_section (version,lang,name,last_update,is_page,in_menu,title,contents) VALUES("
. $versions[$sData['version']] . ",'" . addslashes($sData['language']) . "','"
. addslashes($sName) . "',$now," . dbBool($sData['is_page']) . ","
. dbBool($sData['in_menu']) . ",'" . addslashes($sData['title'])
. "','" . addslashes($sData['contents']) . "')");
$q = $this->db->query("SELECT id FROM man_section WHERE name='" . addslashes($sName)
. "' AND version=" . $versions[$sData['version']]
. " AND lang='" . addslashes($sData['language']) . "'");
list($sections[$sName]['dbid']) = dbFetchArray($q);
}
// Create links between data
foreach ($sections as $sName => $sData) {
if (count($sData['subs'])) {
// In / After section
foreach ($sData['subs'] as $i => $sn) {
$ri = $i - 1;
while ($ri >= 0) {
$sn2 = $sections[$sData['subs'][$ri]];
if ($sn2['is_page'] == $sections[$sn]['is_page']) {
$previous = $sn2['dbid'];
break;
}
$ri --;
}
if ($ri == -1) {
$previous = $sData['dbid'];
}
$this->db->query("UPDATE man_section SET in_section={$sData['dbid']},after_section=$previous WHERE id={$sections[$sn]['dbid']}");
}
}
if ($sData['linkto'] != '') {
if (is_array($sections[$sData['linkto']])) {
$this->db->query("UPDATE man_section SET link_to={$sections[$sData['linkto']]['dbid']} WHERE id={$sData['dbid']}");
} else {
$q = $this->db->query("SELECT id FROM man_section WHERE name='" . addslashes($sData['linkto']) . "' AND version="
. $versions[$sData['version']] . " AND lang='" . addslashes($sData['language']) . "'");
if ($q && dbCount($q) == 1) {
list($toid) = dbFetchArray($q);
$this->db->query("UPDATE man_section SET link_to=$toid WHERE id={$sData['dbid']}");
}
}
}
}
// Update indices
$banwords = array();
foreach ($sections as $sName => $sData) {
if (!is_array($banwords[$sData['language']])) {
$ban = array();
$q = $this->db->query("SELECT word FROM man_index_ban WHERE lang='" . addslashes($sData['language']) . "'");
while ($r = dbFetchArray($q)) {
array_push($ban, $r[0]);
}
$banwords[$sData['lang']] = $ban;
}
$text = preg_replace('/<[^>]+>/', '', $sData['title']) . " ";
$text .= preg_replace('/<[^>]+>/', '', $sData['contents']);
$text = preg_replace('/["\s\.,;:!\(\)<>&]+/', ' ', $text);
$tl = explode(' ', $text);
$rtl = array();
foreach ($tl as $word) {
$word = strtolower($word);
if ($word != '' && !in_array($word, $banwords[$sData['lang']])) {
$rtl[$word] ++;
}
}
foreach ($rtl as $word => $count) {
$this->db->query("INSERT INTO man_index(word,wcount,lang,section) VALUES ('" . addslashes($word)
. "',$count,'" . addslashes($sData['language']) . "',{$sData['dbid']})");
}
}
}
}
?>