| 337 | bank.Lock(); |
| 338 | |
| 339 | if (bank.error()) |
| 340 | { |
| 341 | std::cerr << "Error: Failed to load PBO: " << pboPath << std::endl; |
| 342 | bank.Unlock(); |
| 343 | return 1; |
| 344 | } |
| 345 | |
| 346 | Ref<IFileBuffer> data = bank.Read(filePath.c_str()); |
| 347 | if (!data || data->GetSize() == 0) |
| 348 | { |
| 349 | std::cerr << "Error: File not found in PBO: " << filePath << std::endl; |
| 350 | bank.Unlock(); |
| 351 | return 1; |
| 352 | } |
| 353 | |
| 354 | // Keep redirected binary payloads byte-exact on Windows. |
| 355 | #ifdef _WIN32 |
| 356 | _setmode(_fileno(stdout), _O_BINARY); |
| 357 | #endif |
| 358 | std::cout.write(static_cast<const char*>(data->GetData()), static_cast<std::streamsize>(data->GetSize())); |
| 359 | std::cout.flush(); |
| 360 | |
| 361 | bank.Unlock(); |
| 362 | return 0; |
| 363 | } |
| 364 | |
| 365 | int PboCommand::Extract(const std::string& pboPath, const std::string& outputDir, const std::string& fileFilter) |
| 366 | { |
| 367 | struct stat st; |
| 368 | if (stat(pboPath.c_str(), &st) != 0) |
| 369 | { |
| 370 | std::cerr << "Error: File not found: " << pboPath << std::endl; |
| 371 | return 1; |
| 372 | } |
| 373 | |
| 374 | std::string bankName = StripPboExtension(pboPath); |
| 375 | QFBank bank; |
| 376 | if (!bank.open(RString(bankName.c_str()))) |
| 377 | { |