Skip to content

Commit bb2769b

Browse files
committed
add raw list tags, add option to read large list tags in raw mode
1 parent 202b9c1 commit bb2769b

File tree

2 files changed

+98
-10
lines changed

2 files changed

+98
-10
lines changed

src/Tag/ListTag.php

+73-8
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,23 @@ class ListTag extends ArrayValueTag
1111
public const TYPE = TagType::TAG_List;
1212
protected int $contentTagType = TagType::TAG_End;
1313

14+
protected ?int $rawContentLength = null;
15+
protected ?string $rawContent = null;
16+
protected ?int $rawContentFormat = null;
17+
1418
/**
1519
* @inheritDoc
1620
*/
1721
public function writeContent(Writer $writer): static
1822
{
19-
$writer->getSerializer()->writeByte($this->contentTagType)->writeLengthPrefix($this->count());
20-
$this->writeValues($writer);
23+
$writer->getSerializer()->writeByte($this->contentTagType);
24+
if ($this->isRaw()) {
25+
$writer->getSerializer()->writeLengthPrefix($this->rawContentLength);
26+
$writer->write($this->rawContent);
27+
} else {
28+
$writer->getSerializer()->writeLengthPrefix($this->count());
29+
$this->writeValues($writer);
30+
}
2131
return $this;
2232
}
2333

@@ -48,6 +58,10 @@ public function getContentTag(): int
4858
*/
4959
public function setContentTag(int $contentTagType): ListTag
5060
{
61+
if ($this->isRaw()) {
62+
throw new Exception("Raw list tags cannot be modified");
63+
}
64+
5165
/** @var Tag $value */
5266
foreach ($this->valueArray as $value) {
5367
if ($value::TYPE !== $contentTagType) {
@@ -93,11 +107,21 @@ protected function checkArrayValue($value): bool
93107

94108
/**
95109
* @inheritDoc
110+
* @throws Exception
96111
*/
97112
protected function readContent(Reader $reader): static
98113
{
99114
$this->contentTagType = $reader->getDeserializer()->readByte()->getValue();
100-
return parent::readContent($reader);
115+
$length = $reader->getDeserializer()->readLengthPrefix()->getValue();
116+
$maxLength = $this->options->getMaxListTagLength();
117+
if ($maxLength !== null && $length > $maxLength) {
118+
$this->rawContentFormat = $reader->getFormat();
119+
$this->rawContentLength = $length;
120+
$this->rawContent = static::readValueTagsRaw($reader, $this->options, $this->contentTagType, $length);
121+
return $this;
122+
}
123+
$this->valueArray = $this->readValues($reader, $length);
124+
return $this;
101125
}
102126

103127
/**
@@ -108,19 +132,41 @@ protected static function readContentRaw(Reader $reader, TagOptions $options): s
108132
{
109133
$contentTagType = $reader->getDeserializer()->readByte();
110134
$length = $reader->getDeserializer()->readLengthPrefix();
135+
136+
return $contentTagType->getRawData() . $length->getRawData() .
137+
static::readValueTagsRaw($reader, $options, $contentTagType->getValue(), $length->getValue());
138+
}
139+
140+
/**
141+
* @param Reader $reader
142+
* @param TagOptions $options
143+
* @param int $contentType
144+
* @param int $length
145+
* @return string
146+
* @throws Exception
147+
*/
148+
protected static function readValueTagsRaw(Reader $reader, TagOptions $options, int $contentType, int $length): string
149+
{
111150
$valueData = "";
112151

113152
/** @var Tag $tagClass */
114-
$tagClass = Tag::getTagClass($contentTagType->getValue());
153+
$tagClass = Tag::getTagClass($contentType);
115154
if (is_null($tagClass)) {
116-
throw new Exception("Unknown ListTag content type " . $contentTagType->getValue());
155+
throw new Exception("Unknown ListTag content type " . $contentType);
117156
}
118-
$lengthVal = $length->getValue();
119-
for ($i = 0; $i < $lengthVal; $i++) {
157+
for ($i = 0; $i < $length; $i++) {
120158
$valueData .= $tagClass::readRaw($reader, $options, false);
121159
}
122160

123-
return $contentTagType->getRawData() . $length->getRawData() . $valueData;
161+
return $valueData;
162+
}
163+
164+
/**
165+
* @return bool
166+
*/
167+
public function isRaw(): bool
168+
{
169+
return $this->rawContent !== null;
124170
}
125171

126172
/**
@@ -144,6 +190,10 @@ protected function getTagTypeString(): string
144190
*/
145191
public function offsetSet($offset, $value)
146192
{
193+
if ($this->isRaw()) {
194+
throw new Exception("Raw list tags cannot be modified");
195+
}
196+
147197
/** @var Tag $previousValue */
148198
$previousValue = $this->valueArray[$offset] ?? null;
149199
parent::offsetSet($offset, $value);
@@ -156,6 +206,10 @@ public function offsetSet($offset, $value)
156206
*/
157207
public function offsetUnset($offset)
158208
{
209+
if ($this->isRaw()) {
210+
throw new Exception("Raw list tags cannot be modified");
211+
}
212+
159213
/** @var Tag $previousValue */
160214
$previousValue = $this->valueArray[$offset] ?? null;
161215
$previousValue?->setParentTag(null);
@@ -185,4 +239,15 @@ public function equals(Tag $tag): bool
185239
}
186240
return true;
187241
}
242+
243+
/**
244+
* @inheritDoc
245+
*/
246+
protected function getValueString(): string
247+
{
248+
if ($this->isRaw()) {
249+
return strlen($this->rawContent) . " bytes";
250+
}
251+
return parent::getValueString();
252+
}
188253
}

src/Tag/TagOptions.php

+25-2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ class TagOptions
1414
*/
1515
protected ?array $parsedCompoundPaths = null;
1616

17+
/**
18+
* @var int|null
19+
*/
20+
protected ?int $maxListTagLength = null;
21+
1722
/**
1823
* @param string[] $rawCompoundPaths
1924
* @return $this
@@ -51,10 +56,10 @@ public function getParsedCompoundPaths(): ?array
5156
}
5257

5358
/**
54-
* @param CompoundTag $tag
59+
* @param Tag $tag
5560
* @return bool
5661
*/
57-
public function shouldBeReadRaw(CompoundTag $tag): bool
62+
public function shouldBeReadRaw(Tag $tag): bool
5863
{
5964
$path = $tag->getStringPath();
6065
if($path === "") {
@@ -69,4 +74,22 @@ public function shouldBeReadRaw(CompoundTag $tag): bool
6974
}
7075
return false;
7176
}
77+
78+
/**
79+
* @param int|null $maxListTagLength
80+
* @return $this
81+
*/
82+
public function setMaxListTagLength(?int $maxListTagLength): static
83+
{
84+
$this->maxListTagLength = $maxListTagLength;
85+
return $this;
86+
}
87+
88+
/**
89+
* @return int|null
90+
*/
91+
public function getMaxListTagLength(): ?int
92+
{
93+
return $this->maxListTagLength;
94+
}
7295
}

0 commit comments

Comments
 (0)