]> git.cworth.org Git - apitrace/blobdiff - json.hpp
Use the glGetVertexAttrib*ARB as well.
[apitrace] / json.hpp
index 4eeed8b59d7134666af32658fd8c7296a715c97e..d13793ebd64925f253c6a88e509b1213fbfc9e87 100644 (file)
--- a/json.hpp
+++ b/json.hpp
 
 #include <assert.h>
 #include <stddef.h>
+#include <wchar.h>
 
 #include <ostream>
+#include <iomanip>
 
 
 class JSONWriter
@@ -43,6 +45,7 @@ private:
 
     int level;
     bool value;
+    char space;
 
     void newline(void) {
         os << "\n";
@@ -53,38 +56,147 @@ private:
     void separator(void) {
         if (value) {
             os << ",";
+            switch (space) {
+            case '\0':
+                break;
+            case '\n':
+                newline();
+                break;
+            default:
+                os << space;
+                break;
+            }
+        } else {
+            if (space == '\n') {
+                newline();
+            }
         }
     }
 
-    void escapeString(const char *str) {
-        const unsigned char *p = (const unsigned char *)str;
+    void escapeAsciiString(const char *str) {
         os << "\"";
+
+        const unsigned char *src = (const unsigned char *)str;
         unsigned char c;
-        while ((c = *p++) != 0) {
-            if (c == '\"')
-                os << "\\\"";
-            else if (c == '\\')
-                os << "\\\\";
-            else if (c >= 0x20 && c <= 0x7e)
-                os << c;
-            else if (c == '\t')
-                os << "\\t";
-            else if (c == '\r')
-                os << "\\r";
-            else if (c == '\n')
-                os << "&#10;";
-            else {
-                unsigned octal0 = c & 0x7;
-                unsigned octal1 = (c >> 3) & 0x7;
-                unsigned octal2 = (c >> 3) & 0x7;
-                os << "\\";
-                if (octal2)
-                    os << octal2;
-                if (octal1)
-                    os << octal1;
-                os << octal0;
+        while ((c = *src++)) {
+            if ((c == '\"') ||
+                (c == '\\')) {
+                // escape character
+                os << '\\' << (unsigned char)c;
+            } else if ((c >= 0x20 && c <= 0x7e) ||
+                        c == '\t' ||
+                        c == '\r' ||
+                        c == '\n') {
+                // pass-through character
+                os << (unsigned char)c;
+            } else {
+                assert(0);
+                os << "?";
             }
         }
+
+        os << "\"";
+    }
+
+    void escapeUnicodeString(const char *str) {
+        os << "\"";
+
+        const char *locale = setlocale(LC_CTYPE, "");
+        const char *src = str;
+        mbstate_t state;
+
+        memset(&state, 0, sizeof state);
+
+        do {
+            // Convert characters one at a time in order to recover from
+            // conversion errors
+            wchar_t c;
+            size_t written = mbsrtowcs(&c, &src, 1, &state);
+            if (written == 0) {
+                // completed
+                break;
+            } if (written == (size_t)-1) {
+                // conversion error -- skip 
+                os << "?";
+                do {
+                    ++src;
+                } while (*src & 0x80);
+            } else if ((c == '\"') ||
+                       (c == '\\')) {
+                // escape character
+                os << '\\' << (unsigned char)c;
+            } else if ((c >= 0x20 && c <= 0x7e) ||
+                        c == '\t' ||
+                        c == '\r' ||
+                        c == '\n') {
+                // pass-through character
+                os << (unsigned char)c;
+            } else {
+                // unicode
+                os << "\\u" << std::setfill('0') << std::hex << std::setw(4) << (unsigned)c;
+                os << std::dec;
+            }
+        } while (src);
+
+        setlocale(LC_CTYPE, locale);
+
+        os << "\"";
+    }
+
+    void encodeBase64String(const unsigned char *bytes, size_t size) {
+        const char *table64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+        unsigned char c0, c1, c2, c3;
+        char buf[4];
+        unsigned written;
+
+        os << "\"";
+
+        written = 0;
+        while (size >= 3) {
+            c0 = bytes[0] >> 2;
+            c1 = ((bytes[0] & 0x03) << 4) | ((bytes[1] & 0xf0) >> 4);
+            c2 = ((bytes[1] & 0x0f) << 2) | ((bytes[2] & 0xc0) >> 6);
+            c3 = bytes[2] & 0x3f;
+
+            buf[0] = table64[c0];
+            buf[1] = table64[c1];
+            buf[2] = table64[c2];
+            buf[3] = table64[c3];
+
+            os.write(buf, 4);
+
+            bytes += 3;
+            size -= 3;
+            ++written;
+
+            if (written >= 76/4 && size) {
+                os << "\n";
+                written = 0;
+            }
+        }
+
+        if (size > 0) {
+            c0 = bytes[0] >> 2;
+            c1 = ((bytes[0] & 0x03) << 4);
+            buf[2] = '=';
+            buf[3] = '=';
+            
+            if (size > 1) {
+                c1 |= ((bytes[1] & 0xf0) >> 4);
+                c2 = ((bytes[1] & 0x0f) << 2);
+                if (size > 2) {
+                    c2 |= ((bytes[2] & 0xc0) >> 6);
+                    c3 = bytes[2] & 0x3f;
+                    buf[3] = table64[c3];
+                }
+                buf[2] = table64[c2];
+            }
+            buf[1] = table64[c1];
+            buf[0] = table64[c0];
+
+            os.write(buf, 4);
+        }
+
         os << "\"";
     }
 
@@ -92,7 +204,8 @@ public:
     JSONWriter(std::ostream &_os) : 
         os(_os), 
         level(0),
-        value(false)
+        value(false),
+        space(0)
     {
         beginObject();
     }
@@ -103,6 +216,7 @@ public:
     }
 
     inline void beginObject() {
+        separator();
         os << "{";
         ++level;
         value = false;
@@ -114,12 +228,14 @@ public:
             newline();
         os << "}";
         value = true;
+        space = '\n';
     }
 
     inline void beginMember(const char * name) {
+        space = 0;
         separator();
         newline();
-        escapeString(name);
+        escapeAsciiString(name);
         os << ": ";
         value = false;
     }
@@ -127,42 +243,85 @@ public:
     inline void endMember(void) {
         assert(value);
         value = true;
+        space = 0;
     }
 
     inline void beginArray() {
         separator();
         os << "[";
+        ++level;
         value = false;
+        space = 0;
     }
 
     inline void endArray(void) {
+        --level;
+        if (space == '\n') {
+            newline();
+        }
         os << "]";
         value = true;
+        space = '\n';
     }
 
     inline void writeString(const char *s) {
         separator();
-        escapeString(s);
-        value = false;
+        escapeUnicodeString(s);
+        value = true;
+        space = ' ';
+    }
+
+    inline void writeBase64(const void *bytes, size_t size) {
+        separator();
+        encodeBase64String((const unsigned char *)bytes, size);
+        value = true;
+        space = ' ';
     }
 
     inline void writeNull(void) {
         separator();
         os << "null";
         value = true;
+        space = ' ';
     }
 
     inline void writeBool(bool b) {
         separator();
         os << (b ? "true" : "false");
         value = true;
+        space = ' ';
     }
 
     template<class T>
-    void writeNumber(T n) {
-        separator();
-        os << n;
-        value = true;
+    inline void writeNumber(T n) {
+        if (n != n) {
+            // NaN
+            writeNull();
+        } else {
+            separator();
+            os << std::dec << std::setprecision(9) << n;
+            value = true;
+            space = ' ';
+        }
+    }
+    
+    inline void writeStringMember(const char *name, const char *s) {
+        beginMember(name);
+        writeString(s);
+        endMember();
+    }
+
+    inline void writeBoolMember(const char *name, bool b) {
+        beginMember(name);
+        writeBool(b);
+        endMember();
+    }
+
+    template<class T>
+    inline void writeNumberMember(const char *name, T n) {
+        beginMember(name);
+        writeNumber(n);
+        endMember();
     }
 };