From eab0d3426d990b3088e00894ab6a7fb0b22400f8 Mon Sep 17 00:00:00 2001
From: Kevin Whitaker <eyecreate@eyecreate.org>
Date: Fri, 15 Sep 2023 15:51:40 +0000
Subject: [PATCH] Added xml dependencies that should run on uPy. Start
 nextcloud code.

---
 ElementTree.py | 132 +++++++++++++++++++++++++++++++++++
 uNextcloud.py  |  15 ++++
 xmltok2.py     | 183 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 330 insertions(+)
 create mode 100644 ElementTree.py
 create mode 100644 uNextcloud.py
 create mode 100644 xmltok2.py

diff --git a/ElementTree.py b/ElementTree.py
new file mode 100644
index 0000000..254c5d1
--- /dev/null
+++ b/ElementTree.py
@@ -0,0 +1,132 @@
+# This file is part of the standard library of Pycopy project, minimalist
+# and lightweight Python implementation.
+#
+# https://github.com/pfalcon/pycopy
+# https://github.com/pfalcon/pycopy-lib
+#
+# The MIT License (MIT)
+#
+# Copyright (c) 2018-2020 Paul Sokolovsky
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+import io
+import xmltok2
+
+
+class ParseError(Exception):
+    pass
+
+
+class Element:
+
+    def __init__(self):
+        self.tag = None
+        self.attrib = {}
+        self.text = None
+        self.tail = None
+        self._children = []
+
+    def __getitem__(self, i):
+        return self._children[i]
+
+    def __len__(self):
+        return len(self._children)
+
+    def append(self, el):
+        self._children.append(el)
+
+    def get(self, key, default=None):
+        return self.attrib.get(key, default)
+
+    def set(self, key, value):
+        self.attrib[key] = value
+
+    def write(self, file):
+        assert self.tag is not None
+        file.write("<%s" % self.tag)
+        for k, v in self.attrib.items():
+            file.write(' {}="{}"'.format(k, v))
+        file.write(">")
+        if self.text is not None:
+            file.write(self.text)
+        for t in self._children:
+            t.write(file)
+        file.write("</%s>" % self.tag)
+        if self.tail is not None:
+            file.write(self.tail)
+
+
+class ElementTree:
+
+    def __init__(self, root):
+        self.root = root
+
+    def getroot(self):
+        return self.root
+
+    def write(self, file):
+        self.root.write(file)
+        file.write("\n")
+
+
+def parse_el(stream):
+    stack = []
+    root = None
+    last = None
+
+    for ev in xmltok2.tokenize(stream):
+        typ = ev[0]
+
+        if typ == xmltok2.START_TAG:
+            el = Element()
+            el.tag = ev[2]
+            if not stack:
+                root = el
+            else:
+                stack[-1]._children.append(el)
+            stack.append(el)
+            last = None
+
+        elif typ == xmltok2.ATTR:
+            # Ignore attrs of processing instructions
+            if stack:
+                stack[-1].attrib[ev[2]] = ev[3]
+
+        elif typ == xmltok2.TEXT:
+            if last is None:
+                stack[-1].text = ev[1]
+            else:
+                last.tail = ev[1]
+
+        elif typ == xmltok2.END_TAG:
+            if stack[-1].tag != ev[2]:
+                raise ParseError("mismatched tag: /%s (expected: /%s)" % (ev[1][1], stack[-1].tag))
+            last = stack.pop()
+
+    return root
+
+
+def parse(source):
+    return ElementTree(parse_el(source))
+
+
+def fromstring(data):
+    buf = io.StringIO(data)
+    return parse_el(buf)
diff --git a/uNextcloud.py b/uNextcloud.py
new file mode 100644
index 0000000..983b273
--- /dev/null
+++ b/uNextcloud.py
@@ -0,0 +1,15 @@
+import ElementTree
+from urllib import urequest
+import sdcard
+import gc
+import uos
+
+
+class uNextcloud:
+
+    def __init__(self):
+        self.sd_spi = machine.SPI(0, sck=machine.Pin(18, machine.Pin.OUT), mosi=machine.Pin(19, machine.Pin.OUT), miso=machine.Pin(16, machine.Pin.OUT))
+        self.sd = sdcard.SDCard(sd_spi, machine.Pin(22))
+        uos.mount(sd, "/sd")
+        gc.collect() 
+
diff --git a/xmltok2.py b/xmltok2.py
new file mode 100644
index 0000000..43ca0b1
--- /dev/null
+++ b/xmltok2.py
@@ -0,0 +1,183 @@
+# This file is part of the standard library of Pycopy project, minimalist
+# and lightweight Python implementation.
+#
+# https://github.com/pfalcon/pycopy
+# https://github.com/pfalcon/pycopy-lib
+#
+# The MIT License (MIT)
+#
+# Copyright (c) 2018-2019 Paul Sokolovsky
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+TEXT = "TEXT"
+START_TAG = "START_TAG"
+#START_TAG_DONE = "START_TAG_DONE"
+END_TAG = "END_TAG"
+PI = "PI"
+#PI_DONE = "PI_DONE"
+ATTR = "ATTR"
+#ATTR_VAL = "ATTR_VAL"
+
+class XMLSyntaxError(Exception):
+    pass
+
+class XMLTokenizer:
+
+    def __init__(self, f):
+        self.f = f
+        self.c = ""
+        self.nextch()
+
+    def getch(self):
+        c = self.c
+        self.nextch()
+        return c
+
+    def eof(self):
+        return self.c == ""
+
+    def nextch(self):
+        self.c = self.f.read(1)
+
+    def skip_ws(self):
+        while self.c.isspace():
+            self.nextch()
+
+    def isident(self):
+        self.skip_ws()
+        return self.c.isalpha()
+
+    def getident(self):
+        self.skip_ws()
+        ident = ""
+        while self.c:
+            c = self.c
+            if not(c.isalpha() or c.isdigit() or c in "_-."):
+                break
+            ident += self.getch()
+        return ident
+
+    def putnsident(self, res):
+        ns = ""
+        ident = self.getident()
+        if self.c == ":":
+            self.nextch()
+            ns = ident
+            ident = self.getident()
+        res[1] = ns
+        res[2] = ident
+
+    def match(self, c):
+        self.skip_ws()
+        if self.c == c:
+            self.nextch()
+            return True
+        return False
+
+    def expect(self, c):
+        if not self.match(c):
+            raise XMLSyntaxError
+
+    def lex_attrs_till(self, res):
+        while self.isident():
+            res[0] = ATTR
+            self.putnsident(res)
+            self.expect("=")
+            quote = self.getch()
+            if quote != '"' and quote != "'":
+                raise XMLSyntaxError
+            val = ""
+            while self.c != quote:
+                val += self.getch()
+            self.expect(quote)
+            res[3] = val
+            yield res
+            res[3] = None
+
+    def tokenize(self):
+        res = [None, None, None, None]
+        while not self.eof():
+            if self.match("<"):
+                if self.match("/"):
+                    res[0] = END_TAG
+                    self.putnsident(res)
+                    yield res
+                    self.expect(">")
+                elif self.match("?"):
+                    res[0] = PI
+                    res[1] = self.getident()
+                    yield res
+                    yield from self.lex_attrs_till(res)
+                    self.expect("?")
+                    self.expect(">")
+                elif self.match("!"):
+                    self.expect("-")
+                    self.expect("-")
+                    last3 = ''
+                    while True:
+                        last3 = last3[-2:] + self.getch()
+                        if last3 == "-->":
+                            break
+                else:
+                    res[0] = START_TAG
+                    self.putnsident(res)
+                    ns = res[1]
+                    tag = res[2]
+                    yield res
+                    yield from self.lex_attrs_till(res)
+                    if self.match("/"):
+                        res[0] = END_TAG
+                        res[1] = ns
+                        res[2] = tag
+                        yield res
+                    self.expect(">")
+            else:
+                text = ""
+                while self.c and self.c != "<":
+                    text += self.getch()
+                if text:
+                    res[0] = TEXT
+                    res[1] = text
+                    res[2] = None
+                    yield res
+
+
+def gfind(gen, pred):
+    for i in gen:
+        if pred(i):
+            return i
+
+def text_of(gen, tag):
+    # Return text content of a leaf tag from tokenizer stream
+    def match_tag(t):
+        if t[0] != START_TAG:
+            return False
+        if isinstance(tag, tuple):
+            return t[1] == tag[0] and t[2] == tag[1]
+        return t[2] == tag
+
+    gfind(gen, match_tag)
+    # Assumes no attributes
+    res = next(gen)
+    assert res[0] == TEXT
+    return res[1]
+
+def tokenize(file):
+    return XMLTokenizer(file).tokenize()
-- 
GitLab