001/*
002 * $Id: Utilities.java 4847 2011-05-05 19:46:13Z redlab_b $
003 *
004 * This file is part of the iText (R) project.
005 * Copyright (c) 1998-2011 1T3XT BVBA
006 * Authors: Bruno Lowagie, Paulo Soares, et al.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU Affero General Public License version 3
010 * as published by the Free Software Foundation with the addition of the
011 * following permission added to Section 15 as permitted in Section 7(a):
012 * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY 1T3XT,
013 * 1T3XT DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
014 *
015 * This program is distributed in the hope that it will be useful, but
016 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
017 * or FITNESS FOR A PARTICULAR PURPOSE.
018 * See the GNU Affero General Public License for more details.
019 * You should have received a copy of the GNU Affero General Public License
020 * along with this program; if not, see http://www.gnu.org/licenses or write to
021 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
022 * Boston, MA, 02110-1301 USA, or download the license from the following URL:
023 * http://itextpdf.com/terms-of-use/
024 *
025 * The interactive user interfaces in modified source and object code versions
026 * of this program must display Appropriate Legal Notices, as required under
027 * Section 5 of the GNU Affero General Public License.
028 *
029 * In accordance with Section 7(b) of the GNU Affero General Public License,
030 * a covered work must retain the producer line in every PDF that is created
031 * or manipulated using iText.
032 *
033 * You can be released from the requirements of the license by purchasing
034 * a commercial license. Buying such a license is mandatory as soon as you
035 * develop commercial activities involving the iText software without
036 * disclosing the source code of your own applications.
037 * These activities include: offering paid services to customers as an ASP,
038 * serving PDFs on the fly in a web application, shipping iText with a closed
039 * source product.
040 *
041 * For more information, please contact iText Software Corp. at this
042 * address: sales@itextpdf.com
043 */
044package com.itextpdf.text;
045
046import java.io.File;
047import java.io.FileInputStream;
048import java.io.IOException;
049import java.io.InputStream;
050import java.net.MalformedURLException;
051import java.net.URL;
052import java.util.Collections;
053import java.util.Hashtable;
054import java.util.Properties;
055import java.util.Set;
056
057import com.itextpdf.text.pdf.PRTokeniser;
058
059/**
060 * A collection of convenience methods that were present in many different iText
061 * classes.
062 */
063
064public class Utilities {
065
066        /**
067         * Gets the keys of a Hashtable.
068         * Marked as deprecated, not used anywhere anymore.
069         * @param <K> type for the key
070         * @param <V> type for the value
071         * @param table
072         *            a Hashtable
073         * @return the keyset of a Hashtable (or an empty set if table is null)
074         */
075        @Deprecated
076        public static <K, V>  Set<K> getKeySet(final Hashtable<K, V> table) {
077                return table == null ? Collections.<K>emptySet() : table.keySet();
078        }
079
080        /**
081         * Utility method to extend an array.
082         *
083         * @param original
084         *            the original array or <CODE>null</CODE>
085         * @param item
086         *            the item to be added to the array
087         * @return a new array with the item appended
088         */
089        public static Object[][] addToArray(Object original[][], final Object item[]) {
090                if (original == null) {
091                        original = new Object[1][];
092                        original[0] = item;
093                        return original;
094                } else {
095                        Object original2[][] = new Object[original.length + 1][];
096                        System.arraycopy(original, 0, original2, 0, original.length);
097                        original2[original.length] = item;
098                        return original2;
099                }
100        }
101
102        /**
103         * Checks for a true/false value of a key in a Properties object.
104         * @param attributes
105         * @param key
106         * @return a true/false value of a key in a Properties object
107         */
108        public static boolean checkTrueOrFalse(final Properties attributes, final String key) {
109                return "true".equalsIgnoreCase(attributes.getProperty(key));
110        }
111
112        /**
113         * Unescapes an URL. All the "%xx" are replaced by the 'xx' hex char value.
114         * @param src the url to unescape
115         * @return the unescaped value
116         */
117        public static String unEscapeURL(final String src) {
118            StringBuffer bf = new StringBuffer();
119            char[] s = src.toCharArray();
120            for (int k = 0; k < s.length; ++k) {
121                char c = s[k];
122                if (c == '%') {
123                    if (k + 2 >= s.length) {
124                        bf.append(c);
125                        continue;
126                    }
127                    int a0 = PRTokeniser.getHex(s[k + 1]);
128                    int a1 = PRTokeniser.getHex(s[k + 2]);
129                    if (a0 < 0 || a1 < 0) {
130                        bf.append(c);
131                        continue;
132                    }
133                    bf.append((char)(a0 * 16 + a1));
134                    k += 2;
135                }
136                else
137                    bf.append(c);
138            }
139            return bf.toString();
140        }
141
142        /**
143         * This method makes a valid URL from a given filename.
144         * <P>
145         * This method makes the conversion of this library from the JAVA 2 platform
146         * to a JDK1.1.x-version easier.
147         *
148         * @param filename
149         *            a given filename
150         * @return a valid URL
151         * @throws MalformedURLException
152         */
153        public static URL toURL(final String filename) throws MalformedURLException {
154        try {
155            return new URL(filename);
156        }
157        catch (Exception e) {
158            return new File(filename).toURI().toURL();
159        }
160        }
161
162        /**
163         * This method is an alternative for the <CODE>InputStream.skip()</CODE>
164         * -method that doesn't seem to work properly for big values of <CODE>size
165         * </CODE>.
166         *
167         * @param is
168         *            the <CODE>InputStream</CODE>
169         * @param size
170         *            the number of bytes to skip
171         * @throws IOException
172         */
173        static public void skip(final InputStream is, int size) throws IOException {
174            long n;
175                while (size > 0) {
176                n = is.skip(size);
177                if (n <= 0)
178                    break;
179                        size -= n;
180                }
181        }
182
183        /**
184         * Measurement conversion from millimeters to points.
185         * @param       value   a value in millimeters
186         * @return      a value in points
187         * @since       2.1.2
188         */
189        public static final float millimetersToPoints(final float value) {
190            return inchesToPoints(millimetersToInches(value));
191        }
192
193        /**
194         * Measurement conversion from millimeters to inches.
195         * @param       value   a value in millimeters
196         * @return      a value in inches
197         * @since       2.1.2
198         */
199        public static final float millimetersToInches(final float value) {
200            return value / 25.4f;
201        }
202
203        /**
204         * Measurement conversion from points to millimeters.
205         * @param       value   a value in points
206         * @return      a value in millimeters
207         * @since       2.1.2
208         */
209        public static final float pointsToMillimeters(final float value) {
210            return inchesToMillimeters(pointsToInches(value));
211        }
212
213        /**
214         * Measurement conversion from points to inches.
215         * @param       value   a value in points
216         * @return      a value in inches
217         * @since       2.1.2
218         */
219        public static final float pointsToInches(final float value) {
220            return value / 72f;
221        }
222
223        /**
224         * Measurement conversion from inches to millimeters.
225         * @param       value   a value in inches
226         * @return      a value in millimeters
227         * @since       2.1.2
228         */
229        public static final float inchesToMillimeters(final float value) {
230            return value * 25.4f;
231        }
232
233        /**
234         * Measurement conversion from inches to points.
235         * @param       value   a value in inches
236         * @return      a value in points
237         * @since       2.1.2
238         */
239        public static final float inchesToPoints(final float value) {
240            return value * 72f;
241        }
242
243    /**
244     * Check if the value of a character belongs to a certain interval
245     * that indicates it's the higher part of a surrogate pair.
246     * @param c the character
247     * @return  true if the character belongs to the interval
248     * @since   2.1.2
249     */
250    public static boolean isSurrogateHigh(final char c) {
251        return c >= '\ud800' && c <= '\udbff';
252    }
253
254    /**
255     * Check if the value of a character belongs to a certain interval
256     * that indicates it's the lower part of a surrogate pair.
257     * @param c the character
258     * @return  true if the character belongs to the interval
259     * @since   2.1.2
260     */
261    public static boolean isSurrogateLow(final char c) {
262        return c >= '\udc00' && c <= '\udfff';
263    }
264
265    /**
266     * Checks if two subsequent characters in a String are
267     * are the higher and the lower character in a surrogate
268     * pair (and therefore eligible for conversion to a UTF 32 character).
269     * @param text      the String with the high and low surrogate characters
270     * @param idx       the index of the 'high' character in the pair
271     * @return  true if the characters are surrogate pairs
272     * @since   2.1.2
273     */
274    public static boolean isSurrogatePair(final String text, final int idx) {
275        if (idx < 0 || idx > text.length() - 2)
276            return false;
277        return isSurrogateHigh(text.charAt(idx)) && isSurrogateLow(text.charAt(idx + 1));
278    }
279
280    /**
281     * Checks if two subsequent characters in a character array are
282     * are the higher and the lower character in a surrogate
283     * pair (and therefore eligible for conversion to a UTF 32 character).
284     * @param text      the character array with the high and low surrogate characters
285     * @param idx       the index of the 'high' character in the pair
286     * @return  true if the characters are surrogate pairs
287     * @since   2.1.2
288     */
289    public static boolean isSurrogatePair(final char[] text, final int idx) {
290        if (idx < 0 || idx > text.length - 2)
291            return false;
292        return isSurrogateHigh(text[idx]) && isSurrogateLow(text[idx + 1]);
293    }
294
295    /**
296     * Returns the code point of a UTF32 character corresponding with
297     * a high and a low surrogate value.
298     * @param highSurrogate     the high surrogate value
299     * @param lowSurrogate      the low surrogate value
300     * @return  a code point value
301     * @since   2.1.2
302     */
303    public static int convertToUtf32(final char highSurrogate, final char lowSurrogate) {
304         return (highSurrogate - 0xd800) * 0x400 + lowSurrogate - 0xdc00 + 0x10000;
305    }
306
307    /**
308     * Converts a unicode character in a character array to a UTF 32 code point value.
309     * @param text      a character array that has the unicode character(s)
310     * @param idx       the index of the 'high' character
311     * @return  the code point value
312     * @since   2.1.2
313     */
314    public static int convertToUtf32(final char[] text, final int idx) {
315         return (text[idx] - 0xd800) * 0x400 + text[idx + 1] - 0xdc00 + 0x10000;
316    }
317
318    /**
319     * Converts a unicode character in a String to a UTF32 code point value
320     * @param text      a String that has the unicode character(s)
321     * @param idx       the index of the 'high' character
322     * @return  the codepoint value
323     * @since   2.1.2
324     */
325    public static int convertToUtf32(final String text, final int idx) {
326         return (text.charAt(idx) - 0xd800) * 0x400 + text.charAt(idx + 1) - 0xdc00 + 0x10000;
327    }
328
329    /**
330     * Converts a UTF32 code point value to a String with the corresponding character(s).
331     * @param codePoint a Unicode value
332     * @return  the corresponding characters in a String
333     * @since   2.1.2
334     */
335    public static String convertFromUtf32(int codePoint) {
336        if (codePoint < 0x10000)
337            return Character.toString((char)codePoint);
338        codePoint -= 0x10000;
339        return new String(new char[]{(char)(codePoint / 0x400 + 0xd800), (char)(codePoint % 0x400 + 0xdc00)});
340    }
341
342    /**
343     * Reads the contents of a file to a String.
344     * @param   path    the path to the file
345     * @return  a String with the contents of the file
346     * @throws IOException
347     * @since   iText 5.0.0
348     */
349        public static String readFileToString(final String path) throws IOException {
350                return readFileToString(new File(path));
351        }
352
353    /**
354     * Reads the contents of a file to a String.
355     * @param   file    a file
356     * @return  a String with the contents of the file
357     * @throws IOException if file was not found or could not be read.
358     * @since   iText 5.0.0
359     */
360        public static String readFileToString(final File file) throws IOException {
361                byte[] jsBytes = new byte[(int) file.length()];
362            FileInputStream f = new FileInputStream(file);
363            f.read(jsBytes);
364            return new String(jsBytes);
365        }
366}