| 401 | } |
| 402 | |
| 403 | DecodedImage DecodePAABuffer(const void* data, size_t size, bool isPaa) |
| 404 | { |
| 405 | DecodedImage img; |
| 406 | QIStream in(static_cast<const char*>(data), static_cast<int>(size)); |
| 407 | |
| 408 | int desc = fgetiw(in); |
| 409 | bool alpha = false; |
| 410 | PacFormat format = PacFormatFromDesc(desc, alpha); |
| 411 | if (format == PacFormatN) |
| 412 | { |
| 413 | in.seekg(-2, QIOS::cur); |
| 414 | format = isPaa ? PacARGB4444 : PacP8; |
| 415 | } |
| 416 | |
| 417 | PacPalette pal; |
| 418 | int offsets[16]; |
| 419 | for (int i = 0; i < 16; i++) |
| 420 | offsets[i] = -1; |
| 421 | if (pal.Load(in, offsets, 16)) |
| 422 | return img; |
| 423 | |
| 424 | PacLevelMem mip; |
| 425 | if (offsets[0] >= 0) |
| 426 | mip.SetStart(offsets[0]); |
| 427 | if (mip.Init(in, format) != 0) |
| 428 | return img; |
| 429 | |
| 430 | img.width = mip._w; |
| 431 | img.height = mip._h; |
| 432 | // Dimensions come from the mip header; reject absurd sizes before width*height*4 |
| 433 | // overflows int (a tiny rgba alloc the decoders then overrun) or drives a huge |
| 434 | // allocation. PAA textures are far below this cap. |
| 435 | if (img.width <= 0 || img.height <= 0 || img.width > 8192 || img.height > 8192) |
| 436 | { |
| 437 | return img; |
| 438 | } |
| 439 | img.rgba.resize(img.width * img.height * 4); |
| 440 | |
| 441 | bool isDXT = (format >= PacDXT1 && format <= PacDXT5); |
| 442 | |
| 443 | if (format == PacARGB8888) |
| 444 | { |
| 445 | // ARGB8888: raw data, no LZSS. Convert ARGB → RGBA. |
| 446 | mip.SeekLevel(in); |
| 447 | int mw = fgetiw(in), mh = fgetiw(in); |
| 448 | if (mw == 0 && mh == 0) |
| 449 | { |
| 450 | img.rgba.clear(); |
| 451 | return img; |
| 452 | } |
| 453 | int dSize = fgeti24(in); |
| 454 | std::vector<uint8_t> rawData(dSize); |
| 455 | in.read(reinterpret_cast<char*>(rawData.data()), dSize); |
| 456 | // The conversion loop below reads width*height*4 raw bytes; reject a payload |
| 457 | // too small to cover them rather than read past rawData (heap over-read). |
| 458 | if (static_cast<int>(rawData.size()) < img.width * img.height * 4) |
| 459 | { |
| 460 | img.rgba.clear(); |
no test coverage detected