2022-12-11 19:47:43 +08:00
|
|
|
#include "freeprojectsetformat.h"
|
2022-12-16 15:54:02 +08:00
|
|
|
#include "../utils.h"
|
2022-12-11 19:47:43 +08:00
|
|
|
#include <QFile>
|
|
|
|
#include <QXmlStreamReader>
|
2022-12-16 14:41:24 +08:00
|
|
|
#include <QXmlStreamWriter>
|
2022-12-11 19:47:43 +08:00
|
|
|
|
|
|
|
QList<POJProblem> importFreeProblemSet(const QString &filename)
|
|
|
|
{
|
|
|
|
QFile file(filename);
|
|
|
|
QList<POJProblem> problems;
|
2022-12-16 15:54:02 +08:00
|
|
|
if (!file.open(QFile::ReadOnly)) {
|
|
|
|
throw FileError(QObject::tr("Can't open file \"%1\" for read.").arg(filename));
|
|
|
|
}
|
2022-12-11 19:47:43 +08:00
|
|
|
QXmlStreamReader xml;
|
|
|
|
xml.setDevice(&file);
|
|
|
|
POJProblem currentProblem;
|
|
|
|
POJProblemCase currentCase;
|
|
|
|
QString currentEleName;
|
|
|
|
while(!xml.atEnd()) {
|
|
|
|
xml.readNext();
|
|
|
|
switch (xml.tokenType()) {
|
|
|
|
case QXmlStreamReader::TokenType::StartElement:
|
|
|
|
currentEleName = xml.name().toString();
|
|
|
|
if (xml.name()=="item") {
|
|
|
|
currentProblem=std::make_shared<OJProblem>();
|
|
|
|
} else if (currentProblem &&
|
2022-12-11 21:46:51 +08:00
|
|
|
(xml.name()=="test_input")) {
|
2022-12-11 19:47:43 +08:00
|
|
|
currentCase = std::make_shared<OJProblemCase>();
|
|
|
|
foreach (const QXmlStreamAttribute& attr, xml.attributes()) {
|
|
|
|
if (attr.name() == "name") {
|
2022-12-11 21:46:51 +08:00
|
|
|
currentCase->name = attr.value().toString().trimmed();
|
2022-12-11 19:47:43 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
currentCase->name = QObject::tr("Problem Case %1").arg(currentProblem->cases.count()+1);
|
|
|
|
} else if (currentProblem &&
|
|
|
|
xml.name()=="time_limit") {
|
2022-12-13 08:49:20 +08:00
|
|
|
currentEleName = xml.name().toString();
|
2022-12-11 19:47:43 +08:00
|
|
|
foreach (const QXmlStreamAttribute& attr, xml.attributes()) {
|
2022-12-13 08:49:20 +08:00
|
|
|
if (attr.name() == "unit") {
|
|
|
|
if (attr.value()=="ms")
|
|
|
|
currentProblem->timeLimitUnit = ProblemTimeLimitUnit::Milliseconds;
|
|
|
|
else if (attr.value()=="s")
|
|
|
|
currentProblem->timeLimitUnit = ProblemTimeLimitUnit::Seconds;
|
2022-12-11 19:47:43 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (currentProblem &&
|
|
|
|
xml.name()=="memory_limit") {
|
2022-12-13 08:49:20 +08:00
|
|
|
currentEleName = xml.name().toString();
|
2022-12-11 19:47:43 +08:00
|
|
|
foreach (const QXmlStreamAttribute& attr, xml.attributes()) {
|
2022-12-13 08:49:20 +08:00
|
|
|
if (attr.name() == "unit") {
|
|
|
|
if (attr.value()=="mb")
|
|
|
|
currentProblem->memoryLimitUnit = ProblemMemoryLimitUnit::MB;
|
|
|
|
else if (attr.value()=="kb")
|
|
|
|
currentProblem->memoryLimitUnit = ProblemMemoryLimitUnit::KB;
|
|
|
|
else if (attr.value()=="gb")
|
|
|
|
currentProblem->memoryLimitUnit = ProblemMemoryLimitUnit::GB;
|
2022-12-11 19:47:43 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case QXmlStreamReader::TokenType::EndElement:
|
|
|
|
currentEleName.clear();
|
|
|
|
if (currentProblem && xml.name()=="item") {
|
|
|
|
problems.append(currentProblem);
|
|
|
|
currentProblem.reset();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case QXmlStreamReader::TokenType::Characters:
|
2022-12-11 21:46:51 +08:00
|
|
|
if (currentCase && currentProblem && currentEleName=="test_input") {
|
2022-12-11 19:47:43 +08:00
|
|
|
currentCase->input = xml.text().toString();
|
2022-12-11 21:46:51 +08:00
|
|
|
} else if (currentCase && currentProblem && currentEleName=="test_output" ) {
|
2022-12-11 19:47:43 +08:00
|
|
|
currentCase->expected = xml.text().toString();
|
|
|
|
currentProblem->cases.append(currentCase);
|
|
|
|
currentCase.reset();
|
|
|
|
} else if (currentProblem && currentEleName=="description") {
|
|
|
|
currentProblem->description = xml.text().toString();
|
|
|
|
} else if (currentProblem && currentEleName=="hint") {
|
|
|
|
currentProblem->hint = xml.text().toString();
|
|
|
|
} else if (currentProblem && currentEleName=="title") {
|
2022-12-13 08:49:20 +08:00
|
|
|
currentProblem->name = xml.text().toString().trimmed().replace(" "," ");
|
2022-12-11 21:46:51 +08:00
|
|
|
} else if (currentProblem && currentEleName=="url") {
|
|
|
|
currentProblem->url = xml.text().toString().trimmed();
|
2022-12-11 19:47:43 +08:00
|
|
|
} else if (currentProblem && currentEleName=="time_limit") {
|
|
|
|
currentProblem->timeLimit = xml.text().toInt();
|
|
|
|
} else if (currentProblem && currentEleName=="memory_limit") {
|
|
|
|
currentProblem->memoryLimit = xml.text().toInt();
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return problems;
|
|
|
|
}
|
2022-12-16 14:41:24 +08:00
|
|
|
|
|
|
|
void exportFreeProblemSet(const QList<POJProblem> &problems, const QString &filename)
|
|
|
|
{
|
|
|
|
QFile file(filename);
|
2022-12-16 15:54:02 +08:00
|
|
|
if (!file.open(QFile::WriteOnly|QFile::Truncate)) {
|
|
|
|
throw FileError(QObject::tr("Can't open file \"%1\" for write.").arg(filename));
|
|
|
|
}
|
2022-12-16 14:41:24 +08:00
|
|
|
QXmlStreamWriter writer(&file);
|
|
|
|
writer.setAutoFormatting(true);
|
|
|
|
writer.writeStartDocument();
|
2022-12-16 15:54:02 +08:00
|
|
|
//fps
|
|
|
|
{
|
|
|
|
writer.writeStartElement("fps");
|
|
|
|
writer.writeAttribute("version","1.4");
|
|
|
|
writer.writeAttribute("url","https://github.com/zhblue/freeproblemset/");
|
|
|
|
{
|
|
|
|
writer.writeStartElement("generator");
|
|
|
|
writer.writeAttribute("name","RedPanda-C++");
|
2024-05-08 09:56:00 +08:00
|
|
|
writer.writeAttribute("url","http://royqh.net/redpandacpp/");
|
2022-12-16 15:54:02 +08:00
|
|
|
writer.writeEndElement(); // generator
|
|
|
|
}
|
|
|
|
foreach(const POJProblem& problem,problems) {
|
|
|
|
writer.writeStartElement("item");
|
|
|
|
{
|
|
|
|
writer.writeStartElement("title");
|
|
|
|
writer.writeCDATA(problem->name);
|
|
|
|
writer.writeEndElement(); //title
|
|
|
|
}
|
|
|
|
{
|
|
|
|
writer.writeStartElement("url");
|
|
|
|
writer.writeCDATA(problem->url);
|
|
|
|
writer.writeEndElement();//url
|
|
|
|
}
|
|
|
|
{
|
|
|
|
QString unit;
|
|
|
|
switch(problem->timeLimitUnit) {
|
|
|
|
case ProblemTimeLimitUnit::Milliseconds:
|
|
|
|
unit = "ms";
|
|
|
|
break;
|
|
|
|
case ProblemTimeLimitUnit::Seconds:
|
|
|
|
unit = "s";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
writer.writeStartElement("time_limit");
|
|
|
|
writer.writeAttribute("unit",unit);
|
|
|
|
writer.writeCDATA(QString("%1").arg(problem->timeLimit));
|
|
|
|
writer.writeEndElement(); //time_limit
|
|
|
|
}
|
|
|
|
{
|
|
|
|
QString unit;
|
|
|
|
switch(problem->memoryLimitUnit) {
|
|
|
|
case ProblemMemoryLimitUnit::MB:
|
|
|
|
unit = "mb";
|
|
|
|
break;
|
|
|
|
case ProblemMemoryLimitUnit::KB:
|
|
|
|
unit = "kb";
|
|
|
|
break;
|
|
|
|
case ProblemMemoryLimitUnit::GB:
|
|
|
|
unit = "gb";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
writer.writeStartElement("memory_limit");
|
|
|
|
writer.writeAttribute("unit",unit);
|
|
|
|
writer.writeCDATA(QString("%1").arg(problem->memoryLimit));
|
|
|
|
writer.writeEndElement(); //memory_limit
|
|
|
|
}
|
|
|
|
{
|
|
|
|
writer.writeStartElement("description");
|
|
|
|
writer.writeCDATA(problem->description);
|
|
|
|
writer.writeEndElement(); //description
|
|
|
|
}
|
|
|
|
foreach(const POJProblemCase& pCase, problem->cases) {
|
|
|
|
writer.writeStartElement("test_input");
|
|
|
|
writer.writeAttribute("name",pCase->name);
|
|
|
|
writer.writeCDATA(pCase->input);
|
|
|
|
writer.writeEndElement(); //test_input
|
|
|
|
writer.writeStartElement("test_output");
|
|
|
|
writer.writeCDATA(pCase->expected);
|
|
|
|
writer.writeEndElement(); //test_output
|
|
|
|
}
|
|
|
|
{
|
|
|
|
writer.writeStartElement("hint");
|
|
|
|
writer.writeCDATA(problem->hint);
|
|
|
|
writer.writeEndElement(); //hint
|
|
|
|
}
|
|
|
|
writer.writeEndElement(); //item
|
|
|
|
}
|
|
|
|
writer.writeEndElement(); //fps
|
|
|
|
}
|
2022-12-16 14:41:24 +08:00
|
|
|
writer.writeEndDocument();
|
2022-12-16 15:54:02 +08:00
|
|
|
if (writer.hasError()) {
|
|
|
|
throw FileError(QObject::tr("Error when writing file \"%1\".").arg(filename));
|
|
|
|
}
|
2022-12-16 14:41:24 +08:00
|
|
|
}
|