@@ -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}
0 commit comments