1 /* //device/libs/android_runtime/android_util_XmlBlock.cpp 2 ** 3 ** Copyright 2006, The Android Open Source Project 4 ** 5 ** Licensed under the Apache License, Version 2.0 (the "License"); 6 ** you may not use this file except in compliance with the License. 7 ** You may obtain a copy of the License at 8 ** 9 ** http://www.apache.org/licenses/LICENSE-2.0 10 ** 11 ** Unless required by applicable law or agreed to in writing, software 12 ** distributed under the License is distributed on an "AS IS" BASIS, 13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 ** See the License for the specific language governing permissions and 15 ** limitations under the License. 16 */ 17 18 #define LOG_TAG "XmlBlock" 19 20 #include "jni.h" 21 #include <utils/misc.h> 22 #include <android_runtime/AndroidRuntime.h> 23 #include <utils/AssetManager.h> 24 #include <utils/Log.h> 25 26 #include <utils/ResourceTypes.h> 27 28 #include <stdio.h> 29 30 namespace android { 31 32 // ---------------------------------------------------------------------------- 33 34 static void doThrow(JNIEnv* env, const char* exc, const char* msg = NULL) 35 { 36 jclass npeClazz; 37 38 npeClazz = env->FindClass(exc); 39 LOG_FATAL_IF(npeClazz == NULL, "Unable to find class %s", exc); 40 41 env->ThrowNew(npeClazz, msg); 42 } 43 44 static jint android_content_XmlBlock_nativeCreate(JNIEnv* env, jobject clazz, 45 jbyteArray bArray, 46 jint off, jint len) 47 { 48 if (bArray == NULL) { 49 doThrow(env, "java/lang/NullPointerException"); 50 return 0; 51 } 52 53 jsize bLen = env->GetArrayLength(bArray); 54 if (off < 0 || off >= bLen || len < 0 || len > bLen || (off+len) > bLen) { 55 doThrow(env, "java/lang/IndexOutOfBoundsException"); 56 return 0; 57 } 58 59 jbyte* b = env->GetByteArrayElements(bArray, NULL); 60 ResXMLTree* osb = new ResXMLTree(b+off, len, true); 61 env->ReleaseByteArrayElements(bArray, b, 0); 62 63 if (osb == NULL || osb->getError() != NO_ERROR) { 64 doThrow(env, "java/lang/IllegalArgumentException"); 65 return 0; 66 } 67 68 return (jint)osb; 69 } 70 71 static jint android_content_XmlBlock_nativeGetStringBlock(JNIEnv* env, jobject clazz, 72 jint token) 73 { 74 ResXMLTree* osb = (ResXMLTree*)token; 75 if (osb == NULL) { 76 doThrow(env, "java/lang/NullPointerException"); 77 return 0; 78 } 79 80 return (jint)&osb->getStrings(); 81 } 82 83 static jint android_content_XmlBlock_nativeCreateParseState(JNIEnv* env, jobject clazz, 84 jint token) 85 { 86 ResXMLTree* osb = (ResXMLTree*)token; 87 if (osb == NULL) { 88 doThrow(env, "java/lang/NullPointerException"); 89 return 0; 90 } 91 92 ResXMLParser* st = new ResXMLParser(*osb); 93 if (st == NULL) { 94 doThrow(env, "java/lang/OutOfMemoryError"); 95 return 0; 96 } 97 98 st->restart(); 99 100 return (jint)st; 101 } 102 103 static jint android_content_XmlBlock_nativeNext(JNIEnv* env, jobject clazz, 104 jint token) 105 { 106 ResXMLParser* st = (ResXMLParser*)token; 107 if (st == NULL) { 108 return ResXMLParser::END_DOCUMENT; 109 } 110 111 do { 112 jint code = (jint)st->next(); 113 switch (code) { 114 case ResXMLParser::START_TAG: 115 return 2; 116 case ResXMLParser::END_TAG: 117 return 3; 118 case ResXMLParser::TEXT: 119 return 4; 120 case ResXMLParser::START_DOCUMENT: 121 return 0; 122 case ResXMLParser::END_DOCUMENT: 123 return 1; 124 case ResXMLParser::BAD_DOCUMENT: 125 goto bad; 126 } 127 } while (true); 128 129 bad: 130 doThrow(env, "org/xmlpull/v1/XmlPullParserException", 131 "Corrupt XML binary file"); 132 return ResXMLParser::BAD_DOCUMENT; 133 } 134 135 static jint android_content_XmlBlock_nativeGetNamespace(JNIEnv* env, jobject clazz, 136 jint token) 137 { 138 ResXMLParser* st = (ResXMLParser*)token; 139 if (st == NULL) { 140 return -1; 141 } 142 143 return (jint)st->getElementNamespaceID(); 144 } 145 146 static jint android_content_XmlBlock_nativeGetName(JNIEnv* env, jobject clazz, 147 jint token) 148 { 149 ResXMLParser* st = (ResXMLParser*)token; 150 if (st == NULL) { 151 return -1; 152 } 153 154 return (jint)st->getElementNameID(); 155 } 156 157 static jint android_content_XmlBlock_nativeGetText(JNIEnv* env, jobject clazz, 158 jint token) 159 { 160 ResXMLParser* st = (ResXMLParser*)token; 161 if (st == NULL) { 162 return -1; 163 } 164 165 return (jint)st->getTextID(); 166 } 167 168 static jint android_content_XmlBlock_nativeGetLineNumber(JNIEnv* env, jobject clazz, 169 jint token) 170 { 171 ResXMLParser* st = (ResXMLParser*)token; 172 if (st == NULL) { 173 doThrow(env, "java/lang/NullPointerException"); 174 return 0; 175 } 176 177 return (jint)st->getLineNumber(); 178 } 179 180 static jint android_content_XmlBlock_nativeGetAttributeCount(JNIEnv* env, jobject clazz, 181 jint token) 182 { 183 ResXMLParser* st = (ResXMLParser*)token; 184 if (st == NULL) { 185 doThrow(env, "java/lang/NullPointerException"); 186 return 0; 187 } 188 189 return (jint)st->getAttributeCount(); 190 } 191 192 static jint android_content_XmlBlock_nativeGetAttributeNamespace(JNIEnv* env, jobject clazz, 193 jint token, jint idx) 194 { 195 ResXMLParser* st = (ResXMLParser*)token; 196 if (st == NULL) { 197 doThrow(env, "java/lang/NullPointerException"); 198 return 0; 199 } 200 201 return (jint)st->getAttributeNamespaceID(idx); 202 } 203 204 static jint android_content_XmlBlock_nativeGetAttributeName(JNIEnv* env, jobject clazz, 205 jint token, jint idx) 206 { 207 ResXMLParser* st = (ResXMLParser*)token; 208 if (st == NULL) { 209 doThrow(env, "java/lang/NullPointerException"); 210 return 0; 211 } 212 213 return (jint)st->getAttributeNameID(idx); 214 } 215 216 static jint android_content_XmlBlock_nativeGetAttributeResource(JNIEnv* env, jobject clazz, 217 jint token, jint idx) 218 { 219 ResXMLParser* st = (ResXMLParser*)token; 220 if (st == NULL) { 221 doThrow(env, "java/lang/NullPointerException"); 222 return 0; 223 } 224 225 return (jint)st->getAttributeNameResID(idx); 226 } 227 228 static jint android_content_XmlBlock_nativeGetAttributeDataType(JNIEnv* env, jobject clazz, 229 jint token, jint idx) 230 { 231 ResXMLParser* st = (ResXMLParser*)token; 232 if (st == NULL) { 233 doThrow(env, "java/lang/NullPointerException"); 234 return 0; 235 } 236 237 return (jint)st->getAttributeDataType(idx); 238 } 239 240 static jint android_content_XmlBlock_nativeGetAttributeData(JNIEnv* env, jobject clazz, 241 jint token, jint idx) 242 { 243 ResXMLParser* st = (ResXMLParser*)token; 244 if (st == NULL) { 245 doThrow(env, "java/lang/NullPointerException"); 246 return 0; 247 } 248 249 return (jint)st->getAttributeData(idx); 250 } 251 252 static jint android_content_XmlBlock_nativeGetAttributeStringValue(JNIEnv* env, jobject clazz, 253 jint token, jint idx) 254 { 255 ResXMLParser* st = (ResXMLParser*)token; 256 if (st == NULL) { 257 doThrow(env, "java/lang/NullPointerException"); 258 return 0; 259 } 260 261 return (jint)st->getAttributeValueStringID(idx); 262 } 263 264 static jint android_content_XmlBlock_nativeGetAttributeIndex(JNIEnv* env, jobject clazz, 265 jint token, 266 jstring ns, jstring name) 267 { 268 ResXMLParser* st = (ResXMLParser*)token; 269 if (st == NULL || name == NULL) { 270 doThrow(env, "java/lang/NullPointerException"); 271 return 0; 272 } 273 274 const char16_t* ns16 = NULL; 275 jsize nsLen = 0; 276 if (ns) { 277 ns16 = env->GetStringChars(ns, NULL); 278 nsLen = env->GetStringLength(ns); 279 } 280 281 const char16_t* name16 = env->GetStringChars(name, NULL); 282 jsize nameLen = env->GetStringLength(name); 283 284 jint idx = (jint)st->indexOfAttribute(ns16, nsLen, name16, nameLen); 285 286 if (ns) { 287 env->ReleaseStringChars(ns, ns16); 288 } 289 env->ReleaseStringChars(name, name16); 290 291 return idx; 292 } 293 294 static jint android_content_XmlBlock_nativeGetIdAttribute(JNIEnv* env, jobject clazz, 295 jint token) 296 { 297 ResXMLParser* st = (ResXMLParser*)token; 298 if (st == NULL) { 299 doThrow(env, "java/lang/NullPointerException"); 300 return 0; 301 } 302 303 ssize_t idx = st->indexOfID(); 304 return idx >= 0 ? (jint)st->getAttributeValueStringID(idx) : -1; 305 } 306 307 static jint android_content_XmlBlock_nativeGetClassAttribute(JNIEnv* env, jobject clazz, 308 jint token) 309 { 310 ResXMLParser* st = (ResXMLParser*)token; 311 if (st == NULL) { 312 doThrow(env, "java/lang/NullPointerException"); 313 return 0; 314 } 315 316 ssize_t idx = st->indexOfClass(); 317 return idx >= 0 ? (jint)st->getAttributeValueStringID(idx) : -1; 318 } 319 320 static jint android_content_XmlBlock_nativeGetStyleAttribute(JNIEnv* env, jobject clazz, 321 jint token) 322 { 323 ResXMLParser* st = (ResXMLParser*)token; 324 if (st == NULL) { 325 doThrow(env, "java/lang/NullPointerException"); 326 return 0; 327 } 328 329 ssize_t idx = st->indexOfStyle(); 330 if (idx < 0) { 331 return 0; 332 } 333 334 Res_value value; 335 if (st->getAttributeValue(idx, &value) < 0) { 336 return 0; 337 } 338 339 return value.dataType == value.TYPE_REFERENCE 340 || value.dataType == value.TYPE_ATTRIBUTE 341 ? value.data : 0; 342 } 343 344 static void android_content_XmlBlock_nativeDestroyParseState(JNIEnv* env, jobject clazz, 345 jint token) 346 { 347 ResXMLParser* st = (ResXMLParser*)token; 348 if (st == NULL) { 349 doThrow(env, "java/lang/NullPointerException"); 350 return; 351 } 352 353 delete st; 354 } 355 356 static void android_content_XmlBlock_nativeDestroy(JNIEnv* env, jobject clazz, 357 jint token) 358 { 359 ResXMLTree* osb = (ResXMLTree*)token; 360 if (osb == NULL) { 361 doThrow(env, "java/lang/NullPointerException"); 362 return; 363 } 364 365 delete osb; 366 } 367 368 // ---------------------------------------------------------------------------- 369 370 /* 371 * JNI registration. 372 */ 373 static JNINativeMethod gXmlBlockMethods[] = { 374 /* name, signature, funcPtr */ 375 { "nativeCreate", "([BII)I", 376 (void*) android_content_XmlBlock_nativeCreate }, 377 { "nativeGetStringBlock", "(I)I", 378 (void*) android_content_XmlBlock_nativeGetStringBlock }, 379 { "nativeCreateParseState", "(I)I", 380 (void*) android_content_XmlBlock_nativeCreateParseState }, 381 { "nativeNext", "(I)I", 382 (void*) android_content_XmlBlock_nativeNext }, 383 { "nativeGetNamespace", "(I)I", 384 (void*) android_content_XmlBlock_nativeGetNamespace }, 385 { "nativeGetName", "(I)I", 386 (void*) android_content_XmlBlock_nativeGetName }, 387 { "nativeGetText", "(I)I", 388 (void*) android_content_XmlBlock_nativeGetText }, 389 { "nativeGetLineNumber", "(I)I", 390 (void*) android_content_XmlBlock_nativeGetLineNumber }, 391 { "nativeGetAttributeCount", "(I)I", 392 (void*) android_content_XmlBlock_nativeGetAttributeCount }, 393 { "nativeGetAttributeNamespace","(II)I", 394 (void*) android_content_XmlBlock_nativeGetAttributeNamespace }, 395 { "nativeGetAttributeName", "(II)I", 396 (void*) android_content_XmlBlock_nativeGetAttributeName }, 397 { "nativeGetAttributeResource", "(II)I", 398 (void*) android_content_XmlBlock_nativeGetAttributeResource }, 399 { "nativeGetAttributeDataType", "(II)I", 400 (void*) android_content_XmlBlock_nativeGetAttributeDataType }, 401 { "nativeGetAttributeData", "(II)I", 402 (void*) android_content_XmlBlock_nativeGetAttributeData }, 403 { "nativeGetAttributeStringValue", "(II)I", 404 (void*) android_content_XmlBlock_nativeGetAttributeStringValue }, 405 { "nativeGetAttributeIndex", "(ILjava/lang/String;Ljava/lang/String;)I", 406 (void*) android_content_XmlBlock_nativeGetAttributeIndex }, 407 { "nativeGetIdAttribute", "(I)I", 408 (void*) android_content_XmlBlock_nativeGetIdAttribute }, 409 { "nativeGetClassAttribute", "(I)I", 410 (void*) android_content_XmlBlock_nativeGetClassAttribute }, 411 { "nativeGetStyleAttribute", "(I)I", 412 (void*) android_content_XmlBlock_nativeGetStyleAttribute }, 413 { "nativeDestroyParseState", "(I)V", 414 (void*) android_content_XmlBlock_nativeDestroyParseState }, 415 { "nativeDestroy", "(I)V", 416 (void*) android_content_XmlBlock_nativeDestroy }, 417 }; 418 419 int register_android_content_XmlBlock(JNIEnv* env) 420 { 421 return AndroidRuntime::registerNativeMethods(env, 422 "android/content/res/XmlBlock", gXmlBlockMethods, NELEM(gXmlBlockMethods)); 423 } 424 425 }; // namespace android 426 427