Add escaping of semicolon and equals in node tags.
authorTom Hughes <tom@compton.nu>
Wed, 21 Nov 2007 13:30:55 +0000 (13:30 +0000)
committerTom Hughes <tom@compton.nu>
Wed, 21 Nov 2007 13:30:55 +0000 (13:30 +0000)
Based on patch from Dave Stubbs.

app/controllers/amf_controller.rb
app/models/node.rb
lib/tags.rb [new file with mode: 0644]

index 095ae47864addf40f5d4f97029c36f234f991a17..b7667b71d8857ce91cbddc1525b1d4fff78d8cc8 100644 (file)
@@ -794,31 +794,25 @@ end
 
 
 def sqlescape(a)
-  a.gsub(/[\000-\037]/,"").gsub("'","''").gsub(92.chr,92.chr+92.chr)
+  a.gsub(/[\000-\037]/,"").gsub("'","''").gsub(92.chr) {92.chr+92.chr}
 end
 
 def tag2array(a)
   tags={}
-  a.gsub(';;;','#%').split(';').each do |b|
-    b.gsub!('#%',';;;')
-    b.gsub!('===','#%')
-    k,v=b.split('=')
-    if k.nil? then k='' end
-    if v.nil? then v='' end
-    tags[k.gsub('#%','=').gsub(':','|')]=v.gsub('#%','=')
+  Tags.split(a) do |k, v|
+    tags[k.gsub(':','|')]=v
   end
   tags
 end
 
 def array2tag(a)
-  str=''
+  tags = []
   a.each do |k,v|
     if v=='' then next end
     if v[0,6]=='(type ' then next end
-    if str!='' then str+=';' end
-    str+=k.gsub(';',';;;').gsub('=','===').gsub('|',':')+'='+v.gsub(';',';;;').gsub('=','===')
+    tags << [k.gsub('|',':'), v]
   end
-  str
+  return Tags.join(tags)
 end
 
 def getuserid(token)
index 9ed5c3bbf4cd0983f0d48ea623af788480d2df6d..59aa4d36ffd01ef845896ca1199594253a6ef0fe 100644 (file)
@@ -57,10 +57,7 @@ class Node < GeoRecord
           tags << [tag['k'],tag['v']]
         end
 
-        tags = tags.collect { |k,v| "#{k}=#{v}" }.join(';')
-        tags = '' if tags.nil?
-
-        node.tags = tags
+        node.tags = Tags.join(tags)
       end
     rescue
       node = nil
@@ -102,25 +99,15 @@ class Node < GeoRecord
 
     el1['user'] = user_display_name_cache[self.user_id] unless user_display_name_cache[self.user_id].nil?
 
-    Node.split_tags(el1, self.tags)
+    Tags.split(self.tags) do |k,v|
+      el2 = XML::Node.new('tag')
+      el2['k'] = k.to_s
+      el2['v'] = v.to_s
+      el1 << el2
+    end
+
     el1['visible'] = self.visible.to_s
     el1['timestamp'] = self.timestamp.xmlschema
     return el1
   end
-
-  def self.split_tags(el, tags)
-    tags.split(';').each do |tag|
-      parts = tag.split('=')
-      key = ''
-      val = ''
-      key = parts[0].strip unless parts[0].nil?
-      val = parts[1].strip unless parts[1].nil?
-      if key != '' && val != ''
-        el2 = XML::Node.new('tag')
-        el2['k'] = key.to_s
-        el2['v'] = val.to_s
-        el << el2
-      end
-    end
-  end
 end
diff --git a/lib/tags.rb b/lib/tags.rb
new file mode 100644 (file)
index 0000000..2095b09
--- /dev/null
@@ -0,0 +1,42 @@
+module Tags
+  def self.join(tags)
+    joined = tags.collect { |k,v| "#{escape_string(k)}=#{escape_string(v)}" }.join(';')
+    joined = '' if joined.nil?
+    return joined
+  end
+
+  def self.escape_string(tag)
+    return tag.gsub(/[;=\\]/) { |v| escape_char(v) }
+  end
+
+  def self.escape_char(v)
+    case v
+      when ';' then return '\\s'
+      when '=' then return '\\e'
+    end
+    return '\\\\'
+  end
+
+  def self.split(tags)
+    tags.split(';').each do |tag|
+      key,val = tag.split('=').collect { |s| s.strip }
+      key = '' if key.nil?
+      val = '' if val.nil?
+      if key != '' && val != ''
+        yield unescape_string(key),unescape_string(val)
+      end
+    end
+  end
+
+  def self.unescape_string(tag)
+    return tag.gsub(/\\[se\\]/) { |v| unescape_char(v) }
+  end
+
+  def self.unescape_char(v)
+    case v
+      when '\\s' then return ';'
+      when '\\e' then return '='
+    end
+    return '\\'
+  end
+end