Skip to content

Commit

Permalink
add raw list tags, add option to read large list tags in raw mode
Browse files Browse the repository at this point in the history
  • Loading branch information
KurtThiemann committed Apr 5, 2023
1 parent 202b9c1 commit bb2769b
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 10 deletions.
81 changes: 73 additions & 8 deletions src/Tag/ListTag.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,23 @@ class ListTag extends ArrayValueTag
public const TYPE = TagType::TAG_List;
protected int $contentTagType = TagType::TAG_End;

protected ?int $rawContentLength = null;
protected ?string $rawContent = null;
protected ?int $rawContentFormat = null;

/**
* @inheritDoc
*/
public function writeContent(Writer $writer): static
{
$writer->getSerializer()->writeByte($this->contentTagType)->writeLengthPrefix($this->count());
$this->writeValues($writer);
$writer->getSerializer()->writeByte($this->contentTagType);
if ($this->isRaw()) {
$writer->getSerializer()->writeLengthPrefix($this->rawContentLength);
$writer->write($this->rawContent);
} else {
$writer->getSerializer()->writeLengthPrefix($this->count());
$this->writeValues($writer);
}
return $this;
}

Expand Down Expand Up @@ -48,6 +58,10 @@ public function getContentTag(): int
*/
public function setContentTag(int $contentTagType): ListTag
{
if ($this->isRaw()) {
throw new Exception("Raw list tags cannot be modified");
}

/** @var Tag $value */
foreach ($this->valueArray as $value) {
if ($value::TYPE !== $contentTagType) {
Expand Down Expand Up @@ -93,11 +107,21 @@ protected function checkArrayValue($value): bool

/**
* @inheritDoc
* @throws Exception
*/
protected function readContent(Reader $reader): static
{
$this->contentTagType = $reader->getDeserializer()->readByte()->getValue();
return parent::readContent($reader);
$length = $reader->getDeserializer()->readLengthPrefix()->getValue();
$maxLength = $this->options->getMaxListTagLength();
if ($maxLength !== null && $length > $maxLength) {
$this->rawContentFormat = $reader->getFormat();
$this->rawContentLength = $length;
$this->rawContent = static::readValueTagsRaw($reader, $this->options, $this->contentTagType, $length);
return $this;
}
$this->valueArray = $this->readValues($reader, $length);
return $this;
}

/**
Expand All @@ -108,19 +132,41 @@ protected static function readContentRaw(Reader $reader, TagOptions $options): s
{
$contentTagType = $reader->getDeserializer()->readByte();
$length = $reader->getDeserializer()->readLengthPrefix();

return $contentTagType->getRawData() . $length->getRawData() .
static::readValueTagsRaw($reader, $options, $contentTagType->getValue(), $length->getValue());
}

/**
* @param Reader $reader
* @param TagOptions $options
* @param int $contentType
* @param int $length
* @return string
* @throws Exception
*/
protected static function readValueTagsRaw(Reader $reader, TagOptions $options, int $contentType, int $length): string
{
$valueData = "";

/** @var Tag $tagClass */
$tagClass = Tag::getTagClass($contentTagType->getValue());
$tagClass = Tag::getTagClass($contentType);
if (is_null($tagClass)) {
throw new Exception("Unknown ListTag content type " . $contentTagType->getValue());
throw new Exception("Unknown ListTag content type " . $contentType);
}
$lengthVal = $length->getValue();
for ($i = 0; $i < $lengthVal; $i++) {
for ($i = 0; $i < $length; $i++) {
$valueData .= $tagClass::readRaw($reader, $options, false);
}

return $contentTagType->getRawData() . $length->getRawData() . $valueData;
return $valueData;
}

/**
* @return bool
*/
public function isRaw(): bool
{
return $this->rawContent !== null;
}

/**
Expand All @@ -144,6 +190,10 @@ protected function getTagTypeString(): string
*/
public function offsetSet($offset, $value)
{
if ($this->isRaw()) {
throw new Exception("Raw list tags cannot be modified");
}

/** @var Tag $previousValue */
$previousValue = $this->valueArray[$offset] ?? null;
parent::offsetSet($offset, $value);
Expand All @@ -156,6 +206,10 @@ public function offsetSet($offset, $value)
*/
public function offsetUnset($offset)
{
if ($this->isRaw()) {
throw new Exception("Raw list tags cannot be modified");
}

/** @var Tag $previousValue */
$previousValue = $this->valueArray[$offset] ?? null;
$previousValue?->setParentTag(null);
Expand Down Expand Up @@ -185,4 +239,15 @@ public function equals(Tag $tag): bool
}
return true;
}

/**
* @inheritDoc
*/
protected function getValueString(): string
{
if ($this->isRaw()) {
return strlen($this->rawContent) . " bytes";
}
return parent::getValueString();
}
}
27 changes: 25 additions & 2 deletions src/Tag/TagOptions.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ class TagOptions
*/
protected ?array $parsedCompoundPaths = null;

/**
* @var int|null
*/
protected ?int $maxListTagLength = null;

/**
* @param string[] $rawCompoundPaths
* @return $this
Expand Down Expand Up @@ -51,10 +56,10 @@ public function getParsedCompoundPaths(): ?array
}

/**
* @param CompoundTag $tag
* @param Tag $tag
* @return bool
*/
public function shouldBeReadRaw(CompoundTag $tag): bool
public function shouldBeReadRaw(Tag $tag): bool
{
$path = $tag->getStringPath();
if($path === "") {
Expand All @@ -69,4 +74,22 @@ public function shouldBeReadRaw(CompoundTag $tag): bool
}
return false;
}

/**
* @param int|null $maxListTagLength
* @return $this
*/
public function setMaxListTagLength(?int $maxListTagLength): static
{
$this->maxListTagLength = $maxListTagLength;
return $this;
}

/**
* @return int|null
*/
public function getMaxListTagLength(): ?int
{
return $this->maxListTagLength;
}
}

0 comments on commit bb2769b

Please sign in to comment.