@@ -11,13 +11,23 @@ class ListTag extends ArrayValueTag
11
11
public const TYPE = TagType::TAG_List;
12
12
protected int $ contentTagType = TagType::TAG_End;
13
13
14
+ protected ?int $ rawContentLength = null ;
15
+ protected ?string $ rawContent = null ;
16
+ protected ?int $ rawContentFormat = null ;
17
+
14
18
/**
15
19
* @inheritDoc
16
20
*/
17
21
public function writeContent (Writer $ writer ): static
18
22
{
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
+ }
21
31
return $ this ;
22
32
}
23
33
@@ -48,6 +58,10 @@ public function getContentTag(): int
48
58
*/
49
59
public function setContentTag (int $ contentTagType ): ListTag
50
60
{
61
+ if ($ this ->isRaw ()) {
62
+ throw new Exception ("Raw list tags cannot be modified " );
63
+ }
64
+
51
65
/** @var Tag $value */
52
66
foreach ($ this ->valueArray as $ value ) {
53
67
if ($ value ::TYPE !== $ contentTagType ) {
@@ -93,11 +107,21 @@ protected function checkArrayValue($value): bool
93
107
94
108
/**
95
109
* @inheritDoc
110
+ * @throws Exception
96
111
*/
97
112
protected function readContent (Reader $ reader ): static
98
113
{
99
114
$ 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 ;
101
125
}
102
126
103
127
/**
@@ -108,19 +132,41 @@ protected static function readContentRaw(Reader $reader, TagOptions $options): s
108
132
{
109
133
$ contentTagType = $ reader ->getDeserializer ()->readByte ();
110
134
$ 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
+ {
111
150
$ valueData = "" ;
112
151
113
152
/** @var Tag $tagClass */
114
- $ tagClass = Tag::getTagClass ($ contentTagType -> getValue () );
153
+ $ tagClass = Tag::getTagClass ($ contentType );
115
154
if (is_null ($ tagClass )) {
116
- throw new Exception ("Unknown ListTag content type " . $ contentTagType -> getValue () );
155
+ throw new Exception ("Unknown ListTag content type " . $ contentType );
117
156
}
118
- $ lengthVal = $ length ->getValue ();
119
- for ($ i = 0 ; $ i < $ lengthVal ; $ i ++) {
157
+ for ($ i = 0 ; $ i < $ length ; $ i ++) {
120
158
$ valueData .= $ tagClass ::readRaw ($ reader , $ options , false );
121
159
}
122
160
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 ;
124
170
}
125
171
126
172
/**
@@ -144,6 +190,10 @@ protected function getTagTypeString(): string
144
190
*/
145
191
public function offsetSet ($ offset , $ value )
146
192
{
193
+ if ($ this ->isRaw ()) {
194
+ throw new Exception ("Raw list tags cannot be modified " );
195
+ }
196
+
147
197
/** @var Tag $previousValue */
148
198
$ previousValue = $ this ->valueArray [$ offset ] ?? null ;
149
199
parent ::offsetSet ($ offset , $ value );
@@ -156,6 +206,10 @@ public function offsetSet($offset, $value)
156
206
*/
157
207
public function offsetUnset ($ offset )
158
208
{
209
+ if ($ this ->isRaw ()) {
210
+ throw new Exception ("Raw list tags cannot be modified " );
211
+ }
212
+
159
213
/** @var Tag $previousValue */
160
214
$ previousValue = $ this ->valueArray [$ offset ] ?? null ;
161
215
$ previousValue ?->setParentTag(null );
@@ -185,4 +239,15 @@ public function equals(Tag $tag): bool
185
239
}
186
240
return true ;
187
241
}
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
+ }
188
253
}
0 commit comments