├── .gitignore ├── build.gradle ├── doc ├── about.html ├── development.html ├── documentation.html ├── license.html └── samples.html ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── jitpack.yml ├── license.txt ├── readme.md ├── samples ├── EventList.java ├── KDomRoundtrip.java ├── LongStringTest.java ├── Roundtrip.java ├── WbxmlRoundtrip.java ├── Weblogs.java ├── YesNoGame.java ├── bogdan.xml ├── sample.xml └── simple.xml ├── samples_midp └── Newsreader.java ├── settings.gradle └── src ├── main ├── java │ ├── module-info.java │ └── org │ │ └── kxml2 │ │ ├── io │ │ ├── KXmlParser.java │ │ └── KXmlSerializer.java │ │ ├── kdom │ │ ├── Document.java │ │ ├── Element.java │ │ └── Node.java │ │ └── wap │ │ ├── Wbxml.java │ │ ├── WbxmlParser.java │ │ ├── WbxmlSerializer.java │ │ ├── syncml │ │ └── SyncML.java │ │ ├── wml │ │ └── Wml.java │ │ └── wv │ │ └── WV.java └── resources │ └── META-INF │ └── services │ └── org.xmlpull.v1.XmlPullParserFactory └── test └── java └── TestWb.java /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | .gradle/ 3 | .idea/ 4 | target/ 5 | out/ 6 | .project 7 | .classpath 8 | /bootstrap.xml 9 | /font-awesome.xml 10 | *.*~ 11 | *.iml 12 | **/*.iml 13 | *.ipl 14 | **/*.ipl 15 | *.iwl 16 | **/*.iwl 17 | /logs 18 | *.log 19 | config.properties 20 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | apply plugin: 'maven' 3 | 4 | group = 'com.github.stefanhaustein' 5 | version = '2.5.0' 6 | 7 | java { 8 | modularity.inferModulePath.set(true) 9 | sourceCompatibility = JavaVersion.VERSION_1_9 10 | targetCompatibility = JavaVersion.VERSION_1_9 11 | } 12 | 13 | // This is in case we ever use non-ASCII chars in sources 14 | compileJava.options.encoding = 'UTF-8' 15 | compileTestJava.options.encoding = 'UTF-8' 16 | 17 | repositories { 18 | mavenLocal() 19 | maven { 20 | url "https://dl.bintray.com/unverbraucht/java9-fixed-jars" 21 | } 22 | } 23 | 24 | dependencies { 25 | implementation(group: 'org.xmlpull', name: 'xmlpull', version: '1.1.4.0') 26 | testImplementation(group: 'junit', name: 'junit', version: '4.12') 27 | } 28 | 29 | task sourcesJar(type: Jar, dependsOn: classes) { 30 | classifier 'sources' 31 | from sourceSets.main.allSource 32 | } 33 | 34 | artifacts { 35 | archives sourcesJar 36 | } 37 | -------------------------------------------------------------------------------- /doc/about.html: -------------------------------------------------------------------------------- 1 | 2 | About kXML 3 | 4 | 5 | 6 | 7 | 8 |

About kXML

9 | 10 |

kXML is a small XML pull parser, specially designed for constrained environments such as Applets, Personal Java or MIDP devices. In contrast to kXML 1, kXML 2 is based on the common 11 | XML pull API.

12 | 13 | 14 |

Pull based XML parsing combines some of the advantages of SAX and DOM:

15 | 16 | 30 | 31 | 32 |

kXML History and Versions

33 | 34 | 35 | 36 | 37 | 41 | 42 | 43 | 44 | 49 | 50 | 51 | 52 | 55 | 56 |
XPXP was the predecessor of kXML, a simple wrapper that turned a given SAX parser 38 | into a pull parser. 39 | XP was originally implemented to simplify message (de)serialization in the Infolayer project, 40 | which is quite cumbersome with push parsers (SAX). XP was initially released at 1999-12-25.
kXML1To use the pull parser on embedded devices, it was necessary to get 45 | rid of the SAX dependency. kXML1 is a simple pull parser, based on event objects. 46 | kXML1 is now deprecated, please use kXML2 instead. kXML1 is archieved at 47 | kxml.objectweb.org. The initial public release 48 | of kXML 1 was at 2000-07-25.
kXML2The current version of kXML. In contrast to kXML1, it features cursor 53 | API instead of event objects, leading to a reduced footprint and less object 54 | creation overhead. kXML 2 is released under the BSD license.
57 | 58 | 59 | 60 | 61 | 62 |

XML Conformance

63 | 64 |

In order to keep kXML as small as possible, no efforts are made to recognize certain well-formedness errors that would require additional detection code, such as

65 | 66 | 71 | 72 |

Thus, kXML will accept some XML documents that should actually be rejected. Of course, an XML parser should detect all syntax errors to discourage the creation of bogous documents that work with one parser and do not work with another. Thus, if you are not limited by memory constraints, please use MXP, which is also faster than kXML.

73 | 74 |

75 | (C) 1999-2005 Stefan Haustein 76 |

77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /doc/development.html: -------------------------------------------------------------------------------- 1 | 2 |

kXML Development

3 | 4 |

The development resources of the kXML project (mailing list, CVS repository, files) are hosted at 5 | sourceforge.net:

6 | 7 | 10 | 11 |

If you experience any bugs or incompatibilities, please try the 12 | latest version from CVS before filing a bug report -- a fix may be 13 | available there already.

14 | 15 | 16 | -------------------------------------------------------------------------------- /doc/documentation.html: -------------------------------------------------------------------------------- 1 |

kXML 2 Documentation

2 | 3 | 4 |

kXML 2 implements the XmlPull API. Please find general information about 5 | XmlPull parsers including the interface documentation at 6 | xmlpull.org.

7 | 8 |

Naveen Balani has written a nice 10 | introduction to kxml 2 for IBM Developer Works.

11 | 12 |

For kXML specific classes, in particular for WBXML, please refer 13 | to the kXML API Documentation:

14 | 17 | 18 | 19 |

Special Features

20 | 21 |

kXML has two "special" features that are intended to simplify developers' life in constrained environments:

22 | 23 | 28 | 29 | 30 |

Recommended Calling Conventions

31 | 32 | When handing an XMLpull parser to subroutines, it is recommended that the current 33 | position is on a start tag (allowing the subroutine to analyze the attributes). 34 | The post condition should usually be that the current position is the matching end tag. 35 | 36 | 37 |

Parsing Element-Only and Text-Only Content

38 | 39 |

General XML content can be parsed with the XML pull API using a loop advanving 40 | to the next event and a switch statement that depends on the event type. However, 41 | when using XML for data transfer (in contrast to text documents), most XML elements 42 | contain either only text or only other elements (possibly with further sub-elements). 43 | For those common cases, the parsing process can be simplified significantly by 44 | using the XmlPull API methods nextTag and nextText. 45 | 46 | Additionally, the method require() may optionally be used to assert a 47 | certain parser state. The following sample illustrates both situations and methods. 48 | The outer element elements has element-only content; the contained 49 | text-elements have text-only content:

50 | 51 |
 52 | <elements>
 53 |   <text>text1</text>
 54 |   <text>text2</text>
 55 | </elements>  
 56 | 
57 | 58 |

Parsing Code

59 |
 60 | parser.nextTag();
 61 | parser.require(XmlPullParser.START_TAG, null, "elements");
 62 | 
 63 | while(parser.nextTag() == XmlPullParser.START_TAG) {
 64 |   parser.require(XmlPullParser.START_TAG, null, "text");
 65 | 
 66 |    // handle element content
 67 |    System.out.println("text content: "+ parser.nextText());
 68 | 
 69 |   parser.require(XmlPullParser.END_TAG, null, "text");
 70 | }
 71 | 
 72 | parser.require(XmlPullParser.END_TAG, null, "elements");
 73 | 
74 | 75 |

nextTag() advances to the next 76 | start or end tag, skipping insignificant events such as white space, 77 | comments and PIs. nextText() requires that the current position 78 | is a start tag. It returns the text content of the corresponding element. 79 | The post condition is that the current position is an end tag. 80 | Please note that the calls require() are optional assertions, 81 | they may be left out completely.

82 | 83 | 84 |

Articles about kXML 1 and 2

85 | 86 | 87 | 88 | 89 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 101 | 102 | 103 | 104 | 106 | 107 | 108 |
2003-09-01New article about 90 | kXML 2 written by Naveen Balani published at IBM Developer Works
2003-04-04New article about kXML 1 written by Robert Cadenaat published at DevX
2002-03-25New article about kXML and WBXML comprssion 100 | written by Eric Giguere available at the SUN developer connection
2002-03-07New artikle about kXML 1 105 | written by Jonathan Knudsen available at the SUN developer connection
109 | -------------------------------------------------------------------------------- /doc/license.html: -------------------------------------------------------------------------------- 1 |

kXML License

2 | 3 |

kXML is licensed under the BSD license (see below). Please note that 4 | the BSD license mandates to keep the copyright note when including 5 | kXML in own projects. If you are using kXML in your own project 6 | (open source or not), please let us know, so we can link it at our 7 | samples page.

8 | 9 |
10 | Copyright (c) 2002-2007 Stefan Haustein, Oberhausen, Rhld., Germany
11 | 
12 | Permission is hereby granted, free of charge, to any person obtaining a copy
13 | of this software and associated documentation files (the "Software"), to deal
14 | in the Software without restriction, including without limitation the rights
15 | to use, copy, modify, merge, publish, distribute, sublicense, and/or
16 | sell copies of the Software, and to permit persons to whom the Software is
17 | furnished to do so, subject to the following conditions:
18 | 
19 | The  above copyright notice and this permission notice shall be included in
20 | all copies or substantial portions of the Software.
21 | 
22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
28 | IN THE SOFTWARE. 
29 | 
-------------------------------------------------------------------------------- /doc/samples.html: -------------------------------------------------------------------------------- 1 | 2 |

kXML Samples

3 | 4 |

Some small code snippets illustrating basic parsing operations can be examined via 5 | viewcvs:

6 | 9 | 10 |

There are also some nice open source projects built on kXML that illustrate how to use the parser:

11 | 15 | 16 |

If you are using kXML in your own project 17 | (open source or not), please let us know, so we can link to it here.

18 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kobjects/kxml2/8ab596248a9c70c8cafe286efb013642cc821d11/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /jitpack.yml: -------------------------------------------------------------------------------- 1 | jdk: 2 | - openjdk9 3 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2002,2003, Stefan Haustein, Oberhausen, Rhld., Germany 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | sell copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | IN THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # README 2 | - Interested in Kotlin? Try [KtXml](https://github.com/kobjects/ktxml) and provide feedback! 3 | - Now the content of `org.xmlpull.v1.XmlPullParserFactory` is split across multiple lines `org.kxml2.io.KXmlParser` & `org.kxml2.io.KXmlSerializer` instead of comma separated `org.kxml2.io.KXmlParser,org.kxml2.io.KXmlSerializer` which bombs in Java 9+. This fix will ensure java 9 module system will atleast no complain. Even with this fix, implementation of `XmlPullParserFactory` in `xmlpull` is still nothing but abuse of `ServiceLoader` implementation. But atleast it does not bomb right now 4 | - Library can be added as a dependency using 5 | 6 | ```groovy 7 | repositories { 8 | mavenCentral() 9 | maven { 10 | url "https://jitpack.io" // maven repo where the current library resides 11 | } 12 | maven { 13 | url "https://dl.bintray.com/unverbraucht/java9-fixed-jars" // repo for fetching `xmlpull` dependency that's java 9 enabled 14 | } 15 | } 16 | 17 | dependencies { 18 | implementation("com.github.kobjects:kxml2:") 19 | } 20 | ``` 21 | -------------------------------------------------------------------------------- /samples/EventList.java: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | 3 | import org.kxml2.io.*; 4 | import org.xmlpull.v1.*; 5 | 6 | public class EventList { 7 | 8 | public static void main(String[] args) 9 | throws IOException, XmlPullParserException { 10 | 11 | for (int i = 0; i < 2; i++) { 12 | 13 | XmlPullParser xr = new KXmlParser(); 14 | xr.setInput(new FileReader(args[0])); 15 | 16 | System.out.println(""); 17 | System.out.println( 18 | "*** next" + (i == 0 ? "Token" : "") + " () event list ***"); 19 | System.out.println(""); 20 | 21 | do { 22 | if (i == 0) 23 | xr.nextToken(); 24 | else 25 | xr.next(); 26 | 27 | System.out.println(xr.getPositionDescription()); 28 | 29 | 30 | } while (xr.getEventType() != XmlPullParser.END_DOCUMENT); 31 | } 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /samples/KDomRoundtrip.java: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | 3 | import org.xmlpull.v1.*; 4 | import org.kxml2.kdom.*; 5 | import org.kxml2.io.*; 6 | 7 | 8 | /** 9 | * @author Stefan Haustein 10 | * 11 | * To change this generated comment edit the template variable "typecomment": 12 | * Window>Preferences>Java>Templates. 13 | */ 14 | 15 | public class KDomRoundtrip { 16 | 17 | /** 18 | * Constructor for KDomRoundtrip. 19 | */ 20 | 21 | 22 | public static void main(String[] args) throws IOException, XmlPullParserException { 23 | if (args.length == 0) throw new RuntimeException ("input url expected"); 24 | for (int i = 0; i < args.length; i++) { 25 | System.out.println ("generating KDom from "+args[i]); 26 | 27 | KXmlParser parser = new KXmlParser (); 28 | parser.setInput (new FileReader (args [i])); 29 | parser.setFeature (XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); 30 | 31 | Document doc = new Document (); 32 | doc.parse (parser); 33 | 34 | KXmlSerializer serializer = new KXmlSerializer (); 35 | serializer.setOutput (System.out, null); 36 | 37 | doc.write (serializer); 38 | serializer.flush (); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /samples/LongStringTest.java: -------------------------------------------------------------------------------- 1 | 2 | import org.xmlpull.v1.XmlPullParser; 3 | import org.kxml2.io.KXmlParser; 4 | import java.io.ByteArrayInputStream; 5 | import java.io.InputStreamReader; 6 | 7 | // (C) Michael Walker, sun.com 8 | 9 | public class LongStringTest { 10 | 11 | 12 | public static void main(String[] args) { 13 | String xmlStr = "" 14 | + "" 15 | + "" 16 | + "" 17 | + "" 18 | + "" 19 | + "" 20 | + ""; 21 | System.out.println("xmlStr length: " + xmlStr.length()); 22 | 23 | ByteArrayInputStream bais = new ByteArrayInputStream(xmlStr.getBytes()); 24 | InputStreamReader isr = new InputStreamReader(bais); 25 | 26 | try { 27 | KXmlParser parser = new KXmlParser(); 28 | parser.setInput(isr); 29 | while (parser.next() != XmlPullParser.END_DOCUMENT) { 30 | if (parser.getEventType() == XmlPullParser.START_TAG) { 31 | System.out.println("start tag: " + parser.getName()); 32 | } 33 | } 34 | } catch (Exception ex) { 35 | ex.printStackTrace(); 36 | } 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /samples/Roundtrip.java: -------------------------------------------------------------------------------- 1 | 2 | //package org.xmlpull.v1.samples; 3 | 4 | import java.io.*; 5 | 6 | import org.kxml2.io.*; 7 | import org.xmlpull.v1.*; 8 | public class Roundtrip { 9 | //private static final String FEATURE_XML_ROUNDTRIP= 10 | // "http://xmlpull.org/v1/doc/features.html#xml-roundtrip"; 11 | 12 | XmlPullParser parser; 13 | XmlSerializer serializer; 14 | 15 | public Roundtrip( 16 | XmlPullParser parser, 17 | XmlSerializer serializer) { 18 | this.parser = parser; 19 | this.serializer = serializer; 20 | } 21 | 22 | public void writeStartTag() 23 | throws XmlPullParserException, IOException { 24 | //check forcase when feature xml roundtrip is supported 25 | //if (parser.getFeature (FEATURE_XML_ROUNDTRIP)) { 26 | //TODO: how to do pass through string with actual start tag in getText() 27 | //return; 28 | //} 29 | if (!parser 30 | .getFeature( 31 | XmlPullParser 32 | .FEATURE_REPORT_NAMESPACE_ATTRIBUTES)) { 33 | for (int i = 34 | parser.getNamespaceCount(parser.getDepth() - 1); 35 | i 36 | < parser.getNamespaceCount(parser.getDepth()) 37 | - 1; 38 | i++) { 39 | serializer.setPrefix( 40 | parser.getNamespacePrefix(i), 41 | parser.getNamespaceUri(i)); 42 | } 43 | } 44 | serializer.startTag( 45 | parser.getNamespace(), 46 | parser.getName()); 47 | 48 | for (int i = 0; i < parser.getAttributeCount(); i++) { 49 | serializer.attribute( 50 | parser.getAttributeNamespace(i), 51 | parser.getAttributeName(i), 52 | parser.getAttributeValue(i)); 53 | } 54 | //serializer.closeStartTag(); 55 | } 56 | 57 | public void writeToken() 58 | throws XmlPullParserException, IOException { 59 | switch (parser.getEventType()) { 60 | case XmlPullParser.START_DOCUMENT : 61 | serializer.startDocument (null, null); 62 | break; 63 | 64 | case XmlPullParser.END_DOCUMENT : 65 | serializer.endDocument(); 66 | break; 67 | 68 | case XmlPullParser.START_TAG : 69 | writeStartTag(); 70 | break; 71 | 72 | case XmlPullParser.END_TAG : 73 | serializer.endTag( 74 | parser.getNamespace(), 75 | parser.getName()); 76 | break; 77 | 78 | case XmlPullParser.IGNORABLE_WHITESPACE : 79 | //comment it to remove ignorable whtespaces from XML infoset 80 | serializer.ignorableWhitespace(parser.getText()); 81 | break; 82 | 83 | case XmlPullParser.TEXT : 84 | if(parser.getText() == null) 85 | System.err.println("null text error at: "+parser.getPositionDescription()); 86 | else 87 | serializer.text(parser.getText()); 88 | break; 89 | 90 | case XmlPullParser.ENTITY_REF : 91 | if(parser.getText() != null) 92 | serializer.text(parser.getText()); 93 | else 94 | serializer.entityRef(parser.getName()); 95 | break; 96 | 97 | case XmlPullParser.CDSECT : 98 | serializer.cdsect(parser.getText()); 99 | break; 100 | 101 | case XmlPullParser.PROCESSING_INSTRUCTION : 102 | serializer.processingInstruction( 103 | parser.getText()); 104 | break; 105 | 106 | case XmlPullParser.COMMENT : 107 | serializer.comment(parser.getText()); 108 | break; 109 | 110 | case XmlPullParser.DOCDECL : 111 | serializer.docdecl(parser.getText()); 112 | break; 113 | 114 | default : 115 | throw new RuntimeException( 116 | "unrecognized event: " 117 | + parser.getEventType()); 118 | } 119 | } 120 | 121 | public void roundTrip() 122 | throws XmlPullParserException, IOException { 123 | 124 | while (parser.getEventType() != XmlPullParser.END_DOCUMENT) { 125 | writeToken(); 126 | parser.nextToken(); 127 | } 128 | writeToken(); 129 | serializer.flush(); 130 | } 131 | 132 | public static void main(String[] args) throws Exception { 133 | if (args.length == 0) 134 | throw new RuntimeException("input xml file name expected"); 135 | for (int i = 0; i < args.length; i++) { 136 | System.out.println("processing: " + args[i]); 137 | XmlPullParser pp = new KXmlParser(); 138 | pp.setFeature( 139 | XmlPullParser.FEATURE_PROCESS_NAMESPACES, 140 | true); 141 | XmlSerializer serializer = new KXmlSerializer(); 142 | 143 | pp.setInput(new FileReader(args[i])); 144 | serializer.setOutput(System.out, null); 145 | 146 | (new Roundtrip(pp, serializer)).roundTrip(); 147 | serializer.flush(); 148 | } 149 | } 150 | 151 | } -------------------------------------------------------------------------------- /samples/WbxmlRoundtrip.java: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | 3 | import org.kxml2.io.*; 4 | import org.kxml2.wap.*; 5 | import org.xmlpull.v1.*; 6 | 7 | /* 8 | * Created on 25.09.2003 9 | * 10 | * To change the template for this generated file go to 11 | * Window>Preferences>Java>Code Generation>Code and Comments 12 | */ 13 | 14 | /** 15 | * @author haustein 16 | * 17 | * To change the template for this generated type comment go to 18 | * Window>Preferences>Java>Code Generation>Code and Comments 19 | */ 20 | public class WbxmlRoundtrip { 21 | 22 | public static void main(String[] argv) throws Exception { 23 | 24 | ByteArrayOutputStream bos = new ByteArrayOutputStream(); 25 | 26 | XmlPullParser xp = new KXmlParser(); 27 | xp.setInput(new FileInputStream(argv[0]), null); 28 | XmlSerializer xs = new WbxmlSerializer(); 29 | xs.setOutput(bos, null); 30 | 31 | new Roundtrip(xp, xs).roundTrip(); 32 | 33 | byte[] wbxml = bos.toByteArray(); 34 | 35 | System.out.println("********* WBXML size: "+wbxml.length+" ***********"); 36 | 37 | for(int i = 0; i < wbxml.length; i += 16){ 38 | for (int j = i; j < Math.min(i + 16, wbxml.length); j ++) { 39 | int b = ((int) wbxml[j]) & 0x0ff; 40 | System.out.print(Integer.toHexString(b / 16)); 41 | System.out.print(Integer.toHexString(b % 16)); 42 | System.out.print(' '); 43 | } 44 | 45 | for (int j = i; j < Math.min(i + 16, wbxml.length); j ++) { 46 | int b = wbxml[j]; 47 | System.out.print(b >= 32 && b <= 127 ? (char) b : '?'); 48 | } 49 | 50 | System.out.println(); 51 | } 52 | 53 | ByteArrayInputStream bis = new ByteArrayInputStream(wbxml); 54 | 55 | xp = new WbxmlParser(); 56 | xp.setInput(bis, null); 57 | 58 | xs = new KXmlSerializer(); 59 | xs.setOutput(System.out, null); 60 | 61 | new Roundtrip(xp, xs).roundTrip(); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /samples/Weblogs.java: -------------------------------------------------------------------------------- 1 | import org.xmlpull.v1.*; 2 | 3 | import java.util.*; 4 | import java.io.*; 5 | import java.net.*; 6 | 7 | /** 8 | * A simple example illustrationg some differences of the XmlPull API 9 | * and SAX. For the corresponding SAX based implementation, please refer to 10 | * http://www.cafeconleche.org/slides/sd2001east/xmlandjava/81.html ff. */ 11 | 12 | public class Weblogs { 13 | 14 | static List listChannels() 15 | throws IOException, XmlPullParserException { 16 | return listChannels("http://static.userland.com/weblogMonitor/logs.xml"); 17 | } 18 | 19 | static List listChannels(String uri) 20 | throws IOException, XmlPullParserException { 21 | 22 | Vector result = new Vector(); 23 | 24 | InputStream is = new URL(uri).openStream(); 25 | XmlPullParser parser = 26 | XmlPullParserFactory.newInstance().newPullParser(); 27 | 28 | parser.setInput(is, null); 29 | 30 | parser.nextTag(); 31 | parser.require(XmlPullParser.START_TAG, "", "weblogs"); 32 | 33 | while (parser.nextTag() == XmlPullParser.START_TAG) { 34 | String url = readSingle(parser); 35 | if (url != null) 36 | result.addElement(url); 37 | } 38 | parser.require(XmlPullParser.END_TAG, "", "weblogs"); 39 | 40 | parser.next(); 41 | parser.require(XmlPullParser.END_DOCUMENT, null, null); 42 | 43 | is.close (); 44 | parser.setInput (null); 45 | 46 | return result; 47 | } 48 | 49 | public static String readSingle(XmlPullParser parser) 50 | throws IOException, XmlPullParserException { 51 | 52 | String url = null; 53 | parser.require(XmlPullParser.START_TAG, "", "log"); 54 | 55 | while (parser.nextTag() == XmlPullParser.START_TAG) { 56 | String name = parser.getName(); 57 | String content = parser.nextText(); 58 | if (name.equals("url")) 59 | url = content; 60 | parser.require(XmlPullParser.END_TAG, "", name); 61 | } 62 | parser.require(XmlPullParser.END_TAG, "", "log"); 63 | return url; 64 | } 65 | 66 | public static void main(String[] args) 67 | throws IOException, XmlPullParserException { 68 | 69 | List urls = 70 | args.length > 0 71 | ? listChannels(args[0]) 72 | : listChannels(); 73 | 74 | for (Iterator i = urls.iterator(); i.hasNext();) 75 | System.out.println(i.next()); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /samples/YesNoGame.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Stefan Haustein 3 | * 4 | * To change this generated comment edit the template variable "typecomment": 5 | * Window>Preferences>Java>Templates. 6 | */ 7 | import java.io.*; 8 | import org.xmlpull.v1.*; 9 | import org.kxml2.io.*; 10 | 11 | class Node { 12 | private String text; 13 | private Node yes; // if null, it's an answer 14 | private Node no; 15 | 16 | Node(String answer) { 17 | this.text = answer; 18 | } 19 | 20 | Node(String question, Node yes, Node no) { 21 | this.text = question; 22 | this.yes = yes; 23 | this.no = no; 24 | } 25 | 26 | void run () throws IOException { 27 | 28 | if (yes == null) 29 | System.out.println ("Answer: "+text); 30 | else { 31 | System.out.println (text+ " (y/n)"); 32 | 33 | while (true) { 34 | int i = System.in.read(); 35 | if (i == 'y' || i == 'Y') { 36 | yes.run(); 37 | break; 38 | } 39 | else if (i == 'n' || i == 'N') { 40 | no.run(); 41 | break; 42 | } 43 | } 44 | } 45 | } 46 | 47 | } 48 | 49 | public class YesNoGame { 50 | 51 | public static Node parseAnswer(XmlPullParser p) throws IOException, XmlPullParserException { 52 | p.require(XmlPullParser.START_TAG, "", "answer"); 53 | Node result = new Node (p.nextText()); 54 | p.require(XmlPullParser.END_TAG, "", "answer"); 55 | return result; 56 | } 57 | 58 | public static Node parseQuestion(XmlPullParser p) throws IOException, XmlPullParserException { 59 | p.require(XmlPullParser.START_TAG, "", "question"); 60 | String text = p.getAttributeValue("", "text"); 61 | Node yes = parseNode (p); 62 | Node no = parseNode (p); 63 | p.nextTag(); 64 | p.require(XmlPullParser.END_TAG, "", "question"); 65 | return new Node (text, yes, no); 66 | } 67 | 68 | public static Node parseNode (XmlPullParser p) throws IOException, XmlPullParserException { 69 | p.nextTag (); 70 | p.require(XmlPullParser.START_TAG, "", null); 71 | if (p.getName().equals("question")) 72 | return parseQuestion(p); 73 | else 74 | return parseAnswer(p); 75 | } 76 | 77 | 78 | public static void main(String[] args) throws IOException, XmlPullParserException { 79 | String sample = "\n" 80 | + " \n" 81 | + " It is the Sun!\n" 82 | + " It is a ball!\n" 83 | + " \n" 84 | + " I do not know!\n" 85 | + "\n"; 86 | 87 | XmlPullParser p = new KXmlParser(); 88 | p.setInput (new StringReader (sample)); 89 | 90 | Node game = parseNode (p); 91 | 92 | game.run(); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /samples/bogdan.xml: -------------------------------------------------------------------------------- 1 | 2 | bar 3 | 4 | This is in a new namespace 5 | 6 | (06/15/2004 00:31) <HTML><BODY 7 | bgcolor="#ffffff"><FONT 8 | LANG="0">hiho</FONT></BODY></HTML> 9 | 10 | -------------------------------------------------------------------------------- /samples/sample.xml: -------------------------------------------------------------------------------- 1 | 2 | bar 3 | 4 | This is in a new namespace 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /samples/simple.xml: -------------------------------------------------------------------------------- 1 | 2 | simple test without namespaces! 3 | 4 | This is in a test text namespace 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /samples_midp/Newsreader.java: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | import java.util.Vector; 3 | 4 | import org.kxml2.io.*; 5 | import org.xmlpull.v1.*; 6 | 7 | import javax.microedition.midlet.*; 8 | import javax.microedition.lcdui.*; 9 | import javax.microedition.io.*; 10 | 11 | public class Newsreader extends MIDlet implements CommandListener { 12 | 13 | static final String URL = "http://www.newsforge.com/newsforge.xml"; 14 | static final String TITLE = "NewsForge"; 15 | 16 | Vector descriptions = new Vector(); 17 | List newsList = new List(TITLE, Choice.IMPLICIT); 18 | TextBox textBox = new TextBox("", "", 256, TextField.ANY); 19 | Display display; 20 | 21 | Command backCmd = new Command("Back", Command.BACK, 0); 22 | 23 | class ReadThread extends Thread { 24 | 25 | public void run() { 26 | try { 27 | HttpConnection httpConnection = (HttpConnection) Connector.open(URL); 28 | 29 | KXmlParser parser = new KXmlParser(); 30 | 31 | parser.setInput(new InputStreamReader(httpConnection.openInputStream())); 32 | 33 | // parser.relaxed = true; 34 | 35 | parser.nextTag(); 36 | parser.require(XmlPullParser.START_TAG, null, "backslash"); 37 | 38 | while (parser.nextTag () != XmlPullParser.END_TAG) 39 | readStory(parser); 40 | 41 | parser.require(XmlPullParser.END_TAG, null, "backslash"); 42 | parser.next(); 43 | 44 | parser.require(XmlPullParser.END_DOCUMENT, null, null); 45 | } catch (Exception e) { 46 | e.printStackTrace(); 47 | descriptions.addElement(e.toString()); 48 | newsList.append("Error", null); 49 | } 50 | } 51 | 52 | /** Read a story and append it to the list */ 53 | 54 | void readStory(KXmlParser parser) 55 | throws IOException, XmlPullParserException { 56 | 57 | parser.require(XmlPullParser.START_TAG, null, "story"); 58 | 59 | String title = null; 60 | String description = null; 61 | 62 | while (parser.nextTag() != XmlPullParser.END_TAG) { 63 | 64 | parser.require(XmlPullParser.START_TAG, null, null); 65 | String name = parser.getName(); 66 | 67 | String text = parser.nextText(); 68 | 69 | System.out.println ("<"+name+">"+text); 70 | 71 | if (name.equals("title")) 72 | title = text; 73 | else if (name.equals("description")) 74 | description = text; 75 | 76 | parser.require(XmlPullParser.END_TAG, null, name); 77 | } 78 | parser.require(XmlPullParser.END_TAG, null, "story"); 79 | 80 | if (title != null) { 81 | descriptions.addElement(""+description); 82 | newsList.append(title, null); 83 | } 84 | } 85 | } 86 | 87 | public void startApp() { 88 | display = Display.getDisplay(this); 89 | display.setCurrent(newsList); 90 | newsList.setCommandListener(this); 91 | textBox.setCommandListener(this); 92 | textBox.addCommand(backCmd); 93 | new ReadThread().start(); 94 | } 95 | 96 | public void pauseApp() { 97 | } 98 | 99 | public void commandAction(Command c, Displayable d) { 100 | 101 | if (c == List.SELECT_COMMAND) { 102 | 103 | String text = (String) descriptions.elementAt(newsList.getSelectedIndex()); 104 | 105 | if (textBox.getMaxSize() < text.length()) 106 | textBox.setMaxSize(text.length()); 107 | 108 | textBox.setString(text); 109 | display.setCurrent(textBox); 110 | } else if (c == backCmd) 111 | display.setCurrent(newsList); 112 | } 113 | 114 | public void destroyApp(boolean really) { 115 | } 116 | /* 117 | public static void main(String[] argv) { 118 | org.me4se.MIDletRunner.main (new String [] {"Newsreader"}); 119 | } 120 | */ 121 | } -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'kxml2' 2 | 3 | -------------------------------------------------------------------------------- /src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | module org.kxml { 2 | exports org.kxml2.io; 3 | exports org.kxml2.kdom; 4 | exports org.kxml2.wap; 5 | 6 | requires org.xmlpull; 7 | } -------------------------------------------------------------------------------- /src/main/java/org/kxml2/io/KXmlSerializer.java: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2002,2003, Stefan Haustein, Oberhausen, Rhld., Germany 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | * sell copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in 11 | * all copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | * IN THE SOFTWARE. */ 20 | 21 | 22 | package org.kxml2.io; 23 | 24 | import java.io.*; 25 | import org.xmlpull.v1.*; 26 | 27 | public class KXmlSerializer implements XmlSerializer { 28 | 29 | // static final String UNDEFINED = ":"; 30 | 31 | private Writer writer; 32 | 33 | private boolean pending; 34 | private int auto; 35 | private int depth; 36 | 37 | private String[] elementStack = new String[12]; 38 | //nsp/prefix/name 39 | private int[] nspCounts = new int[4]; 40 | private String[] nspStack = new String[8]; 41 | //prefix/nsp; both empty are "" 42 | private boolean[] indent = new boolean[4]; 43 | private boolean unicode; 44 | private String encoding; 45 | 46 | private final void check(boolean close) throws IOException { 47 | if (!pending) 48 | return; 49 | 50 | depth++; 51 | pending = false; 52 | 53 | if (indent.length <= depth) { 54 | boolean[] hlp = new boolean[depth + 4]; 55 | System.arraycopy(indent, 0, hlp, 0, depth); 56 | indent = hlp; 57 | } 58 | indent[depth] = indent[depth - 1]; 59 | 60 | for (int i = nspCounts[depth - 1]; 61 | i < nspCounts[depth]; 62 | i++) { 63 | writer.write(' '); 64 | writer.write("xmlns"); 65 | if (!"".equals(nspStack[i * 2])) { 66 | writer.write(':'); 67 | writer.write(nspStack[i * 2]); 68 | } 69 | else if ("".equals(getNamespace()) && !"".equals(nspStack[i * 2 + 1])) 70 | throw new IllegalStateException("Cannot set default namespace for elements in no namespace"); 71 | writer.write("=\""); 72 | writeEscaped(nspStack[i * 2 + 1], '"'); 73 | writer.write('"'); 74 | } 75 | 76 | if (nspCounts.length <= depth + 1) { 77 | int[] hlp = new int[depth + 8]; 78 | System.arraycopy(nspCounts, 0, hlp, 0, depth + 1); 79 | nspCounts = hlp; 80 | } 81 | 82 | nspCounts[depth + 1] = nspCounts[depth]; 83 | // nspCounts[depth + 2] = nspCounts[depth]; 84 | 85 | writer.write(close ? " />" : ">"); 86 | } 87 | 88 | private final void writeEscaped(String s, int quot) 89 | throws IOException { 90 | 91 | for (int i = 0; i < s.length(); i++) { 92 | char c = s.charAt(i); 93 | switch (c) { 94 | case '\n': 95 | case '\r': 96 | case '\t': 97 | if(quot == -1) 98 | writer.write(c); 99 | else 100 | writer.write("&#"+((int) c)+';'); 101 | break; 102 | case '&' : 103 | writer.write("&"); 104 | break; 105 | case '>' : 106 | writer.write(">"); 107 | break; 108 | case '<' : 109 | writer.write("<"); 110 | break; 111 | case '"' : 112 | case '\'' : 113 | if (c == quot) { 114 | writer.write( 115 | c == '"' ? """ : "'"); 116 | break; 117 | } 118 | default : 119 | //if(c < ' ') 120 | // throw new IllegalArgumentException("Illegal control code:"+((int) c)); 121 | 122 | if (i < s.length() - 1) { 123 | char cLow = s.charAt(i + 1); 124 | // c is high surrogate and cLow is low surrogate 125 | if (c >= 0xd800 && c <= 0xdbff && cLow >= 0xdc00 && cLow <= 0xdfff) { 126 | // write surrogate pair as single code point 127 | int n = ((c - 0xd800) << 10) + (cLow - 0xdc00) + 0x010000; 128 | writer.write("&#" + n + ";"); 129 | i++; // Skip the low surrogate 130 | break; 131 | } 132 | // Does nothing smart about orphan surrogates, just output them "as is" 133 | } 134 | if (c >= ' ' && c !='@' && (c < 127 || unicode)) { 135 | writer.write(c); 136 | } else { 137 | writer.write("&#" + ((int) c) + ";"); 138 | } 139 | } 140 | } 141 | } 142 | 143 | /* 144 | private final void writeIndent() throws IOException { 145 | writer.write("\r\n"); 146 | for (int i = 0; i < depth; i++) 147 | writer.write(' '); 148 | }*/ 149 | 150 | public void docdecl(String dd) throws IOException { 151 | writer.write(""); 154 | } 155 | 156 | public void endDocument() throws IOException { 157 | while (depth > 0) { 158 | endTag( 159 | elementStack[depth * 3 - 3], 160 | elementStack[depth * 3 - 1]); 161 | } 162 | flush(); 163 | } 164 | 165 | public void entityRef(String name) throws IOException { 166 | check(false); 167 | writer.write('&'); 168 | writer.write(name); 169 | writer.write(';'); 170 | } 171 | 172 | public boolean getFeature(String name) { 173 | //return false; 174 | return ( 175 | "http://xmlpull.org/v1/doc/features.html#indent-output" 176 | .equals( 177 | name)) 178 | ? indent[depth] 179 | : false; 180 | } 181 | 182 | public String getPrefix(String namespace, boolean create) { 183 | try { 184 | return getPrefix(namespace, false, create); 185 | } 186 | catch (IOException e) { 187 | throw new RuntimeException(e.toString()); 188 | } 189 | } 190 | 191 | private final String getPrefix( 192 | String namespace, 193 | boolean includeDefault, 194 | boolean create) 195 | throws IOException { 196 | 197 | for (int i = nspCounts[depth + 1] * 2 - 2; 198 | i >= 0; 199 | i -= 2) { 200 | if (nspStack[i + 1].equals(namespace) 201 | && (includeDefault || !nspStack[i].equals(""))) { 202 | String cand = nspStack[i]; 203 | for (int j = i + 2; 204 | j < nspCounts[depth + 1] * 2; 205 | j++) { 206 | if (nspStack[j].equals(cand)) { 207 | cand = null; 208 | break; 209 | } 210 | } 211 | if (cand != null) 212 | return cand; 213 | } 214 | } 215 | 216 | if (!create) 217 | return null; 218 | 219 | String prefix; 220 | 221 | if ("".equals(namespace)) 222 | prefix = ""; 223 | else { 224 | do { 225 | prefix = "n" + (auto++); 226 | for (int i = nspCounts[depth + 1] * 2 - 2; 227 | i >= 0; 228 | i -= 2) { 229 | if (prefix.equals(nspStack[i])) { 230 | prefix = null; 231 | break; 232 | } 233 | } 234 | } 235 | while (prefix == null); 236 | } 237 | 238 | boolean p = pending; 239 | pending = false; 240 | setPrefix(prefix, namespace); 241 | pending = p; 242 | return prefix; 243 | } 244 | 245 | public Object getProperty(String name) { 246 | throw new RuntimeException("Unsupported property"); 247 | } 248 | 249 | public void ignorableWhitespace(String s) 250 | throws IOException { 251 | text(s); 252 | } 253 | 254 | public void setFeature(String name, boolean value) { 255 | if ("http://xmlpull.org/v1/doc/features.html#indent-output" 256 | .equals(name)) { 257 | indent[depth] = value; 258 | } 259 | else 260 | throw new RuntimeException("Unsupported Feature"); 261 | } 262 | 263 | public void setProperty(String name, Object value) { 264 | throw new RuntimeException( 265 | "Unsupported Property:" + value); 266 | } 267 | 268 | public void setPrefix(String prefix, String namespace) 269 | throws IOException { 270 | 271 | check(false); 272 | if (prefix == null) 273 | prefix = ""; 274 | if (namespace == null) 275 | namespace = ""; 276 | 277 | String defined = getPrefix(namespace, true, false); 278 | 279 | // boil out if already defined 280 | 281 | if (prefix.equals(defined)) 282 | return; 283 | 284 | int pos = (nspCounts[depth + 1]++) << 1; 285 | 286 | if (nspStack.length < pos + 1) { 287 | String[] hlp = new String[nspStack.length + 16]; 288 | System.arraycopy(nspStack, 0, hlp, 0, pos); 289 | nspStack = hlp; 290 | } 291 | 292 | nspStack[pos++] = prefix; 293 | nspStack[pos] = namespace; 294 | } 295 | 296 | public void setOutput(Writer writer) { 297 | this.writer = writer; 298 | 299 | // elementStack = new String[12]; //nsp/prefix/name 300 | //nspCounts = new int[4]; 301 | //nspStack = new String[8]; //prefix/nsp 302 | //indent = new boolean[4]; 303 | 304 | nspCounts[0] = 2; 305 | nspCounts[1] = 2; 306 | nspStack[0] = ""; 307 | nspStack[1] = ""; 308 | nspStack[2] = "xml"; 309 | nspStack[3] = "http://www.w3.org/XML/1998/namespace"; 310 | pending = false; 311 | auto = 0; 312 | depth = 0; 313 | 314 | unicode = false; 315 | } 316 | 317 | public void setOutput(OutputStream os, String encoding) 318 | throws IOException { 319 | if (os == null) 320 | throw new IllegalArgumentException(); 321 | setOutput( 322 | encoding == null 323 | ? new OutputStreamWriter(os) 324 | : new OutputStreamWriter(os, encoding)); 325 | this.encoding = encoding; 326 | if (encoding != null 327 | && encoding.toLowerCase().startsWith("utf")) 328 | unicode = true; 329 | } 330 | 331 | public void startDocument( 332 | String encoding, 333 | Boolean standalone) 334 | throws IOException { 335 | writer.write(""); 356 | } 357 | 358 | public XmlSerializer startTag(String namespace, String name) 359 | throws IOException { 360 | check(false); 361 | 362 | // if (namespace == null) 363 | // namespace = ""; 364 | 365 | if (indent[depth]) { 366 | writer.write("\r\n"); 367 | for (int i = 0; i < depth; i++) 368 | writer.write(" "); 369 | } 370 | 371 | int esp = depth * 3; 372 | 373 | if (elementStack.length < esp + 3) { 374 | String[] hlp = new String[elementStack.length + 12]; 375 | System.arraycopy(elementStack, 0, hlp, 0, esp); 376 | elementStack = hlp; 377 | } 378 | 379 | String prefix = 380 | namespace == null 381 | ? "" 382 | : getPrefix(namespace, true, true); 383 | 384 | if ("".equals(namespace)) { 385 | for (int i = nspCounts[depth]; 386 | i < nspCounts[depth + 1]; 387 | i++) { 388 | if ("".equals(nspStack[i * 2]) && !"".equals(nspStack[i * 2 + 1])) { 389 | throw new IllegalStateException("Cannot set default namespace for elements in no namespace"); 390 | } 391 | } 392 | } 393 | 394 | elementStack[esp++] = namespace; 395 | elementStack[esp++] = prefix; 396 | elementStack[esp] = name; 397 | 398 | writer.write('<'); 399 | if (!"".equals(prefix)) { 400 | writer.write(prefix); 401 | writer.write(':'); 402 | } 403 | 404 | writer.write(name); 405 | 406 | pending = true; 407 | 408 | return this; 409 | } 410 | 411 | public XmlSerializer attribute( 412 | String namespace, 413 | String name, 414 | String value) 415 | throws IOException { 416 | if (!pending) 417 | throw new IllegalStateException("illegal position for attribute"); 418 | 419 | // int cnt = nspCounts[depth]; 420 | 421 | if (namespace == null) 422 | namespace = ""; 423 | 424 | // depth--; 425 | // pending = false; 426 | 427 | String prefix = 428 | "".equals(namespace) 429 | ? "" 430 | : getPrefix(namespace, false, true); 431 | 432 | // pending = true; 433 | // depth++; 434 | 435 | /* if (cnt != nspCounts[depth]) { 436 | writer.write(' '); 437 | writer.write("xmlns"); 438 | if (nspStack[cnt * 2] != null) { 439 | writer.write(':'); 440 | writer.write(nspStack[cnt * 2]); 441 | } 442 | writer.write("=\""); 443 | writeEscaped(nspStack[cnt * 2 + 1], '"'); 444 | writer.write('"'); 445 | } 446 | */ 447 | 448 | writer.write(' '); 449 | if (!"".equals(prefix)) { 450 | writer.write(prefix); 451 | writer.write(':'); 452 | } 453 | writer.write(name); 454 | writer.write('='); 455 | char q = value.indexOf('"') == -1 ? '"' : '\''; 456 | writer.write(q); 457 | writeEscaped(value, q); 458 | writer.write(q); 459 | 460 | return this; 461 | } 462 | 463 | public void flush() throws IOException { 464 | check(false); 465 | writer.flush(); 466 | } 467 | /* 468 | public void close() throws IOException { 469 | check(); 470 | writer.close(); 471 | } 472 | */ 473 | public XmlSerializer endTag(String namespace, String name) 474 | throws IOException { 475 | 476 | if (!pending) 477 | depth--; 478 | // if (namespace == null) 479 | // namespace = ""; 480 | 481 | if ((namespace == null 482 | && elementStack[depth * 3] != null) 483 | || (namespace != null 484 | && !namespace.equals(elementStack[depth * 3])) 485 | || !elementStack[depth * 3 + 2].equals(name)) 486 | throw new IllegalArgumentException(" does not match start"); 487 | 488 | if (pending) { 489 | check(true); 490 | depth--; 491 | } 492 | else { 493 | if (indent[depth + 1]) { 494 | writer.write("\r\n"); 495 | for (int i = 0; i < depth; i++) 496 | writer.write(" "); 497 | } 498 | 499 | writer.write("'); 507 | } 508 | 509 | nspCounts[depth + 1] = nspCounts[depth]; 510 | return this; 511 | } 512 | 513 | public String getNamespace() { 514 | return getDepth() == 0 ? null : elementStack[getDepth() * 3 - 3]; 515 | } 516 | 517 | public String getName() { 518 | return getDepth() == 0 ? null : elementStack[getDepth() * 3 - 1]; 519 | } 520 | 521 | public int getDepth() { 522 | return pending ? depth + 1 : depth; 523 | } 524 | 525 | public XmlSerializer text(String text) throws IOException { 526 | check(false); 527 | indent[depth] = false; 528 | writeEscaped(text, -1); 529 | return this; 530 | } 531 | 532 | public XmlSerializer text(char[] text, int start, int len) 533 | throws IOException { 534 | text(new String(text, start, len)); 535 | return this; 536 | } 537 | 538 | public void cdsect(String data) throws IOException { 539 | check(false); 540 | writer.write(""); 543 | } 544 | 545 | public void comment(String comment) throws IOException { 546 | check(false); 547 | writer.write(""); 550 | } 551 | 552 | public void processingInstruction(String pi) 553 | throws IOException { 554 | check(false); 555 | writer.write(""); 558 | } 559 | } 560 | -------------------------------------------------------------------------------- /src/main/java/org/kxml2/kdom/Document.java: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2002,2003, Stefan Haustein, Oberhausen, Rhld., Germany 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | * sell copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in 11 | * all copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | * IN THE SOFTWARE. */ 20 | 21 | 22 | package org.kxml2.kdom; 23 | 24 | import java.io.*; 25 | 26 | import org.xmlpull.v1.*; 27 | /** The document consists of some legacy events and a single root 28 | element. This class basically adds some consistency checks to 29 | Node. */ 30 | 31 | public class Document extends Node { 32 | 33 | protected int rootIndex = -1; 34 | String encoding; 35 | Boolean standalone; 36 | 37 | /** returns "#document" */ 38 | 39 | public String getEncoding () { 40 | return encoding; 41 | } 42 | 43 | public void setEncoding(String enc) { 44 | this.encoding = enc; 45 | } 46 | 47 | public void setStandalone (Boolean standalone) { 48 | this.standalone = standalone; 49 | } 50 | 51 | public Boolean getStandalone() { 52 | return standalone; 53 | } 54 | 55 | 56 | public String getName() { 57 | return "#document"; 58 | } 59 | 60 | /** Adds a child at the given index position. Throws 61 | an exception when a second root element is added */ 62 | 63 | public void addChild(int index, int type, Object child) { 64 | if (type == ELEMENT) { 65 | // if (rootIndex != -1) 66 | // throw new RuntimeException("Only one document root element allowed"); 67 | 68 | rootIndex = index; 69 | } 70 | else if (rootIndex >= index) 71 | rootIndex++; 72 | 73 | super.addChild(index, type, child); 74 | } 75 | 76 | /** reads the document and checks if the last event 77 | is END_DOCUMENT. If not, an exception is thrown. 78 | The end event is consumed. For parsing partial 79 | XML structures, consider using Node.parse (). */ 80 | 81 | public void parse(XmlPullParser parser) 82 | throws IOException, XmlPullParserException { 83 | 84 | parser.require(XmlPullParser.START_DOCUMENT, null, null); 85 | parser.nextToken (); 86 | 87 | encoding = parser.getInputEncoding(); 88 | standalone = (Boolean)parser.getProperty ("http://xmlpull.org/v1/doc/properties.html#xmldecl-standalone"); 89 | 90 | super.parse(parser); 91 | 92 | if (parser.getEventType() != XmlPullParser.END_DOCUMENT) 93 | throw new RuntimeException("Document end expected!"); 94 | 95 | } 96 | 97 | public void removeChild(int index) { 98 | if (index == rootIndex) 99 | rootIndex = -1; 100 | else if (index < rootIndex) 101 | rootIndex--; 102 | 103 | super.removeChild(index); 104 | } 105 | 106 | /** returns the root element of this document. */ 107 | 108 | public Element getRootElement() { 109 | if (rootIndex == -1) 110 | throw new RuntimeException("Document has no root element!"); 111 | 112 | return (Element) getChild(rootIndex); 113 | } 114 | 115 | 116 | /** Writes this node to the given XmlWriter. For node and document, 117 | this method is identical to writeChildren, except that the 118 | stream is flushed automatically. */ 119 | 120 | public void write(XmlSerializer writer) 121 | throws IOException { 122 | 123 | writer.startDocument(encoding, standalone); 124 | writeChildren(writer); 125 | writer.endDocument(); 126 | } 127 | 128 | 129 | } -------------------------------------------------------------------------------- /src/main/java/org/kxml2/kdom/Element.java: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2002,2003, Stefan Haustein, Oberhausen, Rhld., Germany 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | * sell copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in 11 | * all copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | * IN THE SOFTWARE. */ 20 | 21 | package org.kxml2.kdom; 22 | 23 | import java.io.*; 24 | import java.util.*; 25 | 26 | import org.xmlpull.v1.*; 27 | 28 | /** 29 | * In order to create an element, please use the createElement method 30 | * instead of invoking the constructor directly. The right place to 31 | * add user defined initialization code is the init method. */ 32 | 33 | public class Element extends Node { 34 | 35 | protected String namespace; 36 | protected String name; 37 | protected Vector attributes; 38 | protected Node parent; 39 | protected Vector prefixes; 40 | 41 | public Element() { 42 | } 43 | 44 | /** 45 | * called when all properties are set, but before children 46 | * are parsed. Please do not use setParent for initialization 47 | * code any longer. */ 48 | 49 | public void init() { 50 | } 51 | 52 | 53 | 54 | 55 | /** 56 | * removes all children and attributes */ 57 | 58 | public void clear() { 59 | attributes = null; 60 | children = null; 61 | } 62 | 63 | /** 64 | * Forwards creation request to parent if any, otherwise 65 | * calls super.createElement. */ 66 | 67 | public Element createElement( 68 | String namespace, 69 | String name) { 70 | 71 | return (this.parent == null) 72 | ? super.createElement(namespace, name) 73 | : this.parent.createElement(namespace, name); 74 | } 75 | 76 | /** 77 | * Returns the number of attributes of this element. */ 78 | 79 | public int getAttributeCount() { 80 | return attributes == null ? 0 : attributes.size (); 81 | } 82 | 83 | public String getAttributeNamespace (int index) { 84 | return ((String []) attributes.elementAt (index)) [0]; 85 | } 86 | 87 | /* public String getAttributePrefix (int index) { 88 | return ((String []) attributes.elementAt (index)) [1]; 89 | }*/ 90 | 91 | public String getAttributeName (int index) { 92 | return ((String []) attributes.elementAt (index)) [1]; 93 | } 94 | 95 | 96 | public String getAttributeValue (int index) { 97 | return ((String []) attributes.elementAt (index)) [2]; 98 | } 99 | 100 | 101 | public String getAttributeValue (String namespace, String name) { 102 | for (int i = 0; i < getAttributeCount (); i++) { 103 | if (name.equals (getAttributeName (i)) 104 | && (namespace == null || namespace.equals (getAttributeNamespace(i)))) { 105 | return getAttributeValue (i); 106 | } 107 | } 108 | return null; 109 | } 110 | 111 | /** 112 | * Returns the root node, determined by ascending to the 113 | * all parents un of the root element. */ 114 | 115 | public Node getRoot() { 116 | 117 | Element current = this; 118 | 119 | while (current.parent != null) { 120 | if (!(current.parent instanceof Element)) return current.parent; 121 | current = (Element) current.parent; 122 | } 123 | 124 | return current; 125 | } 126 | 127 | /** 128 | * returns the (local) name of the element */ 129 | 130 | public String getName() { 131 | return name; 132 | } 133 | 134 | /** 135 | * returns the namespace of the element */ 136 | 137 | public String getNamespace() { 138 | return namespace; 139 | } 140 | 141 | 142 | /** 143 | * returns the namespace for the given prefix */ 144 | 145 | public String getNamespaceUri (String prefix) { 146 | int cnt = getNamespaceCount (); 147 | for (int i = 0; i < cnt; i++) { 148 | if (prefix == getNamespacePrefix (i) || 149 | (prefix != null && prefix.equals (getNamespacePrefix (i)))) 150 | return getNamespaceUri (i); 151 | } 152 | return parent instanceof Element ? ((Element) parent).getNamespaceUri (prefix) : null; 153 | } 154 | 155 | 156 | /** 157 | * returns the number of declared namespaces, NOT including 158 | * parent elements */ 159 | 160 | public int getNamespaceCount () { 161 | return (prefixes == null ? 0 : prefixes.size ()); 162 | } 163 | 164 | 165 | public String getNamespacePrefix (int i) { 166 | return ((String []) prefixes.elementAt (i)) [0]; 167 | } 168 | 169 | public String getNamespaceUri (int i) { 170 | return ((String []) prefixes.elementAt (i)) [1]; 171 | } 172 | 173 | 174 | /** 175 | * Returns the parent node of this element */ 176 | 177 | public Node getParent() { 178 | return parent; 179 | } 180 | 181 | /* 182 | * Returns the parent element if available, null otherwise 183 | 184 | public Element getParentElement() { 185 | return (parent instanceof Element) 186 | ? ((Element) parent) 187 | : null; 188 | } 189 | */ 190 | 191 | /** 192 | * Builds the child elements from the given Parser. By overwriting 193 | * parse, an element can take complete control over parsing its 194 | * subtree. */ 195 | 196 | public void parse(XmlPullParser parser) 197 | throws IOException, XmlPullParserException { 198 | 199 | for (int i = parser.getNamespaceCount (parser.getDepth () - 1); 200 | i < parser.getNamespaceCount (parser.getDepth ()); i++) { 201 | setPrefix (parser.getNamespacePrefix (i), parser.getNamespaceUri(i)); 202 | } 203 | 204 | 205 | for (int i = 0; i < parser.getAttributeCount (); i++) 206 | setAttribute (parser.getAttributeNamespace (i), 207 | // parser.getAttributePrefix (i), 208 | parser.getAttributeName (i), 209 | parser.getAttributeValue (i)); 210 | 211 | 212 | // if (prefixMap == null) throw new RuntimeException ("!!"); 213 | 214 | init(); 215 | 216 | 217 | if (parser.isEmptyElementTag()) 218 | parser.nextToken (); 219 | else { 220 | parser.nextToken (); 221 | super.parse(parser); 222 | 223 | if (getChildCount() == 0) 224 | addChild(IGNORABLE_WHITESPACE, ""); 225 | } 226 | 227 | parser.require( 228 | XmlPullParser.END_TAG, 229 | getNamespace(), 230 | getName()); 231 | 232 | parser.nextToken (); 233 | } 234 | 235 | 236 | /** 237 | * Sets the given attribute; a value of null removes the attribute */ 238 | 239 | public void setAttribute (String namespace, String name, String value) { 240 | if (attributes == null) 241 | attributes = new Vector (); 242 | 243 | if (namespace == null) 244 | namespace = ""; 245 | 246 | for (int i = attributes.size()-1; i >=0; i--){ 247 | String[] attribut = (String[]) attributes.elementAt(i); 248 | if (attribut[0].equals(namespace) && 249 | attribut[1].equals(name)){ 250 | 251 | if (value == null) { 252 | attributes.removeElementAt(i); 253 | } 254 | else { 255 | attribut[2] = value; 256 | } 257 | return; 258 | } 259 | } 260 | 261 | attributes.addElement 262 | (new String [] {namespace, name, value}); 263 | } 264 | 265 | 266 | /** 267 | * Sets the given prefix; a namespace value of null removess the 268 | * prefix */ 269 | 270 | public void setPrefix (String prefix, String namespace) { 271 | if (prefixes == null) prefixes = new Vector (); 272 | prefixes.addElement (new String [] {prefix, namespace}); 273 | } 274 | 275 | 276 | /** 277 | * sets the name of the element */ 278 | 279 | public void setName(String name) { 280 | this.name = name; 281 | } 282 | 283 | /** 284 | * sets the namespace of the element. Please note: For no 285 | * namespace, please use Xml.NO_NAMESPACE, null is not a legal 286 | * value. Currently, null is converted to Xml.NO_NAMESPACE, but 287 | * future versions may throw an exception. */ 288 | 289 | public void setNamespace(String namespace) { 290 | if (namespace == null) 291 | throw new NullPointerException ("Use \"\" for empty namespace"); 292 | this.namespace = namespace; 293 | } 294 | 295 | /** 296 | * Sets the Parent of this element. Automatically called from the 297 | * add method. Please use with care, you can simply 298 | * create inconsitencies in the document tree structure using 299 | * this method! */ 300 | 301 | protected void setParent(Node parent) { 302 | this.parent = parent; 303 | } 304 | 305 | 306 | /** 307 | * Writes this element and all children to the given XmlWriter. */ 308 | 309 | public void write(XmlSerializer writer) 310 | throws IOException { 311 | 312 | if (prefixes != null) { 313 | for (int i = 0; i < prefixes.size (); i++) { 314 | writer.setPrefix (getNamespacePrefix (i), getNamespaceUri (i)); 315 | } 316 | } 317 | 318 | writer.startTag( 319 | getNamespace(), 320 | getName()); 321 | 322 | int len = getAttributeCount(); 323 | 324 | for (int i = 0; i < len; i++) { 325 | writer.attribute( 326 | getAttributeNamespace(i), 327 | getAttributeName(i), 328 | getAttributeValue(i)); 329 | } 330 | 331 | writeChildren(writer); 332 | 333 | writer.endTag(getNamespace (), getName ()); 334 | } 335 | } 336 | -------------------------------------------------------------------------------- /src/main/java/org/kxml2/kdom/Node.java: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2002,2003, Stefan Haustein, Oberhausen, Rhld., Germany 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | * sell copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in 11 | * all copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | * IN THE SOFTWARE. */ 20 | 21 | package org.kxml2.kdom; 22 | 23 | import java.util.*; 24 | import java.io.*; 25 | import org.xmlpull.v1.*; 26 | /** A common base class for Document and Element, also used for 27 | storing XML fragments. */ 28 | 29 | public class Node { //implements XmlIO{ 30 | 31 | public static final int DOCUMENT = 0; 32 | public static final int ELEMENT = 2; 33 | public static final int TEXT = 4; 34 | public static final int CDSECT = 5; 35 | public static final int ENTITY_REF = 6; 36 | public static final int IGNORABLE_WHITESPACE = 7; 37 | public static final int PROCESSING_INSTRUCTION = 8; 38 | public static final int COMMENT = 9; 39 | public static final int DOCDECL = 10; 40 | 41 | protected Vector children; 42 | protected StringBuffer types; 43 | 44 | /** inserts the given child object of the given type at the 45 | given index. */ 46 | 47 | public void addChild(int index, int type, Object child) { 48 | 49 | if (child == null) 50 | throw new NullPointerException(); 51 | 52 | if (children == null) { 53 | children = new Vector(); 54 | types = new StringBuffer(); 55 | } 56 | 57 | if (type == ELEMENT) { 58 | if (!(child instanceof Element)) 59 | throw new RuntimeException("Element obj expected)"); 60 | 61 | ((Element) child).setParent(this); 62 | } 63 | else if (!(child instanceof String)) 64 | throw new RuntimeException("String expected"); 65 | 66 | children.insertElementAt(child, index); 67 | types.insert(index, (char) type); 68 | } 69 | 70 | /** convenience method for addChild (getChildCount (), child) */ 71 | 72 | public void addChild(int type, Object child) { 73 | addChild(getChildCount(), type, child); 74 | } 75 | 76 | /** Builds a default element with the given properties. Elements 77 | should always be created using this method instead of the 78 | constructor in order to enable construction of specialized 79 | subclasses by deriving custom Document classes. Please note: 80 | For no namespace, please use Xml.NO_NAMESPACE, null is not a 81 | legal value. Currently, null is converted to Xml.NO_NAMESPACE, 82 | but future versions may throw an exception. */ 83 | 84 | public Element createElement(String namespace, String name) { 85 | 86 | Element e = new Element(); 87 | e.namespace = namespace == null ? "" : namespace; 88 | e.name = name; 89 | return e; 90 | } 91 | 92 | /** Returns the child object at the given index. For child 93 | elements, an Element object is returned. For all other child 94 | types, a String is returned. */ 95 | 96 | public Object getChild(int index) { 97 | return children.elementAt(index); 98 | } 99 | 100 | /** Returns the number of child objects */ 101 | 102 | public int getChildCount() { 103 | return children == null ? 0 : children.size(); 104 | } 105 | 106 | /** returns the element at the given index. If the node at the 107 | given index is a text node, null is returned */ 108 | 109 | public Element getElement(int index) { 110 | Object child = getChild(index); 111 | return (child instanceof Element) ? (Element) child : null; 112 | } 113 | 114 | /** Returns the element with the given namespace and name. If the 115 | element is not found, or more than one matching elements are 116 | found, an exception is thrown. */ 117 | 118 | public Element getElement(String namespace, String name) { 119 | 120 | int i = indexOf(namespace, name, 0); 121 | int j = indexOf(namespace, name, i + 1); 122 | 123 | if (i == -1 || j != -1) 124 | throw new RuntimeException( 125 | "Element {" 126 | + namespace 127 | + "}" 128 | + name 129 | + (i == -1 ? " not found in " : " more than once in ") 130 | + this); 131 | 132 | return getElement(i); 133 | } 134 | 135 | /* returns "#document-fragment". For elements, the element name is returned 136 | 137 | public String getName() { 138 | return "#document-fragment"; 139 | } 140 | 141 | /** Returns the namespace of the current element. For Node 142 | and Document, Xml.NO_NAMESPACE is returned. 143 | 144 | public String getNamespace() { 145 | return ""; 146 | } 147 | 148 | public int getNamespaceCount () { 149 | return 0; 150 | } 151 | 152 | /** returns the text content if the element has text-only 153 | content. Throws an exception for mixed content 154 | 155 | public String getText() { 156 | 157 | StringBuffer buf = new StringBuffer(); 158 | int len = getChildCount(); 159 | 160 | for (int i = 0; i < len; i++) { 161 | if (isText(i)) 162 | buf.append(getText(i)); 163 | else if (getType(i) == ELEMENT) 164 | throw new RuntimeException("not text-only content!"); 165 | } 166 | 167 | return buf.toString(); 168 | } 169 | */ 170 | 171 | /** Returns the text node with the given index or null if the node 172 | with the given index is not a text node. */ 173 | 174 | public String getText(int index) { 175 | return (isText(index)) ? (String) getChild(index) : null; 176 | } 177 | 178 | /** Returns the type of the child at the given index. Possible 179 | types are ELEMENT, TEXT, COMMENT, and PROCESSING_INSTRUCTION */ 180 | 181 | public int getType(int index) { 182 | return types.charAt(index); 183 | } 184 | 185 | /** Convenience method for indexOf (getNamespace (), name, 186 | startIndex). 187 | 188 | public int indexOf(String name, int startIndex) { 189 | return indexOf(getNamespace(), name, startIndex); 190 | } 191 | */ 192 | 193 | /** Performs search for an element with the given namespace and 194 | name, starting at the given start index. A null namespace 195 | matches any namespace, please use Xml.NO_NAMESPACE for no 196 | namespace). returns -1 if no matching element was found. */ 197 | 198 | public int indexOf(String namespace, String name, int startIndex) { 199 | 200 | int len = getChildCount(); 201 | 202 | for (int i = startIndex; i < len; i++) { 203 | 204 | Element child = getElement(i); 205 | 206 | if (child != null 207 | && name.equals(child.getName()) 208 | && (namespace == null || namespace.equals(child.getNamespace()))) 209 | return i; 210 | } 211 | return -1; 212 | } 213 | 214 | public boolean isText(int i) { 215 | int t = getType(i); 216 | return t == TEXT || t == IGNORABLE_WHITESPACE || t == CDSECT; 217 | } 218 | 219 | /** Recursively builds the child elements from the given parser 220 | until an end tag or end document is found. 221 | The end tag is not consumed. */ 222 | 223 | public void parse(XmlPullParser parser) 224 | throws IOException, XmlPullParserException { 225 | 226 | boolean leave = false; 227 | 228 | do { 229 | int type = parser.getEventType(); 230 | 231 | // System.out.println(parser.getPositionDescription()); 232 | 233 | switch (type) { 234 | 235 | case XmlPullParser.START_TAG : 236 | { 237 | Element child = 238 | createElement( 239 | parser.getNamespace(), 240 | parser.getName()); 241 | // child.setAttributes (event.getAttributes ()); 242 | addChild(ELEMENT, child); 243 | 244 | // order is important here since 245 | // setparent may perform some init code! 246 | 247 | child.parse(parser); 248 | break; 249 | } 250 | 251 | case XmlPullParser.END_DOCUMENT : 252 | case XmlPullParser.END_TAG : 253 | leave = true; 254 | break; 255 | 256 | default : 257 | if (parser.getText() != null) 258 | addChild( 259 | type == XmlPullParser.ENTITY_REF ? TEXT : type, 260 | parser.getText()); 261 | else if ( 262 | type == XmlPullParser.ENTITY_REF 263 | && parser.getName() != null) { 264 | addChild(ENTITY_REF, parser.getName()); 265 | } 266 | parser.nextToken(); 267 | } 268 | } 269 | while (!leave); 270 | } 271 | 272 | /** Removes the child object at the given index */ 273 | 274 | public void removeChild(int idx) { 275 | children.removeElementAt(idx); 276 | 277 | /*** Modification by HHS - start ***/ 278 | // types.deleteCharAt (index); 279 | /***/ 280 | int n = types.length() - 1; 281 | 282 | for (int i = idx; i < n; i++) 283 | types.setCharAt(i, types.charAt(i + 1)); 284 | 285 | types.setLength(n); 286 | 287 | /*** Modification by HHS - end ***/ 288 | } 289 | 290 | /* returns a valid XML representation of this Element including 291 | attributes and children. 292 | public String toString() { 293 | try { 294 | ByteArrayOutputStream bos = 295 | new ByteArrayOutputStream(); 296 | XmlWriter xw = 297 | new XmlWriter(new OutputStreamWriter(bos)); 298 | write(xw); 299 | xw.close(); 300 | return new String(bos.toByteArray()); 301 | } 302 | catch (IOException e) { 303 | throw new RuntimeException(e.toString()); 304 | } 305 | } 306 | */ 307 | 308 | /** Writes this node to the given XmlWriter. For node and document, 309 | this method is identical to writeChildren, except that the 310 | stream is flushed automatically. */ 311 | 312 | public void write(XmlSerializer writer) throws IOException { 313 | writeChildren(writer); 314 | writer.flush(); 315 | } 316 | 317 | /** Writes the children of this node to the given XmlWriter. */ 318 | 319 | public void writeChildren(XmlSerializer writer) throws IOException { 320 | if (children == null) 321 | return; 322 | 323 | int len = children.size(); 324 | 325 | for (int i = 0; i < len; i++) { 326 | int type = getType(i); 327 | Object child = children.elementAt(i); 328 | switch (type) { 329 | case ELEMENT : 330 | ((Element) child).write(writer); 331 | break; 332 | 333 | case TEXT : 334 | writer.text((String) child); 335 | break; 336 | 337 | case IGNORABLE_WHITESPACE : 338 | writer.ignorableWhitespace((String) child); 339 | break; 340 | 341 | case CDSECT : 342 | writer.cdsect((String) child); 343 | break; 344 | 345 | case COMMENT : 346 | writer.comment((String) child); 347 | break; 348 | 349 | case ENTITY_REF : 350 | writer.entityRef((String) child); 351 | break; 352 | 353 | case PROCESSING_INSTRUCTION : 354 | writer.processingInstruction((String) child); 355 | break; 356 | 357 | case DOCDECL : 358 | writer.docdecl((String) child); 359 | break; 360 | 361 | default : 362 | throw new RuntimeException("Illegal type: " + type); 363 | } 364 | } 365 | } 366 | } 367 | -------------------------------------------------------------------------------- /src/main/java/org/kxml2/wap/Wbxml.java: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2002,2003, Stefan Haustein, Oberhausen, Rhld., Germany 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | * sell copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in 11 | * all copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | * IN THE SOFTWARE. */ 20 | 21 | package org.kxml2.wap; 22 | 23 | 24 | /** contains the WBXML constants */ 25 | 26 | 27 | public interface Wbxml { 28 | 29 | static public final int SWITCH_PAGE = 0; 30 | static public final int END = 1; 31 | static public final int ENTITY = 2; 32 | static public final int STR_I = 3; 33 | static public final int LITERAL = 4; 34 | static public final int EXT_I_0 = 0x40; 35 | static public final int EXT_I_1 = 0x41; 36 | static public final int EXT_I_2 = 0x42; 37 | static public final int PI = 0x43; 38 | static public final int LITERAL_C = 0x44; 39 | static public final int EXT_T_0 = 0x80; 40 | static public final int EXT_T_1 = 0x81; 41 | static public final int EXT_T_2 = 0x82; 42 | static public final int STR_T = 0x83; 43 | static public final int LITERAL_A = 0x084; 44 | static public final int EXT_0 = 0x0c0; 45 | static public final int EXT_1 = 0x0c1; 46 | static public final int EXT_2 = 0x0c2; 47 | static public final int OPAQUE = 0x0c3; 48 | static public final int LITERAL_AC = 0x0c4; 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/org/kxml2/wap/WbxmlParser.java: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2002,2003,2004 Stefan Haustein, Oberhausen, Rhld., Germany 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | * sell copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in 11 | * all copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | * IN THE SOFTWARE. */ 20 | 21 | // Contributors: Bjorn Aadland, Chris Bartley, Nicola Fankhauser, 22 | // Victor Havin, Christian Kurzke, Bogdan Onoiu, 23 | // Elias Ross, Jain Sanjay, David Santoro. 24 | 25 | package org.kxml2.wap; 26 | 27 | import java.io.*; 28 | import java.util.Vector; 29 | import java.util.Hashtable; 30 | 31 | import org.xmlpull.v1.*; 32 | 33 | 34 | public class WbxmlParser implements XmlPullParser { 35 | 36 | static final String HEX_DIGITS = "0123456789abcdef"; 37 | 38 | /** Parser event type for Wbxml-specific events. The Wbxml event code can be 39 | * accessed with getWapCode() */ 40 | 41 | public static final int WAP_EXTENSION = 64; 42 | 43 | static final private String UNEXPECTED_EOF = 44 | "Unexpected EOF"; 45 | static final private String ILLEGAL_TYPE = 46 | "Wrong event type"; 47 | 48 | private InputStream in; 49 | 50 | private int TAG_TABLE = 0; 51 | private int ATTR_START_TABLE = 1; 52 | private int ATTR_VALUE_TABLE = 2; 53 | 54 | private String[] attrStartTable; 55 | private String[] attrValueTable; 56 | private String[] tagTable; 57 | private byte[] stringTable; 58 | private Hashtable cacheStringTable = null; 59 | private boolean processNsp; 60 | 61 | private int depth; 62 | private String[] elementStack = new String[16]; 63 | private String[] nspStack = new String[8]; 64 | private int[] nspCounts = new int[4]; 65 | 66 | private int attributeCount; 67 | private String[] attributes = new String[16]; 68 | private int nextId = -2; 69 | 70 | private Vector tables = new Vector(); 71 | 72 | private int version; 73 | private int publicIdentifierId; 74 | 75 | // StartTag current; 76 | // ParseEvent next; 77 | 78 | private String prefix; 79 | private String namespace; 80 | private String name; 81 | private String text; 82 | 83 | private Object wapExtensionData; 84 | private int wapCode; 85 | 86 | private int type; 87 | 88 | private boolean degenerated; 89 | private boolean isWhitespace; 90 | private String encoding; 91 | 92 | public boolean getFeature(String feature) { 93 | if (XmlPullParser 94 | .FEATURE_PROCESS_NAMESPACES 95 | .equals(feature)) 96 | return processNsp; 97 | else 98 | return false; 99 | } 100 | 101 | public String getInputEncoding() { 102 | return encoding; 103 | } 104 | 105 | public void defineEntityReplacementText( 106 | String entity, 107 | String value) 108 | throws XmlPullParserException { 109 | 110 | // just ignore, has no effect 111 | } 112 | 113 | public Object getProperty(String property) { 114 | return null; 115 | } 116 | 117 | public int getNamespaceCount(int depth) { 118 | if (depth > this.depth) 119 | throw new IndexOutOfBoundsException(); 120 | return nspCounts[depth]; 121 | } 122 | 123 | public String getNamespacePrefix(int pos) { 124 | return nspStack[pos << 1]; 125 | } 126 | 127 | public String getNamespaceUri(int pos) { 128 | return nspStack[(pos << 1) + 1]; 129 | } 130 | 131 | public String getNamespace(String prefix) { 132 | 133 | if ("xml".equals(prefix)) 134 | return "http://www.w3.org/XML/1998/namespace"; 135 | if ("xmlns".equals(prefix)) 136 | return "http://www.w3.org/2000/xmlns/"; 137 | 138 | for (int i = (getNamespaceCount(depth) << 1) - 2; 139 | i >= 0; 140 | i -= 2) { 141 | if (prefix == null) { 142 | if (nspStack[i] == null) 143 | return nspStack[i + 1]; 144 | } 145 | else if (prefix.equals(nspStack[i])) 146 | return nspStack[i + 1]; 147 | } 148 | return null; 149 | } 150 | 151 | public int getDepth() { 152 | return depth; 153 | } 154 | 155 | public String getPositionDescription() { 156 | 157 | StringBuffer buf = 158 | new StringBuffer( 159 | type < TYPES.length ? TYPES[type] : "unknown"); 160 | buf.append(' '); 161 | 162 | if (type == START_TAG || type == END_TAG) { 163 | if (degenerated) 164 | buf.append("(empty) "); 165 | buf.append('<'); 166 | if (type == END_TAG) 167 | buf.append('/'); 168 | 169 | if (prefix != null) 170 | buf.append("{" + namespace + "}" + prefix + ":"); 171 | buf.append(name); 172 | 173 | int cnt = attributeCount << 2; 174 | for (int i = 0; i < cnt; i += 4) { 175 | buf.append(' '); 176 | if (attributes[i + 1] != null) 177 | buf.append( 178 | "{" 179 | + attributes[i] 180 | + "}" 181 | + attributes[i 182 | + 1] 183 | + ":"); 184 | buf.append( 185 | attributes[i 186 | + 2] 187 | + "='" 188 | + attributes[i 189 | + 3] 190 | + "'"); 191 | } 192 | 193 | buf.append('>'); 194 | } 195 | else if (type == IGNORABLE_WHITESPACE); 196 | else if (type != TEXT) 197 | buf.append(getText()); 198 | else if (isWhitespace) 199 | buf.append("(whitespace)"); 200 | else { 201 | String text = getText(); 202 | if (text.length() > 16) 203 | text = text.substring(0, 16) + "..."; 204 | buf.append(text); 205 | } 206 | 207 | return buf.toString(); 208 | } 209 | 210 | public int getLineNumber() { 211 | return -1; 212 | } 213 | 214 | public int getColumnNumber() { 215 | return -1; 216 | } 217 | 218 | public boolean isWhitespace() 219 | throws XmlPullParserException { 220 | if (type != TEXT 221 | && type != IGNORABLE_WHITESPACE 222 | && type != CDSECT) 223 | exception(ILLEGAL_TYPE); 224 | return isWhitespace; 225 | } 226 | 227 | public String getText() { 228 | return text; 229 | } 230 | 231 | public char[] getTextCharacters(int[] poslen) { 232 | if (type >= TEXT) { 233 | poslen[0] = 0; 234 | poslen[1] = text.length(); 235 | char[] buf = new char[text.length()]; 236 | text.getChars(0, text.length(), buf, 0); 237 | return buf; 238 | } 239 | 240 | poslen[0] = -1; 241 | poslen[1] = -1; 242 | return null; 243 | } 244 | 245 | public String getNamespace() { 246 | return namespace; 247 | } 248 | 249 | public String getName() { 250 | return name; 251 | } 252 | 253 | public String getPrefix() { 254 | return prefix; 255 | } 256 | 257 | public boolean isEmptyElementTag() 258 | throws XmlPullParserException { 259 | if (type != START_TAG) 260 | exception(ILLEGAL_TYPE); 261 | return degenerated; 262 | } 263 | 264 | public int getAttributeCount() { 265 | return attributeCount; 266 | } 267 | 268 | public String getAttributeType(int index) { 269 | return "CDATA"; 270 | } 271 | 272 | public boolean isAttributeDefault(int index) { 273 | return false; 274 | } 275 | 276 | public String getAttributeNamespace(int index) { 277 | if (index >= attributeCount) 278 | throw new IndexOutOfBoundsException(); 279 | return attributes[index << 2]; 280 | } 281 | 282 | public String getAttributeName(int index) { 283 | if (index >= attributeCount) 284 | throw new IndexOutOfBoundsException(); 285 | return attributes[(index << 2) + 2]; 286 | } 287 | 288 | public String getAttributePrefix(int index) { 289 | if (index >= attributeCount) 290 | throw new IndexOutOfBoundsException(); 291 | return attributes[(index << 2) + 1]; 292 | } 293 | 294 | public String getAttributeValue(int index) { 295 | if (index >= attributeCount) 296 | throw new IndexOutOfBoundsException(); 297 | return attributes[(index << 2) + 3]; 298 | } 299 | 300 | public String getAttributeValue( 301 | String namespace, 302 | String name) { 303 | 304 | for (int i = (attributeCount << 2) - 4; 305 | i >= 0; 306 | i -= 4) { 307 | if (attributes[i + 2].equals(name) 308 | && (namespace == null 309 | || attributes[i].equals(namespace))) 310 | return attributes[i + 3]; 311 | } 312 | 313 | return null; 314 | } 315 | 316 | public int getEventType() throws XmlPullParserException { 317 | return type; 318 | } 319 | 320 | 321 | // TODO: Reuse resolveWapExtension here? Raw Wap extensions would still be accessible 322 | // via nextToken(); ....? 323 | 324 | public int next() throws XmlPullParserException, IOException { 325 | 326 | isWhitespace = true; 327 | int minType = 9999; 328 | 329 | while (true) { 330 | 331 | String save = text; 332 | 333 | nextImpl(); 334 | 335 | if (type < minType) 336 | minType = type; 337 | 338 | if (minType > CDSECT) continue; // no "real" event so far 339 | 340 | if (minType >= TEXT) { // text, see if accumulate 341 | 342 | if (save != null) text = text == null ? save : save + text; 343 | 344 | switch(peekId()) { 345 | case Wbxml.ENTITY: 346 | case Wbxml.STR_I: 347 | case Wbxml.STR_T: 348 | case Wbxml.LITERAL: 349 | case Wbxml.LITERAL_C: 350 | case Wbxml.LITERAL_A: 351 | case Wbxml.LITERAL_AC: continue; 352 | } 353 | } 354 | 355 | break; 356 | } 357 | 358 | type = minType; 359 | 360 | if (type > TEXT) 361 | type = TEXT; 362 | 363 | return type; 364 | } 365 | 366 | 367 | public int nextToken() throws XmlPullParserException, IOException { 368 | 369 | isWhitespace = true; 370 | nextImpl(); 371 | return type; 372 | } 373 | 374 | 375 | 376 | public int nextTag() throws XmlPullParserException, IOException { 377 | 378 | next(); 379 | if (type == TEXT && isWhitespace) 380 | next(); 381 | 382 | if (type != END_TAG && type != START_TAG) 383 | exception("unexpected type"); 384 | 385 | return type; 386 | } 387 | 388 | 389 | public String nextText() throws XmlPullParserException, IOException { 390 | if (type != START_TAG) 391 | exception("precondition: START_TAG"); 392 | 393 | next(); 394 | 395 | String result; 396 | 397 | if (type == TEXT) { 398 | result = getText(); 399 | next(); 400 | } 401 | else 402 | result = ""; 403 | 404 | if (type != END_TAG) 405 | exception("END_TAG expected"); 406 | 407 | return result; 408 | } 409 | 410 | 411 | public void require(int type, String namespace, String name) 412 | throws XmlPullParserException, IOException { 413 | 414 | if (type != this.type 415 | || (namespace != null && !namespace.equals(getNamespace())) 416 | || (name != null && !name.equals(getName()))) 417 | exception( 418 | "expected: " + (type == WAP_EXTENSION ? "WAP Ext." : (TYPES[type] + " {" + namespace + "}" + name))); 419 | } 420 | 421 | 422 | public void setInput(Reader reader) throws XmlPullParserException { 423 | exception("InputStream required"); 424 | } 425 | 426 | public void setInput(InputStream in, String enc) 427 | throws XmlPullParserException { 428 | 429 | this.in = in; 430 | 431 | try { 432 | version = readByte(); 433 | publicIdentifierId = readInt(); 434 | 435 | if (publicIdentifierId == 0) 436 | readInt(); 437 | 438 | int charset = readInt(); // skip charset 439 | 440 | if (null == enc){ 441 | switch (charset){ 442 | case 4: encoding = "ISO-8859-1"; break; 443 | case 106: encoding = "UTF-8"; break; 444 | // add more if you need them 445 | // http://www.iana.org/assignments/character-sets 446 | // case MIBenum: encoding = Name break; 447 | default: throw new UnsupportedEncodingException(""+charset); 448 | } 449 | }else{ 450 | encoding = enc; 451 | } 452 | 453 | int strTabSize = readInt(); 454 | stringTable = new byte[strTabSize]; 455 | 456 | int ok = 0; 457 | while(ok < strTabSize){ 458 | int cnt = in.read(stringTable, ok, strTabSize - ok); 459 | if(cnt <= 0) break; 460 | ok += cnt; 461 | } 462 | 463 | selectPage(0, true); 464 | selectPage(0, false); 465 | } 466 | catch (IOException e) { 467 | exception("Illegal input format"); 468 | } 469 | } 470 | 471 | public void setFeature(String feature, boolean value) 472 | throws XmlPullParserException { 473 | if (XmlPullParser.FEATURE_PROCESS_NAMESPACES.equals(feature)) 474 | processNsp = value; 475 | else 476 | exception("unsupported feature: " + feature); 477 | } 478 | 479 | public void setProperty(String property, Object value) 480 | throws XmlPullParserException { 481 | throw new XmlPullParserException("unsupported property: " + property); 482 | } 483 | 484 | // ---------------------- private / internal methods 485 | 486 | private final boolean adjustNsp() 487 | throws XmlPullParserException { 488 | 489 | boolean any = false; 490 | 491 | for (int i = 0; i < attributeCount << 2; i += 4) { 492 | // * 4 - 4; i >= 0; i -= 4) { 493 | 494 | String attrName = attributes[i + 2]; 495 | int cut = attrName.indexOf(':'); 496 | String prefix; 497 | 498 | if (cut != -1) { 499 | prefix = attrName.substring(0, cut); 500 | attrName = attrName.substring(cut + 1); 501 | } 502 | else if (attrName.equals("xmlns")) { 503 | prefix = attrName; 504 | attrName = null; 505 | } 506 | else 507 | continue; 508 | 509 | if (!prefix.equals("xmlns")) { 510 | any = true; 511 | } 512 | else { 513 | int j = (nspCounts[depth]++) << 1; 514 | 515 | nspStack = ensureCapacity(nspStack, j + 2); 516 | nspStack[j] = attrName; 517 | nspStack[j + 1] = attributes[i + 3]; 518 | 519 | if (attrName != null 520 | && attributes[i + 3].equals("")) 521 | exception("illegal empty namespace"); 522 | 523 | // prefixMap = new PrefixMap (prefixMap, attrName, attr.getValue ()); 524 | 525 | //System.out.println (prefixMap); 526 | 527 | System.arraycopy( 528 | attributes, 529 | i + 4, 530 | attributes, 531 | i, 532 | ((--attributeCount) << 2) - i); 533 | 534 | i -= 4; 535 | } 536 | } 537 | 538 | if (any) { 539 | for (int i = (attributeCount << 2) - 4; 540 | i >= 0; 541 | i -= 4) { 542 | 543 | String attrName = attributes[i + 2]; 544 | int cut = attrName.indexOf(':'); 545 | 546 | if (cut == 0) 547 | throw new RuntimeException( 548 | "illegal attribute name: " 549 | + attrName 550 | + " at " 551 | + this); 552 | 553 | else if (cut != -1) { 554 | String attrPrefix = 555 | attrName.substring(0, cut); 556 | 557 | attrName = attrName.substring(cut + 1); 558 | 559 | String attrNs = getNamespace(attrPrefix); 560 | 561 | if (attrNs == null) 562 | throw new RuntimeException( 563 | "Undefined Prefix: " 564 | + attrPrefix 565 | + " in " 566 | + this); 567 | 568 | attributes[i] = attrNs; 569 | attributes[i + 1] = attrPrefix; 570 | attributes[i + 2] = attrName; 571 | 572 | for (int j = (attributeCount << 2) - 4; 573 | j > i; 574 | j -= 4) 575 | if (attrName.equals(attributes[j + 2]) 576 | && attrNs.equals(attributes[j])) 577 | exception( 578 | "Duplicate Attribute: {" 579 | + attrNs 580 | + "}" 581 | + attrName); 582 | } 583 | } 584 | } 585 | 586 | int cut = name.indexOf(':'); 587 | 588 | if (cut == 0) 589 | exception("illegal tag name: " + name); 590 | else if (cut != -1) { 591 | prefix = name.substring(0, cut); 592 | name = name.substring(cut + 1); 593 | } 594 | 595 | this.namespace = getNamespace(prefix); 596 | 597 | if (this.namespace == null) { 598 | if (prefix != null) 599 | exception("undefined prefix: " + prefix); 600 | this.namespace = NO_NAMESPACE; 601 | } 602 | 603 | return any; 604 | } 605 | 606 | private final void setTable(int page, int type, String[] table) { 607 | if(stringTable != null){ 608 | throw new RuntimeException("setXxxTable must be called before setInput!"); 609 | } 610 | while(tables.size() < 3*page +3){ 611 | tables.addElement(null); 612 | } 613 | tables.setElementAt(table, page*3+type); 614 | } 615 | 616 | 617 | 618 | 619 | 620 | private final void exception(String desc) 621 | throws XmlPullParserException { 622 | throw new XmlPullParserException(desc, this, null); 623 | } 624 | 625 | 626 | private void selectPage(int nr, boolean tags) throws XmlPullParserException{ 627 | if(tables.size() == 0 && nr == 0) return; 628 | 629 | if(nr*3 > tables.size()) 630 | exception("Code Page "+nr+" undefined!"); 631 | 632 | if(tags) 633 | tagTable = (String[]) tables.elementAt(nr * 3 + TAG_TABLE); 634 | else { 635 | attrStartTable = (String[]) tables.elementAt(nr * 3 + ATTR_START_TABLE); 636 | attrValueTable = (String[]) tables.elementAt(nr * 3 + ATTR_VALUE_TABLE); 637 | } 638 | } 639 | 640 | private final void nextImpl() 641 | throws IOException, XmlPullParserException { 642 | 643 | String s; 644 | 645 | if (type == END_TAG) { 646 | depth--; 647 | } 648 | 649 | if (degenerated) { 650 | type = XmlPullParser.END_TAG; 651 | degenerated = false; 652 | return; 653 | } 654 | 655 | text = null; 656 | prefix = null; 657 | name = null; 658 | 659 | int id = peekId (); 660 | while(id == Wbxml.SWITCH_PAGE){ 661 | nextId = -2; 662 | selectPage(readByte(), true); 663 | id = peekId(); 664 | } 665 | nextId = -2; 666 | 667 | switch (id) { 668 | case -1 : 669 | type = XmlPullParser.END_DOCUMENT; 670 | break; 671 | 672 | case Wbxml.END : 673 | { 674 | int sp = (depth - 1) << 2; 675 | 676 | type = END_TAG; 677 | namespace = elementStack[sp]; 678 | prefix = elementStack[sp + 1]; 679 | name = elementStack[sp + 2]; 680 | } 681 | break; 682 | 683 | case Wbxml.ENTITY : 684 | { 685 | type = ENTITY_REF; 686 | char c = (char) readInt(); 687 | text = "" + c; 688 | name = "#" + ((int) c); 689 | } 690 | 691 | break; 692 | 693 | case Wbxml.STR_I : 694 | type = TEXT; 695 | text = readStrI(); 696 | break; 697 | 698 | case Wbxml.EXT_I_0 : 699 | case Wbxml.EXT_I_1 : 700 | case Wbxml.EXT_I_2 : 701 | case Wbxml.EXT_T_0 : 702 | case Wbxml.EXT_T_1 : 703 | case Wbxml.EXT_T_2 : 704 | case Wbxml.EXT_0 : 705 | case Wbxml.EXT_1 : 706 | case Wbxml.EXT_2 : 707 | case Wbxml.OPAQUE : 708 | 709 | type = WAP_EXTENSION; 710 | wapCode = id; 711 | wapExtensionData = parseWapExtension(id); 712 | break; 713 | 714 | case Wbxml.PI : 715 | throw new RuntimeException("PI curr. not supp."); 716 | // readPI; 717 | // break; 718 | 719 | case Wbxml.STR_T : 720 | { 721 | type = TEXT; 722 | text = readStrT(); 723 | } 724 | break; 725 | 726 | default : 727 | parseElement(id); 728 | } 729 | // } 730 | // while (next == null); 731 | 732 | // return next; 733 | } 734 | 735 | /** Overwrite this method to intercept all wap events */ 736 | 737 | public Object parseWapExtension(int id) throws IOException, XmlPullParserException { 738 | 739 | switch (id) { 740 | case Wbxml.EXT_I_0 : 741 | case Wbxml.EXT_I_1 : 742 | case Wbxml.EXT_I_2 : 743 | return readStrI(); 744 | 745 | case Wbxml.EXT_T_0 : 746 | case Wbxml.EXT_T_1 : 747 | case Wbxml.EXT_T_2 : 748 | return new Integer(readInt()); 749 | 750 | case Wbxml.EXT_0 : 751 | case Wbxml.EXT_1 : 752 | case Wbxml.EXT_2 : 753 | return null; 754 | 755 | case Wbxml.OPAQUE : 756 | { 757 | int count = readInt(); 758 | byte[] buf = new byte[count]; 759 | 760 | while(count > 0){ 761 | count -= in.read(buf, buf.length-count, count); 762 | } 763 | 764 | return buf; 765 | } // case OPAQUE 766 | 767 | 768 | default: 769 | exception("illegal id: "+id); 770 | return null; // dead code 771 | } // SWITCH 772 | } 773 | 774 | public void readAttr() throws IOException, XmlPullParserException { 775 | 776 | int id = readByte(); 777 | int i = 0; 778 | 779 | while (id != 1) { 780 | 781 | while(id == Wbxml.SWITCH_PAGE){ 782 | selectPage(readByte(), false); 783 | id = readByte(); 784 | } 785 | 786 | String name = resolveId(attrStartTable, id); 787 | StringBuffer value; 788 | 789 | int cut = name.indexOf('='); 790 | 791 | if (cut == -1) 792 | value = new StringBuffer(); 793 | else { 794 | value = 795 | new StringBuffer(name.substring(cut + 1)); 796 | name = name.substring(0, cut); 797 | } 798 | 799 | id = readByte(); 800 | while (id > 128 801 | || id == Wbxml.SWITCH_PAGE 802 | || id == Wbxml.ENTITY 803 | || id == Wbxml.STR_I 804 | || id == Wbxml.STR_T 805 | || (id >= Wbxml.EXT_I_0 && id <= Wbxml.EXT_I_2) 806 | || (id >= Wbxml.EXT_T_0 && id <= Wbxml.EXT_T_2)) { 807 | 808 | switch (id) { 809 | case Wbxml.SWITCH_PAGE : 810 | selectPage(readByte(), false); 811 | break; 812 | 813 | case Wbxml.ENTITY : 814 | value.append((char) readInt()); 815 | break; 816 | 817 | case Wbxml.STR_I : 818 | value.append(readStrI()); 819 | break; 820 | 821 | case Wbxml.EXT_I_0 : 822 | case Wbxml.EXT_I_1 : 823 | case Wbxml.EXT_I_2 : 824 | case Wbxml.EXT_T_0 : 825 | case Wbxml.EXT_T_1 : 826 | case Wbxml.EXT_T_2 : 827 | case Wbxml.EXT_0 : 828 | case Wbxml.EXT_1 : 829 | case Wbxml.EXT_2 : 830 | case Wbxml.OPAQUE : 831 | value.append(resolveWapExtension(id, parseWapExtension(id))); 832 | break; 833 | 834 | case Wbxml.STR_T : 835 | value.append(readStrT()); 836 | break; 837 | 838 | default : 839 | value.append( 840 | resolveId(attrValueTable, id)); 841 | } 842 | 843 | id = readByte(); 844 | } 845 | 846 | attributes = ensureCapacity(attributes, i + 4); 847 | 848 | attributes[i++] = ""; 849 | attributes[i++] = null; 850 | attributes[i++] = name; 851 | attributes[i++] = value.toString(); 852 | 853 | attributeCount++; 854 | } 855 | } 856 | 857 | private int peekId () throws IOException { 858 | if (nextId == -2) { 859 | nextId = in.read (); 860 | } 861 | return nextId; 862 | } 863 | 864 | /** overwrite for own WAP extension handling in attributes and high level parsing 865 | * (above nextToken() level) */ 866 | 867 | protected String resolveWapExtension(int id, Object data){ 868 | 869 | if(data instanceof byte[]){ 870 | StringBuffer sb = new StringBuffer(); 871 | byte[] b = (byte[]) data; 872 | 873 | for (int i = 0; i < b.length; i++) { 874 | sb.append(HEX_DIGITS.charAt((b[i] >> 4) & 0x0f)); 875 | sb.append(HEX_DIGITS.charAt(b[i] & 0x0f)); 876 | } 877 | return sb.toString(); 878 | } 879 | 880 | return "$("+data+")"; 881 | } 882 | 883 | String resolveId(String[] tab, int id) throws IOException { 884 | int idx = (id & 0x07f) - 5; 885 | if (idx == -1){ 886 | wapCode = -1; 887 | return readStrT(); 888 | } 889 | if (idx < 0 890 | || tab == null 891 | || idx >= tab.length 892 | || tab[idx] == null) 893 | throw new IOException("id " + id + " undef."); 894 | 895 | wapCode = idx+5; 896 | 897 | return tab[idx]; 898 | } 899 | 900 | void parseElement(int id) 901 | throws IOException, XmlPullParserException { 902 | 903 | type = START_TAG; 904 | name = resolveId(tagTable, id & 0x03f); 905 | 906 | attributeCount = 0; 907 | if ((id & 128) != 0) { 908 | readAttr(); 909 | } 910 | 911 | degenerated = (id & 64) == 0; 912 | 913 | int sp = depth++ << 2; 914 | 915 | // transfer to element stack 916 | 917 | elementStack = ensureCapacity(elementStack, sp + 4); 918 | elementStack[sp + 3] = name; 919 | 920 | if (depth >= nspCounts.length) { 921 | int[] bigger = new int[depth + 4]; 922 | System.arraycopy(nspCounts, 0, bigger, 0, nspCounts.length); 923 | nspCounts = bigger; 924 | } 925 | 926 | nspCounts[depth] = nspCounts[depth - 1]; 927 | 928 | for (int i = attributeCount - 1; i > 0; i--) { 929 | for (int j = 0; j < i; j++) { 930 | if (getAttributeName(i) 931 | .equals(getAttributeName(j))) 932 | exception( 933 | "Duplicate Attribute: " 934 | + getAttributeName(i)); 935 | } 936 | } 937 | 938 | if (processNsp) 939 | adjustNsp(); 940 | else 941 | namespace = ""; 942 | 943 | elementStack[sp] = namespace; 944 | elementStack[sp + 1] = prefix; 945 | elementStack[sp + 2] = name; 946 | 947 | } 948 | 949 | private final String[] ensureCapacity( 950 | String[] arr, 951 | int required) { 952 | if (arr.length >= required) 953 | return arr; 954 | String[] bigger = new String[required + 16]; 955 | System.arraycopy(arr, 0, bigger, 0, arr.length); 956 | return bigger; 957 | } 958 | 959 | int readByte() throws IOException { 960 | int i = in.read(); 961 | if (i == -1) 962 | throw new IOException("Unexpected EOF"); 963 | return i; 964 | } 965 | 966 | int readInt() throws IOException { 967 | int result = 0; 968 | int i; 969 | 970 | do { 971 | i = readByte(); 972 | result = (result << 7) | (i & 0x7f); 973 | } 974 | while ((i & 0x80) != 0); 975 | 976 | return result; 977 | } 978 | 979 | String readStrI() throws IOException { 980 | ByteArrayOutputStream buf = new ByteArrayOutputStream(); 981 | boolean wsp = true; 982 | while (true){ 983 | int i = in.read(); 984 | if (i == 0){ 985 | break; 986 | } 987 | if (i == -1){ 988 | throw new IOException(UNEXPECTED_EOF); 989 | } 990 | if (i > 32){ 991 | wsp = false; 992 | } 993 | buf.write(i); 994 | } 995 | isWhitespace = wsp; 996 | String result = new String(buf.toByteArray(), encoding); 997 | buf.close(); 998 | return result; 999 | } 1000 | 1001 | String readStrT() throws IOException { 1002 | int pos = readInt(); 1003 | // As the main reason of stringTable is compression we build a cache of Strings 1004 | // stringTable is supposed to help create Strings from parts which means some cache hit rate 1005 | // This will help to minimize the Strings created when invoking readStrT() repeatedly 1006 | if (cacheStringTable == null){ 1007 | //Lazy init if device is not using StringTable but inline 0x03 strings 1008 | cacheStringTable = new Hashtable(); 1009 | } 1010 | String forReturn = (String) cacheStringTable.get(new Integer(pos)); 1011 | if (forReturn == null){ 1012 | 1013 | int end = pos; 1014 | while(end < stringTable.length && stringTable[end] != '\0'){ 1015 | end++; 1016 | } 1017 | forReturn = new String(stringTable, pos, end-pos, encoding); 1018 | cacheStringTable.put(new Integer(pos), forReturn); 1019 | } 1020 | return forReturn; 1021 | } 1022 | 1023 | /** 1024 | * Sets the tag table for a given page. 1025 | * The first string in the array defines tag 5, the second tag 6 etc. 1026 | */ 1027 | 1028 | public void setTagTable(int page, String[] table) { 1029 | setTable(page, TAG_TABLE, table); 1030 | 1031 | // this.tagTable = tagTable; 1032 | // if (page != 0) 1033 | // throw new RuntimeException("code pages curr. not supp."); 1034 | } 1035 | 1036 | /** Sets the attribute start Table for a given page. 1037 | * The first string in the array defines attribute 1038 | * 5, the second attribute 6 etc. Please use the 1039 | * character '=' (without quote!) as delimiter 1040 | * between the attribute name and the (start of the) value 1041 | */ 1042 | 1043 | public void setAttrStartTable( 1044 | int page, 1045 | String[] table) { 1046 | 1047 | setTable(page, ATTR_START_TABLE, table); 1048 | } 1049 | 1050 | /** Sets the attribute value Table for a given page. 1051 | * The first string in the array defines attribute value 0x85, 1052 | * the second attribute value 0x86 etc. 1053 | */ 1054 | 1055 | public void setAttrValueTable( 1056 | int page, 1057 | String[] table) { 1058 | 1059 | setTable(page, ATTR_VALUE_TABLE, table); 1060 | } 1061 | 1062 | /** Returns the token ID for start tags or the event type for wap proprietary events 1063 | * such as OPAQUE. 1064 | */ 1065 | 1066 | public int getWapCode(){ 1067 | return wapCode; 1068 | } 1069 | 1070 | public Object getWapExtensionData(){ 1071 | return wapExtensionData; 1072 | } 1073 | 1074 | 1075 | } -------------------------------------------------------------------------------- /src/main/java/org/kxml2/wap/WbxmlSerializer.java: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2002,2003, Stefan Haustein, Oberhausen, Rhld., Germany 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | * sell copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in 11 | * all copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | * IN THE SOFTWARE. */ 20 | 21 | //Contributors: Jonathan Cox, Bogdan Onoiu, Jerry Tian 22 | 23 | package org.kxml2.wap; 24 | 25 | import java.io.*; 26 | import java.util.*; 27 | 28 | import org.xmlpull.v1.*; 29 | 30 | // TODO: make some of the "direct" WBXML token writing methods public?? 31 | 32 | /** 33 | * A class for writing WBXML. Does not support namespaces yet. 34 | */ 35 | public class WbxmlSerializer implements XmlSerializer { 36 | 37 | 38 | Hashtable stringTable = new Hashtable(); 39 | 40 | OutputStream out; 41 | 42 | ByteArrayOutputStream buf = new ByteArrayOutputStream(); 43 | ByteArrayOutputStream stringTableBuf = new ByteArrayOutputStream(); 44 | 45 | String pending; 46 | int depth; 47 | String name; 48 | String namespace; 49 | Vector attributes = new Vector(); 50 | 51 | Hashtable attrStartTable = new Hashtable(); 52 | Hashtable attrValueTable = new Hashtable(); 53 | Hashtable tagTable = new Hashtable(); 54 | 55 | private int attrPage; 56 | private int tagPage; 57 | 58 | private String encoding; 59 | 60 | private boolean headerSent = false; 61 | 62 | /** 63 | * Write an attribute. 64 | * Calls to attribute() MUST follow a call to startTag() immediately. 65 | * If there is no prefix defined for the given namespace, 66 | * a prefix will be defined automatically. 67 | */ 68 | public XmlSerializer attribute(String namespace, String name, String value) { 69 | attributes.addElement(name); 70 | attributes.addElement(value); 71 | return this; 72 | } 73 | 74 | 75 | public void cdsect (String cdsect) throws IOException{ 76 | text (cdsect); 77 | } 78 | 79 | /** 80 | * Add comment. Ignore for WBXML. 81 | */ 82 | public void comment (String comment) { 83 | // silently ignore comment 84 | } 85 | 86 | /** 87 | * Docdecl isn't supported for WBXML. 88 | */ 89 | public void docdecl (String docdecl) { 90 | throw new RuntimeException ("Cannot write docdecl for WBXML"); 91 | } 92 | 93 | /** 94 | * EntityReference not supported for WBXML. 95 | */ 96 | public void entityRef (String er) { 97 | throw new RuntimeException ("EntityReference not supported for WBXML"); 98 | } 99 | 100 | /** 101 | * Return current tag depth. 102 | */ 103 | public int getDepth() { 104 | return depth; 105 | } 106 | 107 | /** 108 | * Return the current value of the feature with given name. 109 | */ 110 | public boolean getFeature (String name) { 111 | return false; 112 | } 113 | 114 | /** 115 | * Returns the namespace URI of the current element as set by startTag(). 116 | * Namespaces is not yet implemented. 117 | */ 118 | public String getNamespace() { 119 | // Namespaces is not yet implemented. So only null can be setted 120 | return null; 121 | } 122 | 123 | /** 124 | * Returns the name of the current element as set by startTag(). 125 | * It can only be null before first call to startTag() or when last endTag() 126 | * is called to close first startTag(). 127 | */ 128 | public String getName() { 129 | return pending; 130 | } 131 | 132 | /** 133 | * Prefix for namespace not supported for WBXML. Not yet implemented. 134 | */ 135 | public String getPrefix(String nsp, boolean create) { 136 | throw new RuntimeException ("NYI"); 137 | } 138 | 139 | /** 140 | * Look up the value of a property. 141 | * @param name The name of property. Name is any fully-qualified URI. 142 | * @return The value of named property. 143 | */ 144 | public Object getProperty (String name) { 145 | return null; 146 | } 147 | 148 | public void ignorableWhitespace (String sp) { 149 | } 150 | 151 | /** 152 | * Finish writing. 153 | * All unclosed start tags will be closed and output will be flushed. 154 | * After calling this method no more output can be serialized until 155 | * next call to setOutput(). 156 | */ 157 | public void endDocument() throws IOException { 158 | flush(); 159 | } 160 | 161 | /** 162 | * Write all pending output to the stream. 163 | * After first call string table willn't be used and you can't add tag 164 | * which is not in tag table. 165 | */ 166 | public void flush() throws IOException { 167 | checkPending(false); 168 | 169 | if (!headerSent) { 170 | writeInt(out, stringTableBuf.size()); 171 | out.write(stringTableBuf.toByteArray()); 172 | headerSent = true; 173 | } 174 | 175 | out.write(buf.toByteArray()); 176 | buf.reset(); 177 | } 178 | 179 | public void checkPending(boolean degenerated) throws IOException { 180 | if (pending == null) 181 | return; 182 | 183 | int len = attributes.size(); 184 | 185 | int[] idx = (int[]) tagTable.get(pending); 186 | 187 | // if no entry in known table, then add as literal 188 | if (idx == null) { 189 | buf.write(len == 0 190 | ? (degenerated ? Wbxml.LITERAL : Wbxml.LITERAL_C) 191 | : (degenerated ? Wbxml.LITERAL_A : Wbxml.LITERAL_AC)); 192 | 193 | writeStrT(pending, false); 194 | } else { 195 | if(idx[0] != tagPage){ 196 | tagPage=idx[0]; 197 | buf.write(Wbxml.SWITCH_PAGE); 198 | buf.write(tagPage); 199 | } 200 | buf.write(len == 0 201 | ? (degenerated ? idx[1] : idx[1] | 64) 202 | : (degenerated ? idx[1] | 128 : idx[1] | 192)); 203 | } 204 | 205 | for (int i = 0; i < len;) { 206 | idx = (int[]) attrStartTable.get(attributes.elementAt(i)); 207 | 208 | if (idx == null) { 209 | buf.write(Wbxml.LITERAL); 210 | writeStrT((String) attributes.elementAt(i), false); 211 | } 212 | else { 213 | if(idx[0] != attrPage){ 214 | attrPage = idx[0]; 215 | buf.write(0); 216 | buf.write(attrPage); 217 | } 218 | buf.write(idx[1]); 219 | } 220 | idx = (int[]) attrValueTable.get(attributes.elementAt(++i)); 221 | if (idx == null) { 222 | writeStr((String) attributes.elementAt(i)); 223 | } 224 | else { 225 | if(idx[0] != attrPage){ 226 | attrPage = idx[0]; 227 | buf.write(0); 228 | buf.write(attrPage); 229 | } 230 | buf.write(idx[1]); 231 | } 232 | ++i; 233 | } 234 | 235 | if (len > 0) 236 | buf.write(Wbxml.END); 237 | 238 | pending = null; 239 | attributes.removeAllElements(); 240 | } 241 | 242 | /** 243 | * Not Yet Implemented. 244 | */ 245 | public void processingInstruction(String pi) { 246 | throw new RuntimeException ("PI NYI"); 247 | } 248 | 249 | /** 250 | * Set feature identified by name. There are no supported functions. 251 | */ 252 | public void setFeature(String name, boolean value) { 253 | throw new IllegalArgumentException ("unknown feature "+name); 254 | } 255 | 256 | /** 257 | * Set the output to the given writer. Wbxml requires an OutputStream. 258 | */ 259 | public void setOutput (Writer writer) { 260 | throw new RuntimeException ("Wbxml requires an OutputStream!"); 261 | } 262 | 263 | /** 264 | * Set to use binary output stream with given encoding. 265 | */ 266 | public void setOutput (OutputStream out, String encoding) throws IOException { 267 | 268 | this.encoding = encoding == null ? "UTF-8" : encoding; 269 | this.out = out; 270 | 271 | buf = new ByteArrayOutputStream(); 272 | stringTableBuf = new ByteArrayOutputStream(); 273 | headerSent = false; 274 | 275 | // ok, write header 276 | } 277 | 278 | /** 279 | * Binds the given prefix to the given namespace. Not yet implemented. 280 | */ 281 | public void setPrefix(String prefix, String nsp) { 282 | throw new RuntimeException("NYI"); 283 | } 284 | 285 | /** 286 | * Set the value of a property. There are no supported properties. 287 | */ 288 | public void setProperty(String property, Object value) { 289 | throw new IllegalArgumentException ("unknown property "+property); 290 | } 291 | 292 | /** 293 | * Write version and encoding information. 294 | * This method can only be called just after setOutput. 295 | * @param encoding Document encoding. Default is UTF-8. 296 | * @param standalone Not used in WBXML. 297 | */ 298 | public void startDocument(String encoding, Boolean standalone) throws IOException { 299 | out.write(0x03); // version 1.3 300 | // http://www.openmobilealliance.org/tech/omna/omna-wbxml-public-docid.htm 301 | out.write(0x01); // unknown or missing public identifier 302 | 303 | // default encoding is UTF-8 304 | 305 | if(encoding != null){ 306 | this.encoding = encoding; 307 | } 308 | 309 | if (this.encoding.toUpperCase().equals("UTF-8")){ 310 | out.write(106); 311 | }else if (this.encoding.toUpperCase().equals("ISO-8859-1")){ 312 | out.write(0x04); 313 | }else{ 314 | throw new UnsupportedEncodingException(encoding); 315 | } 316 | } 317 | 318 | 319 | public XmlSerializer startTag(String namespace, String name) throws IOException { 320 | 321 | if (namespace != null && !"".equals(namespace)) 322 | throw new RuntimeException ("NSP NYI"); 323 | 324 | //current = new State(current, prefixMap, name); 325 | 326 | checkPending(false); 327 | pending = name; 328 | depth++; 329 | 330 | return this; 331 | } 332 | 333 | public XmlSerializer text(char[] chars, int start, int len) throws IOException { 334 | checkPending(false); 335 | writeStr(new String(chars, start, len)); 336 | return this; 337 | } 338 | 339 | public XmlSerializer text(String text) throws IOException { 340 | checkPending(false); 341 | writeStr(text); 342 | return this; 343 | } 344 | 345 | /** 346 | * Used in text() and attribute() to write text. 347 | */ 348 | private void writeStr(String text) throws IOException{ 349 | int p0 = 0; 350 | int lastCut = 0; 351 | int len = text.length(); 352 | 353 | if (headerSent) { 354 | writeStrI(buf, text); 355 | return; 356 | } 357 | 358 | while(p0 < len){ 359 | while(p0 < len && text.charAt(p0) < 'A' ){ // skip interpunctation 360 | p0++; 361 | } 362 | int p1 = p0; 363 | while (p1 < len && text.charAt(p1) >= 'A'){ 364 | p1++; 365 | } 366 | 367 | if (p1 - p0 > 10) { 368 | if (p0 > lastCut && text.charAt(p0-1) == ' ' 369 | && stringTable.get(text.substring(p0, p1)) == null){ 370 | buf.write(Wbxml.STR_T); 371 | writeStrT(text.substring(lastCut, p1), false); 372 | } 373 | else { 374 | if(p0 > lastCut && text.charAt(p0-1) == ' '){ 375 | p0--; 376 | } 377 | 378 | if(p0 > lastCut){ 379 | buf.write(Wbxml.STR_T); 380 | writeStrT(text.substring(lastCut, p0), false); 381 | } 382 | buf.write(Wbxml.STR_T); 383 | writeStrT(text.substring(p0, p1), true); 384 | } 385 | lastCut = p1; 386 | } 387 | p0 = p1; 388 | } 389 | 390 | if(lastCut < len){ 391 | buf.write(Wbxml.STR_T); 392 | writeStrT(text.substring(lastCut, len), false); 393 | } 394 | } 395 | 396 | 397 | 398 | public XmlSerializer endTag(String namespace, String name) throws IOException { 399 | // current = current.prev; 400 | if (pending != null) { 401 | checkPending(true); 402 | } else { 403 | buf.write(Wbxml.END); 404 | } 405 | depth--; 406 | return this; 407 | } 408 | 409 | /** 410 | * @throws IOException 411 | */ 412 | public void writeWapExtension(int type, Object data) throws IOException { 413 | checkPending(false); 414 | buf.write(type); 415 | switch(type){ 416 | case Wbxml.EXT_0: 417 | case Wbxml.EXT_1: 418 | case Wbxml.EXT_2: 419 | break; 420 | 421 | case Wbxml.OPAQUE: 422 | byte[] bytes = (byte[]) data; 423 | writeInt(buf, bytes.length); 424 | buf.write(bytes); 425 | break; 426 | 427 | case Wbxml.EXT_I_0: 428 | case Wbxml.EXT_I_1: 429 | case Wbxml.EXT_I_2: 430 | writeStrI(buf, (String) data); 431 | break; 432 | 433 | case Wbxml.EXT_T_0: 434 | case Wbxml.EXT_T_1: 435 | case Wbxml.EXT_T_2: 436 | writeStrT((String) data, false); 437 | break; 438 | 439 | default: 440 | throw new IllegalArgumentException(); 441 | } 442 | } 443 | 444 | // ------------- internal methods -------------------------- 445 | 446 | static void writeInt(OutputStream out, int i) throws IOException { 447 | byte[] buf = new byte[5]; 448 | int idx = 0; 449 | 450 | do { 451 | buf[idx++] = (byte) (i & 0x7f); 452 | i = i >> 7; 453 | } 454 | while (i != 0); 455 | 456 | while (idx > 1) { 457 | out.write(buf[--idx] | 0x80); 458 | } 459 | out.write(buf[0]); 460 | } 461 | 462 | void writeStrI(OutputStream out, String s) throws IOException { 463 | byte[] data = s.getBytes(encoding); 464 | out.write(data); 465 | out.write(0); 466 | } 467 | 468 | private final void writeStrT(String s, boolean mayPrependSpace) throws IOException { 469 | 470 | Integer idx = (Integer) stringTable.get(s); 471 | writeInt(buf, idx == null 472 | ? addToStringTable(s, mayPrependSpace) 473 | : idx.intValue()); 474 | } 475 | 476 | 477 | /** 478 | * Add string to string table. Not permitted after string table has been flushed. 479 | * 480 | * @param s string to be added to the string table 481 | * @param mayPrependSpace is set, a space is prepended to the string to archieve better compression results 482 | * @return offset of s in the string table 483 | */ 484 | public int addToStringTable(String s, boolean mayPrependSpace) throws IOException { 485 | if (headerSent) { 486 | throw new IOException("stringtable sent"); 487 | } 488 | 489 | int i = stringTableBuf.size(); 490 | int offset = i; 491 | if(s.charAt(0) >= '0' && mayPrependSpace){ 492 | s = ' ' + s; 493 | offset++; 494 | } 495 | 496 | stringTable.put(s, new Integer(i)); 497 | if(s.charAt(0) == ' '){ 498 | stringTable.put(s.substring(1), new Integer(i+1)); 499 | } 500 | int j = s.lastIndexOf(' '); 501 | if(j > 1){ 502 | String t = s.substring(j); 503 | int k = t.getBytes("utf-8").length; 504 | stringTable.put(t, new Integer(i+k)); 505 | stringTable.put(s.substring(j+1), new Integer(i+k+1)); 506 | } 507 | 508 | writeStrI(stringTableBuf, s); 509 | stringTableBuf.flush(); 510 | return offset; 511 | } 512 | 513 | /** 514 | * Sets the tag table for a given page. 515 | * The first string in the array defines tag 5, the second tag 6 etc. 516 | */ 517 | public void setTagTable(int page, String[] tagTable) { 518 | // TODO: clear entries in tagTable? 519 | 520 | for (int i = 0; i < tagTable.length; i++) { 521 | if (tagTable[i] != null) { 522 | Object idx = new int[]{page, i+5}; 523 | this.tagTable.put(tagTable[i], idx); 524 | } 525 | } 526 | } 527 | 528 | /** 529 | * Sets the attribute start Table for a given page. 530 | * The first string in the array defines attribute 531 | * 5, the second attribute 6 etc. 532 | * Please use the 533 | * character '=' (without quote!) as delimiter 534 | * between the attribute name and the (start of the) value 535 | */ 536 | public void setAttrStartTable(int page, String[] attrStartTable) { 537 | 538 | for (int i = 0; i < attrStartTable.length; i++) { 539 | if (attrStartTable[i] != null) { 540 | Object idx = new int[] {page, i + 5}; 541 | this.attrStartTable.put(attrStartTable[i], idx); 542 | } 543 | } 544 | } 545 | 546 | /** 547 | * Sets the attribute value Table for a given page. 548 | * The first string in the array defines attribute value 0x85, 549 | * the second attribute value 0x86 etc. 550 | * Must be called BEFORE use attribute(), flush() etc. 551 | */ 552 | public void setAttrValueTable(int page, String[] attrValueTable) { 553 | // clear entries in this.table! 554 | for (int i = 0; i < attrValueTable.length; i++) { 555 | if (attrValueTable[i] != null) { 556 | Object idx = new int[]{page, i + 0x085}; 557 | this.attrValueTable.put(attrValueTable[i], idx); 558 | } 559 | } 560 | } 561 | } 562 | -------------------------------------------------------------------------------- /src/main/java/org/kxml2/wap/syncml/SyncML.java: -------------------------------------------------------------------------------- 1 | package org.kxml2.wap.syncml; 2 | 3 | import org.kxml2.wap.*; 4 | 5 | public abstract class SyncML { 6 | 7 | 8 | // SyncML-Common (-//SYNCML//DTD SyncML 1.2//EN and -//SYNCML//DTD MetInf 1.2//EN) support 9 | 10 | public static WbxmlParser createParser() { 11 | WbxmlParser p = new WbxmlParser(); 12 | p.setTagTable(0, TAG_TABLE_0); 13 | p.setTagTable(1, TAG_TABLE_1); 14 | return p; 15 | } 16 | 17 | public static WbxmlSerializer createSerializer() { 18 | WbxmlSerializer s = new WbxmlSerializer(); 19 | s.setTagTable(0, TAG_TABLE_0); 20 | s.setTagTable(1, TAG_TABLE_1); 21 | return s; 22 | } 23 | 24 | 25 | // SyncML-Common + DMDDF (-//OMA//DTD-DM-DDF 1.2//EN) support 26 | 27 | public static WbxmlParser createDMParser() { 28 | WbxmlParser p = createParser(); 29 | p.setTagTable(2, TAG_TABLE_2_DM); 30 | return p; 31 | } 32 | 33 | public static WbxmlSerializer createDMSerializer() { 34 | WbxmlSerializer s = createSerializer(); 35 | s.setTagTable(2, TAG_TABLE_2_DM); 36 | return s; 37 | } 38 | 39 | // Tables 40 | 41 | public static final String [] TAG_TABLE_0 = { 42 | 43 | // -//SYNCML//DTD SyncML 1.2//EN 44 | 45 | "Add", // 0x05 46 | "Alert", // 0x06 47 | "Archive", // 0x07 48 | "Atomic", // 0x08 49 | "Chal", // 0x09 50 | "Cmd", // 0x0a 51 | "CmdID", // 0x0b 52 | "CmdRef", // 0x0c 53 | "Copy", // 0x0d 54 | "Cred", // 0x0e 55 | "Data", // 0x0f 56 | "Delete", // 0x10 57 | "Exec", // 0x11 58 | "Final", // 0x12 59 | "Get", // 0x13 60 | "Item", // 0x14 61 | "Lang", // 0x15 62 | "LocName", // 0x16 63 | "LocURI", // 0x17 64 | "Map", // 0x18 65 | "MapItem", // 0x19 66 | "Meta", // 0x1a 67 | "MsgID", // 0x1b 68 | "MsgRef", // 0x1c 69 | "NoResp", // 0x1d 70 | "NoResults", // 0x1e 71 | "Put", // 0x1f 72 | "Replace", // 0x20 73 | "RespURI", // 0x21 74 | "Results", // 0x22 75 | "Search", // 0x23 76 | "Sequence", // 0x24 77 | "SessionID", // 0x25 78 | "SftDel", // 0x26 79 | "Source", // 0x27 80 | "SourceRef", // 0x28 81 | "Status", // 0x29 82 | "Sync", // 0x2a 83 | "SyncBody", // 0x2b 84 | "SyncHdr", // 0x2c 85 | "SyncML", // 0x2d 86 | "Target", // 0x2e 87 | "TargetRef", // 0x2f 88 | "Reserved for future use", // 0x30 89 | "VerDTD", // 0x31 90 | "VerProto", // 0x32 91 | "NumberOfChanged",// 0x33 92 | "MoreData", // 0x34 93 | "Field", // 0x35 94 | "Filter", // 0x36 95 | "Record", // 0x37 96 | "FilterType", // 0x38 97 | "SourceParent", // 0x39 98 | "TargetParent", // 0x3a 99 | "Move", // 0x3b 100 | "Correlator" // 0x3c 101 | }; 102 | 103 | public static final String [] TAG_TABLE_1 = { 104 | 105 | // -//SYNCML//DTD MetInf 1.2//EN 106 | 107 | "Anchor", // 0x05 108 | "EMI", // 0x06 109 | "Format", // 0x07 110 | "FreeID", // 0x08 111 | "FreeMem", // 0x09 112 | "Last", // 0x0a 113 | "Mark", // 0x0b 114 | "MaxMsgSize", // 0x0c 115 | "Mem", // 0x0d 116 | "MetInf", // 0x0e 117 | "Next", // 0x0f 118 | "NextNonce", // 0x10 119 | "SharedMem", // 0x11 120 | "Size", // 0x12 121 | "Type", // 0x13 122 | "Version", // 0x14 123 | "MaxObjSize", // 0x15 124 | "FieldLevel" // 0x16 125 | 126 | }; 127 | 128 | public static final String [] TAG_TABLE_2_DM = { 129 | 130 | // -//OMA//DTD-DM-DDF 1.2//EN 131 | 132 | "AccessType", // 0x05 133 | "ACL", // 0x06 134 | "Add", // 0x07 135 | "b64", // 0x08 136 | "bin", // 0x09 137 | "bool", // 0x0a 138 | "chr", // 0x0b 139 | "CaseSense", // 0x0c 140 | "CIS", // 0x0d 141 | "Copy", // 0x0e 142 | "CS", // 0x0f 143 | "date", // 0x10 144 | "DDFName", // 0x11 145 | "DefaultValue", // 0x12 146 | "Delete", // 0x13 147 | "Description", // 0x14 148 | "DDFFormat", // 0x15 149 | "DFProperties", // 0x16 150 | "DFTitle", // 0x17 151 | "DFType", // 0x18 152 | "Dynamic", // 0x19 153 | "Exec", // 0x1a 154 | "float", // 0x1b 155 | "Format", // 0x1c 156 | "Get", // 0x1d 157 | "int", // 0x1e 158 | "Man", // 0x1f 159 | "MgmtTree", // 0x20 160 | "MIME", // 0x21 161 | "Mod", // 0x22 162 | "Name", // 0x23 163 | "Node", // 0x24 164 | "node", // 0x25 165 | "NodeName", // 0x26 166 | "null", // 0x27 167 | "Occurence", // 0x28 168 | "One", // 0x29 169 | "OneOrMore", // 0x2a 170 | "OneOrN", // 0x2b 171 | "Path", // 0x2c 172 | "Permanent", // 0x2d 173 | "Replace", // 0x2e 174 | "RTProperties", // 0x2f 175 | "Scope", // 0x30 176 | "Size", // 0x31 177 | "time", // 0x32 178 | "Title", // 0x33 179 | "TStamp", // 0x34 180 | "Type", // 0x35 181 | "Value", // 0x36 182 | "VerDTD", // 0x37 183 | "VerNo", // 0x38 184 | "xml", // 0x39 185 | "ZeroOrMore", // 0x3a 186 | "ZeroOrN", // 0x3b 187 | "ZeroOrOne" // 0x3c 188 | 189 | }; 190 | 191 | } 192 | 193 | -------------------------------------------------------------------------------- /src/main/java/org/kxml2/wap/wml/Wml.java: -------------------------------------------------------------------------------- 1 | package org.kxml2.wap.wml; 2 | 3 | import org.kxml2.wap.*; 4 | 5 | 6 | /** This class contains the wml coding tables for elements 7 | * and attributes needed by the WmlParser. 8 | */ 9 | 10 | 11 | public abstract class Wml { 12 | 13 | /** Creates a WbxmlParser with the WML code pages set */ 14 | 15 | public static WbxmlParser createParser() { 16 | WbxmlParser p = new WbxmlParser(); 17 | p.setTagTable(0, TAG_TABLE); 18 | p.setAttrStartTable(0, ATTR_START_TABLE); 19 | p.setAttrValueTable(0, ATTR_VALUE_TABLE); 20 | return p; 21 | } 22 | 23 | public static WbxmlSerializer createSerializer() { 24 | WbxmlSerializer s = new WbxmlSerializer(); 25 | s.setTagTable(0, TAG_TABLE); 26 | s.setAttrStartTable(0, ATTR_START_TABLE); 27 | s.setAttrValueTable(0, ATTR_VALUE_TABLE); 28 | return s; 29 | } 30 | 31 | 32 | public static final String [] TAG_TABLE = { 33 | 34 | null, // 05 35 | null, // 06 36 | null, // 07 37 | null, // 08 38 | null, // 09 39 | null, // 0A 40 | null, // 0B 41 | null, // 0C 42 | null, // 0D 43 | null, // 0E 44 | null, // 0F 45 | 46 | null, // 10 47 | null, // 11 48 | null, // 12 49 | null, // 13 50 | null, // 14 51 | null, // 15 52 | null, // 16 53 | null, // 17 54 | null, // 18 55 | null, // 19 56 | null, // 1A 57 | null, // 1B 58 | "a", // 1C 59 | "td", // 1D 60 | "tr", // 1E 61 | "table", // 1F 62 | 63 | "p", // 20 64 | "postfield", // 21 65 | "anchor", // 22 66 | "access", // 23 67 | "b", // 24 68 | "big", // 25 69 | "br", // 26 70 | "card", // 27 71 | "do", // 28 72 | "em", // 29 73 | "fieldset", // 2A 74 | "go", // 2B 75 | "head", // 2C 76 | "i", // 2D 77 | "img", // 2E 78 | "input", // 2F 79 | 80 | "meta", // 30 81 | "noop", // 31 82 | "prev", // 32 83 | "onevent", // 33 84 | "optgroup", // 34 85 | "option", // 35 86 | "refresh", // 36 87 | "select", // 37 88 | "small", // 38 89 | "strong", // 39 90 | null, // 3A 91 | "template", // 3B 92 | "timer", // 3C 93 | "u", // 3D 94 | "setvar", // 3E 95 | "wml", // 3F 96 | }; 97 | 98 | 99 | public static final String [] ATTR_START_TABLE = { 100 | "accept-charset", // 05 101 | "align=bottom", // 06 102 | "align=center", // 07 103 | "align=left", // 08 104 | "align=middle", // 09 105 | "align=right", // 0A 106 | "align=top", // 0B 107 | "alt", // 0C 108 | "content", // 0D 109 | null, // 0E 110 | "domain", // 0F 111 | 112 | "emptyok=false", // 10 113 | "emptyok=true", // 11 114 | "format", // 12 115 | "height", // 13 116 | "hspace", // 14 117 | "ivalue", // 15 118 | "iname", // 16 119 | null, // 17 120 | "label", // 18 121 | "localsrc", // 19 122 | "maxlength", // 1A 123 | "method=get", // 1B 124 | "method=post", // 1C 125 | "mode=nowrap", // 1D 126 | "mode=wrap", // 1E 127 | "multiple=false", // 1F 128 | 129 | "multiple=true", // 20 130 | "name", // 21 131 | "newcontext=false", // 22 132 | "newcontext=true", // 23 133 | "onpick", // 24 134 | "onenterbackward", // 25 135 | "onenterforward", // 26 136 | "ontimer", // 27 137 | "optimal=false", // 28 138 | "optimal=true", // 29 139 | "path", // 2A 140 | null, // 2B 141 | null, // 2C 142 | null, // 2D 143 | "scheme", // 2E 144 | "sendreferer=false", // 2F 145 | 146 | "sendreferer=true", // 30 147 | "size", // 31 148 | "src", // 32 149 | "ordered=true", // 33 150 | "ordered=false", // 34 151 | "tabindex", // 35 152 | "title", // 36 153 | "type", // 37 154 | "type=accept", // 38 155 | "type=delete", // 39 156 | "type=help", // 3A 157 | "type=password", // 3B 158 | "type=onpick", // 3C 159 | "type=onenterbackward", // 3D 160 | "type=onenterforward", // 3E 161 | "type=ontimer", // 3F 162 | 163 | null, // 40 164 | null, // 41 165 | null, // 42 166 | null, // 43 167 | null, // 44 168 | "type=options", // 45 169 | "type=prev", // 46 170 | "type=reset", // 47 171 | "type=text", // 48 172 | "type=vnd.", // 49 173 | "href", // 4A 174 | "href=http://", // 4B 175 | "href=https://", // 4C 176 | "value", // 4D 177 | "vspace", // 4E 178 | "width", // 4F 179 | 180 | "xml:lang", // 50 181 | null, // 51 182 | "align", // 52 183 | "columns", // 53 184 | "class", // 54 185 | "id", // 55 186 | "forua=false", // 56 187 | "forua=true", // 57 188 | "src=http://", // 58 189 | "src=https://", // 59 190 | "http-equiv", // 5A 191 | "http-equiv=Content-Type", // 5B 192 | "content=application/vnd.wap.wmlc;charset=", // 5C 193 | "http-equiv=Expires", // 5D 194 | null, // 5E 195 | null, // 5F 196 | }; 197 | 198 | 199 | public static final String [] ATTR_VALUE_TABLE = { 200 | ".com/", // 85 201 | ".edu/", // 86 202 | ".net/", // 87 203 | ".org/", // 88 204 | "accept", // 89 205 | "bottom", // 8A 206 | "clear", // 8B 207 | "delete", // 8C 208 | "help", // 8D 209 | "http://", // 8E 210 | "http://www.", // 8F 211 | 212 | "https://", // 90 213 | "https://www.", // 91 214 | null, // 92 215 | "middle", // 93 216 | "nowrap", // 94 217 | "onpick", // 95 218 | "onenterbackward", // 96 219 | "onenterforward", // 97 220 | "ontimer", // 98 221 | "options", // 99 222 | "password", // 9A 223 | "reset", // 9B 224 | null, // 9C 225 | "text", // 9D 226 | "top", // 9E 227 | "unknown", // 9F 228 | 229 | "wrap", // A0 230 | "www.", // A1 231 | }; 232 | } 233 | 234 | -------------------------------------------------------------------------------- /src/main/java/org/kxml2/wap/wv/WV.java: -------------------------------------------------------------------------------- 1 | package org.kxml2.wap.wv; 2 | 3 | import java.io.IOException; 4 | 5 | import org.kxml2.wap.*; 6 | 7 | /* 8 | 9 | * WV.java 10 | 11 | * 12 | 13 | * Created on 25 September 2003, 10:40 14 | 15 | */ 16 | 17 | 18 | 19 | 20 | 21 | /** 22 | * Wireless Village CSP 1.1 ("OMA-WV-CSP-V1_1-20021001-A.pdf") 23 | * Wireless Village CSP 1.2 ("OMA-IMPS-WV-CSP_WBXML-v1_2-20030221-C.PDF") 24 | * There are some bugs in the 1.2 spec but this is Ok. 1.2 is candidate 25 | * 26 | 27 | * @author Bogdan Onoiu 28 | 29 | */ 30 | 31 | public abstract class WV { 32 | 33 | 34 | 35 | 36 | 37 | public static WbxmlParser createParser () throws IOException { 38 | 39 | WbxmlParser parser = new WbxmlParser(); 40 | 41 | parser.setTagTable (0, WV.tagTablePage0); 42 | parser.setTagTable (1, WV.tagTablePage1); 43 | parser.setTagTable (2, WV.tagTablePage2); 44 | parser.setTagTable (3, WV.tagTablePage3); 45 | parser.setTagTable (4, WV.tagTablePage4); 46 | parser.setTagTable (5, WV.tagTablePage5); 47 | parser.setTagTable (6, WV.tagTablePage6); 48 | parser.setTagTable (7, WV.tagTablePage7); 49 | parser.setTagTable (8, WV.tagTablePage8); 50 | parser.setTagTable (9, WV.tagTablePage9); 51 | parser.setTagTable (10, WV.tagTablePageA); 52 | 53 | parser.setAttrStartTable (0, WV.attrStartTable); 54 | 55 | parser.setAttrValueTable (0, WV.attrValueTable); 56 | 57 | return parser; 58 | } 59 | 60 | 61 | 62 | public static final String [] tagTablePage0 = { 63 | /* Common ... continue on Page 0x09 */ 64 | "Acceptance", //0x00, 0x05 65 | "AddList", //0x00, 0x06 66 | "AddNickList", //0x00, 0x07 67 | "SName", //0x00, 0x08 68 | "WV-CSP-Message", //0x00, 0x09 69 | "ClientID", //0x00, 0x0A 70 | "Code", //0x00, 0x0B 71 | "ContactList", //0x00, 0x0C 72 | "ContentData", //0x00, 0x0D 73 | "ContentEncoding",//0x00, 0x0E 74 | "ContentSize", //0x00, 0x0F 75 | "ContentType", //0x00, 0x10 76 | "DateTime", //0x00, 0x11 77 | "Description", //0x00, 0x12 78 | "DetailedResult", //0x00, 0x13 79 | "EntityList", //0x00, 0x14 80 | "Group", //0x00, 0x15 81 | "GroupID", //0x00, 0x16 82 | "GroupList", //0x00, 0x17 83 | "InUse", //0x00, 0x18 84 | "Logo", //0x00, 0x19 85 | "MessageCount", //0x00, 0x1A 86 | "MessageID", //0x00, 0x1B 87 | "MessageURI", //0x00, 0x1C 88 | "MSISDN", //0x00, 0x1D 89 | "Name", //0x00, 0x1E 90 | "NickList", //0x00, 0x1F 91 | "NickName", //0x00, 0x20 92 | "Poll", //0x00, 0x21 93 | "Presence", //0x00, 0x22 94 | "PresenceSubList",//0x00, 0x23 95 | "PresenceValue", //0x00, 0x24 96 | "Property", //0x00, 0x25 97 | "Qualifier", //0x00, 0x26 98 | "Recipient", //0x00, 0x27 99 | "RemoveList", //0x00, 0x28 100 | "RemoveNickList", //0x00, 0x29 101 | "Result", //0x00, 0x2A 102 | "ScreenName", //0x00, 0x2B 103 | "Sender", //0x00, 0x2C 104 | "Session", //0x00, 0x2D 105 | "SessionDescriptor",//0x00, 0x2E 106 | "SessionID", //0x00, 0x2F 107 | "SessionType", //0x00, 0x30 108 | "Status", //0x00, 0x31 109 | "Transaction", //0x00, 0x32 110 | "TransactionContent",//0x00, 0x33 111 | "TransactionDescriptor",//0x00, 0x34 112 | "TransactionID", //0x00, 0x35 113 | "TransactionMode",//0x00, 0x36 114 | "URL", //0x00, 0x37 115 | "URLList", //0x00, 0x38 116 | "User", //0x00, 0x39 117 | "UserID", //0x00, 0x3A 118 | "UserList", //0x00, 0x3B 119 | "Validity", //0x00, 0x3C 120 | "Value", //0x00, 0x3D 121 | }; 122 | 123 | public static final String [] tagTablePage1 = { 124 | /* Access ... continue on Page 0x0A */ 125 | "AllFunctions", // 0x01, 0x05 126 | "AllFunctionsRequest", // 0x01, 0x06 127 | "CancelInvite-Request", // 0x01, 0x07 128 | "CancelInviteUser-Request", // 0x01, 0x08 129 | "Capability", // 0x01, 0x09 130 | "CapabilityList", // 0x01, 0x0A 131 | "CapabilityRequest", // 0x01, 0x0B 132 | "ClientCapability-Request", // 0x01, 0x0C 133 | "ClientCapability-Response",// 0x01, 0x0D 134 | "DigestBytes", // 0x01, 0x0E 135 | "DigestSchema", // 0x01, 0x0F 136 | "Disconnect", // 0x01, 0x10 137 | "Functions", // 0x01, 0x11 138 | "GetSPInfo-Request", // 0x01, 0x12 139 | "GetSPInfo-Response", // 0x01, 0x13 140 | "InviteID", // 0x01, 0x14 141 | "InviteNote", // 0x01, 0x15 142 | "Invite-Request", // 0x01, 0x16 143 | "Invite-Response", // 0x01, 0x17 144 | "InviteType", // 0x01, 0x18 145 | "InviteUser-Request", // 0x01, 0x19 146 | "InviteUser-Response", // 0x01, 0x1A 147 | "KeepAlive-Request", // 0x01, 0x1B 148 | "KeepAliveTime", // 0x01, 0x1C 149 | "Login-Request", // 0x01, 0x1D 150 | "Login-Response", // 0x01, 0x1E 151 | "Logout-Request", // 0x01, 0x1F 152 | "Nonce", // 0x01, 0x20 153 | "Password", // 0x01, 0x21 154 | "Polling-Request", // 0x01, 0x22 155 | "ResponseNote", // 0x01, 0x23 156 | "SearchElement", // 0x01, 0x24 157 | "SearchFindings", // 0x01, 0x25 158 | "SearchID", // 0x01, 0x26 159 | "SearchIndex", // 0x01, 0x27 160 | "SearchLimit", // 0x01, 0x28 161 | "KeepAlive-Response", // 0x01, 0x29 162 | "SearchPairList", // 0x01, 0x2A 163 | "Search-Request", // 0x01, 0x2B 164 | "Search-Response", // 0x01, 0x2C 165 | "SearchResult", // 0x01, 0x2D 166 | "Service-Request", // 0x01, 0x2E 167 | "Service-Response", // 0x01, 0x2F 168 | "SessionCookie", // 0x01, 0x30 169 | "StopSearch-Request", // 0x01, 0x31 170 | "TimeToLive", // 0x01, 0x32 171 | "SearchString", // 0x01, 0x33 172 | "CompletionFlag", // 0x01, 0x34 173 | null, // 0x01, 0x35 174 | "ReceiveList", // 0x01, 0x36 /* WV 1.2 */ 175 | "VerifyID-Request", // 0x01, 0x37 /* WV 1.2 */ 176 | "Extended-Request", // 0x01, 0x38 /* WV 1.2 */ 177 | "Extended-Response", // 0x01, 0x39 /* WV 1.2 */ 178 | "AgreedCapabilityList", // 0x01, 0x3A /* WV 1.2 */ 179 | "Extended-Data", // 0x01, 0x3B /* WV 1.2 */ 180 | "OtherServer", // 0x01, 0x3C /* WV 1.2 */ 181 | "PresenceAttributeNSName",//0x01, 0x3D /* WV 1.2 */ 182 | "SessionNSName", // 0x01, 0x3E /* WV 1.2 */ 183 | "TransactionNSName", // 0x01, 0x3F /* WV 1.2 */ 184 | }; 185 | 186 | public static final String [] tagTablePage2 = { 187 | /* Service ... continue on Page 0x08 */ 188 | "ADDGM", // 0x02, 0x05 189 | "AttListFunc", // 0x02, 0x06 190 | "BLENT", // 0x02, 0x07 191 | "CAAUT", // 0x02, 0x08 192 | "CAINV", // 0x02, 0x09 193 | "CALI", // 0x02, 0x0A 194 | "CCLI", // 0x02, 0x0B 195 | "ContListFunc", // 0x02, 0x0C 196 | "CREAG", // 0x02, 0x0D 197 | "DALI", // 0x02, 0x0E 198 | "DCLI", // 0x02, 0x0F 199 | "DELGR", // 0x02, 0x10 200 | "FundamentalFeat",//0x02, 0x11 201 | "FWMSG", // 0x02, 0x12 202 | "GALS", // 0x02, 0x13 203 | "GCLI", // 0x02, 0x14 204 | "GETGM", // 0x02, 0x15 205 | "GETGP", // 0x02, 0x16 206 | "GETLM", // 0x02, 0x17 207 | "GETM", // 0x02, 0x18 208 | "GETPR", // 0x02, 0x19 209 | "GETSPI", // 0x02, 0x1A 210 | "GETWL", // 0x02, 0x1B 211 | "GLBLU", // 0x02, 0x1C 212 | "GRCHN", // 0x02, 0x1D 213 | "GroupAuthFunc",// 0x02, 0x1E 214 | "GroupFeat", // 0x02, 0x1F 215 | "GroupMgmtFunc",// 0x02, 0x20 216 | "GroupUseFunc", // 0x02, 0x21 217 | "IMAuthFunc", // 0x02, 0x22 218 | "IMFeat", // 0x02, 0x23 219 | "IMReceiveFunc",// 0x02, 0x24 220 | "IMSendFunc", // 0x02, 0x25 221 | "INVIT", // 0x02, 0x26 222 | "InviteFunc", // 0x02, 0x27 223 | "MBRAC", // 0x02, 0x28 224 | "MCLS", // 0x02, 0x29 225 | "MDELIV", // 0x02, 0x2A 226 | "NEWM", // 0x02, 0x2B 227 | "NOTIF", // 0x02, 0x2C 228 | "PresenceAuthFunc",//0x02, 0x2D 229 | "PresenceDeliverFunc",//0x02, 0x2E 230 | "PresenceFeat", // 0x02, 0x2F 231 | "REACT", // 0x02, 0x30 232 | "REJCM", // 0x02, 0x31 233 | "REJEC", // 0x02, 0x32 234 | "RMVGM", // 0x02, 0x33 235 | "SearchFunc", // 0x02, 0x34 236 | "ServiceFunc", // 0x02, 0x35 237 | "SETD", // 0x02, 0x36 238 | "SETGP", // 0x02, 0x37 239 | "SRCH", // 0x02, 0x38 240 | "STSRC", // 0x02, 0x39 241 | "SUBGCN", // 0x02, 0x3A 242 | "UPDPR", // 0x02, 0x3B 243 | "WVCSPFeat", // 0x02, 0x3C 244 | "MF", // 0x02, 0x3D /* WV 1.2 */ 245 | "MG", // 0x02, 0x3E /* WV 1.2 */ 246 | "MM" // 0x02, 0x3F /* WV 1.2 */ 247 | }; 248 | 249 | public static final String [] tagTablePage3 = { 250 | /* Client Capability */ 251 | "AcceptedCharset", // 0x03, 0x05 252 | "AcceptedContentLength", // 0x03, 0x06 253 | "AcceptedContentType", // 0x03, 0x07 254 | "AcceptedTransferEncoding", // 0x03, 0x08 255 | "AnyContent", // 0x03, 0x09 256 | "DefaultLanguage", // 0x03, 0x0A 257 | "InitialDeliveryMethod", // 0x03, 0x0B 258 | "MultiTrans", // 0x03, 0x0C 259 | "ParserSize", // 0x03, 0x0D 260 | "ServerPollMin", // 0x03, 0x0E 261 | "SupportedBearer", // 0x03, 0x0F 262 | "SupportedCIRMethod", // 0x03, 0x10 263 | "TCPAddress", // 0x03, 0x11 264 | "TCPPort", // 0x03, 0x12 265 | "UDPPort" // 0x03, 0x13 266 | }; 267 | 268 | public static final String [] tagTablePage4 = { 269 | /* Presence Primitive */ 270 | "CancelAuth-Request", // 0x04, 0x05 271 | "ContactListProperties", // 0x04, 0x06 272 | "CreateAttributeList-Request", // 0x04, 0x07 273 | "CreateList-Request", // 0x04, 0x08 274 | "DefaultAttributeList", // 0x04, 0x09 275 | "DefaultContactList", // 0x04, 0x0A 276 | "DefaultList", // 0x04, 0x0B 277 | "DeleteAttributeList-Request", // 0x04, 0x0C 278 | "DeleteList-Request", // 0x04, 0x0D 279 | "GetAttributeList-Request", // 0x04, 0x0E 280 | "GetAttributeList-Response", // 0x04, 0x0F 281 | "GetList-Request", // 0x04, 0x10 282 | "GetList-Response", // 0x04, 0x11 283 | "GetPresence-Request", // 0x04, 0x12 284 | "GetPresence-Response", // 0x04, 0x13 285 | "GetWatcherList-Request", // 0x04, 0x14 286 | "GetWatcherList-Response", // 0x04, 0x15 287 | "ListManage-Request", // 0x04, 0x16 288 | "ListManage-Response", // 0x04, 0x17 289 | "UnsubscribePresence-Request", // 0x04, 0x18 290 | "PresenceAuth-Request", // 0x04, 0x19 291 | "PresenceAuth-User", // 0x04, 0x1A 292 | "PresenceNotification-Request", // 0x04, 0x1B 293 | "UpdatePresence-Request", // 0x04, 0x1C 294 | "SubscribePresence-Request", // 0x04, 0x1D 295 | "Auto-Subscribe", // 0x04, 0x1E /* WV 1.2 */ 296 | "GetReactiveAuthStatus-Request",// 0x04, 0x1F /* WV 1.2 */ 297 | "GetReactiveAuthStatus-Response",// 0x04, 0x20 /* WV 1.2 */ 298 | }; 299 | 300 | public static final String [] tagTablePage5 = { 301 | /* Presence Attribute */ 302 | "Accuracy", // 0x05, 0x05 303 | "Address", // 0x05, 0x06 304 | "AddrPref", // 0x05, 0x07 305 | "Alias", // 0x05, 0x08 306 | "Altitude", // 0x05, 0x09 307 | "Building", // 0x05, 0x0A 308 | "Caddr", // 0x05, 0x0B 309 | "City", // 0x05, 0x0C 310 | "ClientInfo", // 0x05, 0x0D 311 | "ClientProducer", // 0x05, 0x0E 312 | "ClientType", // 0x05, 0x0F 313 | "ClientVersion", // 0x05, 0x10 314 | "CommC", // 0x05, 0x11 315 | "CommCap", // 0x05, 0x12 316 | "ContactInfo", // 0x05, 0x13 317 | "ContainedvCard", // 0x05, 0x14 318 | "Country", // 0x05, 0x15 319 | "Crossing1", // 0x05, 0x16 320 | "Crossing2", // 0x05, 0x17 321 | "DevManufacturer", // 0x05, 0x18 322 | "DirectContent", // 0x05, 0x19 323 | "FreeTextLocation", // 0x05, 0x1A 324 | "GeoLocation", // 0x05, 0x1B 325 | "Language", // 0x05, 0x1C 326 | "Latitude", // 0x05, 0x1D 327 | "Longitude", // 0x05, 0x1E 328 | "Model", // 0x05, 0x1F 329 | "NamedArea", // 0x05, 0x20 330 | "OnlineStatus", // 0x05, 0x21 331 | "PLMN", // 0x05, 0x22 332 | "PrefC", // 0x05, 0x23 333 | "PreferredContacts",// 0x05, 0x24 334 | "PreferredLanguage",// 0x05, 0x25 335 | "PreferredContent", // 0x05, 0x26 336 | "PreferredvCard", // 0x05, 0x27 337 | "Registration", // 0x05, 0x28 338 | "StatusContent", // 0x05, 0x29 339 | "StatusMood", // 0x05, 0x2A 340 | "StatusText", // 0x05, 0x2B 341 | "Street", // 0x05, 0x2C 342 | "TimeZone", // 0x05, 0x2D 343 | "UserAvailability", // 0x05, 0x2E 344 | "Cap", // 0x05, 0x2F 345 | "Cname", // 0x05, 0x30 346 | "Contact", // 0x05, 0x31 347 | "Cpriority", // 0x05, 0x32 348 | "Cstatus", // 0x05, 0x33 349 | "Note", // 0x05, 0x34 /* WV 1.2 */ 350 | "Zone", // 0x05, 0x35 351 | null, 352 | "Inf_link", // 0x05, 0x37 /* WV 1.2 */ 353 | "InfoLink", // 0x05, 0x38 /* WV 1.2 */ 354 | "Link", // 0x05, 0x39 /* WV 1.2 */ 355 | "Text", // 0x05, 0x3A /* WV 1.2 */ 356 | }; 357 | 358 | public static final String [] tagTablePage6 = { 359 | /* Messaging */ 360 | "BlockList", // 0x06, 0x05 361 | // "BlockUser-Request", // 0x06, 0x06 //This is a bug in the spec 362 | "BlockEntity-Request", // 0x06, 0x06 363 | "DeliveryMethod", // 0x06, 0x07 364 | "DeliveryReport", // 0x06, 0x08 365 | "DeliveryReport-Request", // 0x06, 0x09 366 | "ForwardMessage-Request", // 0x06, 0x0A 367 | "GetBlockedList-Request", // 0x06, 0x0B 368 | "GetBlockedList-Response", // 0x06, 0x0C 369 | "GetMessageList-Request", // 0x06, 0x0D 370 | "GetMessageList-Response", // 0x06, 0x0E 371 | "GetMessage-Request", // 0x06, 0x0F 372 | "GetMessage-Response", // 0x06, 0x10 373 | "GrantList", // 0x06, 0x11 374 | "MessageDelivered", // 0x06, 0x12 375 | "MessageInfo", // 0x06, 0x13 376 | "MessageNotification", // 0x06, 0x14 377 | "NewMessage", // 0x06, 0x15 378 | "RejectMessage-Request", // 0x06, 0x16 379 | "SendMessage-Request", // 0x06, 0x17 380 | "SendMessage-Response", // 0x06, 0x18 381 | "SetDeliveryMethod-Request",// 0x06, 0x19 382 | "DeliveryTime", // 0x06, 0x1A 383 | }; 384 | 385 | public static final String [] tagTablePage7 = { 386 | /* Group */ 387 | "AddGroupMembers-Request", // 0x07, 0x05 388 | "Admin", // 0x07, 0x06 389 | "CreateGroup-Request", // 0x07, 0x07 390 | "DeleteGroup-Request", // 0x07, 0x08 391 | "GetGroupMembers-Request", // 0x07, 0x09 392 | "GetGroupMembers-Response", // 0x07, 0x0A 393 | "GetGroupProps-Request", // 0x07, 0x0B 394 | "GetGroupProps-Response", // 0x07, 0x0C 395 | "GroupChangeNotice", // 0x07, 0x0D 396 | "GroupProperties", // 0x07, 0x0E 397 | "Joined", // 0x07, 0x0F 398 | "JoinedRequest", // 0x07, 0x10 399 | "JoinGroup-Request", // 0x07, 0x11 400 | "JoinGroup-Response", // 0x07, 0x12 401 | "LeaveGroup-Request", // 0x07, 0x13 402 | "LeaveGroup-Response", // 0x07, 0x14 403 | "Left", // 0x07, 0x15 404 | "MemberAccess-Request", // 0x07, 0x16 405 | "Mod", // 0x07, 0x17 406 | "OwnProperties", // 0x07, 0x18 407 | "RejectList-Request", // 0x07, 0x19 408 | "RejectList-Response", // 0x07, 0x1A 409 | "RemoveGroupMembers-Request",// 0x07, 0x1B 410 | "SetGroupProps-Request", // 0x07, 0x1C 411 | "SubscribeGroupNotice-Request", // 0x07, 0x1D 412 | "SubscribeGroupNotice-Response",// 0x07, 0x1E 413 | "Users", // 0x07, 0x1F 414 | "WelcomeNote", // 0x07, 0x20 415 | "JoinGroup", // 0x07, 0x21 416 | "SubscribeNotification", // 0x07, 0x22 417 | "SubscribeType", // 0x07, 0x23 418 | "GetJoinedUsers-Request", // 0x07, 0x24 /* WV 1.2 */ 419 | "GetJoinedUsers-Response", // 0x07, 0x25 /* WV 1.2 */ 420 | "AdminMapList", // 0x07, 0x26 /* WV 1.2 */ 421 | "AdminMapping", // 0x07, 0x27 /* WV 1.2 */ 422 | "Mapping", // 0x07, 0x28 /* WV 1.2 */ 423 | "ModMapping", // 0x07, 0x29 /* WV 1.2 */ 424 | "UserMapList", // 0x07, 0x2A /* WV 1.2 */ 425 | "UserMapping", // 0x07, 0x2B /* WV 1.2 */ 426 | }; 427 | 428 | public static final String [] tagTablePage8 = { 429 | /* Service ... continued */ 430 | "MP", // 0x08, 0x05 /* WV 1.2 */ 431 | "GETAUT", // 0x08, 0x06 /* WV 1.2 */ 432 | "GETJU", // 0x08, 0x07 /* WV 1.2 */ 433 | "VRID", // 0x08, 0x08 /* WV 1.2 */ 434 | "VerifyIDFunc", // 0x08, 0x09 /* WV 1.2 */ 435 | }; 436 | 437 | public static final String [] tagTablePage9 = { 438 | /* Common ... continued */ 439 | "CIR", // 0x09, 0x05 /* WV 1.2 */ 440 | "Domain", // 0x09, 0x06 /* WV 1.2 */ 441 | "ExtBlock", // 0x09, 0x07 /* WV 1.2 */ 442 | "HistoryPeriod", // 0x09, 0x08 /* WV 1.2 */ 443 | "IDList", // 0x09, 0x09 /* WV 1.2 */ 444 | "MaxWatcherList", // 0x09, 0x0A /* WV 1.2 */ 445 | "ReactiveAuthState", // 0x09, 0x0B /* WV 1.2 */ 446 | "ReactiveAuthStatus", // 0x09, 0x0C /* WV 1.2 */ 447 | "ReactiveAuthStatusList", // 0x09, 0x0D /* WV 1.2 */ 448 | "Watcher", // 0x09, 0x0E /* WV 1.2 */ 449 | "WatcherStatus" // 0x09, 0x0F /* WV 1.2 */ 450 | }; 451 | 452 | public static final String [] tagTablePageA = { 453 | /* Access ... continued */ 454 | "WV-CSP-NSDiscovery-Request", //0x0A, 0x05 /* WV 1.2 */ 455 | "WV-CSP-NSDiscovery-Response", //0x0A, 0x06 /* WV 1.2 */ 456 | "VersionList" //0x0A, 0x07 /* WV 1.2 */ 457 | }; 458 | 459 | public static final String [] attrStartTable = { 460 | "xmlns=http://www.wireless-village.org/CSP",// 0x00, 0x05 461 | "xmlns=http://www.wireless-village.org/PA", // 0x00, 0x06 462 | "xmlns=http://www.wireless-village.org/TRC",// 0x00, 0x07 463 | "xmlns=http://www.openmobilealliance.org/DTD/WV-CSP", // 0x00, 0x08 464 | "xmlns=http://www.openmobilealliance.org/DTD/WV-PA", // 0x00, 0x09 465 | "xmlns=http://www.openmobilealliance.org/DTD/WV-TRC", // 0x00, 0x0A 466 | }; 467 | 468 | public static final String [] attrValueTable = { 469 | 470 | "AccessType", // 0x00 /* Common value token */ 471 | "ActiveUsers", // 0x01 /* Common value token */ 472 | "Admin", // 0x02 /* Common value token */ 473 | "application/", // 0x03 /* Common value token */ 474 | "application/vnd.wap.mms-message", // 0x04 /* Common value token */ 475 | "application/x-sms", // 0x05 /* Common value token */ 476 | "AutoJoin", // 0x06 /* Common value token */ 477 | "BASE64", // 0x07 /* Common value token */ 478 | "Closed", // 0x08 /* Common value token */ 479 | "Default", // 0x09 /* Common value token */ 480 | "DisplayName", // 0x0a /* Common value token */ 481 | "F", // 0x0b /* Common value token */ 482 | "G", // 0x0c /* Common value token */ 483 | "GR", // 0x0d /* Common value token */ 484 | "http://", // 0x0e /* Common value token */ 485 | "https://", // 0x0f /* Common value token */ 486 | "image/", // 0x10 /* Common value token */ 487 | "Inband", // 0x11 /* Common value token */ 488 | "IM", // 0x12 /* Common value token */ 489 | "MaxActiveUsers", // 0x13 /* Common value token */ 490 | "Mod", // 0x14 /* Common value token */ 491 | "Name", // 0x15 /* Common value token */ 492 | "None", // 0x16 /* Common value token */ 493 | "N", // 0x17 /* Common value token */ 494 | "Open", // 0x18 /* Common value token */ 495 | "Outband", // 0x19 /* Common value token */ 496 | "PR", // 0x1a /* Common value token */ 497 | "Private", // 0x1b /* Common value token */ 498 | "PrivateMessaging", // 0x1c /* Common value token */ 499 | "PrivilegeLevel", // 0x1d /* Common value token */ 500 | "Public", // 0x1e /* Common value token */ 501 | "P", // 0x1f /* Common value token */ 502 | "Request", // 0x20 /* Common value token */ 503 | "Response", // 0x21 /* Common value token */ 504 | "Restricted", // 0x22 /* Common value token */ 505 | "ScreenName", // 0x23 /* Common value token */ 506 | "Searchable", // 0x24 /* Common value token */ 507 | "S", // 0x25 /* Common value token */ 508 | "SC", // 0x26 /* Common value token */ 509 | "text/", // 0x27 /* Common value token */ 510 | "text/plain", // 0x28 /* Common value token */ 511 | "text/x-vCalendar", // 0x29 /* Common value token */ 512 | "text/x-vCard", // 0x2a /* Common value token */ 513 | "Topic", // 0x2b /* Common value token */ 514 | "T", // 0x2c /* Common value token */ 515 | "Type", // 0x2d /* Common value token */ 516 | "U", // 0x2e /* Common value token */ 517 | "US", // 0x2f /* Common value token */ 518 | "www.wireless-village.org", // 0x30 /* Common value token */ 519 | "AutoDelete", // 0x31 /* Common value token */ /* WV 1.2 */ 520 | "GM", // 0x32 /* Common value token */ /* WV 1.2 */ 521 | "Validity", // 0x33 /* Common value token */ /* WV 1.2 */ 522 | "ShowID", // 0x34 /* Common value token */ /* WV 1.2 */ 523 | "GRANTED", // 0x35 /* Common value token */ /* WV 1.2 */ 524 | "PENDING", // 0x36 /* Common value token */ /* WV 1.2 */ 525 | null, // 0x37 526 | null, // 0x38 527 | null, // 0x39 528 | null, // 0x3a 529 | null, // 0x3b 530 | null, // 0x3c 531 | "GROUP_ID", // 0x3d /* Access value token */ 532 | "GROUP_NAME", // 0x3e /* Access value token */ 533 | "GROUP_TOPIC", // 0x3f /* Access value token */ 534 | "GROUP_USER_ID_JOINED", // 0x40 /* Access value token */ 535 | "GROUP_USER_ID_OWNER", // 0x41 /* Access value token */ 536 | "HTTP", // 0x42 /* Access value token */ 537 | "SMS", // 0x43 /* Access value token */ 538 | "STCP", // 0x44 /* Access value token */ 539 | "SUDP", // 0x45 /* Access value token */ 540 | "USER_ALIAS", // 0x46 /* Access value token */ 541 | "USER_EMAIL_ADDRESS", // 0x47 /* Access value token */ 542 | "USER_FIRST_NAME", // 0x48 /* Access value token */ 543 | "USER_ID", // 0x49 /* Access value token */ 544 | "USER_LAST_NAME", // 0x4a /* Access value token */ 545 | "USER_MOBILE_NUMBER", // 0x4b /* Access value token */ 546 | "USER_ONLINE_STATUS", // 0x4c /* Access value token */ 547 | "WAPSMS", // 0x4d /* Access value token */ 548 | "WAPUDP", // 0x4e /* Access value token */ 549 | "WSP", // 0x4f /* Access value token */ 550 | "GROUP_USER_ID_AUTOJOIN", // 0x50 /* Access value token */ /* WV 1.2 */ 551 | null, // 0x51 552 | null, // 0x52 553 | null, // 0x53 554 | null, // 0x54 555 | null, // 0x55 556 | null, // 0x56 557 | null, // 0x57 558 | null, // 0x58 559 | null, // 0x59 560 | null, // 0x5a 561 | "ANGRY", // 0x5b /* Presence value token */ 562 | "ANXIOUS", // 0x5c /* Presence value token */ 563 | "ASHAMED", // 0x5d /* Presence value token */ 564 | "AUDIO_CALL", // 0x5e /* Presence value token */ 565 | "AVAILABLE", // 0x5f /* Presence value token */ 566 | "BORED", // 0x60 /* Presence value token */ 567 | "CALL", // 0x61 /* Presence value token */ 568 | "CLI", // 0x62 /* Presence value token */ 569 | "COMPUTER", // 0x63 /* Presence value token */ 570 | "DISCREET", // 0x64 /* Presence value token */ 571 | "EMAIL", // 0x65 /* Presence value token */ 572 | "EXCITED", // 0x66 /* Presence value token */ 573 | "HAPPY", // 0x67 /* Presence value token */ 574 | "IM", // 0x68 /* Presence value token */ 575 | "IM_OFFLINE", // 0x69 /* Presence value token */ 576 | "IM_ONLINE", // 0x6a /* Presence value token */ 577 | "IN_LOVE", // 0x6b /* Presence value token */ 578 | "INVINCIBLE", // 0x6c /* Presence value token */ 579 | "JEALOUS", // 0x6d /* Presence value token */ 580 | "MMS", // 0x6e /* Presence value token */ 581 | "MOBILE_PHONE", // 0x6f /* Presence value token */ 582 | "NOT_AVAILABLE", // 0x70 /* Presence value token */ 583 | "OTHER", // 0x71 /* Presence value token */ 584 | "PDA", // 0x72 /* Presence value token */ 585 | "SAD", // 0x73 /* Presence value token */ 586 | "SLEEPY", // 0x74 /* Presence value token */ 587 | "SMS", // 0x75 /* Presence value token */ 588 | "VIDEO_CALL", // 0x76 /* Presence value token */ 589 | "VIDEO_STREAM", // 0x77 /* Presence value token */ 590 | }; 591 | 592 | 593 | } -------------------------------------------------------------------------------- /src/main/resources/META-INF/services/org.xmlpull.v1.XmlPullParserFactory: -------------------------------------------------------------------------------- 1 | org.kxml2.io.KXmlParser 2 | org.kxml2.io.KXmlSerializer 3 | -------------------------------------------------------------------------------- /src/test/java/TestWb.java: -------------------------------------------------------------------------------- 1 | // Test case contributed by Andy Bailey 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.File; 6 | import java.io.FileNotFoundException; 7 | import java.io.FileOutputStream; 8 | import java.io.IOException; 9 | import java.io.StringReader; 10 | import java.io.StringWriter; 11 | import java.nio.charset.StandardCharsets; 12 | import junit.framework.TestCase; 13 | 14 | import org.kxml2.wap.Wbxml; 15 | import org.kxml2.wap.WbxmlSerializer; 16 | import org.xmlpull.v1.XmlPullParser; 17 | import org.xmlpull.v1.XmlPullParserException; 18 | import org.xmlpull.v1.XmlPullParserFactory; 19 | import org.xmlpull.v1.XmlSerializer; 20 | 21 | public class TestWb extends TestCase 22 | { 23 | public void disabled_testWb() throws IllegalArgumentException,IllegalStateException, FileNotFoundException, IOException 24 | { 25 | File file=new File("compress.xml"); 26 | 27 | WbxmlSerializer xs = new WbxmlSerializer(); 28 | boolean compress=true; 29 | 30 | xs.setOutput(new FileOutputStream(file),null); 31 | //xs.setOutput(System.out,"UTF-8"); 32 | //xs.docdecl(); 33 | //xs.setPrefix("","http://www.hazlorealidad.com"); 34 | //xs.startDocument("UTF-8",true); 35 | xs.startDocument(null,null); 36 | //xs.comment("Comment"); 37 | xs.startTag(null,"root"); 38 | xs.startTag(null,"y"); 39 | xs.attribute(null,"name","value"); 40 | xs.writeWapExtension(Wbxml.EXT_T_1,new Integer(2)); 41 | xs.endTag(null,"y"); 42 | xs.startTag(null,"y"); 43 | xs.attribute(null,"name","value"); 44 | xs.writeWapExtension(Wbxml.EXT_T_1,new Integer(2)); 45 | xs.endTag(null,"y"); 46 | xs.endTag(null,"root"); 47 | xs.endDocument(); 48 | xs.flush(); 49 | long len=file.length(); 50 | System.out.println(len+" bytes"); 51 | } 52 | 53 | // Using hex code units to be sure that the system charset does not affect the behavior 54 | private static final String EMOJI_CHAR = "\ud83d\ude48"; 55 | 56 | private static final String XML_TO_PARSE = "\n" 57 | + "\n" 58 | + " \n" 59 | + " \n" 60 | + " Emoji: " + EMOJI_CHAR + "🙈🙈\n" 61 | + "\n"; 62 | 63 | private static void checkParseBeyondBmp(XmlPullParser xpp) throws XmlPullParserException, IOException { 64 | while (xpp.getEventType() != XmlPullParser.END_DOCUMENT) { 65 | switch (xpp.getEventType()) { 66 | case XmlPullParser.CDSECT: 67 | assertTrue(xpp.getText().contains(EMOJI_CHAR)); 68 | break; 69 | case XmlPullParser.COMMENT: 70 | assertTrue(xpp.getText().contains(EMOJI_CHAR)); 71 | break; 72 | case XmlPullParser.TEXT: 73 | final String text = xpp.getText().replaceAll("[\\n\\r\\t ]+", ""); 74 | if (!text.isEmpty()) { 75 | assertTrue(xpp.getText().contains(EMOJI_CHAR)); 76 | } 77 | break; 78 | case XmlPullParser.ENTITY_REF: 79 | assertEquals(EMOJI_CHAR, xpp.getText()); 80 | break; 81 | case XmlPullParser.START_TAG: 82 | for (int i = 0; i < xpp.getAttributeCount(); i++) { 83 | assertEquals(EMOJI_CHAR, xpp.getAttributeValue(i)); 84 | } 85 | break; 86 | } 87 | xpp.nextToken(); 88 | } 89 | } 90 | 91 | public void testParseBeyondBmpFromReader() throws XmlPullParserException, IOException { 92 | final XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); 93 | final XmlPullParser xpp = factory.newPullParser(); 94 | xpp.setInput(new StringReader(XML_TO_PARSE)); 95 | 96 | checkParseBeyondBmp(xpp); 97 | } 98 | 99 | public void testParseBeyondBmpInputStream() throws XmlPullParserException, IOException { 100 | final XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); 101 | final XmlPullParser xpp = factory.newPullParser(); 102 | xpp.setInput(new ByteArrayInputStream(XML_TO_PARSE.getBytes(StandardCharsets.UTF_8)), "utf-8"); 103 | 104 | checkParseBeyondBmp(xpp); 105 | } 106 | 107 | private static final String EXPECTED_XML_SERIALIZATION = "" 108 | + "\n" 109 | + "\n" 110 | + "Emoji: 🙈"; 111 | 112 | private static void checkSerializeBeyondBmp(XmlSerializer serializer) throws IOException { 113 | final String text = "Emoji: " + EMOJI_CHAR; 114 | 115 | serializer.comment(text); 116 | serializer.text("\n"); 117 | serializer.cdsect(text); 118 | serializer.text("\n"); 119 | serializer.startTag(null, "string"); 120 | serializer.attribute(null, "attr", EMOJI_CHAR); 121 | serializer.text(text); 122 | serializer.endTag(null, "string"); 123 | serializer.endDocument(); 124 | } 125 | 126 | public void testSerializeBeyondBmpToOutputStream() throws XmlPullParserException, IOException { 127 | final XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); 128 | factory.setNamespaceAware(true); 129 | final XmlSerializer serializer = factory.newSerializer(); 130 | 131 | final ByteArrayOutputStream os = new ByteArrayOutputStream(); 132 | serializer.setOutput(os, "utf-8"); 133 | 134 | checkSerializeBeyondBmp(serializer); 135 | 136 | assertEquals(EXPECTED_XML_SERIALIZATION, os.toString("utf-8")); 137 | } 138 | 139 | public void testSerializeBeyondBmpToWriter() throws XmlPullParserException, IOException { 140 | final XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); 141 | factory.setNamespaceAware(true); 142 | final XmlSerializer serializer = factory.newSerializer(); 143 | 144 | final StringWriter writer = new StringWriter(); 145 | serializer.setOutput(writer); 146 | 147 | checkSerializeBeyondBmp(serializer); 148 | 149 | assertEquals(EXPECTED_XML_SERIALIZATION, writer.toString()); 150 | } 151 | } 152 | 153 | --------------------------------------------------------------------------------