Skip to content

Commit 109d20d

Browse files
committed
Allow SVG in jury test case visualization
1 parent 4380e39 commit 109d20d

File tree

5 files changed

+42
-11
lines changed

5 files changed

+42
-11
lines changed

webapp/src/Controller/Jury/ProblemController.php

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -606,16 +606,26 @@ public function testcasesAction(Request $request, int $probId): Response
606606
}
607607
$content = file_get_contents($file->getRealPath());
608608
if ($type === 'image') {
609-
$imageType = Utils::getImageType($content, $error);
610-
if ($imageType === false) {
611-
$this->addFlash('danger', sprintf('image: %s', $error));
612-
return $this->redirectToRoute('jury_problem_testcases', ['probId' => $probId]);
613-
}
614-
$thumb = Utils::getImageThumb($content, $thumbnailSize,
615-
$this->dj->getDomjudgeTmpDir(), $error);
616-
if ($thumb === false) {
617-
$this->addFlash('danger', sprintf('image: %s', $error));
618-
return $this->redirectToRoute('jury_problem_testcases', ['probId' => $probId]);
609+
if (mime_content_type($file->getRealPath()) === 'image/svg+xml') {
610+
$content = Utils::sanitizeSvg($content);
611+
if ($content === false) {
612+
$this->addFlash('danger', sprintf('image: %s', $error));
613+
return $this->redirectToRoute('jury_problem_testcases', ['probId' => $probId]);
614+
}
615+
$thumb = $content;
616+
$imageType = 'svg';
617+
} else {
618+
$imageType = Utils::getImageType($content, $error);
619+
if ($imageType === false) {
620+
$this->addFlash('danger', sprintf('image: %s', $error));
621+
return $this->redirectToRoute('jury_problem_testcases', ['probId' => $probId]);
622+
}
623+
$thumb = Utils::getImageThumb($content, $thumbnailSize,
624+
$this->dj->getDomjudgeTmpDir(), $error);
625+
if ($thumb === false) {
626+
$this->addFlash('danger', sprintf('image: %s', $error));
627+
return $this->redirectToRoute('jury_problem_testcases', ['probId' => $probId]);
628+
}
619629
}
620630

621631
$testcase->setImageType($imageType);

webapp/src/Service/DOMJudgeService.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,12 @@ class DOMJudgeService
8585
'image/svg+xml' => 'svg',
8686
];
8787

88+
final public const EXTENSION_TO_MIMETYPE = [
89+
'png' => 'image/png',
90+
'jpg' => 'image/jpeg',
91+
'svg' => 'image/svg+xml',
92+
];
93+
8894
public function __construct(
8995
protected readonly EntityManagerInterface $em,
9096
protected readonly LoggerInterface $logger,

webapp/src/Service/ImportProblemService.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,15 @@ public function importZippedProblem(
427427
break;
428428
}
429429
}
430+
// Handle SVG differently, as a lot of the above concepts do not make sense in this context.
431+
$imageFileName = $baseFileName . '.svg';
432+
if (($imageFile = $zip->getFromName($imageFileName)) !== false) {
433+
if (($imageFile = Utils::sanitizeSvg($imageFile)) === false) {
434+
$messages['warning'][] = sprintf("Contents of '%s' is not safe.", $imageFileName);
435+
}
436+
$imageType = 'svg';
437+
$imageThumb = $imageFile;
438+
}
430439

431440
if (str_contains($testInput, "\r")) {
432441
$messages['warning'][] = "Testcase file '$baseFileName.in' contains Windows newlines.";

webapp/src/Twig/TwigExtension.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ public function getFilters(): array
117117
new TwigFilter('entityIdBadge', $this->entityIdBadge(...), ['is_safe' => ['html']]),
118118
new TwigFilter('medalType', $this->awards->medalType(...)),
119119
new TwigFilter('numTableActions', $this->numTableActions(...)),
120+
new TwigFilter('extensionToMime', $this->extensionToMime(...)),
120121
];
121122
}
122123

@@ -1350,4 +1351,9 @@ protected function numTableActions(array $tableData): int
13501351
}
13511352
return $maxNumActions;
13521353
}
1354+
1355+
public function extensionToMime(string $extension): string
1356+
{
1357+
return DOMJudgeService::EXTENSION_TO_MIMETYPE[$extension];
1358+
}
13531359
}

webapp/templates/jury/submission.html.twig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -742,7 +742,7 @@
742742
<span style="float:right; border: 3px solid #438ec3; margin: 5px; padding: 5px;">
743743
{% set imgUrl = path('jury_problem_testcase_fetch', {'probId': submission.problem.probid, 'rank': run.rank, 'type': 'image'}) %}
744744
<a href="{{ imgUrl }}">
745-
<img src="data:image/{{ run.imageType }};base64,{{ runsOutput[runIdx].image_thumb | base64 }}"/>
745+
<img src="data:{{ run.imageType | extensionToMime }};base64,{{ runsOutput[runIdx].image_thumb | base64 }}"/>
746746
</a>
747747
</span>
748748
{% endif %}

0 commit comments

Comments
 (0)