[buffer] Implement buffer deserialization for format=json

Using a ragel machine.
diff --git a/src/Makefile.am b/src/Makefile.am
index f666d5e..269fabe 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -258,12 +258,14 @@
 .PHONY: unicode-tables arabic-table indic-table
 
 BUILT_SOURCES += \
+	hb-buffer-deserialize-json.hh \
 	hb-buffer-deserialize-text.hh \
 	hb-ot-shape-complex-indic-machine.hh \
 	hb-ot-shape-complex-myanmar-machine.hh \
 	hb-ot-shape-complex-sea-machine.hh \
 	$(NULL)
 EXTRA_DIST += \
+	hb-buffer-deserialize-json.rl \
 	hb-buffer-deserialize-text.rl \
 	hb-ot-shape-complex-indic-machine.rl \
 	hb-ot-shape-complex-myanmar-machine.rl \
diff --git a/src/hb-buffer-deserialize-json.rl b/src/hb-buffer-deserialize-json.rl
new file mode 100644
index 0000000..d93765a
--- /dev/null
+++ b/src/hb-buffer-deserialize-json.rl
@@ -0,0 +1,129 @@
+/*
+ * Copyright © 2013  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_BUFFER_DESERIALIZE_JSON_HH
+#define HB_BUFFER_DESERIALIZE_JSON_HH
+
+#include "hb-private.hh"
+
+%%{
+
+machine deserialize_json;
+alphtype unsigned char;
+write data;
+
+action clear_item {
+	memset (&info, 0, sizeof (info));
+	memset (&pos , 0, sizeof (pos ));
+}
+
+action add_item {
+	buffer->add_info (info);
+	if (buffer->in_error)
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+
+action tok {
+	tok = p;
+}
+
+action parse_glyph {
+	if (!hb_font_glyph_from_string (font,
+					tok, p - tok,
+					&info.codepoint))
+	  return false;
+}
+
+action parse_gid       { if (!parse_uint (tok, p, &info.codepoint)) return false; }
+action parse_cluster   { if (!parse_uint (tok, p, &info.cluster )) return false; }
+action parse_x_offset  { if (!parse_int  (tok, p, &pos.x_offset )) return false; }
+action parse_y_offset  { if (!parse_int  (tok, p, &pos.y_offset )) return false; }
+action parse_x_advance { if (!parse_int  (tok, p, &pos.x_advance)) return false; }
+action parse_y_advance { if (!parse_int  (tok, p, &pos.y_advance)) return false; }
+
+unum	= '0' | [1-9] digit*;
+num	= '-'? unum;
+
+comma = space* ',' space*;
+colon = space* ':' space*;
+
+glyph_name   = '"' (alnum+ >tok %parse_glyph) '"';
+glyph_number = (unum >tok %parse_gid);
+
+glyph	= "\"g\""  colon (glyph_name | glyph_number);
+cluster	= "\"cl\"" colon (unum >tok %parse_cluster);
+xoffset	= "\"dx\"" colon (num >tok %parse_x_offset);
+yoffset	= "\"dy\"" colon (num >tok %parse_y_offset);
+xadvance= "\"ax\"" colon (num >tok %parse_x_advance);
+yadvance= "\"ay\"" colon (num >tok %parse_y_advance);
+
+element = glyph | cluster | xoffset | yoffset | xadvance | yadvance;
+item	=
+	( '{' space* element (comma element)* space* '}')
+	>clear_item
+	@add_item
+	;
+
+main := space* item (comma item)* space* (','|']')?;
+
+}%%
+
+static hb_bool_t
+_hb_buffer_deserialize_glyphs_json (hb_buffer_t *buffer,
+				    const char *buf,
+				    unsigned int buf_len,
+				    const char **end_ptr,
+				    hb_font_t *font)
+{
+  const char *p = buf, *pe = buf + buf_len;
+
+  /* Ensure we have positions. */
+  (void) hb_buffer_get_glyph_positions (buffer, NULL);
+
+  while (p < pe && ISSPACE (*p))
+    p++;
+  if (p < pe && *p == (buffer->len ? ',' : '['))
+  {
+    *end_ptr = ++p;
+  }
+
+  const char *tok = NULL;
+  int cs;
+  hb_glyph_info_t info;
+  hb_glyph_position_t pos;
+  %%{
+    write init;
+    write exec;
+  }%%
+
+  *end_ptr = p;
+
+  return p == pe && *(p-1) != ']';
+}
+
+#endif /* HB_BUFFER_DESERIALIZE_JSON_HH */
diff --git a/src/hb-buffer-deserialize-text.rl b/src/hb-buffer-deserialize-text.rl
index 7c370e7..5272690 100644
--- a/src/hb-buffer-deserialize-text.rl
+++ b/src/hb-buffer-deserialize-text.rl
@@ -30,54 +30,10 @@
 #include "hb-private.hh"
 
 %%{
-  machine deserialize_text;
-  alphtype unsigned char;
-  write data;
-}%%
 
-static hb_bool_t
-parse_uint (const char *pp, const char *end, uint32_t *pv)
-{
-  char buf[32];
-  unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp));
-  strncpy (buf, pp, len);
-  buf[len] = '\0';
-
-  char *p = buf;
-  char *pend = p;
-  uint32_t v;
-
-  errno = 0;
-  v = strtol (p, &pend, 10);
-  if (errno || p == pend || pend - p != end - pp)
-    return false;
-
-  *pv = v;
-  return true;
-}
-
-static hb_bool_t
-parse_int (const char *pp, const char *end, int32_t *pv)
-{
-  char buf[32];
-  unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp));
-  strncpy (buf, pp, len);
-  buf[len] = '\0';
-
-  char *p = buf;
-  char *pend = p;
-  int32_t v;
-
-  errno = 0;
-  v = strtol (p, &pend, 10);
-  if (errno || p == pend || pend - p != end - pp)
-    return false;
-
-  *pv = v;
-  return true;
-}
-
-%%{
+machine deserialize_text;
+alphtype unsigned char;
+write data;
 
 action clear_item {
 	memset (&info, 0, sizeof (info));
@@ -143,10 +99,8 @@
   /* Ensure we have positions. */
   (void) hb_buffer_get_glyph_positions (buffer, NULL);
 
-#define ISSPACE(c) ((c)==' '||(c)=='\f'||(c)=='\n'||(c)=='\r'||(c)=='\t'||(c)=='\v')
   while (p < pe && ISSPACE (*p))
     p++;
-#undef ISSPACE
   if (p < pe && *p == (buffer->len ? '|' : '['))
   {
     *end_ptr = ++p;
diff --git a/src/hb-buffer-serialize.cc b/src/hb-buffer-serialize.cc
index 0271547..dc47ba7 100644
--- a/src/hb-buffer-serialize.cc
+++ b/src/hb-buffer-serialize.cc
@@ -242,15 +242,48 @@
 
 
 static hb_bool_t
-_hb_buffer_deserialize_glyphs_json (hb_buffer_t *buffer,
-				    const char *buf,
-				    unsigned int buf_len,
-				    const char **end_ptr,
-				    hb_font_t *font)
+parse_uint (const char *pp, const char *end, uint32_t *pv)
 {
-  return false;
+  char buf[32];
+  unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp));
+  strncpy (buf, pp, len);
+  buf[len] = '\0';
+
+  char *p = buf;
+  char *pend = p;
+  uint32_t v;
+
+  errno = 0;
+  v = strtol (p, &pend, 10);
+  if (errno || p == pend || pend - p != end - pp)
+    return false;
+
+  *pv = v;
+  return true;
 }
 
+static hb_bool_t
+parse_int (const char *pp, const char *end, int32_t *pv)
+{
+  char buf[32];
+  unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp));
+  strncpy (buf, pp, len);
+  buf[len] = '\0';
+
+  char *p = buf;
+  char *pend = p;
+  int32_t v;
+
+  errno = 0;
+  v = strtol (p, &pend, 10);
+  if (errno || p == pend || pend - p != end - pp)
+    return false;
+
+  *pv = v;
+  return true;
+}
+
+#include "hb-buffer-deserialize-json.hh"
 #include "hb-buffer-deserialize-text.hh"
 
 hb_bool_t
diff --git a/src/hb-private.hh b/src/hb-private.hh
index 91bce9b..0f652ad 100644
--- a/src/hb-private.hh
+++ b/src/hb-private.hh
@@ -516,10 +516,12 @@
 
 /* ASCII tag/character handling */
 
-static inline unsigned char ISALPHA (unsigned char c)
+static inline bool ISALPHA (unsigned char c)
 { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); }
-static inline unsigned char ISALNUM (unsigned char c)
+static inline bool ISALNUM (unsigned char c)
 { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); }
+static inline bool ISSPACE (unsigned char c)
+{ return c == ' ' || c =='\f'|| c =='\n'|| c =='\r'|| c =='\t'|| c =='\v'; }
 static inline unsigned char TOUPPER (unsigned char c)
 { return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; }
 static inline unsigned char TOLOWER (unsigned char c)
diff --git a/src/hb-shape.cc b/src/hb-shape.cc
index e38f59f..67ef7e6 100644
--- a/src/hb-shape.cc
+++ b/src/hb-shape.cc
@@ -38,10 +38,8 @@
 parse_space (const char **pp, const char *end)
 {
   char c;
-#define ISSPACE(c) ((c)==' '||(c)=='\f'||(c)=='\n'||(c)=='\r'||(c)=='\t'||(c)=='\v')
   while (*pp < end && (c = **pp, ISSPACE (c)))
     (*pp)++;
-#undef ISSPACE
 }
 
 static hb_bool_t
diff --git a/src/test-buffer-serialize.cc b/src/test-buffer-serialize.cc
index 71bb431..3577dbf 100644
--- a/src/test-buffer-serialize.cc
+++ b/src/test-buffer-serialize.cc
@@ -106,14 +106,14 @@
     while (hb_buffer_deserialize_glyphs (buf,
 					 p, -1, &p,
 					 font,
-					 HB_BUFFER_SERIALIZE_FORMAT_TEXT))
+					 HB_BUFFER_SERIALIZE_FORMAT_JSON))
       ;
     if (*p && *p != '\n')
       ret = false;
 
     hb_buffer_serialize_glyphs (buf, 0, hb_buffer_get_length (buf),
 				out, sizeof (out), NULL,
-				font, HB_BUFFER_SERIALIZE_FORMAT_TEXT,
+				font, HB_BUFFER_SERIALIZE_FORMAT_JSON,
 				HB_BUFFER_SERIALIZE_FLAGS_DEFAULT);
     puts (out);
   }