diff --git a/CUETools.CTDB/Web/favicon.ico b/CUETools.CTDB/Web/favicon.ico
new file mode 100644
index 0000000..a8346ad
Binary files /dev/null and b/CUETools.CTDB/Web/favicon.ico differ
diff --git a/CUETools.CTDB/Web/index.php b/CUETools.CTDB/Web/index.php
new file mode 100644
index 0000000..1d603f7
--- /dev/null
+++ b/CUETools.CTDB/Web/index.php
@@ -0,0 +1,65 @@
+
+
+
+CUETools DB
+
+
+
+CUETools Database
+Recent additions:");
+printf("");
+printf("Status: %d unique discs.
", filesize("parity/list.txt")/57);
+?>
+
diff --git a/CUETools.CTDB/Web/phpctdb/ctdb.php b/CUETools.CTDB/Web/phpctdb/ctdb.php
new file mode 100644
index 0000000..6e35c46
--- /dev/null
+++ b/CUETools.CTDB/Web/phpctdb/ctdb.php
@@ -0,0 +1,141 @@
+fp = fopen($target_file, 'rb');
+ $this->fpstats = fstat($this->fp);
+ $this->atoms = $this->parse_container_atom(0, $this->fpstats['size']);
+ $this->db = false;
+ foreach ($this->atoms as $entry) if($entry['name'] == 'CTDB') $this->db = $entry;
+ }
+
+ function __destruct() {
+ fclose($this->fp);
+ }
+
+ static function BigEndian2Int($byte_word, $signed = false) {
+
+ $int_value = 0;
+ $byte_wordlen = strlen($byte_word);
+
+ for ($i = 0; $i < $byte_wordlen; $i++) {
+ $int_value += ord($byte_word{$i}) * pow(256, ($byte_wordlen - 1 - $i));
+ }
+
+ if ($signed) {
+ $sign_mask_bit = 0x80 << (8 * ($byte_wordlen - 1));
+ if ($int_value & $sign_mask_bit) {
+ $int_value = 0 - ($int_value & ($sign_mask_bit - 1));
+ }
+ }
+
+ return $int_value;
+ }
+
+ static function LittleEndian2String($number, $minbytes=1, $synchsafe=false) {
+ $intstring = '';
+ while ($number > 0) {
+ if ($synchsafe) {
+ $intstring = $intstring.chr($number & 127);
+ $number >>= 7;
+ } else {
+ $intstring = $intstring.chr($number & 255);
+ $number >>= 8;
+ }
+ }
+ return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT);
+ }
+
+ static function BigEndian2String($number, $minbytes=1, $synchsafe=false) {
+ return strrev(phpCTDB::LittleEndian2String($number, $minbytes, $synchsafe));
+ }
+
+ static function unparse_atom($fp, $atom)
+ {
+// printf('unparse_atom(%s)
', $atom['name']);
+ $offset = ftell($fp);
+ fwrite($fp, phpCTDB::BigEndian2String(0, 4));
+ fwrite($fp, $atom['name']);
+ if (@$atom['subatoms'])
+ foreach ($atom['subatoms'] as $subatom)
+ phpCTDB::unparse_atom($fp, $subatom);
+ else if ($atom['value'])
+ fwrite($fp, $atom['value']);
+ else
+ die(sprintf("couldn't write long atom %s: size %d", $atom['name'], $atom['size']));
+ $pos = ftell($fp);
+ fseek($fp, $offset, SEEK_SET);
+ fwrite($fp, phpCTDB::BigEndian2String($pos - $offset, 4));
+ fseek($fp, $pos, SEEK_SET);
+ }
+
+ function read($offset, $len)
+ {
+ fseek($this->fp, $offset, SEEK_SET);
+ return fread($this->fp, $len);
+ }
+
+ function parse_container_atom($offset, $len)
+ {
+// printf('parse_container_atom(%d, %d)
', $offset, $len);
+ $atoms = false;
+ $fin = $offset + $len;
+ while ($offset < $fin) {
+ fseek($this->fp, $offset, SEEK_SET);
+ $atom_header = fread($this->fp, 8);
+ $atom_size = phpCTDB::BigEndian2Int(substr($atom_header, 0, 4));
+ $atom_name = substr($atom_header, 4, 4);
+ $atom['name'] = $atom_name;
+ $atom['size'] = $atom_size - 8;
+ $atom['offset'] = $offset + 8;
+ if ($atom_size - 8 <= 256)
+ $atom['value'] = fread($this->fp, $atom_size - 8);
+ else
+ $atom['value'] = false;
+// echo $len, ':', $offset, ":", $atom_size, ":", $atom_name, '
';
+ if ($atom_name == 'CTDB' || $atom_name == 'DISC' || $atom_name == 'TOC ' || ($atom_name == 'HEAD' && ($atom_size != 28 || 256 != phpCTDB::BigEndian2Int(substr($atom['value'],0,4)))))
+ {
+ $atom['subatoms'] = $this->parse_container_atom($offset + 8, $atom_size - 8);
+ foreach ($atom['subatoms'] as $param)
+ switch ($param['name']) {
+ case 'HEAD':
+ case 'CRC ':
+ case 'MBID':
+ case 'ART ':
+ case 'nam ':
+ case 'NPAR':
+ case 'CONF':
+ case 'TOTL':
+ case 'PAR ':
+ $atom[$param['name']] = $param;
+ break;
+ case 'DISC':
+ $atom['discs'][] = $param;
+ break;
+ }
+ } else
+ $atom['subatoms'] = false;
+ switch ($atom_name)
+ {
+ case 'CRC ':
+ case 'NPAR':
+ case 'CONF':
+ case 'TOTL':
+ $atom['int'] = phpCTDB::BigEndian2Int($atom['value']);
+ break;
+ }
+ $offset += $atom_size;
+ $atoms[] = $atom;
+ }
+ if ($offset > $fin)
+ die(printf("bad atom: offset=%d, fin=%d", $offset, $fin));
+ return $atoms;
+ }
+}
+?>
diff --git a/CUETools.CTDB/Web/submit.php b/CUETools.CTDB/Web/submit.php
new file mode 100644
index 0000000..a546d57
--- /dev/null
+++ b/CUETools.CTDB/Web/submit.php
@@ -0,0 +1,168 @@
+
+ * @link http://de3.php.net/manual/en/ini.core.php#79564
+ */
+function php_to_byte($v){
+ $l = substr($v, -1);
+ $ret = substr($v, 0, -1);
+ switch(strtoupper($l)){
+ case 'P':
+ $ret *= 1024;
+ case 'T':
+ $ret *= 1024;
+ case 'G':
+ $ret *= 1024;
+ case 'M':
+ $ret *= 1024;
+ case 'K':
+ $ret *= 1024;
+ break;
+ }
+ return $ret;
+}
+
+// Return the human readable size of a file
+// @param int $size a file size
+// @param int $dec a number of decimal places
+
+function filesize_h($size, $dec = 1)
+{
+ $sizes = array('byte(s)', 'kb', 'mb', 'gb');
+ $count = count($sizes);
+ $i = 0;
+
+ while ($size >= 1024 && ($i < $count - 1)) {
+ $size /= 1024;
+ $i++;
+ }
+
+ return round($size, $dec) . ' ' . $sizes[$i];
+}
+
+$file = $_FILES['uploadedfile'];
+
+//echo $file['name'], ini_get('upload_max_filesize');
+
+ // give info on PHP catched upload errors
+ if($file['error']) switch($file['error']){
+ case 1:
+ case 2:
+ echo sprintf($lang['uploadsize'],
+ filesize_h(php_to_byte(ini_get('upload_max_filesize'))));
+ echo "Error ", $file['error'];
+ return;
+ default:
+ echo $lang['uploadfail'];
+ echo "Error ", $file['error'];
+ }
+
+//if ($_SERVER['HTTP_USER_AGENT'] != "CUETools 205") {
+// echo "user agent ", $_SERVER['HTTP_USER_AGENT'], " is not allowed";
+// return;
+//}
+
+$tmpname = $file['tmp_name'];
+$size = (@file_exists($tmpname)) ? filesize($tmpname) : 0;
+if ($size == 0) {
+ echo "no file uploaded";
+ return;
+}
+
+$id = $_POST['id'];
+$err = sscanf($id, "%03d-%04x%04x-%04x%04x-%04x%04x", $tracks, $id1a, $id1b, $id2a, $id2b, $cddbida, $cddbidb);
+$parsedid = sprintf("%03d-%04x%04x-%04x%04x-%04x%04x", $tracks, $id1a, $id1b, $id2a, $id2b, $cddbida, $cddbidb);
+if ($id != $parsedid)
+ die("bad id ". $id);
+
+$target_path = sprintf("parity/%x/%x/%x/%s", $id1b & 15, ($id1b >> 4) & 15, ($id1b >> 8) & 15, $parsedid);
+$target_file = sprintf("%s/ctdb.bin", $target_path, $parsedid);
+
+@mkdir($target_path, 0777, true);
+
+$ctdb = new phpCTDB($tmpname);
+$ctdb1 = @file_exists($target_file) ? new phpCTDB($target_file) : false;
+$merging = $ctdb1 ? true : false;
+
+$ftyp['name'] = 'ftyp';
+$ftyp['value'] = 'CTDB';
+
+$newctdb['name'] = 'CTDB';
+ $newhead['name'] = 'HEAD';
+ $newtotal['name'] = 'TOTL';
+ $newtotal['value'] = $ctdb1 ? phpCTDB::BigEndian2String($ctdb1->db['HEAD']['TOTL']['int'] + 1,4) : $ctdb->db['HEAD']['TOTL']['value'];
+ $newhead['subatoms'][] = $newtotal;
+$newctdb['subatoms'][] = $newhead;
+
+if ($ctdb1)
+foreach ($ctdb1->db['subatoms'] as $disc)
+ if ($disc['name'] == 'DISC')
+ {
+ if ($crc == $disc['CRC ']['value'])
+ die("duplicate entry");
+
+ $newdisc = false;
+ $newdisc['name'] = 'DISC';
+ $newdisc['subatoms'][] = $disc['CRC '];
+ $newdisc['subatoms'][] = $disc['NPAR'];
+ $newdisc['subatoms'][] = $disc['CONF'];
+ $newpar['name'] = 'PAR ';
+ $newpar['value'] = $ctdb1->read($disc['PAR ']['offset'], 16);
+ $newdisc['subatoms'][] = $newpar;
+ $newctdb['subatoms'][] = $newdisc;
+ }
+
+$discs = 0;
+foreach ($ctdb->db['subatoms'] as $disc)
+ if ($disc['name'] == 'DISC')
+ {
+ $crc = $disc['CRC ']['value'];
+
+ $newdisc = false;
+ $newdisc['name'] = 'DISC';
+ $newdisc['subatoms'][] = $disc['CRC '];
+ $newdisc['subatoms'][] = $disc['NPAR'];
+ $newdisc['subatoms'][] = $disc['CONF'];
+ $newpar['name'] = 'PAR ';
+ $newpar['value'] = $ctdb->read($disc['PAR ']['offset'], 16);
+ $newdisc['subatoms'][] = $newpar;
+ $newctdb['subatoms'][] = $newdisc;
+ $discs++;
+ }
+if ($discs > 1)
+ die('One disc at a time, please');
+if ($discs < 1)
+ die('No disc records found');
+
+$tname = sprintf("%s/ctdb.tmp", $target_path);
+$tfp = fopen($tname, 'wb');
+phpCTDB::unparse_atom($tfp,$ftyp);
+phpCTDB::unparse_atom($tfp,$newctdb);
+fclose($tfp);
+unset($ctdb);
+unset($ctdb1);
+
+$crca = phpCTDB::BigEndian2Int(substr($crc,0,2));
+$crcb = phpCTDB::BigEndian2Int(substr($crc,2,2));
+$destname = sprintf("%s/%04x%04x.bin", $target_path, $crca, $crcb);
+if(!move_uploaded_file($tmpname, $destname))
+ die('error uploading file ' . $tmpname . ' to ' . $destname);
+
+if(!rename($tname,sprintf("%s/ctdb.bin", $target_path)))
+ die('error uploading file ' . $target_path);
+
+$listfp = fopen("parity/list.txt", 'a');
+fwrite($listfp, $destname);
+fwrite($listfp, "\n");
+fclose($listfp);
+
+if ($merging)
+ printf("%s has been updated", $parsedid);
+else
+ printf("%s has been uploaded", $parsedid);
+?>