• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.robolectric.shadows;
2 
3 import static org.robolectric.res.android.Errors.NO_ERROR;
4 
5 import android.os.Build.VERSION_CODES;
6 import org.robolectric.annotation.Implementation;
7 import org.robolectric.annotation.Implements;
8 import org.robolectric.res.android.Ref;
9 import org.robolectric.res.android.Registries;
10 import org.robolectric.res.android.ResXMLParser;
11 import org.robolectric.res.android.ResXMLTree;
12 import org.robolectric.res.android.ResourceTypes.Res_value;
13 import org.xmlpull.v1.XmlPullParserException;
14 
15 @Implements(
16     className = "android.content.res.XmlBlock",
17     isInAndroidSdk = false,
18     shadowPicker = ShadowBaseXmlBlock.Picker.class)
19 public class ShadowXmlBlock extends ShadowBaseXmlBlock {
20 
21   @Implementation
nativeCreate(byte[] bArray, int off, int len)22   protected static long nativeCreate(byte[] bArray, int off, int len) {
23     if (bArray == null) {
24       throw new NullPointerException();
25     }
26 
27     int bLen = bArray.length;
28     if (off < 0 || off >= bLen || len < 0 || len > bLen || (off + len) > bLen) {
29       throw new IndexOutOfBoundsException();
30     }
31 
32     // todo: optimize
33     byte[] b = new byte[len];
34     System.arraycopy(bArray, off, b, 0, len);
35 
36     ResXMLTree osb = new ResXMLTree(null);
37     osb.setTo(b, len, true);
38     //    env->ReleaseByteArrayElements(bArray, b, 0);
39 
40     if (osb.getError() != NO_ERROR) {
41       throw new IllegalArgumentException();
42     }
43 
44     return Registries.NATIVE_RES_XML_TREES.register(osb);
45   }
46 
47   @Implementation
nativeGetStringBlock(long obj)48   protected static long nativeGetStringBlock(long obj) {
49     ResXMLTree osb = Registries.NATIVE_RES_XML_TREES.getNativeObject(obj);
50     //    if (osb == NULL) {
51     //      jniThrowNullPointerException(env, NULL);
52     //      return 0;
53     //    }
54 
55     return osb.getStrings().getNativePtr();
56   }
57 
58   @Implementation(maxSdk = VERSION_CODES.P)
nativeCreateParseState(long obj)59   protected static long nativeCreateParseState(long obj) {
60     ResXMLTree osb = Registries.NATIVE_RES_XML_TREES.getNativeObject(obj);
61     //    if (osb == NULL) {
62     //      jniThrowNullPointerException(env, NULL);
63     //      return 0;
64     //    }
65 
66     ResXMLParser st = new ResXMLParser(osb);
67     //    if (st == NULL) {
68     //      jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
69     //      return 0;
70     //    }
71 
72     st.restart();
73 
74     return Registries.NATIVE_RES_XML_PARSERS.register(st);
75   }
76 
77   @Implementation(minSdk = VERSION_CODES.Q)
nativeCreateParseState(long obj, int resid)78   protected static long nativeCreateParseState(long obj, int resid) {
79     ResXMLTree osb = Registries.NATIVE_RES_XML_TREES.getNativeObject(obj);
80     //    if (osb == NULL) {
81     //      jniThrowNullPointerException(env, NULL);
82     //      return 0;
83     //    }
84 
85     ResXMLParser st = new ResXMLParser(osb);
86     //    if (st == NULL) {
87     //      jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
88     //      return 0;
89     //    }
90 
91     st.setSourceResourceId(resid);
92     st.restart();
93 
94     return Registries.NATIVE_RES_XML_PARSERS.register(st);
95   }
96 
97   @Implementation
nativeNext(long state)98   protected static int nativeNext(long state) throws XmlPullParserException {
99     ResXMLParser st = getResXMLParser(state);
100     if (st == null) {
101       return ResXMLParser.event_code_t.END_DOCUMENT;
102     }
103 
104     do {
105       int code = st.next();
106       switch (code) {
107         case ResXMLParser.event_code_t.START_TAG:
108           return 2;
109         case ResXMLParser.event_code_t.END_TAG:
110           return 3;
111         case ResXMLParser.event_code_t.TEXT:
112           return 4;
113         case ResXMLParser.event_code_t.START_DOCUMENT:
114           return 0;
115         case ResXMLParser.event_code_t.END_DOCUMENT:
116           return 1;
117         case ResXMLParser.event_code_t.BAD_DOCUMENT:
118           //                goto bad;
119           throw new XmlPullParserException("Corrupt XML binary file");
120         default:
121           break;
122       }
123 
124     } while (true);
125   }
126 
127   @Implementation
nativeGetNamespace(long state)128   protected static int nativeGetNamespace(long state) {
129     ResXMLParser resXMLParser = getResXMLParser(state);
130     if (resXMLParser == null) {
131       return -1;
132     }
133     return resXMLParser.getElementNamespaceID();
134   }
135 
136   @Implementation
nativeGetName(long state)137   protected static int nativeGetName(long state) {
138     ResXMLParser resXMLParser = getResXMLParser(state);
139     if (resXMLParser == null) {
140       return -1;
141     }
142     return resXMLParser.getElementNameID();
143   }
144 
145   @Implementation
nativeGetText(long state)146   protected static int nativeGetText(long state) {
147     ResXMLParser resXMLParser = getResXMLParser(state);
148     if (resXMLParser == null) {
149       return -1;
150     }
151     return resXMLParser.getTextID();
152   }
153 
154   @Implementation
nativeGetLineNumber(long state)155   protected static int nativeGetLineNumber(long state) {
156     ResXMLParser resXMLParser = getResXMLParser(state);
157     return resXMLParser.getLineNumber();
158   }
159 
160   @Implementation
nativeGetAttributeCount(long state)161   protected static int nativeGetAttributeCount(long state) {
162     ResXMLParser resXMLParser = getResXMLParser(state);
163     return resXMLParser.getAttributeCount();
164   }
165 
166   @Implementation
nativeGetAttributeNamespace(long state, int idx)167   protected static int nativeGetAttributeNamespace(long state, int idx) {
168     ResXMLParser resXMLParser = getResXMLParser(state);
169     return resXMLParser.getAttributeNamespaceID(idx);
170   }
171 
172   @Implementation
nativeGetAttributeName(long state, int idx)173   protected static int nativeGetAttributeName(long state, int idx) {
174     ResXMLParser resXMLParser = getResXMLParser(state);
175     return resXMLParser.getAttributeNameID(idx);
176   }
177 
178   @Implementation
nativeGetAttributeResource(long state, int idx)179   protected static int nativeGetAttributeResource(long state, int idx) {
180     ResXMLParser resXMLParser = getResXMLParser(state);
181     return resXMLParser.getAttributeNameResID(idx);
182   }
183 
184   @Implementation
nativeGetAttributeDataType(long state, int idx)185   protected static int nativeGetAttributeDataType(long state, int idx) {
186     ResXMLParser resXMLParser = getResXMLParser(state);
187     return resXMLParser.getAttributeDataType(idx);
188   }
189 
190   @Implementation
nativeGetAttributeData(long state, int idx)191   protected static int nativeGetAttributeData(long state, int idx) {
192     ResXMLParser resXMLParser = getResXMLParser(state);
193     return resXMLParser.getAttributeData(idx);
194   }
195 
196   @Implementation
nativeGetAttributeStringValue(long state, int idx)197   protected static int nativeGetAttributeStringValue(long state, int idx) {
198     ResXMLParser resXMLParser = getResXMLParser(state);
199     return resXMLParser.getAttributeValueStringID(idx);
200   }
201 
202   @Implementation
nativeGetIdAttribute(long state)203   protected static int nativeGetIdAttribute(long state) {
204     ResXMLParser resXMLParser = getResXMLParser(state);
205     int idx = resXMLParser.indexOfID();
206     return idx >= 0 ? resXMLParser.getAttributeValueStringID(idx) : -1;
207   }
208 
209   @Implementation
nativeGetClassAttribute(long state)210   protected static int nativeGetClassAttribute(long state) {
211     ResXMLParser resXMLParser = getResXMLParser(state);
212     int idx = resXMLParser.indexOfClass();
213     return idx >= 0 ? resXMLParser.getAttributeValueStringID(idx) : -1;
214   }
215 
216   @Implementation
nativeGetStyleAttribute(long state)217   protected static int nativeGetStyleAttribute(long state) {
218     ResXMLParser resXMLParser = getResXMLParser(state);
219     int idx = resXMLParser.indexOfStyle();
220     if (idx < 0) {
221       return 0;
222     }
223 
224     final Ref<Res_value> valueRef = new Ref<>(new Res_value());
225     if (resXMLParser.getAttributeValue(idx, valueRef) < 0) {
226       return 0;
227     }
228     Res_value value = valueRef.get();
229 
230     return value.dataType == org.robolectric.res.android.ResourceTypes.Res_value.TYPE_REFERENCE
231             || value.dataType == org.robolectric.res.android.ResourceTypes.Res_value.TYPE_ATTRIBUTE
232         ? value.data
233         : 0;
234   }
235 
236   @Implementation
nativeGetAttributeIndex(long token, String ns, String name)237   protected static int nativeGetAttributeIndex(long token, String ns, String name) {
238     ResXMLParser st = getResXMLParser(token);
239     if (st == null || name == null) {
240       throw new NullPointerException();
241     }
242 
243     int nsLen = 0;
244     if (ns != null) {
245       nsLen = ns.length();
246     }
247 
248     return st.indexOfAttribute(ns, nsLen, name, name.length());
249   }
250 
251   @Implementation(minSdk = VERSION_CODES.Q)
nativeGetSourceResId(long state)252   protected static int nativeGetSourceResId(long state) {
253     ResXMLParser st = getResXMLParser(state);
254     if (st == null) {
255       return 0;
256     } else {
257       return st.getSourceResourceId();
258     }
259   }
260 
261   @Implementation
nativeDestroyParseState(long state)262   protected static void nativeDestroyParseState(long state) {
263     Registries.NATIVE_RES_XML_PARSERS.unregister(state);
264   }
265 
266   @Implementation
nativeDestroy(long obj)267   protected static void nativeDestroy(long obj) {
268     Registries.NATIVE_RES_XML_TREES.unregister(obj);
269   }
270 
getResXMLParser(long state)271   private static ResXMLParser getResXMLParser(long state) {
272     return Registries.NATIVE_RES_XML_PARSERS.peekNativeObject(state);
273   }
274 
275   /** Shadow of XmlBlock.Parser. */
276   @Implements(className = "android.content.res.XmlBlock$Parser", isInAndroidSdk = false)
277   public static class ShadowParser {
278     private int sourceResourceId;
279 
setSourceResourceId(int sourceResourceId)280     void setSourceResourceId(int sourceResourceId) {
281       this.sourceResourceId = sourceResourceId;
282     }
283 
getSourceResourceId()284     int getSourceResourceId() {
285       return sourceResourceId;
286     }
287   }
288 }
289