2323
2424#include < algorithm>
2525#include < chrono>
26+ #include < cstring>
2627
2728#include " cdrom/cdriso.h"
2829#include " cdrom/ppf.h"
@@ -57,7 +58,8 @@ PCSX::Coroutine<> PCSX::Widgets::IsoBrowser::computeCRC(PCSX::CDRIso* iso) {
5758 m_fullCRC = fullCRC;
5859};
5960
60- void PCSX::Widgets::IsoBrowser::drawFilesystemTree (const ISO9660LowLevel::DirEntry& entry, const std::string& path) {
61+ void PCSX::Widgets::IsoBrowser::drawFilesystemTree (const ISO9660LowLevel::DirEntry& entry, const std::string& path,
62+ std::unordered_set<uint32_t >& visitedDirs) {
6163 auto entries = m_reader->listAllEntriesFrom (entry);
6264
6365 for (auto & [dirEntry, xa] : entries) {
@@ -79,7 +81,10 @@ void PCSX::Widgets::IsoBrowser::drawFilesystemTree(const ISO9660LowLevel::DirEnt
7981 ImGui::TableSetColumnIndex (2 );
8082 ImGui::TextUnformatted (_ (" <DIR>" ));
8183 if (open) {
82- drawFilesystemTree (dirEntry, fullPath);
84+ // Guard against malformed ISOs with directory cycles pointing back to an ancestor.
85+ if (visitedDirs.insert (lba).second ) {
86+ drawFilesystemTree (dirEntry, fullPath, visitedDirs);
87+ }
8388 ImGui::TreePop ();
8489 }
8590 } else {
@@ -636,18 +641,32 @@ significantly by caching the files beforehand.)"));
636641 std::string dest) -> Coroutine<> {
637642 auto time = std::chrono::steady_clock::now ();
638643 IO<File> src (new CDRIsoFile (iso, lba, size, mode));
644+ if (src->failed ()) {
645+ g_system->printf (_ (" ISO extract: failed to open source region.\n " ));
646+ co_return ;
647+ }
639648 IO<File> out (new UvFile (dest, FileOps::TRUNCATE));
640- if (out->failed ()) co_return ;
649+ if (out->failed ()) {
650+ g_system->printf (_ (" ISO extract: failed to open destination file.\n " ));
651+ co_return ;
652+ }
641653 uint8_t buffer[2048 ];
642654 uint32_t remaining = size;
643655 uint32_t written = 0 ;
644656 while (remaining > 0 ) {
645657 uint32_t chunk = std::min (remaining, (uint32_t )sizeof (buffer));
646658 auto read = src->read (buffer, chunk);
647- if (read <= 0 ) break ;
648- out->write (buffer, read);
649- remaining -= read;
650- written += read;
659+ if (read <= 0 ) {
660+ g_system->printf (_ (" ISO extract: failed while reading ISO data.\n " ));
661+ co_return ;
662+ }
663+ auto wrote = out->write (buffer, read);
664+ if (wrote != read) {
665+ g_system->printf (_ (" ISO extract: failed while writing destination file.\n " ));
666+ co_return ;
667+ }
668+ remaining -= static_cast <uint32_t >(read);
669+ written += static_cast <uint32_t >(read);
651670 if (std::chrono::steady_clock::now () - time > std::chrono::milliseconds (50 )) {
652671 self->m_extractionProgress = (float )written / (float )size;
653672 co_yield self->m_extractionCoroutine .awaiter ();
@@ -752,7 +771,9 @@ significantly by caching the files beforehand.)"));
752771 ImGui::TableSetupColumn (_ (" LBA" ), ImGuiTableColumnFlags_WidthFixed, 80 .0f );
753772 ImGui::TableSetupColumn (_ (" Size" ), ImGuiTableColumnFlags_WidthFixed, 100 .0f );
754773 ImGui::TableHeadersRow ();
755- drawFilesystemTree (m_reader->getRootDirEntry (), " " );
774+ std::unordered_set<uint32_t > visitedDirs;
775+ visitedDirs.insert (m_reader->getRootDirEntry ().get <ISO9660LowLevel::DirEntry_LBA>());
776+ drawFilesystemTree (m_reader->getRootDirEntry (), " " , visitedDirs);
756777 ImGui::EndTable ();
757778 }
758779 }
@@ -780,13 +801,20 @@ significantly by caching the files beforehand.)"));
780801 }
781802 auto size = inst.m_file ->size ();
782803 inst.m_editor .ReadFn = [&inst](size_t off) -> ImU8 {
783- ImU8 b;
784- inst.m_file ->readAt (&b, 1 , off);
804+ ImU8 b = 0 ;
805+ auto r = inst.m_file ->readAt (&b, 1 , off);
806+ if (r != 1 ) b = 0 ;
785807 return b;
786808 };
787809 inst.m_editor .WriteFn = [&inst](size_t off, ImU8 d) { inst.m_file ->writeAt (&d, 1 , off); };
788810 inst.m_editor .Cache .BulkReadFn = [&inst](void * dest, size_t off, size_t len) {
789- inst.m_file ->readAt (dest, len, off);
811+ auto r = inst.m_file ->readAt (dest, len, off);
812+ // Zero-fill anything we didn't read so stale buffer contents
813+ // never leak into the hex view on short reads or errors.
814+ if (r < 0 ) r = 0 ;
815+ if (static_cast <size_t >(r) < len) {
816+ std::memset (static_cast <uint8_t *>(dest) + r, 0 , len - static_cast <size_t >(r));
817+ }
790818 };
791819 inst.m_editor .DrawWindow (inst.m_title .c_str (), size);
792820 ++it;
0 commit comments