3ea135bb |
1 | /**\r |
2 | * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r |
3 | *\r |
4 | * This library is free software; you can redistribute it and/or\r |
5 | * modify it under the terms of the GNU Lesser General Public\r |
6 | * License as published by the Free Software Foundation; either\r |
7 | * version 2.1 of the License, or (at your option) any later version.\r |
8 | * \r |
9 | * This library is distributed in the hope that it will be useful,\r |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of\r |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r |
12 | * Lesser General Public License for more details.\r |
13 | * \r |
14 | * You should have received a copy of the GNU Lesser General Public\r |
15 | * License along with this library; if not, write to the Free Software\r |
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r |
17 | * \r |
18 | */\r |
19 | package de.lohndirekt.print.attribute;\r |
20 | \r |
21 | import java.io.ByteArrayOutputStream;\r |
22 | import java.io.UnsupportedEncodingException;\r |
23 | import java.util.Calendar;\r |
24 | import java.util.Date;\r |
25 | import java.util.GregorianCalendar;\r |
26 | import java.util.HashMap;\r |
27 | import java.util.Map;\r |
28 | import java.util.TimeZone;\r |
29 | \r |
30 | import javax.print.attribute.Attribute;\r |
31 | import javax.print.attribute.DateTimeSyntax;\r |
32 | import javax.print.attribute.EnumSyntax;\r |
33 | import javax.print.attribute.IntegerSyntax;\r |
34 | import javax.print.attribute.ResolutionSyntax;\r |
35 | import javax.print.attribute.SetOfIntegerSyntax;\r |
36 | import javax.print.attribute.TextSyntax;\r |
37 | import javax.print.attribute.URISyntax;\r |
38 | \r |
39 | import de.lohndirekt.print.attribute.ipp.Charset;\r |
40 | import de.lohndirekt.print.attribute.ipp.NaturalLanguage;\r |
41 | \r |
42 | public final class AttributeWriter {\r |
43 | \r |
44 | private final static int MILIS_IN_MINUTE = 1000*60;\r |
45 | private final static int MILIS_IN_HOUR =MILIS_IN_MINUTE*60;\r |
46 | private static Map encodings = new HashMap();\r |
47 | \r |
48 | public final static Charset DEFAULT_CHARSET = Charset.ISO_8859_1;\r |
49 | \r |
50 | /**\r |
51 | * @param bytes\r |
52 | * @param byteNr\r |
53 | * @param attribute\r |
54 | * @return\r |
55 | */\r |
56 | private static void fillName(ByteArrayOutputStream out, Attribute attribute) {\r |
57 | String name = attribute.getName();\r |
58 | fillName(out, name);\r |
59 | }\r |
60 | \r |
61 | private static void fillName(ByteArrayOutputStream out, String name) {\r |
62 | //name length\r |
63 | writeInt2(name.length(), out);\r |
64 | //name of attribute\r |
65 | writeString(name, out);\r |
66 | \r |
67 | }\r |
68 | \r |
69 | /**\r |
70 | * @param attribute\r |
71 | * @param bytes\r |
72 | * @return\r |
73 | */\r |
74 | private static void attributeBytes(IntegerSyntax attribute, ByteArrayOutputStream out) {\r |
75 | //value tag\r |
76 | out.write((byte) IppValueTag.INTEGER.getValue());\r |
77 | //name\r |
78 | fillName(out, (Attribute) attribute);\r |
79 | //value length (always 4 bytes)\r |
80 | writeInt2(4, out);\r |
81 | //value\r |
82 | writeInt4(attribute.getValue(), out);\r |
83 | }\r |
84 | \r |
85 | /**\r |
86 | * @param attribute\r |
87 | * @param bytes\r |
88 | * @return\r |
89 | */\r |
90 | private static void attributeBytes(SetOfIntegerSyntax attribute, ByteArrayOutputStream out) {\r |
91 | int[][] members = attribute.getMembers();\r |
92 | for (int i = 0; i < members.length; i++) {\r |
93 | int[] range = members[i];\r |
94 | int lowerBound = range[0];\r |
95 | int upperBound = range[1];\r |
96 | \r |
97 | //value tag\r |
98 | out.write((byte) IppValueTag.RANGE.getValue());\r |
99 | //name\r |
100 | if (i == 0) {\r |
101 | fillName(out, (Attribute) attribute);\r |
102 | } else {\r |
103 | fillName(out, "");\r |
104 | }\r |
105 | //value length (always 8 bytes)\r |
106 | writeInt2(8, out);\r |
107 | \r |
108 | //(Lower bound first)Integer in 4 bytes\r |
109 | writeInt4(lowerBound, out);\r |
110 | //(Upper bound)Integer in 4 bytes\r |
111 | writeInt4(upperBound, out);\r |
112 | }\r |
113 | }\r |
114 | /**\r |
115 | * @param attribute\r |
116 | * @param bytes\r |
117 | * @return\r |
118 | */\r |
119 | private static void attributeBytes(TextSyntax attribute, ByteArrayOutputStream out) {\r |
120 | // value tag\r |
121 | if (attribute instanceof Charset) {\r |
122 | out.write((byte) IppValueTag.CHARSET.getValue());\r |
123 | } else if (attribute instanceof NaturalLanguage) {\r |
124 | out.write((byte) IppValueTag.LANGUAGE.getValue());\r |
125 | } else {\r |
126 | out.write((byte) IppValueTag.NAME.getValue());\r |
127 | }\r |
128 | //name\r |
129 | fillName(out, (Attribute) attribute);\r |
130 | //value length \r |
131 | writeInt2(attribute.toString().length(), out);\r |
132 | writeNameAndTextString(attribute.toString(), out);\r |
133 | }\r |
134 | \r |
135 | /**\r |
136 | * @param attribute\r |
137 | * @param bytes\r |
138 | * @return\r |
139 | */\r |
140 | private static void attributeBytes(EnumSyntax attribute, ByteArrayOutputStream out) {\r |
141 | // Value tag\r |
142 | out.write((byte) IppValueTag.TEXT.getValue());\r |
143 | // Name\r |
144 | fillName(out, (Attribute) attribute);\r |
145 | // value length\r |
146 | writeInt2(attribute.toString().length(), out);\r |
147 | writeString(attribute.toString(), out);\r |
148 | }\r |
149 | \r |
150 | /**\r |
151 | * \r |
152 | * uses UTC time, not local time zone to encode the date\r |
153 | * \r |
154 | * @param attribute\r |
155 | * @param bytes\r |
156 | * @return\r |
157 | */\r |
158 | private static void attributeBytes(DateTimeSyntax attribute, ByteArrayOutputStream out) {\r |
159 | \r |
160 | \r |
161 | //Value tag\r |
162 | out.write((byte) IppValueTag.DATE.getValue());\r |
163 | //Name\r |
164 | fillName(out, (Attribute) attribute);\r |
165 | //Value length (always 11 bytes)\r |
166 | writeInt2(11, out);\r |
167 | \r |
168 | Date date = attribute.getValue();\r |
169 | TimeZone zone = TimeZone.getTimeZone("UTC");\r |
170 | Calendar cal = new GregorianCalendar(zone);\r |
171 | cal.setTime(date);\r |
172 | \r |
173 | int year = cal.get(GregorianCalendar.YEAR);\r |
174 | int month = cal.get(Calendar.MONTH) + 1;\r |
175 | int day = cal.get(Calendar.DAY_OF_MONTH);\r |
176 | int hour = cal.get(Calendar.HOUR_OF_DAY);\r |
177 | int minute = cal.get(Calendar.MINUTE);\r |
178 | int second = cal.get(Calendar.SECOND);\r |
179 | int deci = cal.get(Calendar.MILLISECOND) / 100;\r |
180 | int offset = zone.getOffset(cal.getTimeInMillis());\r |
181 | int hoursFromUtc = offset / MILIS_IN_HOUR;\r |
182 | int minutesFromUtc = offset % MILIS_IN_HOUR / MILIS_IN_MINUTE;\r |
183 | char direction = '+';\r |
184 | if (hoursFromUtc < 0) {\r |
185 | direction = '-';\r |
186 | hoursFromUtc *= -1;\r |
187 | }\r |
188 | writeInt2(year, out);\r |
189 | out.write((byte) month);\r |
190 | out.write((byte) day);\r |
191 | out.write((byte) hour);\r |
192 | out.write((byte) minute);\r |
193 | out.write((byte) second);\r |
194 | out.write((byte) deci);\r |
195 | out.write((byte) direction);\r |
196 | out.write((byte) hoursFromUtc);\r |
197 | out.write((byte) minutesFromUtc);\r |
198 | }\r |
199 | /**\r |
200 | * @param attribute\r |
201 | * @param bytes\r |
202 | * @return\r |
203 | */\r |
204 | private static void attributeBytes(URISyntax attribute, ByteArrayOutputStream out) {\r |
205 | //Value tag\r |
206 | out.write((byte) IppValueTag.URI.getValue());\r |
207 | //Name\r |
208 | fillName(out, (Attribute) attribute);\r |
209 | //value length\r |
210 | writeInt2(attribute.toString().length(), out);\r |
211 | writeString(attribute.toString(), out);\r |
212 | }\r |
213 | \r |
214 | /**\r |
215 | * @param attribute\r |
216 | * @param bytes\r |
217 | * @return\r |
218 | */\r |
219 | private static void attributeBytes(ResolutionSyntax attribute, ByteArrayOutputStream out) {\r |
220 | //Value tag\r |
221 | out.write((byte) IppValueTag.INTEGER.getValue());\r |
222 | //Name\r |
223 | fillName(out, (Attribute) attribute);\r |
224 | //Value length (always 9)\r |
225 | out.write((byte) 0);\r |
226 | out.write((byte) 9);\r |
227 | int feedResolution = attribute.getFeedResolution(ResolutionSyntax.DPI);\r |
228 | int crossFeedResolution = attribute.getCrossFeedResolution(ResolutionSyntax.DPI);\r |
229 | //(Lower bound first)Integer in 4 bytes\r |
230 | writeInt4(crossFeedResolution, out);\r |
231 | //(Upper bound)Integer in 4 bytes\r |
232 | writeInt4(feedResolution, out);\r |
233 | out.write((byte) ResolutionSyntax.DPI);\r |
234 | }\r |
235 | \r |
236 | public static void writeInt4(int value, ByteArrayOutputStream out){\r |
237 | out.write((byte) ((value & 0xff000000) >> 24));\r |
238 | out.write((byte) ((value & 0xff0000) >> 16));\r |
239 | out.write((byte) ((value & 0xff00) >> 8));\r |
240 | out.write((byte) (value & 0xff)); \r |
241 | }\r |
242 | \r |
243 | public static void writeInt2(int value, ByteArrayOutputStream out){\r |
244 | out.write((byte) ((value & 0xff00) >> 8));\r |
245 | out.write((byte) (value & 0xff)); \r |
246 | }\r |
247 | \r |
248 | public static void writeString(String value, ByteArrayOutputStream out, String charsetName) {\r |
249 | byte[] bytes;\r |
250 | try {\r |
251 | bytes = value.getBytes(charsetName);\r |
252 | } catch (UnsupportedEncodingException e) {\r |
253 | throw new IllegalArgumentException(charsetName + " encoding not supported by JVM");\r |
254 | }\r |
255 | out.write(bytes, 0, bytes.length);\r |
256 | }\r |
257 | \r |
258 | public static void writeString(String value, ByteArrayOutputStream out){\r |
259 | writeString(value, out, Charset.US_ASCII.getValue());\r |
260 | }\r |
261 | \r |
262 | public static void writeNameAndTextString(String value, ByteArrayOutputStream out) {\r |
263 | writeString(value, out, DEFAULT_CHARSET.getValue());\r |
264 | }\r |
265 | \r |
266 | /**\r |
267 | * @param attribute\r |
268 | * @return\r |
269 | */\r |
270 | public static void attributeBytes(Attribute attribute, ByteArrayOutputStream out) {\r |
271 | if (attribute instanceof IntegerSyntax) {\r |
272 | attributeBytes((IntegerSyntax) attribute, out);\r |
273 | } else if (attribute instanceof TextSyntax) {\r |
274 | attributeBytes((TextSyntax) attribute, out);\r |
275 | } else if (attribute instanceof DateTimeSyntax) {\r |
276 | attributeBytes((DateTimeSyntax) attribute, out);\r |
277 | } else if (attribute instanceof ResolutionSyntax) {\r |
278 | attributeBytes((ResolutionSyntax) attribute, out);\r |
279 | } else if (attribute instanceof SetOfIntegerSyntax) {\r |
280 | attributeBytes((SetOfIntegerSyntax) attribute, out);\r |
281 | } else if (attribute instanceof EnumSyntax) {\r |
282 | attributeBytes((EnumSyntax) attribute, out);\r |
283 | } else if (attribute instanceof URISyntax) {\r |
284 | attributeBytes((URISyntax) attribute, out);\r |
285 | } else {\r |
286 | throw new IllegalArgumentException("The given attribute is of an unknown SubType (only IntegerSyntax, TextSyntax, DateTimeSyntax, ResolutionSyntax, SetOfIntegerSyntax, EnumSyntax and URISyntax supported)");\r |
287 | }\r |
288 | }\r |
289 | \r |
290 | } |