glom r1617 - in trunk: . glom glom/libglom/data_structure



Author: arminb
Date: Fri May 23 14:43:23 2008
New Revision: 1617
URL: http://svn.gnome.org/viewvc/glom?rev=1617&view=rev

Log:
2008-05-23  Armin Burgmeier  <armin arbur net>

	* glom/libglom/data_structure/field.h:
	* glom/libglom/data_structure/field.cc: Added from_sql() to convert a
	SQL representation to a Gnome::Gda::Value. This is the reverse to the
	sql() function.

	* glom/dialog_import_csv.cc (field_data_func): Remove own unescaping
	code, use Field::from_sql() for preview instead.

	* glom/dialog_import_csv_progress.cc (on_idle_import): Use
	Field::from_sql() to do the actual import. This allows to correctly
	import files that the Export functionality produces, escpecially
	dates and images.


Modified:
   trunk/ChangeLog
   trunk/glom/dialog_import_csv.cc
   trunk/glom/dialog_import_csv_progress.cc
   trunk/glom/libglom/data_structure/field.cc
   trunk/glom/libglom/data_structure/field.h

Modified: trunk/glom/dialog_import_csv.cc
==============================================================================
--- trunk/glom/dialog_import_csv.cc	(original)
+++ trunk/glom/dialog_import_csv.cc	Fri May 23 14:43:23 2008
@@ -33,6 +33,7 @@
 
 const gunichar DELIMITER = ',';
 
+#if 0
 // TODO: Perhaps we should change this to std::string to allow binary data, such
 // as images.
 // TODO: What escaping system is this? Can't we reuse some standard escaping function from somewhere? murrayc
@@ -112,48 +113,38 @@
     return walk;
   }
 }
+#endif
 
 Glib::ustring::const_iterator advance_field(const Glib::ustring::const_iterator& iter, const Glib::ustring::const_iterator& end, Glib::ustring& field)
 {
   Glib::ustring::const_iterator walk = iter;
+
   gunichar quote_char = 0;
+  bool escaped = false;
 
   field.clear();
 
-  while(walk != end)
+  for(; walk != end; ++ walk)
   {
     gunichar c = *walk;
 
+    // Skip escape sequences
+    if(escaped) { field += c; escaped = false; continue; }
+
     // Escaped stuff in quoted strings:
     if(quote_char && c == '\\')
-    {
-      ++ walk;
-      walk = advance_escape(walk, end, c);
-      field.append(1, c);
-    }
+      escaped = true;
     // End of quoted string
     else if(quote_char && c == quote_char)
-    {
       quote_char = 0;
-      ++ walk;
-    }
-    // Begin of quoted string. This allows stuff such as "foo"'bar'baz in a field here,
-    // but it can easily be avoided if it's a problem, by checking walk against iter.
+    // Begin of quoted string.
     else if(!quote_char && (c == '\'' || c == '\"'))
-    {
       quote_char = c;
-      ++ walk;
-    }
     // End of field:
     else if(!quote_char && c == DELIMITER)
-    {
       break;
-    }
-    else
-    {
-      field.append(1, c);
-      ++ walk;
-    }
+
+    field += c; // Just so that we don't need to iterate through the field again, since there is no Glib::ustring::substr(iter, iter)
   }
 
   // TODO: Throw error if still inside a quoted string?
@@ -861,13 +852,39 @@
     // Convert to currently chosen field, if any, and back, too see how it
     // looks like when imported
     sharedptr<Field> field = m_fields[column_number];
-    Glib::ustring text = m_rows[row][column_number];
+    const Glib::ustring& orig_text = m_rows[row][column_number];
+
+    Glib::ustring text;
     if(field)
     {
       bool success;
-      Gnome::Gda::Value value = Glom::Conversions::parse_value(field->get_glom_type(), text, success);
-      if(!success) text = _("<Import failure>");
-      else text = Glom::Conversions::get_text_for_gda_value(field->get_glom_type(), value);
+
+      if(field->get_glom_type() != Field::TYPE_IMAGE)
+      {
+        Gnome::Gda::Value value = field->from_sql(orig_text, success);
+        
+        if(!success) text = _("<Import Failure>");
+        else text = Glom::Conversions::get_text_for_gda_value(field->get_glom_type(), value);
+      }
+      else
+      {
+        // TODO: It is too slow to create the picture here. Maybe we should
+        // create it once and cache it. We could also think about using a
+        // GtkCellRendererPixbuf to show it, then.
+        if(!orig_text.empty() && orig_text != "NULL")
+          text = _("<Picture>");
+      }
+    }
+    else
+    {
+      // TODO: Should we unescape the field's content?
+      text = orig_text;
+    }
+
+    if(text.length() > 32)
+    {
+      text.erase(32);
+      text.append("â");
     }
 
     renderer_combo->set_property("text", text);

Modified: trunk/glom/dialog_import_csv_progress.cc
==============================================================================
--- trunk/glom/dialog_import_csv_progress.cc	(original)
+++ trunk/glom/dialog_import_csv_progress.cc	Fri May 23 14:43:23 2008
@@ -143,7 +143,8 @@
     if(field)
     {
       bool success;
-      Gnome::Gda::Value value = Glom::Conversions::parse_value(field->get_glom_type(), m_data_source->get_data(m_current_row, i), success);
+      Gnome::Gda::Value value = field->from_sql(m_data_source->get_data(m_current_row, i), success);
+
       if(success)
       {
         // Make the value empty if the value is not unique.

Modified: trunk/glom/libglom/data_structure/field.cc
==============================================================================
--- trunk/glom/libglom/data_structure/field.cc	(original)
+++ trunk/glom/libglom/data_structure/field.cc	Fri May 23 14:43:23 2008
@@ -242,6 +242,83 @@
   }
 }
 
+#define ISFIRSTOCTDIGIT(CH) ((CH) >= '0' && (CH) <= '3')
+#define ISOCTDIGIT(CH) ((CH) >= '0' && (CH) <= '7')
+#define OCTVAL(CH) ((CH) - '0')
+
+/// Unescape text that was escaped by the above function. Only unescapes
+/// quoted strings. Nonquoted strings are returned without being modified.
+static std::string glom_unescape_text(const std::string& str)
+{
+  std::string::const_iterator iter = str.begin();
+  if(iter == str.end()) return str;  // Empty string
+  if(*iter != '\'') return str; // Non-quoted
+  ++ iter;
+
+  std::string result;
+
+  while(iter != str.end())
+  {
+    // End here if this is the terminating quotation character, or unescape
+    // '' to '.
+    if(*iter == '\'')
+    {
+      ++ iter;
+      if(iter == str.end() || *iter != '\'') break;
+      result += '\'';
+      ++ iter;
+    }
+    // Unescape "" to ".
+    else if(*iter == '\"')
+    {
+      ++ iter;
+      if(iter == str.end()) break;
+      result += '\"';
+      ++ iter;
+    }
+    // Escape sequence beginning with backslash.
+    else if(*iter == '\\')
+    {
+      ++ iter;
+      if(iter == str.end()) break;
+
+      // Escaped backslash
+      if(*iter == '\\')
+      {
+        result += '\\';
+        ++ iter;
+      }
+      // Some octal representation
+      else if(ISFIRSTOCTDIGIT(*iter))
+      {
+        unsigned char byte = OCTVAL(*iter);
+
+        ++ iter;
+        if(iter != str.end() && ISOCTDIGIT(*iter))
+        {
+          byte = (byte << 3) | OCTVAL(*iter);
+          ++ iter;
+          if(iter != str.end() && ISOCTDIGIT(*iter))
+          {
+            byte = (byte << 3) | OCTVAL(*iter);
+            ++ iter;
+          }
+        }
+
+        result += byte;
+      }
+    }
+    else
+    {
+      // Take char as is
+      result += *iter;
+      ++ iter;
+    }
+  }
+
+  return result;
+}
+
 Glib::ustring Field::sql(const Gnome::Gda::Value& value) const
 {
   //g_warning("Field::sql: glom_type=%d", get_glom_type());
@@ -351,6 +428,64 @@
   return str;
 }
 
+Gnome::Gda::Value Field::from_sql(const Glib::ustring& str, bool& success) const
+{
+  success = true;
+  switch(m_glom_type)
+  {
+  case TYPE_TEXT:
+    {
+      return Gnome::Gda::Value(glom_unescape_text(str));
+    }
+  case TYPE_DATE:
+  case TYPE_TIME:
+    {
+      if(str == "NULL") return Gnome::Gda::Value();
+      Glib::ustring unescaped = glom_unescape_text(str);
+
+      NumericFormat format_ignored; //Because we use ISO format.
+      return Conversions::parse_value(m_glom_type, unescaped, format_ignored, success, true);
+    }
+  case TYPE_NUMERIC:
+    {
+      //No quotes for numbers.
+      NumericFormat format_ignored; //Because we use ISO format.
+      return Conversions::parse_value(m_glom_type, str, format_ignored, success, true);
+    }
+  case TYPE_BOOLEAN:
+    {
+      if(str.lowercase() == "true")
+        return Gnome::Gda::Value(true);
+      return Gnome::Gda::Value(false);
+    }
+  case TYPE_IMAGE:
+    {
+      if(str == "NULL") return Gnome::Gda::Value();
+
+      // We store the data into the format E'some escaped data'::bytea, and we
+      // now expect it in exactly that format now.
+      // We operate on the raw std::string since access into the Glib::ustring
+      // is expensive, and we only check for ASCII stuff anyway.
+      const std::string& raw = str.raw();
+      if(raw.length() >= 10 &&
+         raw.compare(0, 2, "E'") == 0 && raw.compare(raw.length() - 8, 8, "'::bytea") == 0)
+      {
+        std::string unescaped = glom_unescape_text(raw.substr(1, raw.length() - 8));
+        NumericFormat format_ignored; //Because we use ISO format.
+        return Conversions::parse_value(m_glom_type, unescaped, format_ignored, success, true);
+      }
+      else
+      {
+        success = false;
+        return Gnome::Gda::Value();
+      }
+    }
+  default:
+    g_assert_not_reached();
+    break;
+  }
+}
+
 Glib::ustring Field::sql_find(const Gnome::Gda::Value& value) const
 {
   switch(get_glom_type())

Modified: trunk/glom/libglom/data_structure/field.h
==============================================================================
--- trunk/glom/libglom/data_structure/field.h	(original)
+++ trunk/glom/libglom/data_structure/field.h	Fri May 23 14:43:23 2008
@@ -159,6 +159,10 @@
    */
   Glib::ustring sql(const Gnome::Gda::Value& value) const;
 
+  /** Unescape the value again.
+   */
+  Gnome::Gda::Value from_sql(const Glib::ustring& str, bool& success) const;
+
   /** Escape the value so that it can be used in a SQL command for a find.
    */
   Glib::ustring sql_find(const Gnome::Gda::Value& value) const;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]