Initial import.
[clinton/mirror/jspi/.git] / jspi / src / main / java / com / google / code / jspi / AttributeParser.java
diff --git a/jspi/src/main/java/com/google/code/jspi/AttributeParser.java b/jspi/src/main/java/com/google/code/jspi/AttributeParser.java
new file mode 100644 (file)
index 0000000..3af6575
--- /dev/null
@@ -0,0 +1,398 @@
+package com.google.code.jspi;\r
+\r
+\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.lang.reflect.Constructor;\r
+import java.lang.reflect.Field;\r
+import java.lang.reflect.InvocationTargetException;\r
+import java.net.URI;\r
+import java.net.URISyntaxException;\r
+import java.text.DateFormat;\r
+import java.text.DecimalFormat;\r
+import java.text.ParseException;\r
+import java.text.SimpleDateFormat;\r
+import java.util.Date;\r
+import java.util.HashMap;\r
+import java.util.HashSet;\r
+import java.util.Locale;\r
+import java.util.Map;\r
+import java.util.Set;\r
+import java.util.logging.Level;\r
+import java.util.logging.Logger;\r
+\r
+import javax.print.attribute.Attribute;\r
+import javax.print.attribute.EnumSyntax;\r
+\r
+import de.lohndirekt.print.attribute.AttributeWriter;\r
+import de.lohndirekt.print.attribute.IppAttributeName;\r
+import de.lohndirekt.print.attribute.IppDelimiterTag;\r
+import de.lohndirekt.print.attribute.IppValueTag;\r
+import de.lohndirekt.print.attribute.ipp.Charset;\r
+import de.lohndirekt.print.exception.EndOfAttributesException;\r
+\r
+/**\r
+ * @author bpusch\r
+ *\r
+ */\r
+public final class AttributeParser {\r
+\r
+       private final static EndOfAttributesException END_OF_ATTRIBUTES_EXCEPTION = new EndOfAttributesException();\r
+\r
+       private final static Logger log = Logger.getLogger(AttributeParser.class.getName());\r
+\r
+       \r
+\r
+       /**\r
+        * @param name\r
+        * @param values\r
+        * @return\r
+        */\r
+       private static Attribute getAttribute(String name, Object[] values) {\r
+               Attribute attribute = null;\r
+               IppAttributeName attrName = IppAttributeName.get(name);\r
+               Class attrClass = attrName.getAttributeClass();\r
+               Class superClass = attrClass.getSuperclass();\r
+               if (superClass != null) {\r
+                       if (superClass.equals(EnumSyntax.class)) {\r
+                               try {\r
+                                       Field[] fields = attrClass.getDeclaredFields();\r
+                                       for (int i = 0; i < fields.length; i++) {\r
+                                               Field field = fields[i];\r
+                                               if (field.getType().equals(attrClass)) {\r
+                                                       EnumSyntax attr = (EnumSyntax) field.get(null);\r
+                                                       if (values[0] instanceof String) {\r
+                                                               if (attr.toString().equals(values[0])) {\r
+                                                                       attribute = (Attribute) attr;\r
+                                                                       break;\r
+                                                               }\r
+                                                       } else {\r
+                                                               if (attr.getValue() == ((Integer) values[0]).intValue()) {\r
+                                                                       attribute = (Attribute) attr;\r
+                                                                       break;\r
+                                                               }\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                               } catch (SecurityException e) {\r
+                                       log.log(Level.SEVERE, e.getMessage(), e);\r
+                               } catch (IllegalArgumentException e) {\r
+                                       log.log(Level.SEVERE, e.getMessage(), e);\r
+                               } catch (IllegalAccessException e) {\r
+                                       log.log(Level.SEVERE, e.getMessage(), e);\r
+                               }\r
+\r
+                       } else {\r
+                               Class[] parameters = toClassArray(values);\r
+                               try {\r
+                                       Constructor constructor = attrClass.getDeclaredConstructor(parameters);\r
+                                       attribute = (Attribute) constructor.newInstance(values);\r
+                               } catch (SecurityException e) {\r
+                                       log.log(Level.SEVERE, e.getMessage(), e);\r
+                               } catch (NoSuchMethodException e) {\r
+                                       log.log(Level.SEVERE, e.getMessage(), e);\r
+                               } catch (IllegalArgumentException e) {\r
+                                       log.log(Level.SEVERE, e.getMessage(), e);\r
+                               } catch (InstantiationException e) {\r
+                                       log.log(Level.SEVERE, e.getMessage(), e);\r
+                               } catch (IllegalAccessException e) {\r
+                                       log.log(Level.SEVERE, e.getMessage(), e);\r
+                               } catch (InvocationTargetException e) {\r
+                                       log.log(Level.SEVERE, e.getMessage(), e);\r
+                               }\r
+                       }\r
+               }\r
+\r
+               return attribute;\r
+       }\r
+\r
+       /**\r
+            * @param byteArray\r
+            * @param byteCount\r
+            * @param lastAttribute\r
+            * @return\r
+            */\r
+       private static Attribute parseAttribute(InputStream in, Attribute lastAttribute)\r
+               throws IOException, EndOfAttributesException {\r
+\r
+               int valueTag;\r
+               while ((valueTag = in.read()) < IppValueTag.UNSUPPORTED_VALUE.getValue()) {\r
+                       if (valueTag == IppDelimiterTag.END_ATTRIBUTES.getValue()) {\r
+                               throw END_OF_ATTRIBUTES_EXCEPTION;\r
+                       }\r
+               }\r
+\r
+               int nameLength = parseInt2(in);\r
+               //          parse the Attribute-Name\r
+               String name;\r
+               if (nameLength == 0) {\r
+                       name = lastAttribute.getName();\r
+               } else {\r
+                       name = parseString(in, nameLength);\r
+               }\r
+               \r
+\r
+               Object[] values = parseValues(valueTag, in);\r
+\r
+               return getAttribute(name, values);\r
+       }\r
+    \r
+    private static String parseString(InputStream in, int nameLength) throws IOException{\r
+        return parseString(in, nameLength, Charset.US_ASCII.getValue());\r
+    }\r
+    \r
+    private static String parseNameAndTextString(InputStream in, int nameLength) throws IOException{\r
+        return parseString(in, nameLength, AttributeWriter.DEFAULT_CHARSET.getValue());\r
+    }\r
+\r
+       /**\r
+        * @param in\r
+        * @param nameLength\r
+        */\r
+       private static String parseString(InputStream in, int nameLength, String charsetName) throws IOException {\r
+               byte[] bytes = new byte[nameLength];\r
+               in.read(bytes);\r
+               return new String(bytes, charsetName);\r
+\r
+       }\r
+    \r
+    \r
+    \r
+    \r
+       /**\r
+        * @param byteArray\r
+        * @param valueOffset\r
+        * @return\r
+        */\r
+       private static Date parseDate(InputStream in) throws IOException {\r
+               DecimalFormat twoDigits = new DecimalFormat("00");\r
+        DecimalFormat threeDigits = new DecimalFormat("000");\r
+               DecimalFormat fourDigits = new DecimalFormat("0000");\r
+               //year is encoded in network-byte order\r
+               int year = parseInt2(in);\r
+               int month = in.read();\r
+               int day = in.read();\r
+               int hour = in.read();\r
+               int minute = in.read();\r
+               int second = in.read();\r
+               int deci = in.read();\r
+               int mili = deci * 100;\r
+               char direction = (char) in.read();\r
+               int hoursFromUtc = in.read();\r
+               int minutesFromUtc = in.read();\r
+\r
+               String yearString = fourDigits.format(year);\r
+               String monthString = twoDigits.format(month);\r
+               String dayString = twoDigits.format(day);\r
+               String hourString = twoDigits.format(hour);\r
+               String minuteString = twoDigits.format(minute);\r
+               String secondString = twoDigits.format(second);\r
+               String miliString = threeDigits.format(mili);\r
+               String timeZone = direction + twoDigits.format(hoursFromUtc) + twoDigits.format(minutesFromUtc);\r
+               String dateString =\r
+                       yearString\r
+                               + "-"\r
+                               + monthString\r
+                               + "-"\r
+                               + dayString\r
+                               + " "\r
+                               + hourString\r
+                               + ":"\r
+                               + minuteString\r
+                               + ":"\r
+                               + secondString\r
+                               + ":"\r
+                               + miliString\r
+                               + timeZone;\r
+               DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSSZ");\r
+               Date date = null;\r
+               try {\r
+                       date = dateFormat.parse(dateString);\r
+               } catch (ParseException e) {\r
+                       log.log(Level.SEVERE, e.getMessage(), e);\r
+               }\r
+               return date;\r
+       }\r
+\r
+       private static int parseInt4(InputStream in) throws IOException {\r
+\r
+               //Same parsing as in java.io.DataInput readInt()\r
+               int a = in.read();\r
+               int b = in.read();\r
+               int c = in.read();\r
+               int d = in.read();\r
+               int value = (((a & 0xff) << 24) | ((b & 0xff) << 16) | ((c & 0xff) << 8) | (d & 0xff));\r
+               return value;\r
+       }\r
+\r
+       /**\r
+        * @param bytes\r
+        * @param offset\r
+        * @return\r
+        */\r
+       private static int parseInt4(byte[] bytes, int offset) {\r
+\r
+               //Same parsing as in java.io.DataInput readInt()\r
+               byte a = bytes[offset++];\r
+               byte b = bytes[offset++];\r
+               byte c = bytes[offset++];\r
+               byte d = bytes[offset++];\r
+               int value = (((a & 0xff) << 24) | ((b & 0xff) << 16) | ((c & 0xff) << 8) | (d & 0xff));\r
+               return value;\r
+       }\r
+\r
+       private static int parseInt2(InputStream in) throws IOException {\r
+\r
+               //Same parsing as in java.io.DataInput readInt()\r
+               int a = in.read();\r
+               int b = in.read();\r
+               int value = ((a & 0xff) << 8) | ((b & 0xff));\r
+               return value;\r
+       }\r
+\r
+       /**\r
+        * @param bytes\r
+        * @return map of attributes (key -> category, value -> Set with attributes)\r
+        * \r
+        *\r
+        */\r
+       public static Map parseRequest(InputStream response) throws IOException {\r
+               Map attributes = new HashMap();\r
+               long start = System.currentTimeMillis();\r
+               Attribute lastAttribute = null;\r
+               boolean finished = false;\r
+               response.read();\r
+\r
+               while (!finished) {\r
+                       Attribute attribute = null;\r
+                       try {\r
+                               attribute = parseAttribute(response, lastAttribute);\r
+                               if (attribute != null) {\r
+                                       lastAttribute = attribute;\r
+                                       attributes = put(attributes, attribute);\r
+                                       if (log.isLoggable(Level.FINEST)) {\r
+                                               log.finest("parsed attribute(" + attribute.getName() + "): " + attribute.toString());\r
+                                       }\r
+                               } else {\r
+                                       if (log.isLoggable(Level.FINEST)) {\r
+\r
+                                               log.finest("Attribute was null");\r
+                                       }\r
+                               }\r
+                       } catch (EndOfAttributesException e) {\r
+\r
+                               finished = true;\r
+                               if (log.isLoggable(Level.INFO)) {\r
+                                       log.info("--- Attribute parsing finished ---");\r
+                               }\r
+                       }\r
+               }\r
+               long end = System.currentTimeMillis();\r
+               if (log.isLoggable(Level.INFO)) {\r
+                   log.info("Parsing took " + (end - start) + "ms.");\r
+               }\r
+               return attributes;\r
+       }\r
+\r
+       \r
+       /**\r
+     * @param byteArray\r
+     * @param valueOffset\r
+     * @param valueLength\r
+     * @return\r
+     */\r
+       private static URI parseUri(InputStream in, int valueLength) throws IOException {\r
+               String uriString = parseString(in, valueLength);\r
+               URI uri = null;\r
+               try {\r
+                       uri = new URI(uriString);\r
+               } catch (URISyntaxException e) {\r
+                       throw new RuntimeException(e);\r
+               }\r
+               return uri;\r
+       }\r
+\r
+       \r
+       /**\r
+     * @param valueTag\r
+     * @param byteArray\r
+     * @param valueOffset\r
+     * @param valueLength\r
+     * @return\r
+     */\r
+       private static Object[] parseValues(int valueTag, InputStream in) throws IOException {\r
+        int valueLength = parseInt2(in);\r
+               Object[] values = null;\r
+               if (valueTag == IppValueTag.INTEGER.getValue() || valueTag == IppValueTag.ENUM.getValue()) {\r
+                       Integer number = new Integer(parseInt4(in));\r
+                       values = new Object[] { number };\r
+               } else if (\r
+                       valueTag == IppValueTag.STRING.getValue()\r
+                               || valueTag == IppValueTag.TEXT.getValue()\r
+                               || valueTag == IppValueTag.NAME.getValue()){\r
+            String word = parseNameAndTextString(in, valueLength);\r
+            values = new Object[] { word, Locale.getDefault()};                    \r
+        } else if (\r
+            valueTag == IppValueTag.CHARSET.getValue()\r
+                || valueTag == IppValueTag.LANGUAGE.getValue()\r
+                               || valueTag == IppValueTag.MIMETYPE.getValue()) {\r
+                       String word = parseString(in, valueLength);\r
+                       values = new Object[] { word, Locale.getDefault()};\r
+               } else if (valueTag == IppValueTag.URI.getValue()) {\r
+                       URI uri = parseUri(in, valueLength);\r
+                       values = new Object[] { uri };\r
+               } else if (valueTag == IppValueTag.KEYWORD.getValue()) {\r
+                       String word = parseString(in, valueLength);\r
+                       values = new Object[] { word, Locale.getDefault()};\r
+               } else if (valueTag == IppValueTag.BOOLEAN.getValue()) {\r
+                       Integer bool = new Integer(in.read());\r
+                       values = new Object[] { bool };\r
+               } else if (valueTag == IppValueTag.RANGE.getValue()) {\r
+                       Integer lowerBound = new Integer(parseInt4(in));\r
+                       Integer upperBound = new Integer(parseInt4(in));\r
+                       values = new Object[] { lowerBound, upperBound };\r
+               } else if (valueTag == IppValueTag.DATE.getValue()) {\r
+\r
+                       Date date = parseDate(in);\r
+                       values = new Object[] { date };\r
+               } else if (valueTag == IppValueTag.NOVALUE.getValue()) {\r
+                       values = new Object[] {\r
+                       };\r
+               } else {\r
+                       throw new IllegalArgumentException("\"" + Integer.toHexString(valueTag) + "\" is not a valid value-tag");\r
+               }\r
+               return values;\r
+       }\r
+\r
+\r
+       /**\r
+        * @param attributes\r
+        * @param attribute\r
+        */\r
+       private static Map put(Map attributes, Attribute attribute) {\r
+               Set values = (Set) attributes.get(attribute.getCategory());\r
+               if (values == null) {\r
+                       values = new HashSet();\r
+                       attributes.put(attribute.getCategory(), values);\r
+               }\r
+               values.add(attribute);\r
+               return attributes;\r
+       }\r
+\r
+       /**\r
+        * @param values\r
+        * @return\r
+        */\r
+       private static Class[] toClassArray(Object[] values) {\r
+               Class[] classes = new Class[values.length];\r
+               for (int i = 0; i < values.length; i++) {\r
+                       Class clazz = values[i].getClass();\r
+                       if (clazz.equals(Integer.class)) {\r
+                               clazz = int.class;\r
+                       }\r
+                       classes[i] = clazz;\r
+               }\r
+               return classes;\r
+       }\r
+\r
+}\r