mirror of
https://github.com/claunia/cuetools.net.git
synced 2025-12-16 18:14:25 +00:00
CD parity information database
This commit is contained in:
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Management;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using CUETools.CDImage;
|
||||
@@ -17,17 +18,22 @@ namespace CUETools.CTDB
|
||||
private CDImageLayout toc;
|
||||
private HttpStatusCode accResult;
|
||||
private string id;
|
||||
private string subResult;
|
||||
private byte[] contents;
|
||||
private int pos;
|
||||
private int length;
|
||||
private int confidence;
|
||||
private int total;
|
||||
List<DBEntry> entries = new List<DBEntry>();
|
||||
DBEntry selectedEntry;
|
||||
IWebProxy proxy;
|
||||
HttpUploadHelper uploadHelper;
|
||||
|
||||
public CUEToolsDB(CDImageLayout toc)
|
||||
public CUEToolsDB(CDImageLayout toc, IWebProxy proxy)
|
||||
{
|
||||
this.toc = toc;
|
||||
this.length = (int)toc.AudioLength * 588;
|
||||
this.proxy = proxy;
|
||||
this.uploadHelper = new HttpUploadHelper();
|
||||
}
|
||||
|
||||
public void ContactDB(string id)
|
||||
@@ -51,7 +57,7 @@ namespace CUETools.CTDB
|
||||
|
||||
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
|
||||
req.Method = "GET";
|
||||
req.Proxy = WebRequest.GetSystemWebProxy();
|
||||
req.Proxy = proxy;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -76,6 +82,8 @@ namespace CUETools.CTDB
|
||||
}
|
||||
}
|
||||
Parse();
|
||||
if (entries.Count == 0)
|
||||
accResult = HttpStatusCode.NoContent;
|
||||
}
|
||||
catch (WebException ex)
|
||||
{
|
||||
@@ -86,22 +94,23 @@ namespace CUETools.CTDB
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Database entry format:
|
||||
/// 'CTDB' version(0x00000100) size
|
||||
/// 'HEAD' version(0x00000100) size disc-count total-submissions
|
||||
/// 'DISC' version(0x00000100) size
|
||||
/// 'TOC ' version(0x00000100) size track-count preGap
|
||||
/// 'TRAK' ersion(0x00000100) size flags(1==isAudio) length(frames)
|
||||
/// .... track-count
|
||||
/// 'ARDB' version(0x00000100) size pressings-count
|
||||
/// 'ARCD' version(0x00000100) size CRC1 ... CRCN
|
||||
/// .... pressings-count
|
||||
/// 'PAR8' version(0x00000100) size parity-data
|
||||
/// 'CONF' version(0x00000100) size confidence
|
||||
/// 'CRC ' version(0x00000100) size CRC32 min-offset max-offset ...
|
||||
/// .... disc-count
|
||||
/// </summary>
|
||||
static string cpuInfo = null;
|
||||
|
||||
public static string GetCPUID()
|
||||
{
|
||||
if (cpuInfo == null)
|
||||
{
|
||||
ManagementClass mc = new ManagementClass("win32_processor");
|
||||
foreach (ManagementObject mo in mc.GetInstances())
|
||||
{
|
||||
//Get only the first CPU's ID
|
||||
cpuInfo = mo.Properties["processorID"].Value.ToString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return cpuInfo ?? "unknown";
|
||||
}
|
||||
|
||||
public string Submit(int confidence, int total)
|
||||
{
|
||||
if (id == null)
|
||||
@@ -120,75 +129,72 @@ namespace CUETools.CTDB
|
||||
|
||||
UploadFile[] files = new UploadFile[1];
|
||||
MemoryStream newcontents = new MemoryStream();
|
||||
using (DBHDR CTDB = new DBHDR(newcontents, "CTDB", 0x100))
|
||||
using (DBHDR FTYP = new DBHDR(newcontents, "ftyp"))
|
||||
FTYP.Write("CTDB");
|
||||
using (DBHDR CTDB = new DBHDR(newcontents, "CTDB"))
|
||||
{
|
||||
using (DBHDR HEAD = new DBHDR(newcontents, "HEAD", 0x100))
|
||||
using (DBHDR HEAD = CTDB.HDR("HEAD"))
|
||||
{
|
||||
DBHDR.WriteInt(newcontents, 1); // disc count
|
||||
DBHDR.WriteInt(newcontents, total);
|
||||
HEAD.Write(0x100); // version
|
||||
HEAD.Write(1); // disc count
|
||||
HEAD.Write(total); // total submissions
|
||||
HEAD.Write(DateTime.Now); // date
|
||||
}
|
||||
using (DBHDR DISC = new DBHDR(newcontents, "DISC", 0x100))
|
||||
using (DBHDR DISC = CTDB.HDR("DISC"))
|
||||
{
|
||||
using (DBHDR TOC = new DBHDR(newcontents, "TOC ", 0x100))
|
||||
using (DBHDR TOC = DISC.HDR("TOC "))
|
||||
{
|
||||
DBHDR.WriteInt(newcontents, toc.TrackCount);
|
||||
DBHDR.WriteInt(newcontents, toc.Pregap);
|
||||
using (DBHDR INFO = TOC.HDR("INFO"))
|
||||
{
|
||||
INFO.Write(toc.TrackCount);
|
||||
INFO.Write(toc.Pregap);
|
||||
}
|
||||
for (int i = 1; i <= toc.TrackCount; i++)
|
||||
using (DBHDR TRAK = new DBHDR(newcontents, "TRAK", 0x100))
|
||||
using (DBHDR TRAK = TOC.HDR("TRAK"))
|
||||
{
|
||||
DBHDR.WriteInt(newcontents, toc[i].IsAudio ? 1 : 0);
|
||||
DBHDR.WriteInt(newcontents, toc[i].Length);
|
||||
TRAK.Write(toc[i].IsAudio ? 1 : 0);
|
||||
TRAK.Write(toc[i].Length);
|
||||
}
|
||||
}
|
||||
using (DBHDR PAR8 = new DBHDR(newcontents, "CONF", 0x100))
|
||||
{
|
||||
DBHDR.WriteInt(newcontents, confidence);
|
||||
}
|
||||
using (DBHDR PAR8 = new DBHDR(newcontents, "CRC ", 0x100))
|
||||
{
|
||||
DBHDR.WriteInt(newcontents, verify.CRC);
|
||||
}
|
||||
using (DBHDR PAR8 = new DBHDR(newcontents, "PAR8", 0x100))
|
||||
{
|
||||
newcontents.Write(verify.Parity, 0, verify.Parity.Length);
|
||||
}
|
||||
using (DBHDR USER = DISC.HDR("USER")) USER.Write(GetCPUID());
|
||||
using (DBHDR TOOL = DISC.HDR("TOOL")) TOOL.Write("CUETools 205");
|
||||
using (DBHDR DATE = DISC.HDR("DATE")) DATE.Write(DateTime.Now);
|
||||
using (DBHDR CONF = DISC.HDR("CONF")) CONF.Write(confidence);
|
||||
using (DBHDR NPAR = DISC.HDR("NPAR")) NPAR.Write(verify.NPAR);
|
||||
using (DBHDR CRC_ = DISC.HDR("CRC ")) CRC_.Write(verify.CRC);
|
||||
using (DBHDR PAR_ = DISC.HDR("PAR ")) PAR_.Write(verify.Parity);
|
||||
}
|
||||
}
|
||||
newcontents.Position = 0;
|
||||
files[0] = new UploadFile(newcontents, "uploadedfile", "data.bin", "image/binary");
|
||||
HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://db.cuetools.net/uploader.php");
|
||||
req.Proxy = WebRequest.GetSystemWebProxy();
|
||||
req.Proxy = proxy;
|
||||
req.UserAgent = "CUETools 205";
|
||||
NameValueCollection form = new NameValueCollection();
|
||||
form.Add("id", String.Format("{0:d3}-{1:x8}-{2:x8}-{3:x8}", toc.AudioTracks, discId1, discId2, cddbDiscId));
|
||||
HttpWebResponse resp = HttpUploadHelper.Upload(req, files, form);
|
||||
string errtext;
|
||||
HttpWebResponse resp = uploadHelper.Upload(req, files, form);
|
||||
using (Stream s = resp.GetResponseStream())
|
||||
using (StreamReader sr = new StreamReader(s))
|
||||
{
|
||||
errtext = sr.ReadToEnd();
|
||||
}
|
||||
return errtext;
|
||||
subResult = sr.ReadToEnd();
|
||||
return subResult;
|
||||
}
|
||||
|
||||
private string ReadHDR(out int end)
|
||||
{
|
||||
int size = ReadInt();
|
||||
string res = Encoding.ASCII.GetString(contents, pos, 4);
|
||||
pos += 4;
|
||||
int version = ReadInt();
|
||||
if (version >= 0x200)
|
||||
throw new Exception("unsupported CTDB version");
|
||||
int size = ReadInt();
|
||||
end = pos + size;
|
||||
end = pos + size - 8;
|
||||
return res;
|
||||
}
|
||||
|
||||
private int ReadInt()
|
||||
{
|
||||
int value =
|
||||
(contents[pos] +
|
||||
(contents[pos + 1] << 8) +
|
||||
(contents[pos + 2] << 16) +
|
||||
(contents[pos + 3] << 24));
|
||||
(contents[pos + 3] +
|
||||
(contents[pos + 2] << 8) +
|
||||
(contents[pos + 1] << 16) +
|
||||
(contents[pos + 0] << 24));
|
||||
pos += 4;
|
||||
return value;
|
||||
}
|
||||
@@ -196,10 +202,10 @@ namespace CUETools.CTDB
|
||||
private uint ReadUInt()
|
||||
{
|
||||
uint value =
|
||||
((uint)contents[pos] +
|
||||
((uint)contents[pos + 1] << 8) +
|
||||
((uint)contents[pos + 2] << 16) +
|
||||
((uint)contents[pos + 3] << 24));
|
||||
((uint)contents[pos + 3] +
|
||||
((uint)contents[pos + 2] << 8) +
|
||||
((uint)contents[pos + 1] << 16) +
|
||||
((uint)contents[pos + 0] << 24));
|
||||
pos += 4;
|
||||
return value;
|
||||
}
|
||||
@@ -212,12 +218,21 @@ namespace CUETools.CTDB
|
||||
pos = 0;
|
||||
int end;
|
||||
string hdr = ReadHDR(out end);
|
||||
if (hdr != "CTDB") throw new Exception("invalid CTDB file");
|
||||
if (end != contents.Length) throw new Exception("incomplete CTDB file");
|
||||
uint magic = ReadUInt();
|
||||
if (hdr != "ftyp" || magic != 0x43544442 || end != pos)
|
||||
throw new Exception("invalid CTDB file");
|
||||
hdr = ReadHDR(out end);
|
||||
if (hdr != "HEAD") throw new Exception("invalid CTDB file");
|
||||
if (hdr != "CTDB" || end != contents.Length)
|
||||
throw new Exception("invalid CTDB file");
|
||||
hdr = ReadHDR(out end);
|
||||
if (hdr != "HEAD")
|
||||
throw new Exception("invalid CTDB file");
|
||||
uint version = ReadUInt();
|
||||
int discCount = ReadInt();
|
||||
total = ReadInt();
|
||||
if (discCount <= 0 || version >= 0x200)
|
||||
throw new Exception("invalid CTDB file");
|
||||
// date
|
||||
pos = end;
|
||||
while (pos < contents.Length)
|
||||
{
|
||||
@@ -229,11 +244,11 @@ namespace CUETools.CTDB
|
||||
}
|
||||
int endDisc = end;
|
||||
uint crc = 0;
|
||||
int parPos = 0, parLen = 0, conf = 0;
|
||||
int parPos = 0, parLen = 0, conf = 0, npar = 0;
|
||||
while (pos < endDisc)
|
||||
{
|
||||
hdr = ReadHDR(out end);
|
||||
if (hdr == "PAR8")
|
||||
if (hdr == "PAR ")
|
||||
{
|
||||
parPos = pos;
|
||||
parLen = end - pos;
|
||||
@@ -242,10 +257,13 @@ namespace CUETools.CTDB
|
||||
crc = ReadUInt();
|
||||
else if (hdr == "CONF")
|
||||
conf = ReadInt();
|
||||
else if (hdr == "NPAR")
|
||||
npar = ReadInt();
|
||||
pos = end;
|
||||
}
|
||||
if (parPos != 0)
|
||||
entries.Add(new DBEntry(parPos, parLen, conf, crc));
|
||||
if (parPos != 0 && npar >= 2 && npar <= 16 && conf >= 0)
|
||||
//if (parPos != 0 && npar >= 2 && npar <= 16 && conf != 0)
|
||||
entries.Add(new DBEntry(parPos, parLen, conf, npar, crc));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,16 +271,22 @@ namespace CUETools.CTDB
|
||||
{
|
||||
foreach (DBEntry entry in entries)
|
||||
{
|
||||
verify.VerifyParity(contents, entry.pos, entry.len);
|
||||
if (!verify.HasErrors || verify.CanRecover)
|
||||
confidence = entry.conf;
|
||||
break;
|
||||
if (!verify.FindOffset(entry.npar, contents, entry.pos, entry.crc, out entry.offset, out entry.hasErrors))
|
||||
entry.canRecover = false;
|
||||
else if (entry.hasErrors)
|
||||
{
|
||||
entry.repair = verify.VerifyParity(entry.npar, contents, entry.pos, entry.len, entry.offset);
|
||||
entry.canRecover = entry.repair.CanRecover;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Init()
|
||||
public void Init(bool encode)
|
||||
{
|
||||
verify = new CDRepairEncode(length, 10 * 588 * 2, 8, accResult == HttpStatusCode.OK);
|
||||
int npar = 8;
|
||||
foreach (DBEntry entry in entries)
|
||||
npar = Math.Max(npar, entry.npar);
|
||||
verify = new CDRepairEncode(length, 10 * 588 * 2, npar, entries.Count > 0, encode);
|
||||
}
|
||||
|
||||
public int Total
|
||||
@@ -299,35 +323,95 @@ namespace CUETools.CTDB
|
||||
}
|
||||
}
|
||||
|
||||
public DBEntry SelectedEntry
|
||||
{
|
||||
set
|
||||
{
|
||||
selectedEntry = value;
|
||||
}
|
||||
get
|
||||
{
|
||||
return selectedEntry;
|
||||
}
|
||||
}
|
||||
|
||||
public string Status
|
||||
{
|
||||
get
|
||||
{
|
||||
//sw.WriteLine("CUETools DB CRC: {0:x8}", Verify.CRC);
|
||||
string res = null;
|
||||
if (DBStatus != null)
|
||||
return DBStatus;
|
||||
if (!verify.HasErrors)
|
||||
return string.Format("verified OK, confidence {0}/{1}", confidence, total);
|
||||
if (verify.CanRecover)
|
||||
return string.Format("contains correctable errors, confidence {0}/{1}", confidence, total);
|
||||
return "could not be verified";
|
||||
res = DBStatus;
|
||||
else
|
||||
{
|
||||
DBEntry popular = null;
|
||||
foreach (DBEntry entry in entries)
|
||||
if (!entry.hasErrors || entry.canRecover)
|
||||
if (popular == null || entry.conf > popular.conf)
|
||||
popular = entry;
|
||||
if (popular != null)
|
||||
res = popular.Status;
|
||||
foreach (DBEntry entry in entries)
|
||||
if (entry != popular && (!entry.hasErrors || entry.canRecover))
|
||||
res += ", or " + entry.Status;
|
||||
if (res == null)
|
||||
res = "could not be verified";
|
||||
}
|
||||
if (subResult != null)
|
||||
res += ", " + subResult;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<DBEntry> Entries
|
||||
{
|
||||
get
|
||||
{
|
||||
return entries;
|
||||
}
|
||||
}
|
||||
|
||||
public HttpUploadHelper UploadHelper
|
||||
{
|
||||
get
|
||||
{
|
||||
return uploadHelper;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class DBEntry
|
||||
public class DBEntry
|
||||
{
|
||||
public int pos;
|
||||
public int len;
|
||||
public int conf;
|
||||
public int npar;
|
||||
public int offset;
|
||||
public uint crc;
|
||||
public bool hasErrors;
|
||||
public bool canRecover;
|
||||
public CDRepairFix repair;
|
||||
|
||||
public DBEntry(int pos, int len, int conf, uint crc)
|
||||
public DBEntry(int pos, int len, int conf, int npar, uint crc)
|
||||
{
|
||||
this.pos = pos;
|
||||
this.len = len;
|
||||
this.conf = conf;
|
||||
this.crc = crc;
|
||||
this.npar = npar;
|
||||
}
|
||||
|
||||
public string Status
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!hasErrors)
|
||||
return string.Format("verified OK, confidence {0}", conf);
|
||||
if (canRecover)
|
||||
return string.Format("contains {1} correctable errors, confidence {0}", conf, repair.CorrectableErrors);
|
||||
return "could not be verified";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,41 +420,74 @@ namespace CUETools.CTDB
|
||||
private long lenOffs;
|
||||
private MemoryStream stream;
|
||||
|
||||
public DBHDR(MemoryStream stream, string name, int version)
|
||||
public DBHDR(MemoryStream stream, string name)
|
||||
{
|
||||
this.stream = stream;
|
||||
stream.Write(Encoding.ASCII.GetBytes(name), 0, 4);
|
||||
WriteInt(stream, version);
|
||||
lenOffs = stream.Position;
|
||||
WriteInt(stream, 0);
|
||||
Write(0);
|
||||
Write(name);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
long fin = stream.Position;
|
||||
stream.Position = lenOffs;
|
||||
WriteInt(stream, (int)(fin - lenOffs - 4));
|
||||
Write((int)(fin - lenOffs));
|
||||
stream.Position = fin;
|
||||
}
|
||||
|
||||
public static void WriteInt(MemoryStream stream, int value)
|
||||
public void Write(int value)
|
||||
{
|
||||
byte[] temp = new byte[4];
|
||||
temp[0] = (byte)(value & 0xff);
|
||||
temp[1] = (byte)((value >> 8) & 0xff);
|
||||
temp[2] = (byte)((value >> 16) & 0xff);
|
||||
temp[3] = (byte)((value >> 24) & 0xff);
|
||||
stream.Write(temp, 0, 4);
|
||||
temp[3] = (byte)(value & 0xff);
|
||||
temp[2] = (byte)((value >> 8) & 0xff);
|
||||
temp[1] = (byte)((value >> 16) & 0xff);
|
||||
temp[0] = (byte)((value >> 24) & 0xff);
|
||||
Write(temp);
|
||||
}
|
||||
|
||||
public static void WriteInt(MemoryStream stream, uint value)
|
||||
public void Write(uint value)
|
||||
{
|
||||
byte[] temp = new byte[4];
|
||||
temp[0] = (byte)(value & 0xff);
|
||||
temp[1] = (byte)((value >> 8) & 0xff);
|
||||
temp[2] = (byte)((value >> 16) & 0xff);
|
||||
temp[3] = (byte)((value >> 24) & 0xff);
|
||||
stream.Write(temp, 0, 4);
|
||||
temp[3] = (byte)(value & 0xff);
|
||||
temp[2] = (byte)((value >> 8) & 0xff);
|
||||
temp[1] = (byte)((value >> 16) & 0xff);
|
||||
temp[0] = (byte)((value >> 24) & 0xff);
|
||||
Write(temp);
|
||||
}
|
||||
|
||||
public void Write(long value)
|
||||
{
|
||||
byte[] temp = new byte[8];
|
||||
temp[7] = (byte)((value) & 0xff);
|
||||
temp[6] = (byte)((value >> 8) & 0xff);
|
||||
temp[5] = (byte)((value >> 16) & 0xff);
|
||||
temp[4] = (byte)((value >> 24) & 0xff);
|
||||
temp[3] = (byte)((value >> 32) & 0xff);
|
||||
temp[2] = (byte)((value >> 40) & 0xff);
|
||||
temp[1] = (byte)((value >> 48) & 0xff);
|
||||
temp[0] = (byte)((value >> 56) & 0xff);
|
||||
Write(temp);
|
||||
}
|
||||
|
||||
public void Write(string value)
|
||||
{
|
||||
Write(Encoding.UTF8.GetBytes(value));
|
||||
}
|
||||
|
||||
public void Write(DateTime value)
|
||||
{
|
||||
Write(value.ToFileTimeUtc());
|
||||
}
|
||||
|
||||
public void Write(byte[] value)
|
||||
{
|
||||
stream.Write(value, 0, value.Length);
|
||||
}
|
||||
|
||||
public DBHDR HDR(string name)
|
||||
{
|
||||
return new DBHDR(stream, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user