C++, PHP: various bugfixes and improvements

backup
Christian Seiler 2 weeks ago
parent 3e87cb8dbe
commit 4e03152676
  1. 25
      cpp/clivis/main.cpp
  2. 10
      cpp/src/monoformat_structured.cpp
  3. 14
      php/monoformat_structured.php
  4. 178
      php/schedule.php

@ -126,19 +126,31 @@ static void showContents2(std::span<std::byte const> data, std::size_t tick, std
} }
int main(int argc, char** argv) { int main(int argc, char** argv) {
if (argc != 2 || !argv[1]) { if (argc < 2 || !argv[1]) {
std::ostringstream buf; std::ostringstream buf;
buf << "Usage: " << argv[0] << " filename\n"; buf << "Usage: " << argv[0] << " filename [timestamp]\n";
std::cerr << buf.str(); std::cerr << buf.str();
return 1; return 1;
} }
if (std::string_view{argv[1]} == "--help") { if (std::string_view{argv[1]} == "--help") {
std::ostringstream buf; std::ostringstream buf;
buf << "Usage: " << argv[0] << " filename\n"; buf << "Usage: " << argv[0] << " filename [timestamp]\n";
std::cout << buf.str() << std::flush; std::cout << buf.str() << std::flush;
return 0; return 0;
} }
std::int64_t timestamp = -1;
if (argc > 2) {
char* endptr = nullptr;
timestamp = strtoll(argv[2], &endptr, 10);
if (!endptr || *endptr) {
std::ostringstream buf;
buf << "Usage: " << argv[0] << " filename [timestamp]\n";
std::cerr << buf.str();
return 1;
}
}
try { try {
auto contents = readEntireFile<std::vector<std::byte>>(argv[1]); auto contents = readEntireFile<std::vector<std::byte>>(argv[1]);
auto file = monoformat::parseFile(contents); auto file = monoformat::parseFile(contents);
@ -159,11 +171,12 @@ int main(int argc, char** argv) {
std::signal(SIGTERM, &handleCtrlC); std::signal(SIGTERM, &handleCtrlC);
std::size_t tick = 0; std::size_t tick = 0;
while (!g_ctrlCPressed.load(std::memory_order_relaxed)) { while (!g_ctrlCPressed.load(std::memory_order_relaxed)) {
std::int64_t currentTime = timestamp == -1 ? time(nullptr) : timestamp;
clearScreen(); clearScreen();
//showContents(*file, tick, time(nullptr), customFonts); //showContents(*file, tick, currentTime, customFonts);
showContents2(contents, tick, time(nullptr)); showContents2(contents, tick, currentTime);
std::ostringstream buf; std::ostringstream buf;
buf << "Animation Tick: " << tick << "\n"; buf << "Animation Tick: " << tick << ", Timestamp = " << currentTime << "\n";
std::cout << buf.str() << std::flush; std::cout << buf.str() << std::flush;
std::this_thread::sleep_for(std::chrono::milliseconds{40}); std::this_thread::sleep_for(std::chrono::milliseconds{40});
++tick; ++tick;

@ -403,13 +403,13 @@ std::expected<std::unique_ptr<AnimationElement>, ParseError> AnimationElement::p
return std::unexpected(reserved_.error()); return std::unexpected(reserved_.error());
} }
std::size_t imageSize = ((*width) * (*height) + 8 - 1) / 8; std::size_t imageSize = ((*width) * (*height) + 8 - 1) / 8;
auto imageData = readBuffer(buffer, imageSize); auto imageData = readBuffer(buffer, imageSize * (*numberOfFrames));
if (!imageData) { if (!imageData) {
return std::unexpected(reserved_.error()); return std::unexpected(reserved_.error());
} }
std::size_t rounded = (imageSize + 4 - 1) / 4 * 4; std::size_t rounded = (imageSize * (*numberOfFrames) + 4 - 1) / 4 * 4;
if (imageSize < rounded) { if (imageSize * (*numberOfFrames) < rounded) {
buffer = buffer.subspan(rounded - imageSize); buffer = buffer.subspan(rounded - imageSize * (*numberOfFrames));
} }
auto result = std::make_unique<AnimationElement>(*x, *y, *width, *height, *numberOfFrames, *updateInterval); auto result = std::make_unique<AnimationElement>(*x, *y, *width, *height, *numberOfFrames, *updateInterval);
@ -2883,7 +2883,7 @@ std::expected<std::unique_ptr<ExpiryDateSection>, ParseError> ExpiryDateSection:
if (!type) { if (!type) {
return std::unexpected(type.error()); return std::unexpected(type.error());
} }
if (*type != static_cast<std::uint8_t>(SectionType::CustomFont)) { if (*type != static_cast<std::uint8_t>(SectionType::ExpiryDate)) {
return std::unexpected(ParseError::InvalidValue); return std::unexpected(ParseError::InvalidValue);
} }
auto size = readU24LE(buffer); auto size = readU24LE(buffer);

@ -103,7 +103,7 @@ class ImageElement extends Element {
} }
public function setImage(array $image) { public function setImage(array $image) {
$n = $m_width * $m_height; $n = $this->m_width * $this->m_height;
if (count($image) != $n) { if (count($image) != $n) {
$actual = count($image); $actual = count($image);
throw new \ValueError("Cannot update the image of an ImageElement: the number of pixels supplied, $actual, is not the expected number, $n"); throw new \ValueError("Cannot update the image of an ImageElement: the number of pixels supplied, $actual, is not the expected number, $n");
@ -222,7 +222,7 @@ class AnimationElement extends Element {
$max = count($this->m_frames) - 1; $max = count($this->m_frames) - 1;
throw new \ValueError("Cannot retrieve a frame of an AnimationElement: the frame index $n is not in the range [0..$max]"); throw new \ValueError("Cannot retrieve a frame of an AnimationElement: the frame index $n is not in the range [0..$max]");
} }
$nPixels = $m_width * $m_height; $nPixels = $this->m_width * $this->m_height;
if (count($image) != $nPixels) { if (count($image) != $nPixels) {
$actual = count($image); $actual = count($image);
throw new \ValueError("Cannot update a frame of an AnimationElement: the number of pixels supplied, $actual, is not the expected number, $nPixels"); throw new \ValueError("Cannot update a frame of an AnimationElement: the number of pixels supplied, $actual, is not the expected number, $nPixels");
@ -251,7 +251,7 @@ class AnimationElement extends Element {
} }
public function serializeBinary(int $formatVersion): string { public function serializeBinary(int $formatVersion): string {
$result = pack("vvvvvvvvv", $result = pack("vvvvvvvv",
ElementType::Animation->value, ElementType::Animation->value,
$this->m_x, $this->m_x,
$this->m_y, $this->m_y,
@ -280,7 +280,7 @@ class AnimationElement extends Element {
public static function parseBinary(string &$data, int $formatVersion): AnimationElement { public static function parseBinary(string &$data, int $formatVersion): AnimationElement {
[$type, $x, $y, $width, $height, $nFrames, $updateInterval, $reserved] = array_values(unpack("v8", substr($data, 0, 16))); [$type, $x, $y, $width, $height, $nFrames, $updateInterval, $reserved] = array_values(unpack("v8", substr($data, 0, 16)));
$type = ElementType::from($type); $type = ElementType::from($type);
if ($type != ElementType::AnimationElement) { if ($type != ElementType::Animation) {
throw new \ValueError("Could not unserialize an animation element: type mismatch"); throw new \ValueError("Could not unserialize an animation element: type mismatch");
} }
$n = $width * $height; $n = $width * $height;
@ -352,7 +352,7 @@ class HScrollImageElement extends Element {
} }
public function setImage(array $image) { public function setImage(array $image) {
$n = $m_contentWidth * $m_height; $n = $this->m_contentWidth * $this->m_height;
if (count($image) != $n) { if (count($image) != $n) {
$actual = count($image); $actual = count($image);
throw new \ValueError("Cannot update the image of an HScrollImageElement: the number of pixels supplied, $actual, is not the expected number, $n"); throw new \ValueError("Cannot update the image of an HScrollImageElement: the number of pixels supplied, $actual, is not the expected number, $n");
@ -481,7 +481,7 @@ class VScrollImageElement extends Element {
} }
public function setImage(array $image) { public function setImage(array $image) {
$n = $m_width * $m_contentHeight; $n = $this->m_width * $this->m_contentHeight;
if (count($image) != $n) { if (count($image) != $n) {
$actual = count($image); $actual = count($image);
throw new \ValueError("Cannot update the image of a VScrollImageElement: the number of pixels supplied, $actual, is not the expected number, $n"); throw new \ValueError("Cannot update the image of a VScrollImageElement: the number of pixels supplied, $actual, is not the expected number, $n");
@ -950,7 +950,7 @@ class HScrollTextElement extends Element {
} }
public function flags(): ScrollFlags { public function flags(): ScrollFlags {
return $this->m_textFlags; return $this->m_flags;
} }
public function scrollSpeed(): int { public function scrollSpeed(): int {

@ -0,0 +1,178 @@
<?php
include_once("monoformat_schema.php");
include_once("monoformat_structured.php");
function replaceTalkInfo($str, $talks) {
return preg_replace_callback("/\\$\\{([^}]*)\\}/", function ($matches) use ($talks) {
if (str_contains($matches[1], ".")) {
[$id, $what] = explode(".", $matches[1], 2);
$id = (int) $id;
if ($id < 0 || $id >= count($talks)) {
return "";
}
$talk = $talks[$id];
if (array_key_exists($what, $talk)) {
return $talk[$what];
} else {
return "";
}
} else {
return "";
}
}, $str);
}
$roomMapping = [
];
if (!isset($_GET["mac"]) or !array_key_exists($_GET["mac"], $roomMapping)) {
/* We didn't find this device in the mapping, so let's just
* send a default file to the user.
*/
Header("Content-Type: application/octet-stream");
readfile(dirname(__FILE__) . "/noroom.bin");
exit(0);
}
$roomGUID = strtolower($roomMapping[$_GET["mac"]]);
$pretalx = json_decode(file_get_contents("schedule.json"), true);
$roomName = null;
foreach ($pretalx["schedule"]["conference"]["rooms"] as $room) {
$thisRoomGUID = strtolower($room["guid"]);
if ($thisRoomGUID === $roomGUID) {
$roomName = $room["name"];
break;
}
}
if ($roomName === null) {
die("Room not found!");
}
$talks = [];
$now = new DateTimeImmutable("now");
foreach ($pretalx["schedule"]["conference"]["days"] as $day) {
if (!array_key_exists($roomName, $day["rooms"])) {
continue;
}
$roomTalks = $day["rooms"][$roomName];
foreach ($roomTalks as $t) {
[$h, $m] = explode(":", $t["duration"]);
$duration = $h * 3600 + $m * 60;
$duration = DateInterval::createFromDateString("$duration sec");
$speakers = [];
foreach ($t["persons"] as $person) {
array_push($speakers, $person["name"]);
}
$talkBegin = new DateTimeImmutable($t["date"]);
$talkEnd = $talkBegin->add($duration);
if ($talkEnd < $now) {
continue;
}
$talk = [
"Time" => $talkBegin->format("H:i"),
"Duration" => $duration->format("H:i"),
"Persons" => implode(", ", $speakers),
"Title" => $t["title"],
"_start" => $talkBegin,
"_end" => $talkEnd,
];
array_push($talks, $talk);
}
}
$template = file_get_contents(dirname(__FILE__) . "/template.bin");
$template = monoformat\parseFile($template);
if (count($template->sections) != 1 or $template->sections[0]->sectionType() != monoformat\SectionType::AlwaysDrawn) {
die("Invalid section in template file");
}
$elements = [];
for ($i = 0; $i < $template->sections[0]->elementCount(); ++$i) {
array_push($elements, $template->sections[0]->elementAt($i));
}
$end_template = file_get_contents(dirname(__FILE__) . "/endscreen.bin");
$end_template = monoformat\parseFile($end_template);
if (count($end_template->sections) != 1 or $end_template->sections[0]->sectionType() != monoformat\SectionType::AlwaysDrawn) {
die("Invalid section in end screen template file");
}
$end_elements = [];
for ($i = 0; $i < $end_template->sections[0]->elementCount(); ++$i) {
array_push($end_elements, $end_template->sections[0]->elementAt($i));
}
$n = 42;
$last = false;
if ($n > count($talks)) {
$n = count($talks);
$last = true;
}
$lastEnd = 0;
$outputFile = new monoformat\File();
if (!$last) {
$section = new monoformat\ExpiryDateSection();
$section->setExpiryDate($talks[$n - 1]["_end"]->getTimestamp());
array_push($outputFile->sections, $section);
}
for ($i = 0; $i < $n; ++$i) {
$subTalks = array_slice($talks, $i);
$end = $subTalks[0]["_end"]->getTimestamp();
$section = new monoformat\TimeBasedDrawnSection();
$section->setDrawOnFront(true);
$section->setDrawOnBack(true);
$section->setClearBeforeDrawing(true);
$section->setStartTimestamp($lastEnd);
$section->setEndTimestamp($end);
foreach ($elements as $element) {
if ($element->elementType() == monoformat\ElementType::ClippedText) {
$x = $element->x();
$y = $element->y();
$width = $element->width();
$height = $element->height();
$textFlags = $element->textFlags();
$fontIndex = $element->fontIndex();
$text = replaceTalkInfo($element->text(), $subTalks);
$element = new monoformat\ClippedTextElement($x, $y, $width, $height, $textFlags, $fontIndex, $text);
} else if ($element->elementType() == monoformat\ElementType::HScrollText) {
$x = $element->x();
$y = $element->y();
$width = $element->width();
$height = $element->height();
$textFlags = $element->textFlags();
$flags = $element->flags();
$scrollSpeed = $element->scrollSpeed();
$fontIndex = $element->fontIndex();
$text = replaceTalkInfo($element->text(), $subTalks) . " ";
$element = new monoformat\HScrollTextElement($x, $y, $width, $height, $textFlags, $flags, $scrollSpeed, $fontIndex, $text);
}
$section->appendElement($element);
}
array_push($outputFile->sections, $section);
$lastEnd = $end;
}
if ($last) {
$section = new monoformat\TimeBasedDrawnSection();
$section->setDrawOnFront(true);
$section->setDrawOnBack(true);
$section->setClearBeforeDrawing(true);
$section->setStartTimestamp($lastEnd);
// Set this far enough in the future that it doesn't matter
$section->setEndTimestamp($lastEnd + 86400 * 300);
foreach ($end_elements as $element) {
$section->appendElement($element);
}
array_push($outputFile->sections, $section);
}
Header("Content-Type: application/octet-stream");
print(monoformat\serializeFile($outputFile));
?>
Loading…
Cancel
Save