Committed the initial version of the UPnP Extra bundle (FELIX-52).
It requires org.osgi.compendium
git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@391437 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/org.apache.felix.upnp.extra/pom.xml b/org.apache.felix.upnp.extra/pom.xml
new file mode 100644
index 0000000..31a8734
--- /dev/null
+++ b/org.apache.felix.upnp.extra/pom.xml
@@ -0,0 +1,50 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix</artifactId>
+ <version>0.8.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>osgi-bundle</packaging>
+ <groupId>org.apache.felix</groupId>
+ <name>Apache Felix UPnP Extra </name>
+ <artifactId>org.apache.felix.upnp.extra</artifactId>
+ <version>0.1.0-SNAPSHOT</version>
+ <!-- <url>http://maven.apache.org</url> -->
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <version>4.0</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix.plugins</groupId>
+ <artifactId>maven-osgi-plugin</artifactId>
+ <!-- <version>${pom.version}</version> -->
+ <extensions>true</extensions>
+ <configuration>
+ <osgiManifest>
+ <bundleName>UPnPExtra</bundleName>
+ <bundleVendor>Apache Software Foundation</bundleVendor>
+ <bundleVersion>0.1.0</bundleVersion>
+ <bundleDescription>
+ A library used to extend the integration between UPnP and OSGi that is not part of the standard. Also services that allow to change the beahviour of the UPnP Base Driver
+ </bundleDescription>
+ <bundleSymbolicName>org.apache.felix.upnp.extra</bundleSymbolicName>
+ <importPackage>
+ org.osgi.service.upnp;specification-version=1.1,org.apache.felix.upnp.extra.util;specification-version=1.0,org.apache.felix.upnp.extra.controller;specification-version=1.0
+ </importPackage>
+ <exportPackage>
+ org.apache.felix.upnp.extra.util;specification-version=1.0,org.apache.felix.upnp.extra.controller;specification-version=1.0
+ </exportPackage>
+ </osgiManifest>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/org.apache.felix.upnp.extra/src/main/java/org/apache/felix/upnp/extra/controller/DevicesInfo.java b/org.apache.felix.upnp.extra/src/main/java/org/apache/felix/upnp/extra/controller/DevicesInfo.java
new file mode 100644
index 0000000..e1ff5f5
--- /dev/null
+++ b/org.apache.felix.upnp.extra/src/main/java/org/apache/felix/upnp/extra/controller/DevicesInfo.java
@@ -0,0 +1,60 @@
+/*
+ DomoWare UPnP Base Driver is an implementation of the OSGi UnP Device Spcifaction
+ Copyright (C) 2004 Matteo Demuru, Francesco Furfari, Stefano "Kismet" Lenzi
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ You can contact us at:
+ {matte-d, sygent, kismet-sl} [at] users.sourceforge.net
+ */
+package org.apache.felix.upnp.extra.controller;
+
+/**
+ * @author Stefano "Kismet" Lenzi
+ * @author Francesco Furfari
+ */
+public interface DevicesInfo{
+ /**
+ *
+ * Allow you to get the URL that poinr to the XML description of
+ * a device specified by UUID.
+ *
+ * @param udn the UUID that identify a device
+ * @return The String that rappresent the URL that point to the description of the Device
+ */
+ public String getLocationURL(String udn);
+
+ /**
+ *
+ * Allow you to get the URL that poinr to the XML description of
+ * a service specified by ServiceId and UUID of the device that
+ * contain the service
+ *
+ * @param udn the UUID of the device that contain the service
+ * @param serviceId the ServiceId of the service
+ * @return The String that rappresent the URL that point to the description of the Service
+ */
+ public String getSCPDURL(String udn,String serviceId);
+
+ /**
+ * Allow you to get the absolue URL of a link that is conatin in a device
+ *
+ * @param udn the UUID of the UPnP Device
+ * @param link the relative link that you want to resolve
+ * @return The String that rappresent the absolute URL to the resourse specified by link
+ */
+ public String resolveRelativeUrl(String udn, String link);
+
+}
diff --git a/org.apache.felix.upnp.extra/src/main/java/org/apache/felix/upnp/extra/controller/DriverController.java b/org.apache.felix.upnp.extra/src/main/java/org/apache/felix/upnp/extra/controller/DriverController.java
new file mode 100644
index 0000000..3b210c6
--- /dev/null
+++ b/org.apache.felix.upnp.extra/src/main/java/org/apache/felix/upnp/extra/controller/DriverController.java
@@ -0,0 +1,82 @@
+/*
+ DomoWare UPnP Base Driver is an implementation of the OSGi UnP Device Spcifaction
+ Copyright (C) 2004 Matteo Demuru, Francesco Furfari, Stefano "Kismet" Lenzi
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ You can contact us at:
+ {matte-d, sygent, kismet-sl} [at] users.sourceforge.net
+ */
+package org.apache.felix.upnp.extra.controller;
+
+//import java.net.InetAddress;
+
+/**
+ * @author Stefano "Kismet" Lenzi
+ * @author Francesco Furfari
+ */
+public interface DriverController {
+ /**
+ * String for searching all the device on UPnP Network
+ */
+ public final static String ALL_DEVICE = "ssdp:all";
+
+ /**
+ * String for searching only root device on UPnP Network
+ */
+ public final static String ROOT_DEVICE = "upnp:rootdevice";
+ /*
+ public InetAddress[] getBindAddress();
+
+ public void setBindAddress(InetAddress[] IPs);
+ */
+
+ /**
+ * Set how much messages should be sent by UPnP Base Driver
+ * for debugging purpose
+ *
+ * @param n the level of log that you want to set
+ */
+ public void setLogLevel(int n);
+
+ /**
+ *
+ * @return the actual value of log level
+ */
+ public int getLogLevel();
+
+ /**
+ * Set if the message of the UPnP Stack should be reported or not
+ *
+ * @param b true if you want show messages from UPnP Stack false otherwise
+ */
+ public void setCyberDebug(boolean b);
+
+ /**
+ *
+ * @return true if the reporting of UPnP Stack message is active false otherwise
+ */
+ public boolean getCyberDebug();
+
+ /**
+ * Sent a search message on the UPnP Network, and refresh the device
+ * founded by UPnP Base Driver
+ *
+ * @param target The SSDP string used for the search
+ */
+ public void search(String target);
+
+
+}
diff --git a/org.apache.felix.upnp.extra/src/main/java/org/apache/felix/upnp/extra/util/Constants.java b/org.apache.felix.upnp.extra/src/main/java/org/apache/felix/upnp/extra/util/Constants.java
new file mode 100644
index 0000000..c29b3e6
--- /dev/null
+++ b/org.apache.felix.upnp.extra/src/main/java/org/apache/felix/upnp/extra/util/Constants.java
@@ -0,0 +1,36 @@
+/*
+ DomoWare UPnP Base Driver is an implementation of the OSGi UnP Device Spcifaction
+ Copyright (C) 2004 Matteo Demuru, Francesco Furfari, Stefano "Kismet" Lenzi
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ You can contact us at:
+ {matte-d, sygent, kismet-sl} [at] users.sourceforge.net
+ */
+package org.apache.felix.upnp.extra.util;
+/**
+ *
+ * @author Stefano "Kismet" Lenzi
+ *
+ */
+public interface Constants {
+ /**
+ * If this property is set on a UPnP Device means that the
+ * device service is been created by UPnP base Driver. <br>
+ * The value of the do not mean nothing. <br>
+ * The name of the property is "UPnP.device.import".
+ */
+ public static final String UPNP_IMPORT = "UPnP.device.imported";
+}
diff --git a/org.apache.felix.upnp.extra/src/main/java/org/apache/felix/upnp/extra/util/Converter.java b/org.apache.felix.upnp.extra/src/main/java/org/apache/felix/upnp/extra/util/Converter.java
new file mode 100644
index 0000000..abd5612
--- /dev/null
+++ b/org.apache.felix.upnp.extra/src/main/java/org/apache/felix/upnp/extra/util/Converter.java
@@ -0,0 +1,256 @@
+/*
+DomoWare UPnP Base Driver is an implementation of the OSGi UnP Device Spcifaction
+Copyright (C) 2004 Matteo Demuru, Francesco Furfari, Stefano "Kismet" Lenzi
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+You can contact us at:
+ {matte-d, sygent, kismet-sl} [at] users.sourceforge.net
+*/
+
+package org.apache.felix.upnp.extra.util;
+
+import java.text.*;
+import java.util.*;
+
+//import org.apache.xerces.impl.dv.util.*;
+import org.apache.xerces.impl.dv.util.Base64;
+import org.apache.xerces.impl.dv.util.HexBin;
+import org.osgi.service.upnp.*;
+
+/**
+ * @author Stefano "Kismet" Lenzi
+ *
+ *
+ */
+public class Converter {
+
+ /**
+ *
+ * @param value Object that contain the value
+ * @param upnpType String conating the UPnP Type of the Object
+ * @return a String that contain the UPnP rappresentation of the value contained in Object
+ * of type specified by typeUPnP
+ */
+ public static String toString(Object value,String upnpType) throws Exception{
+ if((value==null)||(upnpType==null))
+ throw new NullPointerException("Must be specified a valid value and upnpType");
+
+ if(value instanceof Number){
+ if(value instanceof Integer){
+ return value.toString();
+ }else if(value instanceof Float){
+ return value.toString();
+ }else if(value instanceof Long){
+ if(upnpType.equals(UPnPStateVariable.TYPE_TIME)){
+ long l = ((Long)value).longValue();
+ if(l<0) throw new IllegalArgumentException(l+ "Must be greater than 0");
+ Calendar c = Calendar.getInstance();
+ c.set(Calendar.HOUR_OF_DAY,(int) (l/3600000));
+ int x=(int) (l % 3600000);
+ c.set(Calendar.MINUTE,(int) (x / 60000));
+ c.set(Calendar.SECOND,(x % 60000)/1000);
+ SimpleDateFormat sdt = new SimpleDateFormat("HH:mm:ss");
+ return sdt.format(c.getTime());
+ }else if(upnpType.equals(UPnPStateVariable.TYPE_TIME_TZ)){
+ long l = ((Long)value).longValue();
+ if(l<0) throw new IllegalArgumentException(l+ "Must be greater than 0");
+ Calendar c = Calendar.getInstance();
+ c.set(Calendar.HOUR_OF_DAY,(int) (l/3600000));
+ int x=(int) (l % 3600000);
+ c.set(Calendar.MINUTE,(int) (x / 60000));
+ c.set(Calendar.SECOND,(x % 60000)/1000);
+ SimpleDateFormat sdt = new SimpleDateFormat("HH:mm:ssZ");
+ return sdt.format(c.getTime());
+ }else{
+ //Must be UPnPStateVariable.TYPE_UI4)
+ return value.toString();
+ }
+ }else if(value instanceof Double){
+ if(upnpType.equals(UPnPStateVariable.TYPE_FIXED_14_4)){
+ return Long.toString(((Double)value).longValue())+"."+
+ Integer.toString((int) (((((Double)value).doubleValue()*10000D) % 10000)));
+ }else{
+ //Must be UPnPStateVariable.TYPE_R8 or UPnPStateVariable.TYPE_NUMBER
+ return value.toString();
+ }
+ }
+ }else if(value instanceof Date){
+ if(upnpType.equals("dateTime")){
+ SimpleDateFormat sdt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
+ return sdt.format(value);
+ }else if(upnpType.equals("dateTime.tz")){
+ SimpleDateFormat sdt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
+ return sdt.format(value);
+ }else if(upnpType.equals("date")){
+ SimpleDateFormat sdt = new SimpleDateFormat("yyyy-MM-dd");
+ return sdt.format(value);
+ }
+ }else if(value instanceof Boolean){
+ //Must be UPnPStateVariable.TYPE_BOOLEAN
+ if(((Boolean)value).booleanValue()){
+ return "1";
+ }else{
+ return "0";
+ }
+ }else if(value instanceof Character){
+ //Must be UPnPStateVariable.TYPE_CHAR
+ return value.toString();
+ }else if(value instanceof String){
+ return value.toString();
+ //Must be one of
+ // UPnPStateVariable.TYPE_STRING or
+ // UPnPStateVariable.TYPE_URI or
+ // UPnPStateVariable.TYPE_UUID
+ }else if(value instanceof byte[]){
+ if(upnpType.equals("bin.hex")){
+ return HexBin.encode((byte[]) value);
+ }else if(upnpType.equals("bin.base64")){
+ return Base64.encode((byte[]) value);
+ }
+ }
+ throw new IllegalArgumentException("Invalid Binding");
+ }
+
+ /**
+ *
+ * @param value
+ * @param upnpType
+ * @return
+ */
+ public static Object parseString(String value,String upnpType) throws Exception{
+ if (value ==null && upnpType.equals("string"))
+ value = "";
+ if((value==null)||(upnpType==null))
+ throw new NullPointerException("Must be specified a valid value and upnpType");
+
+ if (upnpType.equals("ui1") || upnpType.equals("ui2")
+ || upnpType.equals("i1") || upnpType.equals("i2")
+ || upnpType.equals("i4") || upnpType.equals("int")) {
+
+ return new Integer(value);
+ } else if (upnpType.equals("ui4")){
+ return new Long(value);
+ } else if(upnpType.equals("time")){
+ String[] timeFormats=new String[]{"HH:mm:ss"};
+ Date d=getDateValue(value,timeFormats,timeFormats);
+
+ Calendar c = Calendar.getInstance();
+ c.setTime(d);
+ return new Long(
+ c.get(Calendar.HOUR_OF_DAY)*3600000
+ +c.get(Calendar.MINUTE)*60000
+ +c.get(Calendar.SECOND)*1000
+ );
+ } else if(upnpType.equals("time.tz")) {
+ String[] timeFormats=new String[]{"HH:mm:ssZ","HH:mm:ss"};
+ Date d=getDateValue(value,timeFormats,timeFormats);
+ TimeZone tz = TimeZone.getDefault();
+ int dst = tz.getDSTSavings();
+ Calendar c = Calendar.getInstance(tz);
+ c.setTime(d);
+
+ if(timeFormats[0].equals("HH:mm:ssZ")&&(dst!=0))
+ c.add(Calendar.MILLISECOND,dst);
+ return new Long(
+ c.get(Calendar.HOUR_OF_DAY)*3600000
+ +c.get(Calendar.MINUTE)*60000
+ +c.get(Calendar.SECOND)*1000
+ );
+ } else if (upnpType.equals("r4") || upnpType.equals("float")) {
+ return new Float(value);
+ } else if (upnpType.equals("r8") || upnpType.equals("number")
+ || upnpType.equals("fixed.14.4")){
+ return new Double(value);
+ } else if (upnpType.equals("char")) {
+ return new Character(value.charAt(0));
+ } else if (upnpType.equals("string") || upnpType.equals("uri")
+ || upnpType.equals("uuid")) {
+ return value;
+ } else if (upnpType.equals("date")) {
+ String[] timeFormats=new String[]{"yyyy-MM-dd"};
+
+ Date d=getDateValue(value,timeFormats,timeFormats);
+ return d;
+ } else if (upnpType.equals("dateTime")) {
+
+ String[] timeFormats=new String[]{
+ "yyyy-MM-dd",
+ "yyyy-MM-dd'T'HH:mm:ss"
+ };
+
+ Date d=getDateValue(value,timeFormats,timeFormats);
+ return d;
+ } else if (upnpType.equals("dateTime.tz")) {
+
+ String[] timeFormats=new String[]{
+ "yyyy-MM-dd",
+ "yyyy-MM-dd'T'HH:mm:ss",
+ "yyyy-MM-dd'T'HH:mm:ssZ"
+ };
+
+ Date d=getDateValue(value,timeFormats,timeFormats);
+ return d;
+ } else if (upnpType.equals("boolean")) {
+ if(value.equalsIgnoreCase("yes") || value.equalsIgnoreCase("true")
+ || value.equalsIgnoreCase("1"))
+ return new Boolean(true);
+ else
+ return new Boolean(false);
+ } else if (upnpType.equals("bin.base64")) {
+ return Base64.decode(value);
+ } else if (upnpType.equals("bin.hex")) {
+ return HexBin.decode(value);
+ }
+ throw new IllegalArgumentException("Invalid Binding");
+ }
+
+ private static String normalizeTimeZone(String value){
+ if(value.endsWith("Z")){
+ value=value.substring(0,value.length()-1)+"+0000";
+ }else if((value.length()>7)
+ &&(value.charAt(value.length()-3)==':')
+ &&((value.charAt(value.length()-6)=='-')||(value.charAt(value.length()-6)=='+'))){
+
+ value=value.substring(0,value.length()-3)+value.substring(value.length()-2);
+ }
+ return value;
+ }
+
+ /**
+ * @param value
+ * @param timeFormats
+ * @param choosedIndex
+ * @return
+ * @throws ParseException
+ */
+ private static Date getDateValue(String value, String[] timeFormats, String[] choosedIndex) throws ParseException {
+ ParsePosition position = null;
+ Date d;
+ value=normalizeTimeZone(value);
+ for (int i=0; i<timeFormats.length; i++) {
+ position = new ParsePosition(0);
+ SimpleDateFormat sdt = new SimpleDateFormat(timeFormats[i]);
+ d=sdt.parse(value,position);
+ if(d!=null){
+ if(position.getIndex()>=value.length()){
+ choosedIndex[0]=timeFormats[i];
+ return d;
+ }
+ }
+ }
+ throw new ParseException("Error parsing "+value,position.getIndex());
+ }
+}
diff --git a/org.apache.felix.upnp.extra/src/main/java/org/apache/felix/upnp/extra/util/UPnPException.java b/org.apache.felix.upnp.extra/src/main/java/org/apache/felix/upnp/extra/util/UPnPException.java
new file mode 100644
index 0000000..9807ba6
--- /dev/null
+++ b/org.apache.felix.upnp.extra/src/main/java/org/apache/felix/upnp/extra/util/UPnPException.java
@@ -0,0 +1,52 @@
+/*
+ DomoWare UPnP Base Driver is an implementation of the OSGi UnP Device Spcifaction
+ Copyright (C) 2004 Matteo Demuru, Francesco Furfari, Stefano "Kismet" Lenzi
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ You can contact us at:
+ {matte-d, sygent, kismet-sl} [at] users.sourceforge.net
+ */
+package org.apache.felix.upnp.extra.util;
+
+/**
+ * @author Stefano "Kismet" Lenzi
+ * @author Francesco Furfari
+ *
+ */
+public class UPnPException extends Exception {
+
+ private int errorCode;
+
+ public UPnPException(int errorCode, String errorDescription,
+ Throwable t) {
+ super(errorDescription, t);
+ this.errorCode = errorCode;
+ }
+
+ public UPnPException(int errorCode, String errorDescription) {
+ super(errorDescription);
+ this.errorCode = errorCode;
+ }
+
+ public String getErrorDescription() {
+ return getMessage();
+ }
+
+ public int getErrorCode() {
+ return errorCode;
+ }
+
+}
diff --git a/org.apache.felix.upnp.extra/src/main/java/org/apache/xerces/impl/dv/util/Base64.java b/org.apache.felix.upnp.extra/src/main/java/org/apache/xerces/impl/dv/util/Base64.java
new file mode 100644
index 0000000..bd01597
--- /dev/null
+++ b/org.apache.felix.upnp.extra/src/main/java/org/apache/xerces/impl/dv/util/Base64.java
@@ -0,0 +1,304 @@
+/*
+ * Copyright 1999-2002,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.xerces.impl.dv.util;
+
+/**
+ * This class provides encode/decode for RFC 2045 Base64 as
+ * defined by RFC 2045, N. Freed and N. Borenstein.
+ * RFC 2045: Multipurpose Internet Mail Extensions (MIME)
+ * Part One: Format of Internet Message Bodies. Reference
+ * 1996 Available at: http://www.ietf.org/rfc/rfc2045.txt
+ * This class is used by XML Schema binary format validation
+ *
+ * This implementation does not encode/decode streaming
+ * data. You need the data that you will encode/decode
+ * already on a byte arrray.
+ *
+ * @xerces.internal
+ *
+ * @author Jeffrey Rodriguez
+ * @author Sandy Gao
+ * @version $Id: Base64.java,v 1.15 2004/10/14 15:20:18 mrglavas Exp $
+ */
+public final class Base64 {
+
+ static private final int BASELENGTH = 128;
+ static private final int LOOKUPLENGTH = 64;
+ static private final int TWENTYFOURBITGROUP = 24;
+ static private final int EIGHTBIT = 8;
+ static private final int SIXTEENBIT = 16;
+ static private final int SIXBIT = 6;
+ static private final int FOURBYTE = 4;
+ static private final int SIGN = -128;
+ static private final char PAD = '=';
+ static private final boolean fDebug = false;
+ static final private byte [] base64Alphabet = new byte[BASELENGTH];
+ static final private char [] lookUpBase64Alphabet = new char[LOOKUPLENGTH];
+
+ static {
+
+ for (int i = 0; i < BASELENGTH; ++i) {
+ base64Alphabet[i] = -1;
+ }
+ for (int i = 'Z'; i >= 'A'; i--) {
+ base64Alphabet[i] = (byte) (i-'A');
+ }
+ for (int i = 'z'; i>= 'a'; i--) {
+ base64Alphabet[i] = (byte) ( i-'a' + 26);
+ }
+
+ for (int i = '9'; i >= '0'; i--) {
+ base64Alphabet[i] = (byte) (i-'0' + 52);
+ }
+
+ base64Alphabet['+'] = 62;
+ base64Alphabet['/'] = 63;
+
+ for (int i = 0; i<=25; i++)
+ lookUpBase64Alphabet[i] = (char)('A'+i);
+
+ for (int i = 26, j = 0; i<=51; i++, j++)
+ lookUpBase64Alphabet[i] = (char)('a'+ j);
+
+ for (int i = 52, j = 0; i<=61; i++, j++)
+ lookUpBase64Alphabet[i] = (char)('0' + j);
+ lookUpBase64Alphabet[62] = (char)'+';
+ lookUpBase64Alphabet[63] = (char)'/';
+
+ }
+
+ protected static boolean isWhiteSpace(char octect) {
+ return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);
+ }
+
+ protected static boolean isPad(char octect) {
+ return (octect == PAD);
+ }
+
+ protected static boolean isData(char octect) {
+ return (octect < BASELENGTH && base64Alphabet[octect] != -1);
+ }
+
+ protected static boolean isBase64(char octect) {
+ return (isWhiteSpace(octect) || isPad(octect) || isData(octect));
+ }
+
+ /**
+ * Encodes hex octects into Base64
+ *
+ * @param binaryData Array containing binaryData
+ * @return Encoded Base64 array
+ */
+ public static String encode(byte[] binaryData) {
+
+ if (binaryData == null)
+ return null;
+
+ int lengthDataBits = binaryData.length*EIGHTBIT;
+ if (lengthDataBits == 0) {
+ return "";
+ }
+
+ int fewerThan24bits = lengthDataBits%TWENTYFOURBITGROUP;
+ int numberTriplets = lengthDataBits/TWENTYFOURBITGROUP;
+ int numberQuartet = fewerThan24bits != 0 ? numberTriplets+1 : numberTriplets;
+ char encodedData[] = null;
+
+ encodedData = new char[numberQuartet*4];
+
+ byte k=0, l=0, b1=0,b2=0,b3=0;
+
+ int encodedIndex = 0;
+ int dataIndex = 0;
+ if (fDebug) {
+ System.out.println("number of triplets = " + numberTriplets );
+ }
+
+ for (int i=0; i<numberTriplets; i++) {
+ b1 = binaryData[dataIndex++];
+ b2 = binaryData[dataIndex++];
+ b3 = binaryData[dataIndex++];
+
+ if (fDebug) {
+ System.out.println( "b1= " + b1 +", b2= " + b2 + ", b3= " + b3 );
+ }
+
+ l = (byte)(b2 & 0x0f);
+ k = (byte)(b1 & 0x03);
+
+ byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
+
+ byte val2 = ((b2 & SIGN)==0)?(byte)(b2>>4):(byte)((b2)>>4^0xf0);
+ byte val3 = ((b3 & SIGN)==0)?(byte)(b3>>6):(byte)((b3)>>6^0xfc);
+
+ if (fDebug) {
+ System.out.println( "val2 = " + val2 );
+ System.out.println( "k4 = " + (k<<4));
+ System.out.println( "vak = " + (val2 | (k<<4)));
+ }
+
+ encodedData[encodedIndex++] = lookUpBase64Alphabet[ val1 ];
+ encodedData[encodedIndex++] = lookUpBase64Alphabet[ val2 | ( k<<4 )];
+ encodedData[encodedIndex++] = lookUpBase64Alphabet[ (l <<2 ) | val3 ];
+ encodedData[encodedIndex++] = lookUpBase64Alphabet[ b3 & 0x3f ];
+ }
+
+ // form integral number of 6-bit groups
+ if (fewerThan24bits == EIGHTBIT) {
+ b1 = binaryData[dataIndex];
+ k = (byte) ( b1 &0x03 );
+ if (fDebug) {
+ System.out.println("b1=" + b1);
+ System.out.println("b1<<2 = " + (b1>>2) );
+ }
+ byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
+ encodedData[encodedIndex++] = lookUpBase64Alphabet[ val1 ];
+ encodedData[encodedIndex++] = lookUpBase64Alphabet[ k<<4 ];
+ encodedData[encodedIndex++] = PAD;
+ encodedData[encodedIndex++] = PAD;
+ } else if (fewerThan24bits == SIXTEENBIT) {
+ b1 = binaryData[dataIndex];
+ b2 = binaryData[dataIndex +1 ];
+ l = ( byte ) ( b2 &0x0f );
+ k = ( byte ) ( b1 &0x03 );
+
+ byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
+ byte val2 = ((b2 & SIGN)==0)?(byte)(b2>>4):(byte)((b2)>>4^0xf0);
+
+ encodedData[encodedIndex++] = lookUpBase64Alphabet[ val1 ];
+ encodedData[encodedIndex++] = lookUpBase64Alphabet[ val2 | ( k<<4 )];
+ encodedData[encodedIndex++] = lookUpBase64Alphabet[ l<<2 ];
+ encodedData[encodedIndex++] = PAD;
+ }
+
+ return new String(encodedData);
+ }
+
+ /**
+ * Decodes Base64 data into octects
+ *
+ * @param encoded string containing Base64 data
+ * @return Array containind decoded data.
+ */
+ public static byte[] decode(String encoded) {
+
+ if (encoded == null)
+ return null;
+
+ char[] base64Data = encoded.toCharArray();
+ // remove white spaces
+ int len = removeWhiteSpace(base64Data);
+
+ if (len%FOURBYTE != 0) {
+ return null;//should be divisible by four
+ }
+
+ int numberQuadruple = (len/FOURBYTE );
+
+ if (numberQuadruple == 0)
+ return new byte[0];
+
+ byte decodedData[] = null;
+ byte b1=0,b2=0,b3=0,b4=0;
+ char d1=0,d2=0,d3=0,d4=0;
+
+ int i = 0;
+ int encodedIndex = 0;
+ int dataIndex = 0;
+ decodedData = new byte[ (numberQuadruple)*3];
+
+ for (; i<numberQuadruple-1; i++) {
+
+ if (!isData( (d1 = base64Data[dataIndex++]) )||
+ !isData( (d2 = base64Data[dataIndex++]) )||
+ !isData( (d3 = base64Data[dataIndex++]) )||
+ !isData( (d4 = base64Data[dataIndex++]) ))
+ return null;//if found "no data" just return null
+
+ b1 = base64Alphabet[d1];
+ b2 = base64Alphabet[d2];
+ b3 = base64Alphabet[d3];
+ b4 = base64Alphabet[d4];
+
+ decodedData[encodedIndex++] = (byte)( b1 <<2 | b2>>4 ) ;
+ decodedData[encodedIndex++] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) );
+ decodedData[encodedIndex++] = (byte)( b3<<6 | b4 );
+ }
+
+ if (!isData( (d1 = base64Data[dataIndex++]) ) ||
+ !isData( (d2 = base64Data[dataIndex++]) )) {
+ return null;//if found "no data" just return null
+ }
+
+ b1 = base64Alphabet[d1];
+ b2 = base64Alphabet[d2];
+
+ d3 = base64Data[dataIndex++];
+ d4 = base64Data[dataIndex++];
+ if (!isData( (d3 ) ) ||
+ !isData( (d4 ) )) {//Check if they are PAD characters
+ if (isPad( d3 ) && isPad( d4)) { //Two PAD e.g. 3c[Pad][Pad]
+ if ((b2 & 0xf) != 0)//last 4 bits should be zero
+ return null;
+ byte[] tmp = new byte[ i*3 + 1 ];
+ System.arraycopy( decodedData, 0, tmp, 0, i*3 );
+ tmp[encodedIndex] = (byte)( b1 <<2 | b2>>4 ) ;
+ return tmp;
+ } else if (!isPad( d3) && isPad(d4)) { //One PAD e.g. 3cQ[Pad]
+ b3 = base64Alphabet[ d3 ];
+ if ((b3 & 0x3 ) != 0)//last 2 bits should be zero
+ return null;
+ byte[] tmp = new byte[ i*3 + 2 ];
+ System.arraycopy( decodedData, 0, tmp, 0, i*3 );
+ tmp[encodedIndex++] = (byte)( b1 <<2 | b2>>4 );
+ tmp[encodedIndex] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) );
+ return tmp;
+ } else {
+ return null;//an error like "3c[Pad]r", "3cdX", "3cXd", "3cXX" where X is non data
+ }
+ } else { //No PAD e.g 3cQl
+ b3 = base64Alphabet[ d3 ];
+ b4 = base64Alphabet[ d4 ];
+ decodedData[encodedIndex++] = (byte)( b1 <<2 | b2>>4 ) ;
+ decodedData[encodedIndex++] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) );
+ decodedData[encodedIndex++] = (byte)( b3<<6 | b4 );
+
+ }
+
+ return decodedData;
+ }
+
+ /**
+ * remove WhiteSpace from MIME containing encoded Base64 data.
+ *
+ * @param data the byte array of base64 data (with WS)
+ * @return the new length
+ */
+ protected static int removeWhiteSpace(char[] data) {
+ if (data == null)
+ return 0;
+
+ // count characters that's not whitespace
+ int newSize = 0;
+ int len = data.length;
+ for (int i = 0; i < len; i++) {
+ if (!isWhiteSpace(data[i]))
+ data[newSize++] = data[i];
+ }
+ return newSize;
+ }
+}
diff --git a/org.apache.felix.upnp.extra/src/main/java/org/apache/xerces/impl/dv/util/HexBin.java b/org.apache.felix.upnp.extra/src/main/java/org/apache/xerces/impl/dv/util/HexBin.java
new file mode 100644
index 0000000..0a3b3a3
--- /dev/null
+++ b/org.apache.felix.upnp.extra/src/main/java/org/apache/xerces/impl/dv/util/HexBin.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 1999-2002,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.xerces.impl.dv.util;
+
+/**
+ * format validation
+ *
+ * This class encodes/decodes hexadecimal data
+ *
+ * @xerces.internal
+ *
+ * @author Jeffrey Rodriguez
+ * @version $Id: HexBin.java,v 1.13 2004/10/14 15:20:18 mrglavas Exp $
+ */
+public final class HexBin {
+ static private final int BASELENGTH = 128;
+ static private final int LOOKUPLENGTH = 16;
+ static final private byte [] hexNumberTable = new byte[BASELENGTH];
+ static final private char [] lookUpHexAlphabet = new char[LOOKUPLENGTH];
+
+
+ static {
+ for (int i = 0; i < BASELENGTH; i++ ) {
+ hexNumberTable[i] = -1;
+ }
+ for ( int i = '9'; i >= '0'; i--) {
+ hexNumberTable[i] = (byte) (i-'0');
+ }
+ for ( int i = 'F'; i>= 'A'; i--) {
+ hexNumberTable[i] = (byte) ( i-'A' + 10 );
+ }
+ for ( int i = 'f'; i>= 'a'; i--) {
+ hexNumberTable[i] = (byte) ( i-'a' + 10 );
+ }
+
+ for(int i = 0; i<10; i++ ) {
+ lookUpHexAlphabet[i] = (char)('0'+i);
+ }
+ for(int i = 10; i<=15; i++ ) {
+ lookUpHexAlphabet[i] = (char)('A'+i -10);
+ }
+ }
+
+ /**
+ * Encode a byte array to hex string
+ *
+ * @param binaryData array of byte to encode
+ * @return return encoded string
+ */
+ static public String encode(byte[] binaryData) {
+ if (binaryData == null)
+ return null;
+ int lengthData = binaryData.length;
+ int lengthEncode = lengthData * 2;
+ char[] encodedData = new char[lengthEncode];
+ int temp;
+ for (int i = 0; i < lengthData; i++) {
+ temp = binaryData[i];
+ if (temp < 0)
+ temp += 256;
+ encodedData[i*2] = lookUpHexAlphabet[temp >> 4];
+ encodedData[i*2+1] = lookUpHexAlphabet[temp & 0xf];
+ }
+ return new String(encodedData);
+ }
+
+ /**
+ * Decode hex string to a byte array
+ *
+ * @param encoded encoded string
+ * @return return array of byte to encode
+ */
+ static public byte[] decode(String encoded) {
+ if (encoded == null)
+ return null;
+ int lengthData = encoded.length();
+ if (lengthData % 2 != 0)
+ return null;
+
+ char[] binaryData = encoded.toCharArray();
+ int lengthDecode = lengthData / 2;
+ byte[] decodedData = new byte[lengthDecode];
+ byte temp1, temp2;
+ char tempChar;
+ for( int i = 0; i<lengthDecode; i++ ){
+ tempChar = binaryData[i*2];
+ temp1 = (tempChar < BASELENGTH) ? hexNumberTable[tempChar] : -1;
+ if (temp1 == -1)
+ return null;
+ tempChar = binaryData[i*2+1];
+ temp2 = (tempChar < BASELENGTH) ? hexNumberTable[tempChar] : -1;
+ if (temp2 == -1)
+ return null;
+ decodedData[i] = (byte)((temp1 << 4) | temp2);
+ }
+ return decodedData;
+ }
+}