1 2 /* ==================================================================== 3 * The Apache Software License, Version 1.1 4 * 5 * Copyright (c) 2002 The Apache Software Foundation. All rights 6 * reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in 17 * the documentation and/or other materials provided with the 18 * distribution. 19 * 20 * 3. The end-user documentation included with the redistribution, 21 * if any, must include the following acknowledgment: 22 * "This product includes software developed by the 23 * Apache Software Foundation (http://www.apache.org/)." 24 * Alternately, this acknowledgment may appear in the software itself, 25 * if and wherever such third-party acknowledgments normally appear. 26 * 27 * 4. The names "Apache" and "Apache Software Foundation" and 28 * "Apache POI" must not be used to endorse or promote products 29 * derived from this software without prior written permission. For 30 * written permission, please contact apache@apache.org. 31 * 32 * 5. Products derived from this software may not be called "Apache", 33 * "Apache POI", nor may "Apache" appear in their name, without 34 * prior written permission of the Apache Software Foundation. 35 * 36 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 37 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 38 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 39 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 40 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 41 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 42 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 43 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 44 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 45 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 46 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 47 * SUCH DAMAGE. 48 * ==================================================================== 49 * 50 * This software consists of voluntary contributions made by many 51 * individuals on behalf of the Apache Software Foundation. For more 52 * information on the Apache Software Foundation, please see 53 * <http://www.apache.org/>. 54 */ 55 56 package org.apache.poi.util; 57 58 import java.io.UnsupportedEncodingException; 59 60 import java.text.NumberFormat; 61 import java.text.FieldPosition; 62 63 /** 64 * Title: String Utility 65 * Description: Collection of string handling utilities 66 * @author Andrew C. Oliver 67 * @version 1.0 68 */ 69 70 public class StringUtil 71 { 72 private StringUtil() 73 { 74 } 75 76 /** 77 * given a byte array of 16-bit unicode characters, compress to 78 * 8-bit and return a string 79 * 80 * @param string the byte array to be converted 81 * @param offset the initial offset into the byte array. it is 82 * assumed that string[ offset ] and string[ offset 83 * + 1 ] contain the first 16-bit unicode character 84 * @len the length of the final string 85 * 86 * @param len 87 * @return the converted string 88 * 89 * @exception ArrayIndexOutOfBoundsException if offset is out of 90 * bounds for the byte array (i.e., is negative or is 91 * greater than or equal to string.length) 92 * @exception IllegalArgumentException if len is too large (i.e., 93 * there is not enough data in string to create a 94 * String of that length) 95 */ 96 97 public static String getFromUnicode(final byte [] string, 98 final int offset, final int len) 99 throws ArrayIndexOutOfBoundsException, IllegalArgumentException 100 { 101 if ((offset < 0) || (offset >= string.length)) 102 { 103 throw new ArrayIndexOutOfBoundsException("Illegal offset"); 104 } 105 if ((len < 0) || (((string.length - offset) / 2) < len)) 106 { 107 throw new IllegalArgumentException("Illegal length"); 108 } 109 byte[] bstring = new byte[ len ]; 110 int index = offset + 1; // start with low bits. 111 112 for (int k = 0; k < len; k++) 113 { 114 bstring[ k ] = string[ index ]; 115 index += 2; 116 } 117 return new String(bstring); 118 } 119 120 /** 121 * given a byte array of 16-bit unicode characters, compress to 122 * 8-bit and return a string 123 * 124 * @param string the byte array to be converted 125 * 126 * @return the converted string 127 */ 128 129 public static String getFromUnicode(final byte [] string) 130 { 131 return getFromUnicode(string, 0, string.length / 2); 132 } 133 134 /** 135 * write compressed unicode 136 * 137 * @param input the String containing the data to be written 138 * @param output the byte array to which the data is to be written 139 * @param offset an offset into the byte arrat at which the data 140 * is start when written 141 */ 142 143 public static void putCompressedUnicode(final String input, 144 final byte [] output, 145 final int offset) 146 { 147 int strlen = input.length(); 148 149 for (int k = 0; k < strlen; k++) 150 { 151 output[ offset + k ] = ( byte ) input.charAt(k); 152 } 153 } 154 155 /** 156 * Write uncompressed unicode 157 * 158 * @param input the String containing the unicode data to be 159 * written 160 * @param output the byte array to hold the uncompressed unicode 161 * @param offset the offset to start writing into the byte array 162 */ 163 164 public static void putUncompressedUnicode(final String input, 165 final byte [] output, 166 final int offset) 167 { 168 int strlen = input.length(); 169 170 for (int k = 0; k < strlen; k++) 171 { 172 char c = input.charAt(k); 173 174 output[ offset + (2 * k) ] = ( byte ) c; 175 output[ offset + (2 * k) + 1 ] = ( byte ) (c >> 8); 176 } 177 } 178 179 public static String format(String message, Object [] params) 180 { 181 int currentParamNumber = 0; 182 StringBuffer formattedMessage = new StringBuffer(); 183 184 for (int i = 0; i < message.length(); i++) 185 { 186 if (message.charAt(i) == '%') 187 { 188 if (currentParamNumber >= params.length) 189 { 190 formattedMessage.append("?missing data?"); 191 } 192 else if ((params[ currentParamNumber ] instanceof Number) 193 && (i + 1 < message.length())) 194 { 195 i += matchOptionalFormatting( 196 ( Number ) params[ currentParamNumber++ ], 197 message.substring(i + 1), formattedMessage); 198 } 199 else 200 { 201 formattedMessage 202 .append(params[ currentParamNumber++ ].toString()); 203 } 204 } 205 else 206 { 207 if ((message.charAt(i) == '\\') && (i + 1 < message.length()) 208 && (message.charAt(i + 1) == '%')) 209 { 210 formattedMessage.append('%'); 211 i++; 212 } 213 else 214 { 215 formattedMessage.append(message.charAt(i)); 216 } 217 } 218 } 219 return formattedMessage.toString(); 220 } 221 222 private static int matchOptionalFormatting(Number number, 223 String formatting, 224 StringBuffer outputTo) 225 { 226 NumberFormat numberFormat = NumberFormat.getInstance(); 227 228 if ((0 < formatting.length()) 229 && Character.isDigit(formatting.charAt(0))) 230 { 231 numberFormat 232 .setMinimumIntegerDigits(Integer 233 .parseInt(formatting.charAt(0) + "")); 234 if ((2 < formatting.length()) && (formatting.charAt(1) == '.') 235 && Character.isDigit(formatting.charAt(2))) 236 { 237 numberFormat 238 .setMaximumFractionDigits(Integer 239 .parseInt(formatting.charAt(2) + "")); 240 numberFormat.format(number, outputTo, new FieldPosition(0)); 241 return 3; 242 } 243 numberFormat.format(number, outputTo, new FieldPosition(0)); 244 return 1; 245 } 246 else if ((0 < formatting.length()) && (formatting.charAt(0) == '.')) 247 { 248 if ((1 < formatting.length()) 249 && Character.isDigit(formatting.charAt(1))) 250 { 251 numberFormat 252 .setMaximumFractionDigits(Integer 253 .parseInt(formatting.charAt(1) + "")); 254 numberFormat.format(number, outputTo, new FieldPosition(0)); 255 return 2; 256 } 257 } 258 numberFormat.format(number, outputTo, new FieldPosition(0)); 259 return 1; 260 } 261 } 262