Selaa lähdekoodia

Amend sanitization of format strings. Support ' without stb_printf. Simpler loops, will also be used for ImStrv branch. (8ee77f1) (#3604)
Widgets: Sliders: Fix a bug where numbers after format specifier (eg. %d123) would cause RoundScalarWithFormatT() return incorrect value.

ocornut 4 vuotta sitten
vanhempi
commit
e842b196df
1 muutettua tiedostoa jossa 23 lisäystä ja 24 poistoa
  1. 23 24
      imgui_widgets.cpp

+ 23 - 24
imgui_widgets.cpp

@@ -2077,37 +2077,36 @@ static const char* ImAtoi(const char* src, TYPE* output)
     return src;
     return src;
 }
 }
 
 
+// Sanitize format
+// - Zero terminate so extra characters after format (e.g. "%f123") don't confuse atof/atoi
+// - stb_sprintf.h supports several new modifiers which format numbers in a way that also makes them incompatible atof/atoi.
+static void SanitizeFormatString(const char* fmt, char* fmt_out, size_t fmt_out_size)
+{
+    const char* fmt_end = ImParseFormatFindEnd(fmt);
+    IM_ASSERT((size_t)(fmt_end - fmt + 1) < fmt_out_size); // Format is too long, let us know if this happens to you!
+    while (fmt < fmt_end)
+    {
+        char c = *(fmt++);
+        if (c != '\'' && c != '$' && c != '_') // Custom flags provided by stb_sprintf.h. POSIX 2008 also supports '.
+            *(fmt_out++) = c;
+    }
+    *fmt_out = 0; // Zero-terminate
+}
+
 template<typename TYPE, typename SIGNEDTYPE>
 template<typename TYPE, typename SIGNEDTYPE>
 TYPE ImGui::RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, TYPE v)
 TYPE ImGui::RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, TYPE v)
 {
 {
     const char* fmt_start = ImParseFormatFindStart(format);
     const char* fmt_start = ImParseFormatFindStart(format);
     if (fmt_start[0] != '%' || fmt_start[1] == '%') // Don't apply if the value is not visible in the format string
     if (fmt_start[0] != '%' || fmt_start[1] == '%') // Don't apply if the value is not visible in the format string
         return v;
         return v;
+
+    // Sanitize format
+    char fmt_sanitized[32];
+    SanitizeFormatString(fmt_start, fmt_sanitized, IM_ARRAYSIZE(fmt_sanitized));
+    fmt_start = fmt_sanitized;
+
+    // Format value with our rounding, and read back
     char v_str[64];
     char v_str[64];
-    char fmt[32];
-    const char* fmt_end = ImParseFormatFindEnd(fmt_start);
-    IM_ASSERT(fmt_end - fmt_start < IM_ARRAYSIZE(fmt) && "Number format is too long!");
-#ifdef IMGUI_USE_STB_SPRINTF
-    // stb_sprintf.h supports several new modifiers which format numbers in a way that makes them incompatible with
-    // ImAtof()/ImAtoi(). Copy format string omitting incompatible modifiers and anything past the end of format specifier.
-    int fmt_len = 0;
-    for (int i = 0, end = fmt_end - fmt_start; i < end; i++)
-    {
-        char c = fmt_start[i];
-        if (c == '\'' || c == '$' || c == '_')                                  // Custom flags provided by stb_sprintf.h
-            continue;
-        fmt[fmt_len++] = c;
-    }
-    fmt[fmt_len] = 0;
-    fmt_start = fmt;
-#else
-    // Extra characters after format specifier may confuse ImAtof()/ImAtoi(), therefore copying is performed, excluding anything beyond.
-    if (*fmt_end != 0)
-    {
-        ImStrncpy(fmt, fmt_start, fmt_end - fmt_start + 1);
-        fmt_start = fmt;
-    }
-#endif
     ImFormatString(v_str, IM_ARRAYSIZE(v_str), fmt_start, v);
     ImFormatString(v_str, IM_ARRAYSIZE(v_str), fmt_start, v);
     const char* p = v_str;
     const char* p = v_str;
     while (*p == ' ')
     while (*p == ' ')