1/*
2 * Copyright (C) 2007-2008 Esmertec AG.
3 * Copyright (C) 2007-2008 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package com.android.messaging.mmslib.pdu;
19
20import android.util.Log;
21
22import java.io.ByteArrayOutputStream;
23import java.io.IOException;
24import java.io.UnsupportedEncodingException;
25import java.util.ArrayList;
26
27/**
28 * Encoded-string-value = Text-string | Value-length Char-set Text-string
29 */
30public class EncodedStringValue implements Cloneable {
31    private static final String TAG = "EncodedStringValue";
32    private static final boolean DEBUG = false;
33    private static final boolean LOCAL_LOGV = false;
34
35    /**
36     * The Char-set value.
37     */
38    private int mCharacterSet;
39
40    /**
41     * The Text-string value.
42     */
43    private byte[] mData;
44
45    /**
46     * Constructor.
47     *
48     * @param charset the Char-set value
49     * @param data    the Text-string value
50     * @throws NullPointerException if Text-string value is null.
51     */
52    public EncodedStringValue(int charset, byte[] data) {
53        // TODO: CharSet needs to be validated against MIBEnum.
54        if (null == data) {
55            throw new NullPointerException("EncodedStringValue: Text-string is null.");
56        }
57
58        mCharacterSet = charset;
59        mData = new byte[data.length];
60        System.arraycopy(data, 0, mData, 0, data.length);
61    }
62
63    /**
64     * Constructor.
65     *
66     * @param data the Text-string value
67     * @throws NullPointerException if Text-string value is null.
68     */
69    public EncodedStringValue(byte[] data) {
70        this(CharacterSets.DEFAULT_CHARSET, data);
71    }
72
73    public EncodedStringValue(String data) {
74        this(CharacterSets.DEFAULT_CHARSET, data);
75    }
76
77    /**
78     * Constructor
79     *
80     * @param charset
81     * @param data The text in Java String
82     * @throws NullPointerException if Text-string value is null.
83     */
84    public EncodedStringValue(int charset, String data) {
85        if (null == data) {
86            throw new NullPointerException("EncodedStringValue: Text-string is null");
87        }
88        mCharacterSet = charset;
89        try {
90            mData = data.getBytes(CharacterSets.getMimeName(charset));
91        } catch (UnsupportedEncodingException e) {
92            Log.e(TAG, "Input encoding " + charset + " must be supported.", e);
93            mData = data.getBytes();
94        }
95    }
96
97    /**
98     * Get Char-set value.
99     *
100     * @return the value
101     */
102    public int getCharacterSet() {
103        return mCharacterSet;
104    }
105
106    /**
107     * Set Char-set value.
108     *
109     * @param charset the Char-set value
110     */
111    public void setCharacterSet(int charset) {
112        // TODO: CharSet needs to be validated against MIBEnum.
113        mCharacterSet = charset;
114    }
115
116    /**
117     * Get Text-string value.
118     *
119     * @return the value
120     */
121    public byte[] getTextString() {
122        byte[] byteArray = new byte[mData.length];
123
124        System.arraycopy(mData, 0, byteArray, 0, mData.length);
125        return byteArray;
126    }
127
128    /**
129     * Set Text-string value.
130     *
131     * @param textString the Text-string value
132     * @throws NullPointerException if Text-string value is null.
133     */
134    public void setTextString(byte[] textString) {
135        if (null == textString) {
136            throw new NullPointerException("EncodedStringValue: Text-string is null.");
137        }
138
139        mData = new byte[textString.length];
140        System.arraycopy(textString, 0, mData, 0, textString.length);
141    }
142
143    /**
144     * Convert this object to a {@link java.lang.String}. If the encoding of
145     * the EncodedStringValue is null or unsupported, it will be
146     * treated as iso-8859-1 encoding.
147     *
148     * @return The decoded String.
149     */
150    public String getString() {
151        if (CharacterSets.ANY_CHARSET == mCharacterSet) {
152            return new String(mData); // system default encoding.
153        } else {
154            try {
155                String name = CharacterSets.getMimeName(mCharacterSet);
156                return new String(mData, name);
157            } catch (UnsupportedEncodingException e) {
158                if (LOCAL_LOGV) {
159                    Log.v(TAG, e.getMessage(), e);
160                }
161                try {
162                    return new String(mData, CharacterSets.MIMENAME_ISO_8859_1);
163                } catch (UnsupportedEncodingException exception) {
164                    return new String(mData); // system default encoding.
165                }
166            }
167        }
168    }
169
170    /**
171     * Append to Text-string.
172     *
173     * @param textString the textString to append
174     * @throws NullPointerException if the text String is null
175     *                              or an IOException occured.
176     */
177    public void appendTextString(byte[] textString) {
178        if (null == textString) {
179            throw new NullPointerException("Text-string is null.");
180        }
181
182        if (null == mData) {
183            mData = new byte[textString.length];
184            System.arraycopy(textString, 0, mData, 0, textString.length);
185        } else {
186            ByteArrayOutputStream newTextString = new ByteArrayOutputStream();
187            try {
188                newTextString.write(mData);
189                newTextString.write(textString);
190            } catch (IOException e) {
191                e.printStackTrace();
192                throw new NullPointerException(
193                        "appendTextString: failed when write a new Text-string");
194            }
195
196            mData = newTextString.toByteArray();
197        }
198    }
199
200    /*
201     * (non-Javadoc)
202     * @see java.lang.Object#clone()
203     */
204    @Override
205    public Object clone() throws CloneNotSupportedException {
206        super.clone();
207        int len = mData.length;
208        byte[] dstBytes = new byte[len];
209        System.arraycopy(mData, 0, dstBytes, 0, len);
210
211        try {
212            return new EncodedStringValue(mCharacterSet, dstBytes);
213        } catch (Exception e) {
214            Log.e(TAG, "failed to clone an EncodedStringValue: " + this);
215            e.printStackTrace();
216            throw new CloneNotSupportedException(e.getMessage());
217        }
218    }
219
220    /**
221     * Split this encoded string around matches of the given pattern.
222     *
223     * @param pattern the delimiting pattern
224     * @return the array of encoded strings computed by splitting this encoded
225     *         string around matches of the given pattern
226     */
227    public EncodedStringValue[] split(String pattern) {
228        String[] temp = getString().split(pattern);
229        EncodedStringValue[] ret = new EncodedStringValue[temp.length];
230        for (int i = 0; i < ret.length; ++i) {
231            try {
232                ret[i] = new EncodedStringValue(mCharacterSet,
233                        temp[i].getBytes());
234            } catch (NullPointerException exception) {
235                // Can't arrive here
236                return null;
237            }
238        }
239        return ret;
240    }
241
242    /**
243     * Extract an EncodedStringValue[] from a given String.
244     */
245    public static EncodedStringValue[] extract(String src) {
246        String[] values = src.split(";");
247
248        ArrayList<EncodedStringValue> list = new ArrayList<EncodedStringValue>();
249        for (int i = 0; i < values.length; i++) {
250            if (values[i].length() > 0) {
251                list.add(new EncodedStringValue(values[i]));
252            }
253        }
254
255        int len = list.size();
256        if (len > 0) {
257            return list.toArray(new EncodedStringValue[len]);
258        } else {
259            return null;
260        }
261    }
262
263    /**
264     * Concatenate an EncodedStringValue[] into a single String.
265     */
266    public static String concat(EncodedStringValue[] addr) {
267        StringBuilder sb = new StringBuilder();
268        int maxIndex = addr.length - 1;
269        for (int i = 0; i <= maxIndex; i++) {
270            sb.append(addr[i].getString());
271            if (i < maxIndex) {
272                sb.append(";");
273            }
274        }
275
276        return sb.toString();
277    }
278
279    public static EncodedStringValue copy(EncodedStringValue value) {
280        if (value == null) {
281            return null;
282        }
283
284        return new EncodedStringValue(value.mCharacterSet, value.mData);
285    }
286
287    public static EncodedStringValue[] encodeStrings(String[] array) {
288        int count = array.length;
289        if (count > 0) {
290            EncodedStringValue[] encodedArray = new EncodedStringValue[count];
291            for (int i = 0; i < count; i++) {
292                encodedArray[i] = new EncodedStringValue(array[i]);
293            }
294            return encodedArray;
295        }
296        return null;
297    }
298}
299