add xml tree iterator webdav

Tue, 14 Jan 2020 22:05:34 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Tue, 14 Jan 2020 22:05:34 +0100
branch
webdav
changeset 223
bbaec8415c10
parent 222
5f05e56cb8e2
child 224
0de1ec82628e

add xml tree iterator

src/server/public/webdav.h file | annotate | diff | comparison | revisions
src/server/test/webdav.c file | annotate | diff | comparison | revisions
src/server/webdav/multistatus.c file | annotate | diff | comparison | revisions
src/server/webdav/xml.c file | annotate | diff | comparison | revisions
--- a/src/server/public/webdav.h	Tue Jan 14 20:05:18 2020 +0100
+++ b/src/server/public/webdav.h	Tue Jan 14 22:05:34 2020 +0100
@@ -75,6 +75,8 @@
 #define WS_NODE_CDATA          4
 #define WS_NODE_ENTITY_REF     5
 
+typedef int(*wsxml_func)(WSXmlNode *, void *);
+
 /* propfind settings */
 
 /*
@@ -328,6 +330,13 @@
         WebdavVFSProperties properties,
         struct stat *s);
 
+int wsxml_iterator(
+        pool_handle_t *pool,
+        WSXmlNode *node,
+        wsxml_func begincb,
+        wsxml_func endcb,
+        void *udata);
+
 #ifdef	__cplusplus
 }
 #endif
--- a/src/server/test/webdav.c	Tue Jan 14 20:05:18 2020 +0100
+++ b/src/server/test/webdav.c	Tue Jan 14 22:05:34 2020 +0100
@@ -40,6 +40,8 @@
 #include "vfs.h"
 #include "webdav.h"
 
+static int webdav_is_initialized = 0;
+
 /* ----------------------------- Test Backends --------------------------*/
 
 static int backend2_init_called = 0;
@@ -148,6 +150,13 @@
         WebdavPropfindRequest **out_propfind,
         const char *xml)
 {
+    if(!webdav_is_initialized) {
+        if(webdav_init(NULL, NULL, NULL) != REQ_PROCEED) {
+            return 1;
+        }
+        webdav_is_initialized = 1;
+    }
+    
     Session *sn = testutil_session();
     Request *rq = testutil_request(sn->pool, "PROPFIND", "/");
     
@@ -684,14 +693,17 @@
 }
 
 UCX_TEST(test_msresponse_addproperty) {
-    Session *sn = testutil_session();
-    Request *rq = testutil_request(sn->pool, "PROPFIND", "/");
-    Multistatus *ms = multistatus_response(sn, rq);
-    MSResponse *r;
+    Session *sn;
+    Request *rq;
     
     UCX_TEST_BEGIN;
     
-    r = (MSResponse*)ms->response.addresource((WebdavResponse*)ms, "/");
+    WebdavOperation *op = test_propfind_op(&sn, &rq, TEST_PROPFIND1);
+    UCX_TEST_ASSERT(op, "init failed");
+    UCX_TEST_ASSERT(op->response, "no response");
+    
+    Multistatus *ms = (Multistatus*)op->response;
+    MSResponse *r = (MSResponse*)ms->response.addresource((WebdavResponse*)ms, "/");
     
     WebdavProperty p1;
     WebdavProperty p[16];
@@ -699,6 +711,7 @@
     
     // init test data
     p1.namespace = webdav_dav_namespace();
+    p1.nsdef = NULL;
     p1.lang = NULL;
     p1.name = "test1";
     p1.value.data = NULL;
@@ -706,6 +719,7 @@
     
     for(int i=0;i<8;i++) {
         p[i].namespace = webdav_dav_namespace();
+        p[i].nsdef = NULL;
         p[i].name = names[i];
         p[i].lang = NULL;
         p[i].value.node = NULL;
--- a/src/server/webdav/multistatus.c	Tue Jan 14 20:05:18 2020 +0100
+++ b/src/server/webdav/multistatus.c	Tue Jan 14 22:05:34 2020 +0100
@@ -77,7 +77,7 @@
     ZERO(res, sizeof(MSResponse));
     
     // set href
-    res->resource.href = pool_strdup(response->op->sn->pool, path);
+    res->resource.href = pool_strdup(ms->sn->pool, path);
     
     // add resource funcs
     res->resource.addproperty = msresponse_addproperty;
--- a/src/server/webdav/xml.c	Tue Jan 14 20:05:18 2020 +0100
+++ b/src/server/webdav/xml.c	Tue Jan 14 22:05:34 2020 +0100
@@ -30,7 +30,116 @@
 #include <stdlib.h>
 #include <string.h>
 
+
 #include "xml.h"
 
+typedef struct StackElm {
+    WSXmlNode *node; // list of nodes
+    WSXmlNode *parent; // if not NULL, call endcb after node->next is NULL
+    struct StackElm *next;
+} StackElm;
 
+#define STACK_PUSH(stack, elm) if(stack) { elm->next = stack; } stack = elm;
 
+int wsxml_iterator(
+        pool_handle_t *pool,
+        WSXmlNode *node,
+        wsxml_func begincb,
+        wsxml_func endcb,
+        void *udata)
+{  
+    if(!node) {
+        return 0;
+    }
+    
+    StackElm *stack = pool_malloc(pool, sizeof(StackElm));
+    if(!stack) {
+        return 1; // OOM
+    }
+    stack->next = NULL;
+    stack->node = node;
+    stack->parent = NULL;
+    
+    int ret = 0;
+    int br = 0;
+    while(stack) {
+        StackElm *cur = stack;
+        WSXmlNode *xmlnode = cur->node; // get top stack element
+        stack = cur->next;              // and remove it
+        cur->next = NULL;
+        
+        while(xmlnode) {
+            // element begin callback
+            if(begincb(xmlnode, udata)) {
+                br = 1;
+                break; // I don't like break with labels - is this wrong?
+            }
+            
+            if(xmlnode->children) {
+                // put the children on the stack
+                // the next stack iteration will process the children
+                StackElm *newelm = pool_malloc(pool, sizeof(StackElm));
+                if(!newelm) {
+                    ret = 1;
+                    br = 1;
+                    break;
+                }
+                newelm->next = NULL;
+                newelm->node = xmlnode->children;
+                // setting the parent will make sure endcb will be called
+                // for the current xmlnode after all children are processed
+                newelm->parent = xmlnode;
+                
+                // if xmlnode->next is not NULL, there are still nodes at
+                // this level, therefore we have to put these also on the
+                // stack
+                // this way, the remaining nodes are processed after all
+                // children of the current node are processed
+                if(xmlnode->next) {
+                    // reuse current StackElm
+                    cur->node = xmlnode->next;
+                    STACK_PUSH(stack, cur);
+                    cur = NULL;
+                }
+                
+                // now we can put the children on the stack
+                STACK_PUSH(stack, newelm);
+                // break, because we don't want to process xmlnode->next now
+                break;
+            } else {
+                // no children means, the end callback can be called directly
+                // after the begin callback (no intermediate nodes)
+                if(endcb(xmlnode, udata)) {
+                    br = 1;
+                    break;
+                }
+            }
+            
+            // continue with next node at this level
+            xmlnode = xmlnode->next;
+        }
+        if(br) {
+            break; // break because of an error
+        }
+        
+        if(cur) {
+            if(cur->parent) {
+                if(endcb(cur->parent, udata)) {
+                    break;
+                }
+            }
+            pool_free(pool, cur);
+        }
+    }
+    
+    // free all remaining elements
+    StackElm *elm = stack;
+    while(elm) {
+        StackElm *next = elm->next;
+        pool_free(pool, elm);
+        elm = next;
+    }
+
+    return ret;
+}
+

mercurial