Code

r11451@tres: ted | 2006-04-17 22:21:33 -0700
[inkscape.git] / src / dom / uri.cpp
index 286857e4177c7c87bb160991f90fd613f3f5f729..ff5e91ff8180d78a84d17962024b44f0db805c09 100644 (file)
@@ -236,6 +236,32 @@ DOMString URI::getPath() const
     return path;
 }
 
+DOMString URI::getNativePath() const
+{
+    DOMString npath;
+#ifdef __WIN32__
+    unsigned int firstChar = 0;
+    if (path.size() >= 3)
+        {
+        if (path[0] == '/' &&
+            isLetter(path[1]) &&
+            path[2] == ':')
+            firstChar++;
+         }
+    for (unsigned int i=firstChar ; i<path.size() ; i++)
+        {
+        XMLCh ch = (XMLCh) path[i];
+        if (ch == '/')
+            npath.push_back((XMLCh)'\\');
+        else
+            npath.push_back(ch);
+        }
+#else
+    npath = path;
+#endif
+    return npath;
+}
+
 
 bool URI::isAbsolute() const
 {
@@ -309,27 +335,105 @@ URI URI::resolve(const URI &other) const
             unsigned int pos = path.rfind('/');
             if (pos != path.npos)
                 {
-                DOMString tpath = path.substr(pos);
+                DOMString tpath = path.substr(0, pos+1);
                 tpath.append(other.path);
                 newUri.path = tpath;
-                newUri.normalize();
                 }
             }
         }
+
+    newUri.normalize();
     return newUri;
 }
 
 
 /**
- *
+ *  This follows the Java URI algorithm:
+ *   1. All "." segments are removed.
+ *   2. If a ".." segment is preceded by a non-".." segment
+ *          then both of these segments are removed. This step
+ *          is repeated until it is no longer applicable.
+ *   3. If the path is relative, and if its first segment
+ *          contains a colon character (':'), then a "." segment
+ *          is prepended. This prevents a relative URI with a path
+ *          such as "a:b/c/d" from later being re-parsed as an
+ *          opaque URI with a scheme of "a" and a scheme-specific
+ *          part of "b/c/d". (Deviation from RFC 2396)
  */
-void URI::normalize() const
+void URI::normalize()
 {
+    std::vector<DOMString> segments;
 
+    //## Collect segments
+    if (path.size()<2)
+        return;
+    bool abs = false;
+    unsigned int pos=0;
+    if (path[0]=='/')
+        {
+        abs = true;
+        pos++;
+        }
+    while (pos < path.size())
+        {
+        unsigned int pos2 = path.find('/', pos);
+        if (pos2==path.npos)
+            {
+            DOMString seg = path.substr(pos);
+            //printf("last segment:%s\n", 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());
+            segments.push_back(seg);
+            }
+        pos = pos2;
+        pos++;
+        }
 
+    //## Clean up (normalize) segments
+    bool edited = false;
+    std::vector<DOMString>::iterator iter;
+    for (iter=segments.begin() ; iter!=segments.end() ; )
+        {
+        DOMString s = *iter;
+        if (s == ".")
+            {
+            iter = segments.erase(iter);
+            edited = true;
+            }
+        else if (s == ".." &&
+                 iter != segments.begin() &&
+                 *(iter-1) != "..")
+            {
+            iter--; //back up, then erase two entries
+            iter = segments.erase(iter);
+            iter = segments.erase(iter);
+            edited = true;
+            }
+        else
+            iter++;
+        }
 
-
-
+    //## Rebuild path, if necessary
+    if (edited)
+        {
+        path.clear();
+        if (abs)
+            {
+            path.append("/");
+            }
+        std::vector<DOMString>::iterator iter;
+        for (iter=segments.begin() ; iter!=segments.end() ; iter++)
+            {
+            if (iter != segments.begin())
+                path.append("/");
+            path.append(*iter);
+            }
+        }
 
 }
 
@@ -452,7 +556,12 @@ int URI::parseHierarchicalPart(int p0)
 
     //# Are we absolute?
     ch = peek(p);
-    if (ch == '/')
+    if (isLetter(ch) && peek(p+1)==':')
+        {
+        absolute = true;
+        path.push_back((XMLCh)'/');
+        }
+    else if (ch == '/')
         {
         absolute = true;
         if (p>p0) //in other words, if '/' is not the first char
@@ -566,11 +675,21 @@ bool URI::parse(const DOMString &str)
 {
 
     parselen = str.size();
-    DOMString tmp = str;
+
+    DOMString tmp;
+    for (unsigned int i=0 ; i<str.size() ; i++)
+        {
+        XMLCh ch = (XMLCh) str[i];
+        if (ch == '\\')
+            tmp.push_back((XMLCh)'/');
+        else
+            tmp.push_back(ch);
+        }
     parsebuf = (char *) tmp.c_str();
 
 
     int p = parse(0);
+    normalize();
 
     if (p < 0)
         {