Code

New Dutch calligraphy and interpolate tutorial
[inkscape.git] / src / dom / uri.cpp
index af808f40dfc99c508b6872d469d58ad818bea29e..b8a9a04fb08cda6751444939553c937936d30b23 100644 (file)
@@ -10,7 +10,7 @@
  * Authors:
  *   Bob Jamison
  *
- * Copyright (C) 2005-2007 Bob Jamison
+ * Copyright (C) 2005-2008 Bob Jamison
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
 
 
 #include "uri.h"
-#include "charclass.h"
+#include "ucd.h"
 
 #include <stdio.h>
 #include <stdarg.h>
-
+#include <vector>
 
 
 namespace org
@@ -49,7 +49,7 @@ namespace dom
 typedef struct
 {
     int  ival;
-    char *sval;
+    char const *sval;
     int  port;
 } LookupEntry;
 
@@ -142,14 +142,14 @@ void URI::init()
     parsebuf  = NULL;
     parselen  = 0;
     scheme    = SCHEME_NONE;
-    schemeStr = "";
+    schemeStr.clear();
     port      = 0;
-    authority = "";
-    path      = "";
+    authority.clear();
+    path.clear();
     absolute  = false;
     opaque    = false;
-    query     = "";
-    fragment  = "";
+    query.clear();
+    fragment.clear();
 }
 
 
@@ -173,6 +173,29 @@ void URI::assign(const URI &other)
 //#########################################################################
 //#A T T R I B U T E S
 //#########################################################################
+static const char *hexChars = "0123456789abcdef";
+
+static DOMString toStr(const std::vector<int> &arr)
+{
+    DOMString buf;
+    std::vector<int>::const_iterator iter;
+    for (iter=arr.begin() ; iter!=arr.end() ; iter++)
+        {
+        int ch = *iter;
+        if (isprint(ch))
+            buf.push_back((XMLCh)ch);
+        else
+            {
+            buf.push_back('%');
+            int hi = ((ch>>4) & 0xf);
+            buf.push_back(hexChars[hi]);
+            int lo = ((ch   ) & 0xf);
+            buf.push_back(hexChars[lo]);
+            }
+        }
+    return buf;
+}
+
 
 DOMString URI::toString() const
 {
@@ -180,18 +203,18 @@ DOMString URI::toString() const
     if (authority.size() > 0)
         {
         str.append("//");
-        str.append(authority);
+        str.append(toStr(authority));
         }
-    str.append(path);
+    str.append(toStr(path));
     if (query.size() > 0)
         {
         str.append("?");
-        str.append(query);
+        str.append(toStr(query));
         }
     if (fragment.size() > 0)
         {
         str.append("#");
-        str.append(fragment);
+        str.append(toStr(fragment));
         }
     return str;
 }
@@ -210,7 +233,7 @@ DOMString URI::getSchemeStr() const
 
 DOMString URI::getAuthority() const
 {
-    DOMString ret = authority;
+    DOMString ret = toStr(authority);
     if (portSpecified && port>=0)
         {
         char buf[7];
@@ -222,7 +245,8 @@ DOMString URI::getAuthority() const
 
 DOMString URI::getHost() const
 {
-    return authority;
+    DOMString str = toStr(authority);
+    return str;
 }
 
 int URI::getPort() const
@@ -233,31 +257,33 @@ int URI::getPort() const
 
 DOMString URI::getPath() const
 {
-    return path;
+    DOMString str = toStr(path);
+    return str;
 }
 
 DOMString URI::getNativePath() const
 {
+    DOMString pathStr = toStr(path);
     DOMString npath;
 #ifdef __WIN32__
     unsigned int firstChar = 0;
-    if (path.size() >= 3)
+    if (pathStr.size() >= 3)
         {
-        if (path[0] == '/' &&
-            isLetter(path[1]) &&
-            path[2] == ':')
+        if (pathStr[0] == '/' &&
+            uni_is_letter(pathStr[1]) &&
+            pathStr[2] == ':')
             firstChar++;
          }
-    for (unsigned int i=firstChar ; i<path.size() ; i++)
+    for (unsigned int i=firstChar ; i<pathStr.size() ; i++)
         {
-        XMLCh ch = (XMLCh) path[i];
+        XMLCh ch = (XMLCh) pathStr[i];
         if (ch == '/')
             npath.push_back((XMLCh)'\\');
         else
             npath.push_back(ch);
         }
 #else
-    npath = path;
+    npath = pathStr;
 #endif
     return npath;
 }
@@ -276,13 +302,72 @@ bool URI::isOpaque() const
 
 DOMString URI::getQuery() const
 {
-    return query;
+    DOMString str = toStr(query);
+    return str;
 }
 
 
 DOMString URI::getFragment() const
 {
-    return fragment;
+    DOMString str = toStr(fragment);
+    return str;
+}
+
+
+
+
+static int find(const std::vector<int> &str, int ch, int startpos)
+{
+    for (unsigned int i = startpos ; i < str.size() ; i++)
+        {
+        if (ch == str[i])
+            return i;
+        }
+    return -1;
+}
+
+
+static int findLast(const std::vector<int> &str, int ch)
+{
+    /**
+     * Fixed.  Originally I used an unsigned int for str.size(),
+     * which was dumb, since i>=0 would always be true.
+     */
+    for (int i = ((int)str.size())-1 ; i>=0 ; i--)
+        {
+        if (ch == str[i])
+            return i;
+        }
+    return -1;
+}
+
+
+static bool sequ(const std::vector<int> &str, const char *key)
+{
+    char *c = (char *)key;
+    for (unsigned int i=0 ; i<str.size() ; i++)
+        {
+        if (! (*c))
+            return false;
+        if (*c != str[i])
+            return false;
+        }
+    return true;
+}
+
+
+static std::vector<int> substr(const std::vector<int> &str,
+                      int startpos, int len)
+{
+    std::vector<int> buf;
+    unsigned int pos = startpos;
+    for (int i=0 ; i<len ; i++)
+        {
+        if (pos >= str.size())
+            break;
+        buf.push_back(str[pos++]);
+        }
+    return buf;
 }
 
 
@@ -332,12 +417,16 @@ URI URI::resolve(const URI &other) const
             }
         else
             {
-            DOMString::size_type pos = path.find_last_of('/');
-            if (pos != path.npos)
+            int pos = findLast(path, '/');
+            if (pos >= 0)
                 {
-                DOMString tpath = path.substr(0, pos+1);
-                tpath.append(other.path);
-                newUri.path = tpath;
+                newUri.path.clear();
+                //# append my path up to and including the '/'
+                for (int i = 0; i<=pos ; i++)
+                       newUri.path.push_back(path[i]);
+                //# append other path
+                for (unsigned int i = 0; i<other.path.size() ; i++)
+                       newUri.path.push_back(other.path[i]);
                 }
             else
                 newUri.path = other.path;
@@ -345,6 +434,7 @@ URI URI::resolve(const URI &other) const
         }
 
     newUri.normalize();
+
     return newUri;
 }
 
@@ -364,32 +454,35 @@ URI URI::resolve(const URI &other) const
  */
 void URI::normalize()
 {
-    std::vector<DOMString> segments;
+    std::vector< std::vector<int> > segments;
 
     //## Collect segments
     if (path.size()<2)
         return;
     bool abs = false;
-    unsigned int pos=0;
+    int pos=0;
+    int len = (int) path.size();
+
     if (path[0]=='/')
         {
         abs = true;
         pos++;
         }
-    while (pos < path.size())
+
+    while (pos < len)
         {
-        DOMString::size_type pos2 = path.find('/', pos);
-        if (pos2==path.npos)
+        int pos2 = find(path, '/', pos);
+        if (pos2 < 0)
             {
-            DOMString seg = path.substr(pos);
-            //printf("last segment:%s\n", seg.c_str());
+            std::vector<int> seg = substr(path, pos, path.size()-pos);
+            //printf("last segment:%s\n", toStr(seg).c_str());
             segments.push_back(seg);
             break;
             }
         if (pos2>pos)
             {
-            DOMString seg = path.substr(pos, pos2-pos);
-            //printf("segment:%s\n", seg.c_str());
+            std::vector<int> seg = substr(path, pos, pos2-pos);
+            //printf("segment:%s\n", toStr(seg).c_str());
             segments.push_back(seg);
             }
         pos = pos2;
@@ -398,18 +491,17 @@ void URI::normalize()
 
     //## Clean up (normalize) segments
     bool edited = false;
-    std::vector<DOMString>::iterator iter;
+    std::vector< std::vector<int> >::iterator iter;
     for (iter=segments.begin() ; iter!=segments.end() ; )
         {
-        DOMString s = *iter;
-        if (s == ".")
+        std::vector<int> s = *iter;
+        if (sequ(s,"."))
             {
             iter = segments.erase(iter);
             edited = true;
             }
-        else if (s == ".." &&
-                 iter != segments.begin() &&
-                 *(iter-1) != "..")
+        else if (sequ(s, "..") && iter != segments.begin() &&
+                 !sequ(*(iter-1), ".."))
             {
             iter--; //back up, then erase two entries
             iter = segments.erase(iter);
@@ -426,14 +518,16 @@ void URI::normalize()
         path.clear();
         if (abs)
             {
-            path.append("/");
+            path.push_back('/');
             }
-        std::vector<DOMString>::iterator iter;
+        std::vector< std::vector<int> >::iterator iter;
         for (iter=segments.begin() ; iter!=segments.end() ; iter++)
             {
             if (iter != segments.begin())
-                path.append("/");
-            path.append(*iter);
+                path.push_back('/');
+            std::vector<int> seg = *iter;
+            for (unsigned int i = 0; i<seg.size() ; i++)
+                path.push_back(seg[i]);
             }
         }
 
@@ -482,7 +576,7 @@ int URI::peek(int p)
 
 
 
-int URI::match(int p0, char *key)
+int URI::match(int p0, char const *key)
 {
     int p = p0;
     while (p < parselen)
@@ -507,7 +601,7 @@ int URI::parseHex(int p0, int &result)
     int val = 0;
 
     //# Upper 4
-    XMLCh ch = peek(p);
+    int ch = peek(p);
     if (ch >= '0' && ch <= '9')
         val += (ch - '0');
     else if (ch >= 'a' && ch <= 'f')
@@ -535,6 +629,7 @@ int URI::parseHex(int p0, int &result)
         error("parseHex : unexpected character : %c", ch);
         return -1;
         }
+    p++;
     result = val;
     return p;
 }
@@ -544,7 +639,7 @@ int URI::parseHex(int p0, int &result)
 int URI::parseEntity(int p0, int &result)
 {
     int p = p0;
-    XMLCh ch = peek(p);
+    int ch = peek(p);
     if (ch != '&')
         return p0;
     p++;
@@ -558,6 +653,13 @@ int URI::parseEntity(int p0, int &result)
     p = parseHex(p, val);
     if (p<0)
         return -1;
+    ch = peek(p);
+    if (ch != ';')
+        {
+        error("parseEntity: expected ';'");
+        return -1;
+        }
+    p++;
     result = val;
     return p;
 }
@@ -565,7 +667,7 @@ int URI::parseEntity(int p0, int &result)
 int URI::parseAsciiEntity(int p0, int &result)
 {
     int p = p0;
-    XMLCh ch = peek(p);
+    int ch = peek(p);
     if (ch != '%')
         return p0;
     p++;
@@ -615,13 +717,43 @@ int URI::parseHierarchicalPart(int p0)
             ch = peek(p);
             if (ch == '/')
                 break;
+            else if (ch == '&') //IRI entity
+                {
+                int val;
+                p2 = parseEntity(p, val);
+                if (p2<p)
+                    {
+                    return -1;
+                    }
+                p = p2;
+                authority.push_back((XMLCh)val);
+                }
+            else if (ch == '%') //ascii hex excape
+                {
+                int val;
+                p2 = parseAsciiEntity(p, val);
+                if (p2<p)
+                    {
+                    return -1;
+                    }
+                p = p2;
+                authority.push_back((XMLCh)val);
+                }
             else if (ch == ':')
+                {
                 portSpecified = true;
+                p++;
+                }
             else if (portSpecified)
+                {
                 portStr.push_back((XMLCh)ch);
+                p++;
+                }
             else
+                {
                 authority.push_back((XMLCh)ch);
-            p++;
+                p++;
+                }
             }
         if (portStr.size() > 0)
             {
@@ -635,7 +767,7 @@ int URI::parseHierarchicalPart(int p0)
 
     //# Are we absolute?
     ch = peek(p);
-    if (isLetter(ch) && peek(p+1)==':')
+    if (uni_is_letter(ch) && peek(p+1)==':')
         {
         absolute = true;
         path.push_back((XMLCh)'/');
@@ -682,7 +814,7 @@ int URI::parseHierarchicalPart(int p0)
             p++;
             }
         }
-
+    //trace("path:%s", toStr(path).c_str());
     return p;
 }
 
@@ -721,7 +853,7 @@ int URI::parseFragment(int p0)
         ch = peek(p);
         if (ch == '?')
             break;
-        fragment.push_back((XMLCh)ch);
+        fragment.push_back(ch);
         p++;
         }
 
@@ -779,22 +911,30 @@ bool URI::parse(const DOMString &str)
 {
 
     parselen = str.size();
+    parsebuf = new int[str.size()];
+    if (!parsebuf)
+        {
+        error("parse : could not allocate parsebuf");
+        return false;
+        }
 
-    DOMString tmp;
-    for (unsigned int i=0 ; i<str.size() ; i++)
+    DOMString::const_iterator iter;
+    unsigned int i=0;
+    for (iter= str.begin() ; iter!=str.end() ; iter++)
         {
-        XMLCh ch = (XMLCh) str[i];
+        int ch = *iter;
         if (ch == '\\')
-            tmp.push_back((XMLCh)'/');
+            parsebuf[i++] = '/';
         else
-            tmp.push_back(ch);
+            parsebuf[i++] = ch;
         }
-    parsebuf = (char *) tmp.c_str();
 
 
     int p = parse(0);
     normalize();
 
+    delete[] parsebuf;
+
     if (p < 0)
         {
         error("Syntax error");
@@ -802,7 +942,7 @@ bool URI::parse(const DOMString &str)
         }
 
     //printf("uri:%s\n", toString().c_str());
-    //printf("path:%s\n", path.c_str());
+    //printf("parse:%s\n", toStr(path).c_str());
 
     return true;