• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.android.hotspot2.omadm;
2 
3 import org.xml.sax.SAXException;
4 
5 import java.io.IOException;
6 import java.io.InputStream;
7 import java.io.OutputStream;
8 import java.nio.charset.StandardCharsets;
9 import java.util.ArrayList;
10 import java.util.HashMap;
11 import java.util.Iterator;
12 import java.util.List;
13 import java.util.Map;
14 
15 public class MOTree {
16     public static final String MgmtTreeTag = "MgmtTree";
17 
18     public static final String NodeTag = "Node";
19     public static final String NodeNameTag = "NodeName";
20     public static final String PathTag = "Path";
21     public static final String ValueTag = "Value";
22     public static final String RTPropTag = "RTProperties";
23     public static final String TypeTag = "Type";
24     public static final String DDFNameTag = "DDFName";
25 
26     private final String mUrn;
27     private final String mDtdRev;
28     private final OMAConstructed mRoot;
29 
MOTree(XMLNode node, String urn)30     public MOTree(XMLNode node, String urn) throws IOException, SAXException {
31         Iterator<XMLNode> children = node.getChildren().iterator();
32 
33         String dtdRev = null;
34 
35         while (children.hasNext()) {
36             XMLNode child = children.next();
37             if (child.getTag().equals(OMAConstants.SyncMLVersionTag)) {
38                 dtdRev = child.getText();
39                 children.remove();
40                 break;
41             }
42         }
43 
44         mUrn = urn;
45         mDtdRev = dtdRev;
46 
47         mRoot = new MgmtTreeRoot(node, dtdRev);
48 
49         for (XMLNode child : node.getChildren()) {
50             buildNode(mRoot, child);
51         }
52     }
53 
MOTree(String urn, String rev, OMAConstructed root)54     public MOTree(String urn, String rev, OMAConstructed root) throws IOException {
55         mUrn = urn;
56         mDtdRev = rev;
57         mRoot = root;
58     }
59 
buildMgmtTree(String urn, String rev, OMAConstructed root)60     public static MOTree buildMgmtTree(String urn, String rev, OMAConstructed root)
61             throws IOException {
62         OMAConstructed realRoot;
63         switch (urn) {
64             case OMAConstants.PPS_URN:
65             case OMAConstants.DevInfoURN:
66             case OMAConstants.DevDetailURN:
67             case OMAConstants.DevDetailXURN:
68                 realRoot = new MgmtTreeRoot(OMAConstants.OMAVersion);
69                 realRoot.addChild(root);
70                 return new MOTree(urn, rev, realRoot);
71             default:
72                 return new MOTree(urn, rev, root);
73         }
74     }
75 
hasMgmtTreeTag(String text)76     public static boolean hasMgmtTreeTag(String text) {
77         for (int n = 0; n < text.length(); n++) {
78             char ch = text.charAt(n);
79             if (ch > ' ') {
80                 return text.regionMatches(true, n, '<' + MgmtTreeTag + '>',
81                         0, MgmtTreeTag.length() + 2);
82             }
83         }
84         return false;
85     }
86 
87     private static class NodeData {
88         private final String mName;
89         private String mPath;
90         private String mValue;
91 
NodeData(String name)92         private NodeData(String name) {
93             mName = name;
94         }
95 
setPath(String path)96         private void setPath(String path) {
97             mPath = path;
98         }
99 
setValue(String value)100         private void setValue(String value) {
101             mValue = value;
102         }
103 
getName()104         public String getName() {
105             return mName;
106         }
107 
getPath()108         public String getPath() {
109             return mPath;
110         }
111 
getValue()112         public String getValue() {
113             return mValue;
114         }
115     }
116 
buildNode(OMANode parent, XMLNode node)117     private static void buildNode(OMANode parent, XMLNode node) throws IOException {
118         if (!node.getTag().equals(NodeTag))
119             throw new IOException("Node is a '" + node.getTag() + "' instead of a 'Node'");
120 
121         Map<String, XMLNode> checkMap = new HashMap<>(3);
122         String context = null;
123         List<NodeData> values = new ArrayList<>();
124         List<XMLNode> children = new ArrayList<>();
125 
126         NodeData curValue = null;
127 
128         for (XMLNode child : node.getChildren()) {
129             XMLNode old = checkMap.put(child.getTag(), child);
130 
131             switch (child.getTag()) {
132                 case NodeNameTag:
133                     if (curValue != null)
134                         throw new IOException(NodeNameTag + " not expected");
135                     curValue = new NodeData(child.getText());
136 
137                     break;
138                 case PathTag:
139                     if (curValue == null || curValue.getPath() != null)
140                         throw new IOException(PathTag + " not expected");
141                     curValue.setPath(child.getText());
142 
143                     break;
144                 case ValueTag:
145                     if (!children.isEmpty())
146                         throw new IOException(ValueTag + " in constructed node");
147                     if (curValue == null || curValue.getValue() != null)
148                         throw new IOException(ValueTag + " not expected");
149                     curValue.setValue(child.getText());
150                     values.add(curValue);
151                     curValue = null;
152 
153                     break;
154                 case RTPropTag:
155                     if (old != null)
156                         throw new IOException("Duplicate " + RTPropTag);
157                     XMLNode typeNode = getNextNode(child, TypeTag);
158                     XMLNode ddfName = getNextNode(typeNode, DDFNameTag);
159                     context = ddfName.getText();
160                     if (context == null)
161                         throw new IOException("No text in " + DDFNameTag);
162 
163                     break;
164                 case NodeTag:
165                     if (!values.isEmpty())
166                         throw new IOException("Scalar node " + node.getText() + " has Node child");
167                     children.add(child);
168 
169                     break;
170             }
171         }
172 
173         if (values.isEmpty()) {
174             if (curValue == null)
175                 throw new IOException("Missing name");
176 
177             OMANode subNode = parent.addChild(curValue.getName(),
178                     context, null, curValue.getPath());
179 
180             for (XMLNode child : children) {
181                 buildNode(subNode, child);
182             }
183         } else {
184             if (!children.isEmpty())
185                 throw new IOException("Got both sub nodes and value(s)");
186 
187             for (NodeData nodeData : values) {
188                 parent.addChild(nodeData.getName(), context,
189                         nodeData.getValue(), nodeData.getPath());
190             }
191         }
192     }
193 
getNextNode(XMLNode node, String tag)194     private static XMLNode getNextNode(XMLNode node, String tag) throws IOException {
195         if (node == null)
196             throw new IOException("No node for " + tag);
197         if (node.getChildren().size() != 1)
198             throw new IOException("Expected " + node.getTag() + " to have exactly one child");
199         XMLNode child = node.getChildren().iterator().next();
200         if (!child.getTag().equals(tag))
201             throw new IOException("Expected " + node.getTag() + " to have child '" + tag +
202                     "' instead of '" + child.getTag() + "'");
203         return child;
204     }
205 
getUrn()206     public String getUrn() {
207         return mUrn;
208     }
209 
getDtdRev()210     public String getDtdRev() {
211         return mDtdRev;
212     }
213 
getRoot()214     public OMAConstructed getRoot() {
215         return mRoot;
216     }
217 
218     @Override
toString()219     public String toString() {
220         StringBuilder sb = new StringBuilder();
221         sb.append("MO Tree v").append(mDtdRev).append(", urn ").append(mUrn).append(")\n");
222         sb.append(mRoot);
223 
224         return sb.toString();
225     }
226 
marshal(OutputStream out)227     public void marshal(OutputStream out) throws IOException {
228         out.write("tree ".getBytes(StandardCharsets.UTF_8));
229         OMAConstants.serializeString(mDtdRev, out);
230         out.write(String.format("(%s)\n", mUrn).getBytes(StandardCharsets.UTF_8));
231         mRoot.marshal(out, 0);
232     }
233 
unmarshal(InputStream in)234     public static MOTree unmarshal(InputStream in) throws IOException {
235         boolean strip = true;
236         StringBuilder tree = new StringBuilder();
237         for (; ; ) {
238             int octet = in.read();
239             if (octet < 0) {
240                 return null;
241             } else if (octet > ' ') {
242                 tree.append((char) octet);
243                 strip = false;
244             } else if (!strip) {
245                 break;
246             }
247         }
248         if (!tree.toString().equals("tree")) {
249             throw new IOException("Not a tree: " + tree);
250         }
251 
252         String version = OMAConstants.deserializeString(in);
253         int next = in.read();
254         if (next != '(') {
255             throw new IOException("Expected URN in tree definition");
256         }
257         String urn = OMAConstants.readURN(in);
258 
259         OMAConstructed root = OMANode.unmarshal(in);
260 
261         return new MOTree(urn, version, root);
262     }
263 
toXml()264     public String toXml() {
265         StringBuilder sb = new StringBuilder();
266         mRoot.toXml(sb);
267         return sb.toString();
268     }
269 }
270