Skip to content

Commit 6b75e06

Browse files
committed
Do not reread start of header in decoder
1 parent b89cc09 commit 6b75e06

File tree

1 file changed

+61
-64
lines changed

1 file changed

+61
-64
lines changed

src/PIL/BlpImagePlugin.py

+61-64
Original file line numberDiff line numberDiff line change
@@ -259,32 +259,44 @@ class BlpImageFile(ImageFile.ImageFile):
259259

260260
def _open(self) -> None:
261261
self.magic = self.fp.read(4)
262+
if not _accept(self.magic):
263+
msg = f"Bad BLP magic {repr(self.magic)}"
264+
raise BLPFormatError(msg)
262265

266+
compression = struct.unpack("<i", self.fp.read(4))[0]
263267
if self.magic == b"BLP1":
264-
self.fp.seek(4, os.SEEK_CUR)
265-
(self._blp_alpha_depth,) = struct.unpack("<I", self.fp.read(4))
266-
elif self.magic == b"BLP2":
267-
self.fp.seek(5, os.SEEK_CUR)
268-
(self._blp_alpha_depth,) = struct.unpack("<b", self.fp.read(1))
269-
self.fp.seek(2, os.SEEK_CUR)
268+
alpha = struct.unpack("<I", self.fp.read(4))[0] != 0
270269
else:
271-
msg = f"Bad BLP magic {repr(self.magic)}"
272-
raise BLPFormatError(msg)
270+
encoding = struct.unpack("<b", self.fp.read(1))[0]
271+
alpha = struct.unpack("<b", self.fp.read(1))[0] != 0
272+
alpha_encoding = struct.unpack("<b", self.fp.read(1))[0]
273+
self.fp.seek(1, os.SEEK_CUR) # mips
273274

274275
self._size = struct.unpack("<II", self.fp.read(8))
275276

277+
args: tuple[int, int, bool] | tuple[int, int, bool, int]
278+
if self.magic == b"BLP1":
279+
encoding = struct.unpack("<i", self.fp.read(4))[0]
280+
self.fp.seek(4, os.SEEK_CUR) # subtype
281+
282+
args = (compression, encoding, alpha)
283+
offset = 28
284+
else:
285+
args = (compression, encoding, alpha, alpha_encoding)
286+
offset = 20
287+
276288
decoder = self.magic.decode()
277289

278-
self._mode = "RGBA" if self._blp_alpha_depth else "RGB"
279-
self.tile = [ImageFile._Tile(decoder, (0, 0) + self.size, 0, self.mode)]
290+
self._mode = "RGBA" if alpha else "RGB"
291+
self.tile = [ImageFile._Tile(decoder, (0, 0) + self.size, offset, args)]
280292

281293

282294
class _BLPBaseDecoder(ImageFile.PyDecoder):
283295
_pulls_fd = True
284296

285297
def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
286298
try:
287-
self._read_blp_header()
299+
self._read_header()
288300
self._load()
289301
except struct.error as e:
290302
msg = "Truncated BLP file"
@@ -295,28 +307,9 @@ def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int
295307
def _load(self) -> None:
296308
pass
297309

298-
def _read_blp_header(self) -> None:
299-
assert self.fd is not None
300-
self.fd.seek(4)
301-
(self._blp_compression,) = struct.unpack("<i", self._safe_read(4))
302-
303-
if isinstance(self, BLP1Decoder):
304-
(self._blp_alpha_depth,) = struct.unpack("<I", self._safe_read(4))
305-
else:
306-
(self._blp_encoding,) = struct.unpack("<b", self._safe_read(1))
307-
(self._blp_alpha_depth,) = struct.unpack("<b", self._safe_read(1))
308-
(self._blp_alpha_encoding,) = struct.unpack("<b", self._safe_read(1))
309-
self.fd.seek(1, os.SEEK_CUR) # mips
310-
311-
self.size = struct.unpack("<II", self._safe_read(8))
312-
313-
if isinstance(self, BLP1Decoder):
314-
# Only present for BLP1
315-
(self._blp_encoding,) = struct.unpack("<i", self._safe_read(4))
316-
self.fd.seek(4, os.SEEK_CUR) # subtype
317-
318-
self._blp_offsets = struct.unpack("<16I", self._safe_read(16 * 4))
319-
self._blp_lengths = struct.unpack("<16I", self._safe_read(16 * 4))
310+
def _read_header(self) -> None:
311+
self._offsets = struct.unpack("<16I", self._safe_read(16 * 4))
312+
self._lengths = struct.unpack("<16I", self._safe_read(16 * 4))
320313

321314
def _safe_read(self, length: int) -> bytes:
322315
assert self.fd is not None
@@ -332,37 +325,41 @@ def _read_palette(self) -> list[tuple[int, int, int, int]]:
332325
ret.append((b, g, r, a))
333326
return ret
334327

335-
def _read_bgra(self, palette: list[tuple[int, int, int, int]]) -> bytearray:
328+
def _read_bgra(
329+
self, palette: list[tuple[int, int, int, int]], alpha: bool
330+
) -> bytearray:
336331
data = bytearray()
337-
_data = BytesIO(self._safe_read(self._blp_lengths[0]))
332+
_data = BytesIO(self._safe_read(self._lengths[0]))
338333
while True:
339334
try:
340335
(offset,) = struct.unpack("<B", _data.read(1))
341336
except struct.error:
342337
break
343338
b, g, r, a = palette[offset]
344339
d: tuple[int, ...] = (r, g, b)
345-
if self._blp_alpha_depth:
340+
if alpha:
346341
d += (a,)
347342
data.extend(d)
348343
return data
349344

350345

351346
class BLP1Decoder(_BLPBaseDecoder):
352347
def _load(self) -> None:
353-
if self._blp_compression == Format.JPEG:
348+
self._compression, self._encoding, alpha = self.args
349+
350+
if self._compression == Format.JPEG:
354351
self._decode_jpeg_stream()
355352

356-
elif self._blp_compression == 1:
357-
if self._blp_encoding in (4, 5):
353+
elif self._compression == 1:
354+
if self._encoding in (4, 5):
358355
palette = self._read_palette()
359-
data = self._read_bgra(palette)
356+
data = self._read_bgra(palette, alpha)
360357
self.set_as_raw(data)
361358
else:
362-
msg = f"Unsupported BLP encoding {repr(self._blp_encoding)}"
359+
msg = f"Unsupported BLP encoding {repr(self._encoding)}"
363360
raise BLPFormatError(msg)
364361
else:
365-
msg = f"Unsupported BLP compression {repr(self._blp_encoding)}"
362+
msg = f"Unsupported BLP compression {repr(self._encoding)}"
366363
raise BLPFormatError(msg)
367364

368365
def _decode_jpeg_stream(self) -> None:
@@ -371,8 +368,8 @@ def _decode_jpeg_stream(self) -> None:
371368
(jpeg_header_size,) = struct.unpack("<I", self._safe_read(4))
372369
jpeg_header = self._safe_read(jpeg_header_size)
373370
assert self.fd is not None
374-
self._safe_read(self._blp_offsets[0] - self.fd.tell()) # What IS this?
375-
data = self._safe_read(self._blp_lengths[0])
371+
self._safe_read(self._offsets[0] - self.fd.tell()) # What IS this?
372+
data = self._safe_read(self._lengths[0])
376373
data = jpeg_header + data
377374
image = JpegImageFile(BytesIO(data))
378375
Image._decompression_bomb_check(image.size)
@@ -389,47 +386,47 @@ def _decode_jpeg_stream(self) -> None:
389386

390387
class BLP2Decoder(_BLPBaseDecoder):
391388
def _load(self) -> None:
389+
self._compression, self._encoding, alpha, self._alpha_encoding = self.args
390+
392391
palette = self._read_palette()
393392

394393
assert self.fd is not None
395-
self.fd.seek(self._blp_offsets[0])
394+
self.fd.seek(self._offsets[0])
396395

397-
if self._blp_compression == 1:
396+
if self._compression == 1:
398397
# Uncompressed or DirectX compression
399398

400-
if self._blp_encoding == Encoding.UNCOMPRESSED:
401-
data = self._read_bgra(palette)
399+
if self._encoding == Encoding.UNCOMPRESSED:
400+
data = self._read_bgra(palette, alpha)
402401

403-
elif self._blp_encoding == Encoding.DXT:
402+
elif self._encoding == Encoding.DXT:
404403
data = bytearray()
405-
if self._blp_alpha_encoding == AlphaEncoding.DXT1:
406-
linesize = (self.size[0] + 3) // 4 * 8
407-
for yb in range((self.size[1] + 3) // 4):
408-
for d in decode_dxt1(
409-
self._safe_read(linesize), alpha=bool(self._blp_alpha_depth)
410-
):
404+
if self._alpha_encoding == AlphaEncoding.DXT1:
405+
linesize = (self.state.xsize + 3) // 4 * 8
406+
for yb in range((self.state.ysize + 3) // 4):
407+
for d in decode_dxt1(self._safe_read(linesize), alpha):
411408
data += d
412409

413-
elif self._blp_alpha_encoding == AlphaEncoding.DXT3:
414-
linesize = (self.size[0] + 3) // 4 * 16
415-
for yb in range((self.size[1] + 3) // 4):
410+
elif self._alpha_encoding == AlphaEncoding.DXT3:
411+
linesize = (self.state.xsize + 3) // 4 * 16
412+
for yb in range((self.state.ysize + 3) // 4):
416413
for d in decode_dxt3(self._safe_read(linesize)):
417414
data += d
418415

419-
elif self._blp_alpha_encoding == AlphaEncoding.DXT5:
420-
linesize = (self.size[0] + 3) // 4 * 16
421-
for yb in range((self.size[1] + 3) // 4):
416+
elif self._alpha_encoding == AlphaEncoding.DXT5:
417+
linesize = (self.state.xsize + 3) // 4 * 16
418+
for yb in range((self.state.ysize + 3) // 4):
422419
for d in decode_dxt5(self._safe_read(linesize)):
423420
data += d
424421
else:
425-
msg = f"Unsupported alpha encoding {repr(self._blp_alpha_encoding)}"
422+
msg = f"Unsupported alpha encoding {repr(self._alpha_encoding)}"
426423
raise BLPFormatError(msg)
427424
else:
428-
msg = f"Unknown BLP encoding {repr(self._blp_encoding)}"
425+
msg = f"Unknown BLP encoding {repr(self._encoding)}"
429426
raise BLPFormatError(msg)
430427

431428
else:
432-
msg = f"Unknown BLP compression {repr(self._blp_compression)}"
429+
msg = f"Unknown BLP compression {repr(self._compression)}"
433430
raise BLPFormatError(msg)
434431

435432
self.set_as_raw(data)

0 commit comments

Comments
 (0)