1/*
2 * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25package sun.print;
26
27import java.util.Objects;
28import java.io.ByteArrayInputStream;
29
30public class AttributeClass {
31    private String myName;
32    private int myType;
33    private int nameLen;
34    private Object myValue;
35
36    public static final int TAG_UNSUPPORTED_VALUE = 0x10;
37    public static final int TAG_INT = 0x21;
38    public static final int TAG_BOOL = 0x22;
39    public static final int TAG_ENUM = 0x23;
40    public static final int TAG_OCTET = 0x30;
41    public static final int TAG_DATE = 0x31;
42    public static final int TAG_RESOLUTION = 0x32;
43    public static final int TAG_RANGE_INTEGER = 0x33;
44
45    public static final int TAG_TEXT_LANGUAGE = 0x35;
46    public static final int TAG_NAME_LANGUAGE = 0x36;
47
48    public static final int TAG_TEXT_WO_LANGUAGE = 0x41;
49    public static final int TAG_NAME_WO_LANGUAGE = 0x42;
50    public static final int TAG_KEYWORD = 0x44;
51    public static final int TAG_URI = 0x45;
52    public static final int TAG_CHARSET = 0x47;
53    public static final int TAG_NATURALLANGUAGE = 0x48;
54    public static final int TAG_MIME_MEDIATYPE = 0x49;
55    public static final int TAG_MEMBER_ATTRNAME = 0x4A;
56
57
58    public static final AttributeClass ATTRIBUTES_CHARSET =
59        new AttributeClass("attributes-charset",
60                           TAG_CHARSET, "utf-8");
61    public static final AttributeClass ATTRIBUTES_NATURAL_LANGUAGE =
62        new AttributeClass("attributes-natural-language",
63                           TAG_NATURALLANGUAGE, "en");
64
65    /*
66     * value passed in by IPPPrintService.readIPPResponse is a sequence
67     * of bytes with this format
68     * | length1 | byte1 | byte 2 | ... byten | length2 | byte1 ... byten |
69     *      :
70     * | lengthN | byte1 ... byten | total number of values|
71     */
72    protected AttributeClass(String name, int type, Object value) {
73        myName = name;
74        myType = type;
75        nameLen = name.length();
76        myValue = value;
77    }
78
79    public byte getType() {
80        return (byte)myType;
81    }
82
83    public char[] getLenChars() {
84        char[] chars = new char[2];
85        chars[0] = 0;
86        chars[1] = (char)nameLen;
87        return chars;
88    }
89
90    /**
91     * Returns raw data.
92     */
93    public Object getObjectValue() {
94        return myValue;
95    }
96
97    /**
98     * Returns single int value.
99     */
100    public int getIntValue() {
101        byte[] bufArray = (byte[])myValue;
102
103        if (bufArray != null) {
104            byte[] buf = new byte[4];
105            for (int i=0; i<4; i++) {
106                buf[i] = bufArray[i+1];
107            }
108
109            return convertToInt(buf);
110        }
111        return 0;
112    }
113
114    /**
115     * Returns array of int values.
116     */
117    public int[] getArrayOfIntValues() {
118
119        byte[] bufArray = (byte[])myValue;
120        if (bufArray != null) {
121
122            //ArrayList valList = new ArrayList();
123            ByteArrayInputStream bufStream =
124                new ByteArrayInputStream(bufArray);
125            int available = bufStream.available();
126
127            // total number of values is at the end of the stream
128            bufStream.mark(available);
129            bufStream.skip(available-1);
130            int length = bufStream.read();
131            bufStream.reset();
132
133            int[] valueArray = new int[length];
134            for (int i = 0; i < length; i++) {
135                // read length
136                int valLength = bufStream.read();
137                if (valLength != 4) {
138                    // invalid data
139                    return null;
140                }
141
142                byte[] bufBytes = new byte[valLength];
143                bufStream.read(bufBytes, 0, valLength);
144                valueArray[i] = convertToInt(bufBytes);
145
146            }
147            return valueArray;
148        }
149        return null;
150    }
151
152    /**
153     * Returns 2 int values.
154     */
155    public int[] getIntRangeValue() {
156        int[] range = {0, 0};
157        byte[] bufArray = (byte[])myValue;
158        if (bufArray != null) {
159            int nBytes = 4; // 32-bit signed integer
160            for (int j=0; j<2; j++) { // 2 set of integers
161                byte[] intBytes = new byte[nBytes];
162                // REMIND: # bytes should be 8
163                for (int i=0; i< nBytes; i++) {
164                    //+ 1 because the 1st byte is length
165                    intBytes[i] = bufArray[i+(4*j)+1];
166                }
167                range[j] = convertToInt(intBytes);
168            }
169        }
170        return range;
171
172    }
173
174    /**
175     * Returns String value.
176     */
177    public String getStringValue() {
178        //assumes only 1 attribute value.  Will get the first value
179        // if > 1.
180        String strVal = null;
181        byte[] bufArray = (byte[])myValue;
182        if (bufArray != null) {
183            ByteArrayInputStream bufStream =
184                new ByteArrayInputStream(bufArray);
185
186            int valLength = bufStream.read();
187
188            byte[] strBytes = new byte[valLength];
189            bufStream.read(strBytes, 0, valLength);
190            try {
191                strVal = new String(strBytes, "UTF-8");
192            } catch (java.io.UnsupportedEncodingException uee) {
193            }
194        }
195        return strVal;
196    }
197
198
199    /**
200     * Returns array of String values.
201     */
202    public String[] getArrayOfStringValues() {
203
204        byte[] bufArray = (byte[])myValue;
205        if (bufArray != null) {
206            ByteArrayInputStream bufStream =
207                new ByteArrayInputStream(bufArray);
208            int available = bufStream.available();
209
210            // total number of values is at the end of the stream
211            bufStream.mark(available);
212            bufStream.skip(available-1);
213            int length = bufStream.read();
214            bufStream.reset();
215
216            String[] valueArray = new String[length];
217            for (int i = 0; i < length; i++) {
218                // read length
219                int valLength = bufStream.read();
220                byte[] bufBytes = new byte[valLength];
221                bufStream.read(bufBytes, 0, valLength);
222                try {
223                    valueArray[i] = new String(bufBytes, "UTF-8");
224                } catch (java.io.UnsupportedEncodingException uee) {
225                }
226            }
227            return valueArray;
228        }
229        return null;
230    }
231
232
233    /**
234     * Returns single byte value.
235     */
236    public byte getByteValue() {
237        byte[] bufArray = (byte[])myValue;
238
239        if ((bufArray != null) && (bufArray.length>=2)) {
240            return bufArray[1];
241        }
242        return 0;
243    }
244
245    /**
246     * Returns attribute name.
247     */
248    public String getName() {
249        return myName;
250    }
251
252    @Override
253    public boolean equals(Object obj) {
254        if (!(obj instanceof AttributeClass)) {
255            return false;
256        }
257        if (this == obj) {
258            return true;
259        }
260
261        AttributeClass acObj = (AttributeClass) obj;
262        return myType == acObj.getType() &&
263               Objects.equals(myName, acObj.getName()) &&
264               Objects.equals(myValue, acObj.getObjectValue());
265    }
266
267    @Override
268    public int hashCode() {
269        return Objects.hash(myType, myName, myValue);
270    }
271
272    public String toString() {
273        return myName;
274    }
275
276    private int unsignedByteToInt(byte b) {
277        return (b & 0xff);
278    }
279
280    private int convertToInt(byte[] buf) {
281        int intVal = 0;
282        int pos = 0;
283        intVal+= unsignedByteToInt(buf[pos++]) << 24;
284        intVal+= unsignedByteToInt(buf[pos++]) << 16;
285        intVal+= unsignedByteToInt(buf[pos++]) << 8;
286        intVal+= unsignedByteToInt(buf[pos++]) << 0;
287        return intVal;
288    }
289}
290