From f2c0e6ef02ebc639c525a24fcf532b989d2340bb Mon Sep 17 00:00:00 2001 From: Daniel Gerblick Date: Mon, 18 Jul 2022 14:47:28 -0400 Subject: [PATCH] fixed issue causing hyprctl to output ill-formed json when strings include characters needing escaping --- src/debug/HyprCtl.cpp | 44 +++++++++++++++++------------------ src/helpers/MiscFunctions.cpp | 24 +++++++++++++++++++ src/helpers/MiscFunctions.hpp | 1 + 3 files changed, 47 insertions(+), 22 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 402df762..9832a22d 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -38,11 +38,11 @@ R"#({ "active": "%s" },)#", m->ID, - m->szName.c_str(), + escapeJSONStrings(m->szName).c_str(), (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, - m->activeWorkspace, g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName.c_str(), + m->activeWorkspace, escapeJSONStrings(g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName).c_str(), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, @@ -89,11 +89,11 @@ R"#({ w.get(), (int)w->m_vRealPosition.vec().x, (int)w->m_vRealPosition.vec().y, (int)w->m_vRealSize.vec().x, (int)w->m_vRealSize.vec().y, - w->m_iWorkspaceID, (w->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_szName.c_str() : std::string("Invalid workspace " + std::to_string(w->m_iWorkspaceID)).c_str()), + w->m_iWorkspaceID, escapeJSONStrings(w->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_szName : std::string("Invalid workspace " + std::to_string(w->m_iWorkspaceID))).c_str(), (int)w->m_bIsFloating, w->m_iMonitorID, - g_pXWaylandManager->getAppIDClass(w.get()).c_str(), - g_pXWaylandManager->getTitle(w.get()).c_str(), + escapeJSONStrings(g_pXWaylandManager->getAppIDClass(w.get())).c_str(), + escapeJSONStrings(g_pXWaylandManager->getTitle(w.get())).c_str(), w->getPID() ); } @@ -130,8 +130,8 @@ R"#({ "hasfullscreen": %i },)#", w->m_iID, - w->m_szName.c_str(), - g_pCompositor->getMonitorFromID(w->m_iMonitorID)->szName.c_str(), + escapeJSONStrings(w->m_szName).c_str(), + escapeJSONStrings(g_pCompositor->getMonitorFromID(w->m_iMonitorID)->szName).c_str(), g_pCompositor->getWindowsOnWorkspace(w->m_iID), (int)w->m_bHasFullscreenWindow ); @@ -175,11 +175,11 @@ R"#({ PWINDOW, (int)PWINDOW->m_vRealPosition.vec().x, (int)PWINDOW->m_vRealPosition.vec().y, (int)PWINDOW->m_vRealSize.vec().x, (int)PWINDOW->m_vRealSize.vec().y, - PWINDOW->m_iWorkspaceID, (PWINDOW->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID)->m_szName.c_str()), + PWINDOW->m_iWorkspaceID, escapeJSONStrings(PWINDOW->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID)->m_szName).c_str(), (int)PWINDOW->m_bIsFloating, PWINDOW->m_iMonitorID, - g_pXWaylandManager->getAppIDClass(PWINDOW).c_str(), - g_pXWaylandManager->getTitle(PWINDOW).c_str(), + escapeJSONStrings(g_pXWaylandManager->getAppIDClass(PWINDOW)).c_str(), + escapeJSONStrings(g_pXWaylandManager->getTitle(PWINDOW)).c_str(), PWINDOW->getPID() ); } else { @@ -199,7 +199,7 @@ std::string layersRequest(HyprCtl::eHyprCtlOutputFormat format) { R"#("%s": { "levels": { )#", - mon->szName.c_str() + escapeJSONStrings(mon->szName).c_str() ); int layerLevel = 0; @@ -225,7 +225,7 @@ R"#( { layer->geometry.y, layer->geometry.width, layer->geometry.height, - layer->szNamespace.c_str() + escapeJSONStrings(layer->szNamespace).c_str() ); } @@ -285,7 +285,7 @@ R"#( { "name": "%s" },)#", &m, - m.mouse->name + escapeJSONStrings(m.mouse->name).c_str() ); } @@ -308,13 +308,13 @@ R"#( { "active_keymap": "%s" },)#", &k, - k.keyboard->name, - k.currentRules.rules.c_str(), - k.currentRules.model.c_str(), - k.currentRules.layout.c_str(), - k.currentRules.variant.c_str(), - k.currentRules.options.c_str(), - KM + escapeJSONStrings(k.keyboard->name).c_str(), + escapeJSONStrings(k.currentRules.rules).c_str(), + escapeJSONStrings(k.currentRules.model).c_str(), + escapeJSONStrings(k.currentRules.layout).c_str(), + escapeJSONStrings(k.currentRules.variant).c_str(), + escapeJSONStrings(k.currentRules.options).c_str(), + escapeJSONStrings(KM).c_str() ); } @@ -336,7 +336,7 @@ R"#( { },)#", &d, d.pTabletParent, - d.pTabletParent ? d.pTabletParent->wlrDevice ? d.pTabletParent->wlrDevice->name : "" : "" + escapeJSONStrings(d.pTabletParent ? d.pTabletParent->wlrDevice ? d.pTabletParent->wlrDevice->name : "" : "").c_str() ); } @@ -347,7 +347,7 @@ R"#( { "name": "%s" },)#", &d, - d.wlrDevice ? d.wlrDevice->name : "" + escapeJSONStrings(d.wlrDevice ? d.wlrDevice->name : "").c_str() ); } diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index 126600f3..8f8ee0f9 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -3,6 +3,7 @@ #include #include "../Compositor.hpp" #include +#include static const float transforms[][9] = {{ 1.0f, 0.0f, 0.0f, @@ -113,6 +114,29 @@ std::string getFormat(const char *fmt, ...) { return output; } +std::string escapeJSONStrings(const std::string& str) { + std::ostringstream oss; + for (auto &c : str) { + switch (c) { + case '"': oss << "\\\""; break; + case '\\': oss << "\\\\"; break; + case '\b': oss << "\\b"; break; + case '\f': oss << "\\f"; break; + case '\n': oss << "\\n"; break; + case '\r': oss << "\\r"; break; + case '\t': oss << "\\t"; break; + default: + if ('\x00' <= c && c <= '\x1f') { + oss << "\\u" + << std::hex << std::setw(4) << std::setfill('0') << static_cast(c); + } else { + oss << c; + } + } + } + return oss.str(); +} + void scaleBox(wlr_box* box, float scale) { box->width = std::round(box->width * scale); box->height = std::round(box->height * scale); diff --git a/src/helpers/MiscFunctions.hpp b/src/helpers/MiscFunctions.hpp index 108ac7f7..a40471a9 100644 --- a/src/helpers/MiscFunctions.hpp +++ b/src/helpers/MiscFunctions.hpp @@ -5,6 +5,7 @@ void addWLSignal(wl_signal*, wl_listener*, void* pOwner, std::string ownerString); void wlr_signal_emit_safe(struct wl_signal *signal, void *data); std::string getFormat(const char *fmt, ...); // Basically Debug::log to a string +std::string escapeJSONStrings(const std::string& str); void scaleBox(wlr_box*, float); std::string removeBeginEndSpacesTabs(std::string); bool isNumber(const std::string&, bool allowfloat = false);