View | Details | Raw Unified | Return to bug 27921
Collapse All | Expand All

(-)src/java/org/apache/poi/hssf/record/FormatRecord.java (+1 lines)
Lines 144-149 Link Here
144
    public void setFormatString(String fs)
144
    public void setFormatString(String fs)
145
    {
145
    {
146
        field_4_formatstring = fs;
146
        field_4_formatstring = fs;
147
        setUnicodeFlag(!StringUtil.canBeSafelyCompressed(fs));
147
    }
148
    }
148
149
149
    /**
150
    /**
(-)src/java/org/apache/poi/util/StringUtil.java (-310 / +345 lines)
Lines 1-18 Link Here
1
/* ====================================================================
1
/* ====================================================================
2
   Copyright 2003-2004   Apache Software Foundation
2
 Copyright 2003-2004   Apache Software Foundation
3
3
4
   Licensed under the Apache License, Version 2.0 (the "License");
4
 Licensed under the Apache License, Version 2.0 (the "License");
5
   you may not use this file except in compliance with the License.
5
 you may not use this file except in compliance with the License.
6
   You may obtain a copy of the License at
6
 You may obtain a copy of the License at
7
7
8
       http://www.apache.org/licenses/LICENSE-2.0
8
 http://www.apache.org/licenses/LICENSE-2.0
9
9
10
   Unless required by applicable law or agreed to in writing, software
10
 Unless required by applicable law or agreed to in writing, software
11
   distributed under the License is distributed on an "AS IS" BASIS,
11
 distributed under the License is distributed on an "AS IS" BASIS,
12
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
   See the License for the specific language governing permissions and
13
 See the License for the specific language governing permissions and
14
   limitations under the License.
14
 limitations under the License.
15
==================================================================== */
15
 ==================================================================== */
16
16
17
package org.apache.poi.util;
17
package org.apache.poi.util;
18
18
Lines 22-325 Link Here
22
import java.text.FieldPosition;
22
import java.text.FieldPosition;
23
23
24
/**
24
/**
25
 *  Title: String Utility Description: Collection of string handling utilities
25
 * Title: String Utility Description: Collection of string handling utilities
26
 * 
26
 * 
27
 * Now it is quite confusing: the method pairs, in which
27
 * Now it is quite confusing: the method pairs, in which one of them write data
28
 * one of them write data and other read written data are:
28
 * and other read written data are: putUncompressedUnicodeHigh and
29
 * putUncompressedUnicodeHigh and getFromUnicode
29
 * getFromUnicode putUncompressedUnicode and getFromUnicodeHigh
30
 * putUncompressedUnicode     and getFromUnicodeHigh
30
 * 
31
 *
31
 * @author Andrew C. Oliver
32
 *@author     Andrew C. Oliver
32
 * @author Sergei Kozello (sergeikozello at mail.ru) @created May 10, 2002
33
 *@author     Sergei Kozello (sergeikozello at mail.ru)
33
 * @version 1.0
34
 *@created    May 10, 2002
35
 *@version    1.0
36
 */
34
 */
37
35
38
public class StringUtil {
36
public class StringUtil
39
    
37
{
40
    private final static String ENCODING="ISO-8859-1";
38
41
    /**
39
	private final static String ENCODING = "ISO-8859-1";
42
     *  Constructor for the StringUtil object
40
43
     */
41
	/**
44
    private StringUtil() { }
42
	 * Constructor for the StringUtil object
45
43
	 */
46
    
44
	private StringUtil()
47
    /**
45
	{
48
     *  given a byte array of 16-bit unicode characters, compress to 8-bit and
46
	}
49
     *  return a string
47
50
     *
48
	public static boolean canBeSafelyCompressed(String string)
51
     * { 0x16, 0x00 } -> 0x16
49
	{
52
     * 
50
		try
53
     *@param  string                              the byte array to be converted
51
		{
54
     *@param  offset                              the initial offset into the
52
			return string.equals(new String(string.getBytes(ENCODING), ENCODING));
55
     *      byte array. it is assumed that string[ offset ] and string[ offset +
53
		}
56
     *      1 ] contain the first 16-bit unicode character
54
		catch (UnsupportedEncodingException e)
57
     *@param  len
55
		{
58
     *@return                                     the converted string
56
			return false;
59
     *@exception  ArrayIndexOutOfBoundsException  if offset is out of bounds for
57
		}
60
     *      the byte array (i.e., is negative or is greater than or equal to
58
	}
61
     *      string.length)
59
62
     *@exception  IllegalArgumentException        if len is too large (i.e.,
60
	/**
63
     *      there is not enough data in string to create a String of that
61
	 * given a byte array of 16-bit unicode characters, compress to 8-bit and
64
     *      length)
62
	 * return a string
65
     *@len                                        the length of the final string
63
	 *  { 0x16, 0x00 } -> 0x16
66
     */
64
	 * @param string
67
65
	 *            the byte array to be converted
68
    public static String getFromUnicodeHigh(final byte[] string,
66
	 * @param offset
69
            final int offset, final int len)
67
	 *            the initial offset into the byte array. it is assumed that
70
             throws ArrayIndexOutOfBoundsException, IllegalArgumentException {
68
	 *            string[ offset ] and string[ offset + 1 ] contain the first
71
69
	 *            16-bit unicode character
72
        if ((offset < 0) || (offset >= string.length)) {
70
	 * @param len
73
            throw new ArrayIndexOutOfBoundsException("Illegal offset");
71
	 * @return the converted string
74
        }
72
	 * @exception ArrayIndexOutOfBoundsException
75
        if ((len < 0) || (((string.length - offset) / 2) < len)) {
73
	 *                if offset is out of bounds for the byte array (i.e., is
76
            throw new IllegalArgumentException("Illegal length");
74
	 *                negative or is greater than or equal to string.length)
77
        }
75
	 * @exception IllegalArgumentException
78
        
76
	 *                if len is too large (i.e., there is not enough data in
79
        char[] chars = new char[ len ];
77
	 *                string to create a String of that length) @len the length
80
        for ( int i = 0; i < chars.length; i++ ) {
78
	 *                of the final string
81
            chars[i] = (char)( string[ offset + ( 2*i ) ] & 0xFF | 
79
	 */
82
                             ( string[ offset + ( 2*i+1 ) ] << 8 ) );
80
83
        }
81
	public static String getFromUnicodeHigh(final byte[] string, final int offset, final int len) throws ArrayIndexOutOfBoundsException, IllegalArgumentException
84
82
	{
85
        return new String( chars );
83
86
    }
84
		if ((offset < 0) || (offset >= string.length))
87
    
85
		{
88
    
86
			throw new ArrayIndexOutOfBoundsException("Illegal offset");
89
    /**
87
		}
90
     *  given a byte array of 16-bit unicode characters, compress to 8-bit and
88
		if ((len < 0) || (((string.length - offset) / 2) < len))
91
     *  return a string
89
		{
92
     * 
90
			throw new IllegalArgumentException("Illegal length");
93
     * { 0x16, 0x00 } -> 0x16
91
		}
94
     *
92
95
     *@param  string  the byte array to be converted
93
		char[] chars = new char[len];
96
     *@return         the converted string
94
		for (int i = 0; i < chars.length; i++)
97
     */
95
		{
98
96
			chars[i] = (char) (string[offset + (2 * i)] & 0xFF | (string[offset + (2 * i + 1)] << 8));
99
    public static String getFromUnicodeHigh( final byte[] string ) {
97
		}
100
        return getFromUnicodeHigh( string, 0, string.length / 2 );
98
101
    }
99
		return new String(chars);
102
100
	}
103
101
104
    /**
102
	/**
105
     *  given a byte array of 16-bit unicode characters, compress to 8-bit and
103
	 * given a byte array of 16-bit unicode characters, compress to 8-bit and
106
     *  return a string
104
	 * return a string
107
     * 
105
	 *  { 0x16, 0x00 } -> 0x16
108
     * { 0x00, 0x16 } -> 0x16
106
	 * @param string
109
     *
107
	 *            the byte array to be converted
110
     *@param  string                              the byte array to be converted
108
	 * @return the converted string
111
     *@param  offset                              the initial offset into the
109
	 */
112
     *      byte array. it is assumed that string[ offset ] and string[ offset +
110
113
     *      1 ] contain the first 16-bit unicode character
111
	public static String getFromUnicodeHigh(final byte[] string)
114
     *@param  len
112
	{
115
     *@return                                     the converted string
113
		return getFromUnicodeHigh(string, 0, string.length / 2);
116
     *@exception  ArrayIndexOutOfBoundsException  if offset is out of bounds for
114
	}
117
     *      the byte array (i.e., is negative or is greater than or equal to
115
118
     *      string.length)
116
	/**
119
     *@exception  IllegalArgumentException        if len is too large (i.e.,
117
	 * given a byte array of 16-bit unicode characters, compress to 8-bit and
120
     *      there is not enough data in string to create a String of that
118
	 * return a string
121
     *      length)
119
	 *  { 0x00, 0x16 } -> 0x16
122
     *@len                                        the length of the final string
120
	 * @param string
123
     */
121
	 *            the byte array to be converted
124
122
	 * @param offset
125
    public static String getFromUnicode(final byte[] string,
123
	 *            the initial offset into the byte array. it is assumed that
126
            final int offset, final int len)
124
	 *            string[ offset ] and string[ offset + 1 ] contain the first
127
             throws ArrayIndexOutOfBoundsException, IllegalArgumentException {
125
	 *            16-bit unicode character
128
        if ((offset < 0) || (offset >= string.length)) {
126
	 * @param len
129
            throw new ArrayIndexOutOfBoundsException("Illegal offset");
127
	 * @return the converted string
130
        }
128
	 * @exception ArrayIndexOutOfBoundsException
131
        if ((len < 0) || (((string.length - offset) / 2) < len)) {
129
	 *                if offset is out of bounds for the byte array (i.e., is
132
            throw new IllegalArgumentException("Illegal length");
130
	 *                negative or is greater than or equal to string.length)
133
        }
131
	 * @exception IllegalArgumentException
134
132
	 *                if len is too large (i.e., there is not enough data in
135
        
133
	 *                string to create a String of that length) @len the length
136
        char[] chars = new char[ len ];
134
	 *                of the final string
137
        for ( int i = 0; i < chars.length; i++ ) {
135
	 */
138
            chars[i] = (char)( ( string[ offset + ( 2*i ) ] << 8 ) +
136
139
                              string[ offset + ( 2*i+1 ) ] );
137
	public static String getFromUnicode(final byte[] string, final int offset, final int len) throws ArrayIndexOutOfBoundsException, IllegalArgumentException
140
        }
138
	{
141
        
139
		if ((offset < 0) || (offset >= string.length))
142
        return new String( chars );
140
		{
143
    }
141
			throw new ArrayIndexOutOfBoundsException("Illegal offset");
144
142
		}
145
143
		if ((len < 0) || (((string.length - offset) / 2) < len))
146
    /**
144
		{
147
     *  given a byte array of 16-bit unicode characters, compress to 8-bit and
145
			throw new IllegalArgumentException("Illegal length");
148
     *  return a string
146
		}
149
     * 
147
150
     * { 0x00, 0x16 } -> 0x16
148
		char[] chars = new char[len];
151
     *
149
		for (int i = 0; i < chars.length; i++)
152
     *@param  string  the byte array to be converted
150
		{
153
     *@return         the converted string
151
			chars[i] = (char) ((string[offset + (2 * i)] << 8) + string[offset + (2 * i + 1)]);
154
     */
152
		}
155
153
156
    public static String getFromUnicode(final byte[] string) {
154
		return new String(chars);
157
        return getFromUnicode(string, 0, string.length / 2);
155
	}
158
    }
156
159
157
	/**
160
158
	 * given a byte array of 16-bit unicode characters, compress to 8-bit and
161
      /**
159
	 * return a string
162
      * read compressed unicode(8bit)
160
	 *  { 0x00, 0x16 } -> 0x16
163
      * 
161
	 * @param string
164
      * @author Toshiaki Kamoshida(kamoshida.toshiaki at future dot co dot jp)
162
	 *            the byte array to be converted
165
      * 
163
	 * @return the converted string
166
      * @param string byte array to read
164
	 */
167
      * @param offset offset to read byte array
165
168
      * @param len    length to read byte array
166
	public static String getFromUnicode(final byte[] string)
169
      * @return String generated String instance by reading byte array
167
	{
170
      */
168
		return getFromUnicode(string, 0, string.length / 2);
171
     public static String getFromCompressedUnicode(final byte[] string,
169
	}
172
            final int offset, final int len){
170
173
         try{
171
	/**
174
             return new String(string,offset,len,"ISO-8859-1");
172
	 * read compressed unicode(8bit)
175
         }
173
	 * 
176
         catch(UnsupportedEncodingException e){
174
	 * @author Toshiaki Kamoshida(kamoshida.toshiaki at future dot co dot jp)
177
             throw new InternalError();/* unreachable */
175
	 * 
178
         }
176
	 * @param string
179
     }
177
	 *            byte array to read
180
178
	 * @param offset
181
    /**
179
	 *            offset to read byte array
182
     *  write compressed unicode
180
	 * @param len
183
     *
181
	 *            length to read byte array
184
     *@param  input   the String containing the data to be written
182
	 * @return String generated String instance by reading byte array
185
     *@param  output  the byte array to which the data is to be written
183
	 */
186
     *@param  offset  an offset into the byte arrat at which the data is start
184
	public static String getFromCompressedUnicode(final byte[] string, final int offset, final int len)
187
     *      when written
185
	{
188
     */
186
		try
189
187
		{
190
    public static void putCompressedUnicode(final String input,
188
			return new String(string, offset, len, "ISO-8859-1");
191
            final byte[] output,
189
		}
192
            final int offset) {
190
		catch (UnsupportedEncodingException e)
193
        int strlen = input.length();
191
		{
194
192
			throw new InternalError();/* unreachable */
195
        for (int k = 0; k < strlen; k++) {
193
		}
196
            output[offset + k] = (byte) input.charAt(k);
194
	}
197
        }
195
198
    }
196
	/**
199
197
	 * write compressed unicode
200
198
	 * 
201
    /**
199
	 * @param input
202
     *  Write uncompressed unicode
200
	 *            the String containing the data to be written
203
     *
201
	 * @param output
204
     *@param  input   the String containing the unicode data to be written
202
	 *            the byte array to which the data is to be written
205
     *@param  output  the byte array to hold the uncompressed unicode
203
	 * @param offset
206
     *@param  offset  the offset to start writing into the byte array
204
	 *            an offset into the byte arrat at which the data is start when
207
     */
205
	 *            written
208
206
	 */
209
    public static void putUncompressedUnicode(final String input,
207
210
            final byte[] output,
208
	public static void putCompressedUnicode(final String input, final byte[] output, final int offset)
211
            final int offset) {
209
	{
212
        int strlen = input.length();
210
		int strlen = input.length();
213
211
214
        for (int k = 0; k < strlen; k++) {
212
		for (int k = 0; k < strlen; k++)
215
            char c = input.charAt(k);
213
		{
216
214
			output[offset + k] = (byte) input.charAt(k);
217
            output[offset + (2 * k)] = (byte) c;
215
		}
218
            output[offset + (2 * k) + 1] = (byte) (c >> 8);
216
	}
219
        }
217
220
    }
218
	/**
221
219
	 * Write uncompressed unicode
222
    /**
220
	 * 
223
     *  Write uncompressed unicode
221
	 * @param input
224
     *
222
	 *            the String containing the unicode data to be written
225
     *@param  input   the String containing the unicode data to be written
223
	 * @param output
226
     *@param  output  the byte array to hold the uncompressed unicode
224
	 *            the byte array to hold the uncompressed unicode
227
     *@param  offset  the offset to start writing into the byte array
225
	 * @param offset
228
     */
226
	 *            the offset to start writing into the byte array
229
227
	 */
230
    public static void putUncompressedUnicodeHigh(final String input,
228
231
            final byte[] output,
229
	public static void putUncompressedUnicode(final String input, final byte[] output, final int offset)
232
            final int offset) {
230
	{
233
        int strlen = input.length();
231
		int strlen = input.length();
234
232
235
        for (int k = 0; k < strlen; k++) {
233
		for (int k = 0; k < strlen; k++)
236
            char c = input.charAt(k);
234
		{
237
235
			char c = input.charAt(k);
238
            output[offset + (2 * k)] = (byte) (c >> 8);
236
239
            output[offset + (2 * k)] = (byte) c;
237
			output[offset + (2 * k)] = (byte) c;
240
        }
238
			output[offset + (2 * k) + 1] = (byte) (c >> 8);
241
    }
239
		}
242
    
240
	}
243
    
241
244
    
242
	/**
245
243
	 * Write uncompressed unicode
246
    /**
244
	 * 
247
     *  Description of the Method
245
	 * @param input
248
     *
246
	 *            the String containing the unicode data to be written
249
     *@param  message  Description of the Parameter
247
	 * @param output
250
     *@param  params   Description of the Parameter
248
	 *            the byte array to hold the uncompressed unicode
251
     *@return          Description of the Return Value
249
	 * @param offset
252
     */
250
	 *            the offset to start writing into the byte array
253
    public static String format(String message, Object[] params) {
251
	 */
254
        int currentParamNumber = 0;
252
255
        StringBuffer formattedMessage = new StringBuffer();
253
	public static void putUncompressedUnicodeHigh(final String input, final byte[] output, final int offset)
256
254
	{
257
        for (int i = 0; i < message.length(); i++) {
255
		int strlen = input.length();
258
            if (message.charAt(i) == '%') {
256
259
                if (currentParamNumber >= params.length) {
257
		for (int k = 0; k < strlen; k++)
260
                    formattedMessage.append("?missing data?");
258
		{
261
                } else if ((params[currentParamNumber] instanceof Number)
259
			char c = input.charAt(k);
262
                        && (i + 1 < message.length())) {
260
263
                    i += matchOptionalFormatting(
261
			output[offset + (2 * k)] = (byte) (c >> 8);
264
                            (Number) params[currentParamNumber++],
262
			output[offset + (2 * k)] = (byte) c;
265
                            message.substring(i + 1), formattedMessage);
263
		}
266
                } else {
264
	}
267
                    formattedMessage.append(params[currentParamNumber++].toString());
265
268
                }
266
	/**
269
            } else {
267
	 * Description of the Method
270
                if ((message.charAt(i) == '\\') && (i + 1 < message.length())
268
	 * 
271
                        && (message.charAt(i + 1) == '%')) {
269
	 * @param message
272
                    formattedMessage.append('%');
270
	 *            Description of the Parameter
273
                    i++;
271
	 * @param params
274
                } else {
272
	 *            Description of the Parameter
275
                    formattedMessage.append(message.charAt(i));
273
	 * @return Description of the Return Value
276
                }
274
	 */
277
            }
275
	public static String format(String message, Object[] params)
278
        }
276
	{
279
        return formattedMessage.toString();
277
		int currentParamNumber = 0;
280
    }
278
		StringBuffer formattedMessage = new StringBuffer();
281
279
282
280
		for (int i = 0; i < message.length(); i++)
283
    /**
281
		{
284
     *  Description of the Method
282
			if (message.charAt(i) == '%')
285
     *
283
			{
286
     *@param  number      Description of the Parameter
284
				if (currentParamNumber >= params.length)
287
     *@param  formatting  Description of the Parameter
285
				{
288
     *@param  outputTo    Description of the Parameter
286
					formattedMessage.append("?missing data?");
289
     *@return             Description of the Return Value
287
				}
290
     */
288
				else if ((params[currentParamNumber] instanceof Number) && (i + 1 < message.length()))
291
    private static int matchOptionalFormatting(Number number,
289
				{
292
            String formatting,
290
					i += matchOptionalFormatting((Number) params[currentParamNumber++], message.substring(i + 1), formattedMessage);
293
            StringBuffer outputTo) {
291
				}
294
        NumberFormat numberFormat = NumberFormat.getInstance();
292
				else
295
293
				{
296
        if ((0 < formatting.length())
294
					formattedMessage.append(params[currentParamNumber++].toString());
297
                && Character.isDigit(formatting.charAt(0))) {
295
				}
298
            numberFormat.setMinimumIntegerDigits(Integer.parseInt(formatting.charAt(0) + ""));
296
			}
299
            if ((2 < formatting.length()) && (formatting.charAt(1) == '.')
297
			else
300
                    && Character.isDigit(formatting.charAt(2))) {
298
			{
301
                numberFormat.setMaximumFractionDigits(Integer.parseInt(formatting.charAt(2) + ""));
299
				if ((message.charAt(i) == '\\') && (i + 1 < message.length()) && (message.charAt(i + 1) == '%'))
302
                numberFormat.format(number, outputTo, new FieldPosition(0));
300
				{
303
                return 3;
301
					formattedMessage.append('%');
304
            }
302
					i++;
305
            numberFormat.format(number, outputTo, new FieldPosition(0));
303
				}
306
            return 1;
304
				else
307
        } else if ((0 < formatting.length()) && (formatting.charAt(0) == '.')) {
305
				{
308
            if ((1 < formatting.length())
306
					formattedMessage.append(message.charAt(i));
309
                    && Character.isDigit(formatting.charAt(1))) {
307
				}
310
                numberFormat.setMaximumFractionDigits(Integer.parseInt(formatting.charAt(1) + ""));
308
			}
311
                numberFormat.format(number, outputTo, new FieldPosition(0));
309
		}
312
                return 2;
310
		return formattedMessage.toString();
313
            }
311
	}
314
        }
312
315
        numberFormat.format(number, outputTo, new FieldPosition(0));
313
	/**
316
        return 1;
314
	 * Description of the Method
317
    }
315
	 * 
318
    
316
	 * @param number
319
    /**
317
	 *            Description of the Parameter
320
     * @return the encoding we want to use (ISO-8859-1)
318
	 * @param formatting
321
     */
319
	 *            Description of the Parameter
322
    public static String getPreferredEncoding() {
320
	 * @param outputTo
323
        return ENCODING;   
321
	 *            Description of the Parameter
324
    }
322
	 * @return Description of the Return Value
323
	 */
324
	private static int matchOptionalFormatting(Number number, String formatting, StringBuffer outputTo)
325
	{
326
		NumberFormat numberFormat = NumberFormat.getInstance();
327
328
		if ((0 < formatting.length()) && Character.isDigit(formatting.charAt(0)))
329
		{
330
			numberFormat.setMinimumIntegerDigits(Integer.parseInt(formatting.charAt(0) + ""));
331
			if ((2 < formatting.length()) && (formatting.charAt(1) == '.') && Character.isDigit(formatting.charAt(2)))
332
			{
333
				numberFormat.setMaximumFractionDigits(Integer.parseInt(formatting.charAt(2) + ""));
334
				numberFormat.format(number, outputTo, new FieldPosition(0));
335
				return 3;
336
			}
337
			numberFormat.format(number, outputTo, new FieldPosition(0));
338
			return 1;
339
		}
340
		else if ((0 < formatting.length()) && (formatting.charAt(0) == '.'))
341
		{
342
			if ((1 < formatting.length()) && Character.isDigit(formatting.charAt(1)))
343
			{
344
				numberFormat.setMaximumFractionDigits(Integer.parseInt(formatting.charAt(1) + ""));
345
				numberFormat.format(number, outputTo, new FieldPosition(0));
346
				return 2;
347
			}
348
		}
349
		numberFormat.format(number, outputTo, new FieldPosition(0));
350
		return 1;
351
	}
352
353
	/**
354
	 * @return the encoding we want to use (ISO-8859-1)
355
	 */
356
	public static String getPreferredEncoding()
357
	{
358
		return ENCODING;
359
	}
325
}
360
}

Return to bug 27921