#include "calisma_alani_plan.hpp" #include #include #include #include #include #include #include "simdjson.h" namespace fiko { namespace { namespace sj = simdjson; namespace fs = std::filesystem; // ---- JSON yazma yardimcilari (elle bicimlendirme — proje JSON YAZICI // kutuphanesi linklemiyor, bkz. calisma_alani_plan.hpp basi aciklama). ---- std::string jsonKac(const std::string& s) { std::string o; o.reserve(s.size() + 8); for (char c : s) { switch (c) { case '"': o += "\\\""; break; case '\\': o += "\\\\"; break; case '\n': o += "\\n"; break; case '\r': o += "\\r"; break; case '\t': o += "\\t"; break; default: if (static_cast(c) < 0x20) { char buf[8]; snprintf(buf, sizeof(buf), "\\u%04x", c); o += buf; } else { o += c; } } } return o; } std::string js(const std::string& s) { return "\"" + jsonKac(s) + "\""; } std::string jb(bool b) { return b ? "true" : "false"; } } // namespace std::string zamanDamgaOlustur(const char* bicim) { SYSTEMTIME st; GetLocalTime(&st); char buf[64]; if (std::string(bicim) == "iso") { snprintf(buf, sizeof(buf), "%04d-%02d-%02d %02d:%02d:%02d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); } else { snprintf(buf, sizeof(buf), "%04d%02d%02d_%02d%02d%02d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); } return buf; } CalismaAlaniPlani planOlustur(const CatiaKesifSonucu& kesif, const WindowsSurumBilgi& surum) { CalismaAlaniPlani p; p.olusturmaZamani = zamanDamgaOlustur("iso"); p.windowsSurumOzeti = surum.ozet(); // Masaustu sirasi: GUID'lerin kesif listesindeki ILK GORULME sirasina gore. auto guidSirasiBul = [&](const std::string& guid) -> int { if (guid.empty()) return -1; auto it = std::find(p.masaustuGuidSirasi.begin(), p.masaustuGuidSirasi.end(), guid); if (it != p.masaustuGuidSirasi.end()) return static_cast(it - p.masaustuGuidSirasi.begin()); p.masaustuGuidSirasi.push_back(guid); return static_cast(p.masaustuGuidSirasi.size()) - 1; }; for (const auto& o : kesif.oturumlar) { PlanOturum po; po.masaustuGuid = o.masaustuGuid; po.masaustuSira = guidSirasiBul(o.masaustuGuid); po.pencereBasligi = o.pencereBasligi; po.surecYolu = o.surecYolu; po.x = o.x; po.y = o.y; po.genislik = o.genislik; po.yukseklik = o.yukseklik; po.maksimize = o.maksimize; po.minimize = o.minimize; for (const auto& b : o.belgeler) { PlanBelge pb; pb.ad = b.ad; pb.tamYol = b.tamYol; pb.aktif = b.aktifBelge; pb.kayitliMi = b.kayitliMi; po.belgeler.push_back(std::move(pb)); } p.oturumlar.push_back(std::move(po)); } return p; } void planOturumEkleGuncelle(CalismaAlaniPlani& p, PlanOturum yeni) { // masaustu sirasi ataması — planOlustur() icindeki guidSirasiBul lambda'siyla // AYNI mantik (ILK GORULME sirasi, kalici kimlik degil). auto guidSirasiBul = [&](const std::string& guid) -> int { if (guid.empty()) return -1; auto it = std::find(p.masaustuGuidSirasi.begin(), p.masaustuGuidSirasi.end(), guid); if (it != p.masaustuGuidSirasi.end()) return static_cast(it - p.masaustuGuidSirasi.begin()); p.masaustuGuidSirasi.push_back(guid); return static_cast(p.masaustuGuidSirasi.size()) - 1; }; yeni.masaustuSira = guidSirasiBul(yeni.masaustuGuid); // UPSERT: pencereBasligi+surecYolu eslesmesi (oturumEslestir ile AYNI ipucu // ciftini kullanir, bkz. dosya sonundaki oturumEslestir). for (auto& mevcut : p.oturumlar) { if (mevcut.pencereBasligi == yeni.pencereBasligi && mevcut.surecYolu == yeni.surecYolu) { mevcut = std::move(yeni); return; } } p.oturumlar.push_back(std::move(yeni)); } std::string calismaAlaniKlasoru() { wchar_t exeYol[MAX_PATH]{}; GetModuleFileNameW(nullptr, exeYol, MAX_PATH); fs::path klasor = fs::path(exeYol).parent_path() / L"calisma_alanlari"; std::error_code ec; fs::create_directories(klasor, ec); // zaten varsa sessizce basarili return klasor.string(); } std::string sonPlanDosyaYolu() { return (fs::path(calismaAlaniKlasoru()) / "son_calisma_alani.json").string(); } std::string zamanDamgaliPlanDosyaYolu() { std::string ad = "calisma_alani_" + zamanDamgaOlustur("dosya") + ".json"; return (fs::path(calismaAlaniKlasoru()) / ad).string(); } std::string planiJsonaYaz(const CalismaAlaniPlani& p) { std::ostringstream o; o << "{\n"; o << " \"olusturmaZamani\": " << js(p.olusturmaZamani) << ",\n"; o << " \"windowsSurumOzeti\": " << js(p.windowsSurumOzeti) << ",\n"; o << " \"masaustuGuidSirasi\": ["; for (size_t i = 0; i < p.masaustuGuidSirasi.size(); ++i) { if (i) o << ", "; o << js(p.masaustuGuidSirasi[i]); } o << "],\n"; o << " \"oturumlar\": [\n"; for (size_t i = 0; i < p.oturumlar.size(); ++i) { const auto& s = p.oturumlar[i]; o << " {\n"; o << " \"masaustuSira\": " << s.masaustuSira << ",\n"; o << " \"masaustuGuid\": " << js(s.masaustuGuid) << ",\n"; o << " \"pencereBasligi\": " << js(s.pencereBasligi) << ",\n"; o << " \"surecYolu\": " << js(s.surecYolu) << ",\n"; o << " \"x\": " << s.x << ", \"y\": " << s.y << ", \"genislik\": " << s.genislik << ", \"yukseklik\": " << s.yukseklik << ",\n"; o << " \"maksimize\": " << jb(s.maksimize) << ", \"minimize\": " << jb(s.minimize) << ",\n"; o << " \"belgeler\": [\n"; for (size_t j = 0; j < s.belgeler.size(); ++j) { const auto& b = s.belgeler[j]; o << " {\"ad\": " << js(b.ad) << ", \"tamYol\": " << js(b.tamYol) << ", \"aktif\": " << jb(b.aktif) << ", \"kayitliMi\": " << jb(b.kayitliMi) << "}"; o << (j + 1 < s.belgeler.size() ? ",\n" : "\n"); } o << " ]\n"; o << " }"; o << (i + 1 < p.oturumlar.size() ? ",\n" : "\n"); } o << " ]\n"; o << "}\n"; return o.str(); } bool calismaAlaniPlaniYaz(const CalismaAlaniPlani& p, const std::string& dosyaYolu, std::string& hataCikis) { std::error_code ec; fs::create_directories(fs::path(dosyaYolu).parent_path(), ec); std::ofstream f(dosyaYolu, std::ios::binary | std::ios::trunc); if (!f) { hataCikis = "Dosya acilamadi (yazma): " + dosyaYolu; return false; } const std::string icerik = planiJsonaYaz(p); f.write(icerik.data(), static_cast(icerik.size())); if (!f) { hataCikis = "Dosyaya yazma basarisiz: " + dosyaYolu; return false; } f.close(); return true; } // ---- Okuma (simdjson ondemand) — istakip_sema.cpp'deki sStr/sBool kalibiyla // ayni sozlesme: alan yoksa/bozuksa varsayilana duser, cokme yok. ---- namespace { std::string sStr(sj::ondemand::object& o, const char* alan, const char* vars = "") { std::string_view sv; if (o[alan].get_string().get(sv) == sj::SUCCESS) return std::string(sv); return vars; } bool sBool(sj::ondemand::object& o, const char* alan, bool vars = false) { bool b; if (o[alan].get_bool().get(b) == sj::SUCCESS) return b; return vars; } int64_t sInt(sj::ondemand::object& o, const char* alan, int64_t vars = 0) { int64_t v; if (o[alan].get_int64().get(v) == sj::SUCCESS) return v; return vars; } } // namespace bool calismaAlaniPlaniOku(const std::string& dosyaYolu, CalismaAlaniPlani& pCikis, std::string& hataCikis) { std::error_code ec; if (!fs::exists(dosyaYolu, ec)) { hataCikis = "Dosya bulunamadi: " + dosyaYolu; return false; } sj::ondemand::parser parser; sj::padded_string dolu; auto hata = sj::padded_string::load(dosyaYolu).get(dolu); if (hata != sj::SUCCESS) { hataCikis = "Dosya okunamadi: " + dosyaYolu; return false; } sj::ondemand::document doc; if (parser.iterate(dolu).get(doc) != sj::SUCCESS) { hataCikis = "JSON ayristirma basarisiz (bozuk dosya): " + dosyaYolu; return false; } sj::ondemand::object kok; if (doc.get_object().get(kok) != sj::SUCCESS) { hataCikis = "JSON kok nesnesi degil: " + dosyaYolu; return false; } CalismaAlaniPlani p; p.olusturmaZamani = sStr(kok, "olusturmaZamani"); p.windowsSurumOzeti = sStr(kok, "windowsSurumOzeti"); sj::ondemand::array guidDizi; if (kok["masaustuGuidSirasi"].get_array().get(guidDizi) == sj::SUCCESS) { for (auto v : guidDizi) { std::string_view sv; if (v.get_string().get(sv) == sj::SUCCESS) p.masaustuGuidSirasi.emplace_back(sv); } } sj::ondemand::array oturumDizi; if (kok["oturumlar"].get_array().get(oturumDizi) == sj::SUCCESS) { for (auto v : oturumDizi) { sj::ondemand::object so; if (v.get_object().get(so) != sj::SUCCESS) continue; PlanOturum po; po.masaustuSira = static_cast(sInt(so, "masaustuSira", -1)); po.masaustuGuid = sStr(so, "masaustuGuid"); po.pencereBasligi = sStr(so, "pencereBasligi"); po.surecYolu = sStr(so, "surecYolu"); po.x = static_cast(sInt(so, "x")); po.y = static_cast(sInt(so, "y")); po.genislik = static_cast(sInt(so, "genislik")); po.yukseklik = static_cast(sInt(so, "yukseklik")); po.maksimize = sBool(so, "maksimize"); po.minimize = sBool(so, "minimize"); sj::ondemand::array belgeDizi; if (so["belgeler"].get_array().get(belgeDizi) == sj::SUCCESS) { for (auto bv : belgeDizi) { sj::ondemand::object bo; if (bv.get_object().get(bo) != sj::SUCCESS) continue; PlanBelge pb; pb.ad = sStr(bo, "ad"); pb.tamYol = sStr(bo, "tamYol"); pb.aktif = sBool(bo, "aktif"); pb.kayitliMi = sBool(bo, "kayitliMi"); po.belgeler.push_back(std::move(pb)); } } p.oturumlar.push_back(std::move(po)); } } pCikis = std::move(p); return true; } // Plan oturumunu GUNCEL kesifteki bir oturumla eslestirmeye calisir. Kalici // kimlik yok (PID/HWND plana hic girmiyor) — bu yuzden eslestirme ipucu // pencere basligi + surec yolu birlikte esler (ikisi de aynıysa güçlü eşleşme // sayılır). Bulunamazsa nullptr — DURUST: tahmini eşleştirme YAPILMAZ. const CatiaOturumBilgi* oturumEslestir(const PlanOturum& po, const CatiaKesifSonucu& guncel) { for (const auto& g : guncel.oturumlar) { if (g.pencereBasligi == po.pencereBasligi && g.surecYolu == po.surecYolu) return &g; } return nullptr; } std::string planKarsilastirmaRaporu(const CalismaAlaniPlani& plan, const CatiaKesifSonucu& guncel) { std::ostringstream r; r << "Plan karsilastirma raporu (kaydedildi: " << plan.olusturmaZamani << ", " << plan.windowsSurumOzeti << ")\n"; r << " Plandaki oturum sayisi: " << plan.oturumlar.size() << " | Guncel acik oturum sayisi: " << guncel.oturumlar.size() << "\n"; std::vector guncelEslesti(guncel.oturumlar.size(), false); for (size_t i = 0; i < plan.oturumlar.size(); ++i) { const auto& po = plan.oturumlar[i]; const CatiaOturumBilgi* g = oturumEslestir(po, guncel); r << " [" << (i + 1) << "] \"" << po.pencereBasligi << "\" (" << po.belgeler.size() << " belge) — "; if (!g) { r << "BULUNAMADI (bu pencere su an acik degil, Faz 2 olmadan otomatik acilmayacak)\n"; continue; } // guncelEslesti isaretlemek icin g'nin guncel.oturumlar icindeki indeksini bul. for (size_t k = 0; k < guncel.oturumlar.size(); ++k) if (&guncel.oturumlar[k] == g) guncelEslesti[k] = true; r << "ACIK"; if (po.masaustuGuid.empty() || g->masaustuGuid.empty()) { r << ", masaustu karsilastirilamadi (tespit eksik)"; } else if (po.masaustuGuid == g->masaustuGuid) { r << ", ayni sanal masaustunde"; } else { r << ", FARKLI sanal masaustunde (plan: sira " << po.masaustuSira << ")"; } // Belge farklari: tamYol kumesi karsilastirmasi. for (const auto& pb : po.belgeler) { if (pb.tamYol.empty()) continue; bool acikMi = std::any_of(g->belgeler.begin(), g->belgeler.end(), [&](const CatiaBelgeBilgi& b) { return b.tamYol == pb.tamYol; }); if (!acikMi) r << "\n - eksik: " << pb.tamYol; } for (const auto& b : g->belgeler) { if (b.tamYol.empty()) continue; bool plandaMi = std::any_of(po.belgeler.begin(), po.belgeler.end(), [&](const PlanBelge& pb) { return pb.tamYol == b.tamYol; }); if (!plandaMi) r << "\n - plan disinda ek belge: " << b.tamYol; } r << "\n"; } bool ekVar = false; for (size_t k = 0; k < guncel.oturumlar.size(); ++k) { if (guncelEslesti[k]) continue; if (!ekVar) { r << " Planda olmayan, su an acik ek oturumlar:\n"; ekVar = true; } r << " - \"" << guncel.oturumlar[k].pencereBasligi << "\"\n"; } r << " NOT: Bu Faz 1 raporudur — otomatik acma/yukleme/masaustu tasima Faz 2'de " "(henuz uygulanmadi).\n"; return r.str(); } } // namespace fiko