Compare commits

...

2 Commits

Author SHA1 Message Date
Christian Seiler 603a469896 PHP: add full serialization / unserialization (binary & JSON) implementation 2 weeks ago
Christian Seiler 2c69d3a685 C++: fix bug in serialization code (doesn't request correct version for CurrentTimeElement) 2 weeks ago
  1. 6
      cpp/src/monoformat_structured.cpp
  2. 203
      php/monoformat.php
  3. 43
      php/monoformat_bithelpers.php
  4. 210
      php/monoformat_schema.php
  5. 1925
      php/monoformat_structured.php

@ -1899,7 +1899,11 @@ ElementType CurrentTimeElement::elementType() const {
}
std::uint32_t CurrentTimeElement::minimumFormatVersion() const {
return 1;
if (static_cast<std::uint8_t>(m_textFlags) != 0) {
return 2;
} else {
return 1;
}
}
std::size_t CurrentTimeElement::serializeTo(std::span<std::byte> target, std::uint32_t formatVersion) const {

@ -1,203 +0,0 @@
<?php
namespace monoformat {
enum SectionType : int {
case AlwaysDrawn = 1;
case TimeBasedDrawn = 2;
case CustomFont = 32;
}
enum ElementType : int {
case Image = 1;
case Animation = 2;
case HScrollImage = 3;
case VScrollImage = 4;
case Line = 5;
case ClippedText = 16;
case HScrollText = 17;
case CurrentTime = 32;
}
enum LineStyle : int {
case Solid = 0;
}
class Element {
public function serialize() {
return "";
}
}
class HScrollTextElement extends Element {
public $x = 0;
public $y = 0;
public $width = 0;
public $height = 0;
public $flags = 0;
public $scrollSpeed = 0;
public $fontIndex = 0;
public $text = "";
public function serialize() {
$len = strlen($this->text);
$result = pack("vvvvvCCvv",
17,
$this->x,
$this->y,
$this->width,
$this->height,
$this->flags,
$this->scrollSpeed,
$this->fontIndex,
$len);
$result .= (string) $this->text;
if ($len % 4 != 0) {
$n = 4 - ($len % 4);
for ($i = 0; $i < $n; ++$i) {
$result .= chr(0);
}
}
return $result;
}
}
class CurrentTimeElement extends Element {
public $x = 0;
public $y = 0;
public $width = 0;
public $height = 0;
public $fontIndex = 0;
public $utcOffset = 0;
public $flags = 0;
public function serialize() {
$result = pack("vvvvvvvv",
32,
$this->x,
$this->y,
$this->width,
$this->height,
$this->fontIndex,
$this->utcOffset,
$this->flags);
return $result;
}
}
class Section {
public function serialize() {
return "";
}
}
class AlwaysDrawnSection extends Section {
public $drawOnFront = false;
public $drawOnBack = false;
public $clearBeforeDrawing = false;
public $elements = [];
public function serialize() {
$flags = 0;
if ($this->drawOnFront) {
$flags |= 0x01;
}
if ($this->drawOnBack) {
$flags |= 0x02;
}
if ($this->clearBeforeDrawing) {
$flags |= 0x04;
}
$inner = pack("vv", $flags, count($this->elements));
foreach ($this->elements as $element) {
$inner .= $element->serialize();
}
$len = strlen($inner) + 4;
$len = substr(pack("V", $len), 0, 3);
return pack("C", 1) . $len . $inner;
}
}
class File {
public $sections = [];
public function serialize() {
$nSections = count($this->sections);
$result = "\xAF\x7E\x2B\x63";
$result .= pack("Vvv", 1, $nSections, 0);
foreach ($this->sections as $section) {
$result .= $section->serialize();
}
return $result;
}
}
} // namespace monoformat
namespace {
$roomName= "BOOL";
$data = json_decode(file_get_contents("https://cfp.cttue.de/tdf5/schedule/export/schedule.json"), true);
$talks = [];
$now = new DateTimeImmutable("now");
foreach ($data["schedule"]["conference"]["days"] as $day) {
foreach ($day["rooms"][$roomName] as $t) {
[$h, $m] = explode(":", $t["duration"]);
$duration = $h * 3600 + $m * 60;
$duration = DateInterval::createFromDateString("$duration sec");
$talk = [
"date" => new DateTimeImmutable($t["date"]),
"duration" => $duration,
"title" => $t["title"],
];
$talkEnd = $talk["date"]->add($talk["duration"]);
if ($talkEnd < $now) {
continue;
}
if ($talk["date"] > $now && count($talks) > 2) {
break;
}
array_push($talks, $talk);
}
}
$elements = [];
function putText($x, $y, $width, $height, $text) {
global $elements;
$e = new monoformat\HScrollTextElement();
$e->x = $x;
$e->y = $y;
$e->width = $width;
$e->height = $height;
$e->flags = 0;
$e->scrollSpeed = 15;
$e->fontIndex = 0;
$e->text = $text;
array_push($elements, $e);
}
$i = 0;
foreach ($talks as $talk) {
putText(10, $i * 20, 25, 20, $talk["date"]->format("H:i"));
putText(35, $i * 20, 85, 20, $talk["title"]);
++$i;
}
$section = new monoformat\AlwaysDrawnSection();
$section->drawOnFront = true;
$section->drawOnBack = true;
$section->clearBeforeDrawing = true;
$section->elements = $elements;
$file = new monoformat\File();
array_push($file->sections, $section);
Header("Content-Type: application/octet-stream");
print($file->serialize());
} // global
?>

@ -0,0 +1,43 @@
<?php
namespace monoformat {
function isBitSet(int $value, int $bit) {
if ($bit < 0 || $bit >= (PHP_INT_SIZE * 8)) {
return false;
}
$mask = 1 << $bit;
return ($value & $mask) == $mask;
}
function setBit(int &$value, int $bit) {
if ($bit < 0 || $bit >= (PHP_INT_SIZE * 8)) {
return;
}
$mask = 1 << $bit;
$value |= $mask;
}
function unsetBit(int &$value, int $bit) {
if ($bit < 0 || $bit >= (PHP_INT_SIZE * 8)) {
return;
}
$mask = 1 << $bit;
$value &= ~$mask;
}
function maybeSetBit(int &$value, int $bit, int $set) {
if ($bit < 0 || $bit >= (PHP_INT_SIZE * 8)) {
return;
}
$mask = 1 << $bit;
if ($set) {
$value |= $mask;
} else {
$value &= ~$mask;
}
}
} // namespace monoformat
?>

@ -0,0 +1,210 @@
<?php
namespace monoformat {
include_once("monoformat_bithelpers.php");
trait FlagStruct {
public static function fromJSON(array $json) {
$myClass = static::class;
$reflect = new \ReflectionClass($myClass);
$properties = $reflect->getProperties(\ReflectionProperty::IS_PUBLIC);
$result = new $myClass();
foreach ($properties as $property) {
$name = $property->getName();
if (array_key_exists($name, $json)) {
$result->$name = (bool) $json[$name];
}
}
return $result;
}
public function toJSON(): array {
$result = [];
$myClass = static::class;
$reflect = new \ReflectionClass($myClass);
$properties = $reflect->getProperties(\ReflectionProperty::IS_PUBLIC);
foreach ($properties as $property) {
$name = $property->getName();
$result[$name] = $this->$name;
}
return $result;
}
}
enum SectionType : int {
case AlwaysDrawn = 1;
case TimeBasedDrawn = 2;
case MultiTimeBasedDrawn = 3;
case ExpiryDate = 31;
case CustomFont = 32;
public static function fromName(string $name): SectionType {
foreach (self::cases() as $case) {
if ($case->name === $name) {
return $case;
}
}
throw new \ValueError("$name is not a valid backing value for enum " . self::class);
}
}
enum ElementType : int {
case Image = 1;
case Animation = 2;
case HScrollImage = 3;
case VScrollImage = 4;
case Line = 5;
case Box = 6;
case ClippedText = 16;
case HScrollText = 17;
//case VScrollText = 18;
case CurrentTime = 32;
public static function fromName(string $name): SectionType {
foreach (self::cases() as $case) {
if ($case->name === $name) {
return $case;
}
}
throw new \ValueError("$name is not a valid backing value for enum " . self::class);
}
}
class ScrollFlags {
use FlagStruct;
public bool $endless = false;
public bool $invertDirection = false;
public bool $padBefore = false;
public bool $padAfter = false;
public static function fromBitField(int $bitfield): ScrollFlags {
$result = new ScrollFlags();
$result->endless = isBitSet($bitfield, 0);
$result->invertDirection = isBitSet($bitfield, 1);
$result->padBefore = isBitSet($bitfield, 2);
$result->padAfter = isBitSet($bitfield, 3);
return $result;
}
public function toBitField(): int {
$result = 0;
maybeSetBit($result, 0, $this->endless);
maybeSetBit($result, 1, $this->invertDirection);
maybeSetBit($result, 2, $this->padBefore);
maybeSetBit($result, 3, $this->padAfter);
return $result;
}
}
enum LineStyle : int {
case Solid = 0;
public static function fromName(string $name): SectionType {
foreach (self::cases() as $case) {
if ($case->name === $name) {
return $case;
}
}
throw new \ValueError("$name is not a valid backing value for enum " . self::class);
}
}
class LineFlags {
use FlagStruct;
public bool $dark = false;
public static function fromBitField(int $bitfield): LineFlags {
$result = new LineFlags();
$result->dark = isBitSet($bitfield, 0);
return $result;
}
public function toBitField(): int {
$result = 0;
maybeSetBit($result, 0, $this->dark);
return $result;
}
}
enum FillPatternStyle : int {
case Solid = 0;
public static function fromName(string $name): SectionType {
foreach (self::cases() as $case) {
if ($case->name === $name) {
return $case;
}
}
throw new \ValueError("$name is not a valid backing value for enum " . self::class);
}
}
class FillFlags {
use FlagStruct;
public bool $dark = false;
public static function fromBitField(int $bitfield): FillFlags {
$result = new FillFlags();
$result->dark = isBitSet($bitfield, 0);
return $result;
}
public function toBitField(): int {
$result = 0;
maybeSetBit($result, 0, $this->dark);
return $result;
}
}
class TextFlags {
use FlagStruct;
public bool $dark = false;
public static function fromBitField(int $bitfield): TextFlags {
$result = new TextFlags();
$result->dark = isBitSet($bitfield, 0);
return $result;
}
public function toBitField(): int {
$result = 0;
maybeSetBit($result, 0, $this->dark);
return $result;
}
}
class TimeDisplayFlags {
use FlagStruct;
public bool $use12h = false;
public bool $showHours = false;
public bool $showMinutes = false;
public bool $showSeconds = false;
public static function fromBitField(int $bitfield): TimeDisplayFlags {
$result = new TimeDisplayFlags();
$result->use12h = isBitSet($bitfield, 0);
$result->showHours = isBitSet($bitfield, 1);
$result->showMinutes = isBitSet($bitfield, 2);
$result->showSeconds = isBitSet($bitfield, 3);
return $result;
}
public function toBitField(): int {
$result = 0;
maybeSetBit($result, 0, $this->use12h);
maybeSetBit($result, 1, $this->showHours);
maybeSetBit($result, 2, $this->showMinutes);
maybeSetBit($result, 3, $this->showSeconds);
return $result;
}
}
} // namespace monoformat
?>

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save