| 551 | } |
| 552 | |
| 553 | DecodedImage DecodePAAFileMip(const std::string& path, int mipLevel) |
| 554 | { |
| 555 | DecodedImage img; |
| 556 | std::ifstream file(path, std::ios::binary | std::ios::ate); |
| 557 | if (!file.good()) |
| 558 | return img; |
| 559 | |
| 560 | auto fileSize = file.tellg(); |
| 561 | file.seekg(0, std::ios::beg); |
| 562 | std::vector<char> fileData(fileSize); |
| 563 | file.read(fileData.data(), fileSize); |
| 564 | file.close(); |
| 565 | |
| 566 | if (mipLevel == 0) |
| 567 | return DecodePAABuffer(fileData.data(), static_cast<size_t>(fileSize), detectIsPaa(path)); |
| 568 | |
| 569 | // For mip > 0, parse the PAA structure and skip to the requested mip |
| 570 | bool isPaa = detectIsPaa(path); |
| 571 | QIStream in(fileData.data(), static_cast<int>(fileSize)); |
| 572 | |
| 573 | int desc = fgetiw(in); |
| 574 | bool alpha = false; |
| 575 | PacFormat format = PacFormatFromDesc(desc, alpha); |
| 576 | if (format == PacFormatN) |
| 577 | { |
| 578 | in.seekg(-2, QIOS::cur); |
| 579 | format = isPaa ? PacARGB4444 : PacP8; |
| 580 | } |
| 581 | |
| 582 | PacPalette pal; |
| 583 | int offsets[16]; |
| 584 | for (int i = 0; i < 16; i++) |
| 585 | offsets[i] = -1; |
| 586 | if (pal.Load(in, offsets, 16)) |
| 587 | return img; |
| 588 | |
| 589 | // Iterate through mip levels to reach the requested one |
| 590 | PacLevelMem mip; |
| 591 | for (int m = 0; m <= mipLevel; m++) |
| 592 | { |
| 593 | mip = PacLevelMem(); // fresh for each level |
| 594 | if (m < 16 && offsets[m] >= 0) |
| 595 | mip.SetStart(offsets[m]); |
| 596 | // For mips > 0 with known offsets, set expected dimensions |
| 597 | if (m > 0 && offsets[m] >= 0) |
| 598 | { |
| 599 | // will be read by Init anyway |
| 600 | } |
| 601 | if (mip.Init(in, format) != 0) |
| 602 | return img; |
| 603 | } |
| 604 | |
| 605 | img.width = mip._w; |
| 606 | img.height = mip._h; |
| 607 | // Reject absurd dimensions (mip header is attacker-controlled) before |
| 608 | // width*height*4 overflows int into a tiny rgba alloc the decoders overrun. |
| 609 | if (img.width <= 0 || img.height <= 0 || img.width > 8192 || img.height > 8192) |
| 610 | return img; |
no test coverage detected