source: Ballon/out/artifacts/geisa_artifact/WEB-INF/lib/mysql-connector-java-5.1.21/src/com/mysql/jdbc/StringUtils.java @ 766

Last change on this file since 766 was 766, checked in by npipsl, 11 years ago
File size: 50.9 KB
Line 
1/*
2 Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
3 
4
5  The MySQL Connector/J is licensed under the terms of the GPLv2
6  <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
7  There are special exceptions to the terms and conditions of the GPLv2 as it is applied to
8  this software, see the FLOSS License Exception
9  <http://www.mysql.com/about/legal/licensing/foss-exception.html>.
10
11  This program is free software; you can redistribute it and/or modify it under the terms
12  of the GNU General Public License as published by the Free Software Foundation; version 2
13  of the License.
14
15  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
16  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17  See the GNU General Public License for more details.
18
19  You should have received a copy of the GNU General Public License along with this
20  program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth
21  Floor, Boston, MA 02110-1301  USA
22
23
24
25 */
26package com.mysql.jdbc;
27
28import java.io.ByteArrayOutputStream;
29import java.io.IOException;
30import java.io.StringReader;
31import java.io.UnsupportedEncodingException;
32import java.lang.reflect.InvocationTargetException;
33import java.lang.reflect.Method;
34import java.math.BigDecimal;
35import java.nio.ByteBuffer;
36import java.nio.charset.Charset;
37import java.nio.charset.IllegalCharsetNameException;
38import java.nio.charset.UnsupportedCharsetException;
39import java.sql.SQLException;
40import java.util.ArrayList;
41import java.util.List;
42import java.util.StringTokenizer;
43import java.util.concurrent.ConcurrentHashMap;
44
45/**
46 * Various utility methods for converting to/from byte arrays in the platform
47 * encoding
48 *
49 * @author Mark Matthews
50 */
51public class StringUtils {
52       
53        private static final int BYTE_RANGE = (1 + Byte.MAX_VALUE) - Byte.MIN_VALUE;
54
55        private static byte[] allBytes = new byte[BYTE_RANGE];
56
57        private static char[] byteToChars = new char[BYTE_RANGE];
58
59        private static Method toPlainStringMethod;
60
61        static final int WILD_COMPARE_MATCH_NO_WILD = 0;
62
63        static final int WILD_COMPARE_MATCH_WITH_WILD = 1;
64
65        static final int WILD_COMPARE_NO_MATCH = -1;
66
67        private static final ConcurrentHashMap<String,Charset> charsetsByAlias = 
68             new ConcurrentHashMap<String,Charset>();
69
70        private static final String platformEncoding = System.getProperty("file.encoding");
71       
72        private static final String VALID_ID_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ0123456789$_#@";
73       
74        static Charset findCharset(String alias) throws UnsupportedEncodingException {
75                try {
76                        Charset cs = charsetsByAlias.get(alias);
77                       
78                        if (cs == null) {
79                                cs = Charset.forName(alias);
80                                charsetsByAlias.putIfAbsent(alias, cs);
81                        }
82               
83                        return cs;
84                       
85                        // We re-throw these runtimes for compatibility with java.io
86                } catch (UnsupportedCharsetException uce) {
87                        throw new UnsupportedEncodingException(alias);
88                } catch (IllegalCharsetNameException icne) {
89                        throw new UnsupportedEncodingException(alias);
90                } catch (IllegalArgumentException iae) {
91                        throw new UnsupportedEncodingException(alias);
92                }
93        }
94       
95        static {
96                for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) {
97                        allBytes[i - Byte.MIN_VALUE] = (byte) i;
98                }
99
100                String allBytesString = new String(allBytes, 0, Byte.MAX_VALUE
101                                - Byte.MIN_VALUE);
102
103                int allBytesStringLen = allBytesString.length();
104
105                for (int i = 0; (i < (Byte.MAX_VALUE - Byte.MIN_VALUE))
106                                && (i < allBytesStringLen); i++) {
107                        byteToChars[i] = allBytesString.charAt(i);
108                }
109
110                try {
111                        toPlainStringMethod = BigDecimal.class.getMethod("toPlainString",
112                                        new Class[0]);
113                } catch (NoSuchMethodException nsme) {
114                        // that's okay, we fallback to .toString()
115                }
116        }
117
118        /**
119         * Takes care of the fact that Sun changed the output of
120         * BigDecimal.toString() between JDK-1.4 and JDK 5
121         *
122         * @param decimal
123         *            the big decimal to stringify
124         *
125         * @return a string representation of 'decimal'
126         */
127        public static String consistentToString(BigDecimal decimal) {
128                if (decimal == null) {
129                        return null;
130                }
131
132                if (toPlainStringMethod != null) {
133                        try {
134                                return (String) toPlainStringMethod.invoke(decimal, (Object[])null);
135                        } catch (InvocationTargetException invokeEx) {
136                                // that's okay, we fall-through to decimal.toString()
137                        } catch (IllegalAccessException accessEx) {
138                                // that's okay, we fall-through to decimal.toString()
139                        }
140                }
141
142                return decimal.toString();
143        }
144
145        /**
146         * Dumps the given bytes to STDOUT as a hex dump (up to length bytes).
147         *
148         * @param byteBuffer
149         *            the data to print as hex
150         * @param length
151         *            the number of bytes to print
152         *
153         * @return ...
154         */
155        public static final String dumpAsHex(byte[] byteBuffer, int length) {
156                StringBuffer outputBuf = new StringBuffer(length * 4);
157
158                int p = 0;
159                int rows = length / 8;
160
161                for (int i = 0; (i < rows) && (p < length); i++) {
162                        int ptemp = p;
163
164                        for (int j = 0; j < 8; j++) {
165                                String hexVal = Integer.toHexString(byteBuffer[ptemp] & 0xff);
166
167                                if (hexVal.length() == 1) {
168                                        hexVal = "0" + hexVal; //$NON-NLS-1$
169                                }
170
171                                outputBuf.append(hexVal + " "); //$NON-NLS-1$
172                                ptemp++;
173                        }
174
175                        outputBuf.append("    "); //$NON-NLS-1$
176
177                        for (int j = 0; j < 8; j++) {
178                                int b = 0xff & byteBuffer[p];
179                               
180                                if (b > 32 && b < 127) {
181                                        outputBuf.append((char) b + " "); //$NON-NLS-1$
182                                } else {
183                                        outputBuf.append(". "); //$NON-NLS-1$
184                                }
185
186                                p++;
187                        }
188
189                        outputBuf.append("\n"); //$NON-NLS-1$
190                }
191
192                int n = 0;
193
194                for (int i = p; i < length; i++) {
195                        String hexVal = Integer.toHexString(byteBuffer[i] & 0xff);
196
197                        if (hexVal.length() == 1) {
198                                hexVal = "0" + hexVal; //$NON-NLS-1$
199                        }
200
201                        outputBuf.append(hexVal + " "); //$NON-NLS-1$
202                        n++;
203                }
204
205                for (int i = n; i < 8; i++) {
206                        outputBuf.append("   "); //$NON-NLS-1$
207                }
208
209                outputBuf.append("    "); //$NON-NLS-1$
210
211                for (int i = p; i < length; i++) {
212                        int b = 0xff & byteBuffer[i];
213                       
214                        if (b > 32 && b < 127) {
215                                outputBuf.append((char) b + " "); //$NON-NLS-1$
216                        } else {
217                                outputBuf.append(". "); //$NON-NLS-1$
218                        }
219                }
220
221                outputBuf.append("\n"); //$NON-NLS-1$
222
223                return outputBuf.toString();
224        }
225
226        private static boolean endsWith(byte[] dataFrom, String suffix) {
227                for (int i = 1; i <= suffix.length(); i++) {
228                        int dfOffset = dataFrom.length - i;
229                        int suffixOffset = suffix.length() - i;
230                        if (dataFrom[dfOffset] != suffix.charAt(suffixOffset)) {
231                                return false;
232                        }
233                }
234                return true;
235        }
236
237        /**
238         * Unfortunately, SJIS has 0x5c as a high byte in some of its double-byte
239         * characters, so we need to escape it.
240         *
241         * @param origBytes
242         *            the original bytes in SJIS format
243         * @param origString
244         *            the string that had .getBytes() called on it
245         * @param offset
246         *            where to start converting from
247         * @param length
248         *            how many characters to convert.
249         *
250         * @return byte[] with 0x5c escaped
251         */
252        public static byte[] escapeEasternUnicodeByteStream(byte[] origBytes,
253                        String origString, int offset, int length) {
254                if ((origBytes == null) || (origBytes.length == 0)) {
255                        return origBytes;
256                }
257
258                int bytesLen = origBytes.length;
259                int bufIndex = 0;
260                int strIndex = 0;
261
262                ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(bytesLen);
263
264                while (true) {
265                        if (origString.charAt(strIndex) == '\\') {
266                                // write it out as-is
267                                bytesOut.write(origBytes[bufIndex++]);
268
269                                // bytesOut.write(origBytes[bufIndex++]);
270                        } else {
271                                // Grab the first byte
272                                int loByte = origBytes[bufIndex];
273
274                                if (loByte < 0) {
275                                        loByte += 256; // adjust for signedness/wrap-around
276                                }
277
278                                // We always write the first byte
279                                bytesOut.write(loByte);
280
281                                //
282                                // The codepage characters in question exist between
283                                // 0x81-0x9F and 0xE0-0xFC...
284                                //
285                                // See:
286                                //
287                                // http://www.microsoft.com/GLOBALDEV/Reference/dbcs/932.htm
288                                //
289                                // Problematic characters in GBK
290                                //
291                                // U+905C : CJK UNIFIED IDEOGRAPH
292                                //
293                                // Problematic characters in Big5
294                                //
295                                // B9F0 = U+5C62 : CJK UNIFIED IDEOGRAPH
296                                //
297                                if (loByte >= 0x80) {
298                                        if (bufIndex < (bytesLen - 1)) {
299                                                int hiByte = origBytes[bufIndex + 1];
300
301                                                if (hiByte < 0) {
302                                                        hiByte += 256; // adjust for signedness/wrap-around
303                                                }
304
305                                                // write the high byte here, and increment the index
306                                                // for the high byte
307                                                bytesOut.write(hiByte);
308                                                bufIndex++;
309
310                                                // escape 0x5c if necessary
311                                                if (hiByte == 0x5C) {
312                                                        bytesOut.write(hiByte);
313                                                }
314                                        }
315                                } else if (loByte == 0x5c) {
316                                        if (bufIndex < (bytesLen - 1)) {
317                                                int hiByte = origBytes[bufIndex + 1];
318
319                                                if (hiByte < 0) {
320                                                        hiByte += 256; // adjust for signedness/wrap-around
321                                                }
322
323                                                if (hiByte == 0x62) {
324                                                        // we need to escape the 0x5c
325                                                        bytesOut.write(0x5c);
326                                                        bytesOut.write(0x62);
327                                                        bufIndex++;
328                                                }
329                                        }
330                                }
331
332                                bufIndex++;
333                        }
334
335                        if (bufIndex >= bytesLen) {
336                                // we're done
337                                break;
338                        }
339
340                        strIndex++;
341                }
342
343                return bytesOut.toByteArray();
344        }
345
346        /**
347         * Returns the first non whitespace char, converted to upper case
348         *
349         * @param searchIn
350         *            the string to search in
351         *
352         * @return the first non-whitespace character, upper cased.
353         */
354        public static char firstNonWsCharUc(String searchIn) {
355                return firstNonWsCharUc(searchIn, 0);
356        }
357       
358        public static char firstNonWsCharUc(String searchIn, int startAt) {
359                if (searchIn == null) {
360                        return 0;
361                }
362
363                int length = searchIn.length();
364
365                for (int i = startAt; i < length; i++) {
366                        char c = searchIn.charAt(i);
367
368                        if (!Character.isWhitespace(c)) {
369                                return Character.toUpperCase(c);
370                        }
371                }
372
373                return 0;
374        }
375
376        public static char firstAlphaCharUc(String searchIn, int startAt) {
377                if (searchIn == null) {
378                        return 0;
379                }
380
381                int length = searchIn.length();
382
383                for (int i = startAt; i < length; i++) {
384                        char c = searchIn.charAt(i);
385
386                        if (Character.isLetter(c)) {
387                                return Character.toUpperCase(c);
388                        }
389                }
390
391                return 0;
392        }
393       
394        /**
395         * Adds '+' to decimal numbers that are positive (MySQL doesn't understand
396         * them otherwise
397         *
398         * @param dString
399         *            The value as a string
400         *
401         * @return String the string with a '+' added (if needed)
402         */
403        public static final String fixDecimalExponent(String dString) {
404                int ePos = dString.indexOf("E"); //$NON-NLS-1$
405
406                if (ePos == -1) {
407                        ePos = dString.indexOf("e"); //$NON-NLS-1$
408                }
409
410                if (ePos != -1) {
411                        if (dString.length() > (ePos + 1)) {
412                                char maybeMinusChar = dString.charAt(ePos + 1);
413
414                                if (maybeMinusChar != '-' && maybeMinusChar != '+') {
415                                        StringBuffer buf = new StringBuffer(dString.length() + 1);
416                                        buf.append(dString.substring(0, ePos + 1));
417                                        buf.append('+');
418                                        buf.append(dString.substring(ePos + 1, dString.length()));
419                                        dString = buf.toString();
420                                }
421                        }
422                }
423
424                return dString;
425        }
426
427        public static final byte[] getBytes(char[] c,
428                        SingleByteCharsetConverter converter, String encoding,
429                        String serverEncoding, boolean parserKnowsUnicode, ExceptionInterceptor exceptionInterceptor)
430                        throws SQLException {
431                try {
432                        byte[] b = null;
433
434                        if (converter != null) {
435                                b = converter.toBytes(c);
436                        } else if (encoding == null) {
437                                b = new String(c).getBytes();
438                        } else {
439                                String s = new String(c);
440
441                                b = s.getBytes(encoding);
442
443                                if (!parserKnowsUnicode && (encoding.equalsIgnoreCase("SJIS") //$NON-NLS-1$
444                                                || encoding.equalsIgnoreCase("BIG5") //$NON-NLS-1$
445                                || encoding.equalsIgnoreCase("GBK"))) { //$NON-NLS-1$
446
447                                        if (!encoding.equalsIgnoreCase(serverEncoding)) {
448                                                b = escapeEasternUnicodeByteStream(b, s, 0, s.length());
449                                        }
450                                }
451                        }
452
453                        return b;
454                } catch (UnsupportedEncodingException uee) {
455                        throw SQLError.createSQLException(Messages.getString("StringUtils.5") //$NON-NLS-1$
456                                        + encoding + Messages.getString("StringUtils.6"),
457                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT, exceptionInterceptor); //$NON-NLS-1$
458                }
459        }
460
461        public static final byte[] getBytes(char[] c,
462                        SingleByteCharsetConverter converter, String encoding,
463                        String serverEncoding, int offset, int length,
464                        boolean parserKnowsUnicode, ExceptionInterceptor exceptionInterceptor) throws SQLException {
465                try {
466                        byte[] b = null;
467
468                        if (converter != null) {
469                                b = converter.toBytes(c, offset, length);
470                        } else if (encoding == null) {
471                                byte[] temp = new String(c, offset, length).getBytes();
472
473                                length = temp.length;
474                               
475                                b = new byte[length];
476                                System.arraycopy(temp, 0, b, 0, length);
477                        } else {
478                                String s = new String(c, offset, length);
479
480                                byte[] temp = s.getBytes(encoding);
481
482                                length = temp.length;
483                               
484                                b = new byte[length];
485                                System.arraycopy(temp, 0, b, 0, length);
486
487                                if (!parserKnowsUnicode && (encoding.equalsIgnoreCase("SJIS") //$NON-NLS-1$
488                                                || encoding.equalsIgnoreCase("BIG5") //$NON-NLS-1$
489                                || encoding.equalsIgnoreCase("GBK"))) { //$NON-NLS-1$
490
491                                        if (!encoding.equalsIgnoreCase(serverEncoding)) {
492                                                b = escapeEasternUnicodeByteStream(b, s, offset, length);
493                                        }
494                                }
495                        }
496
497                        return b;
498                } catch (UnsupportedEncodingException uee) {
499                        throw SQLError.createSQLException(Messages.getString("StringUtils.10") //$NON-NLS-1$
500                                        + encoding + Messages.getString("StringUtils.11"),
501                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT, exceptionInterceptor); //$NON-NLS-1$
502                }
503        }
504
505        public static final byte[] getBytes(char[] c, String encoding,
506                        String serverEncoding, boolean parserKnowsUnicode, 
507                        MySQLConnection conn, ExceptionInterceptor exceptionInterceptor)
508                        throws SQLException {
509                try {
510                       
511                        SingleByteCharsetConverter converter = null;
512                       
513                        if (conn != null) {
514                                converter = conn.getCharsetConverter(encoding);
515                        } else {
516                                converter = SingleByteCharsetConverter.getInstance(encoding, null);
517                        }
518
519                        return getBytes(c, converter, encoding, serverEncoding,
520                                        parserKnowsUnicode, exceptionInterceptor);
521                } catch (UnsupportedEncodingException uee) {
522                        throw SQLError.createSQLException(Messages.getString("StringUtils.0") //$NON-NLS-1$
523                                        + encoding + Messages.getString("StringUtils.1"),
524                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT, exceptionInterceptor); //$NON-NLS-1$
525                }
526        }
527
528        /**
529         * Returns the byte[] representation of the given string (re)using the given
530         * charset converter, and the given encoding.
531         *
532         * @param s
533         *            the string to convert
534         * @param converter
535         *            the converter to reuse
536         * @param encoding
537         *            the character encoding to use
538         * @param serverEncoding
539         *            DOCUMENT ME!
540         * @param parserKnowsUnicode
541         *            DOCUMENT ME!
542         *
543         * @return byte[] representation of the string
544         *
545         * @throws SQLException
546         *             if an encoding unsupported by the JVM is supplied.
547         */
548        public static final byte[] getBytes(String s,
549                        SingleByteCharsetConverter converter, String encoding,
550                        String serverEncoding, boolean parserKnowsUnicode, ExceptionInterceptor exceptionInterceptor)
551                        throws SQLException {
552                try {
553                        byte[] b = null;
554
555                        if (converter != null) {
556                                b = converter.toBytes(s);
557                        } else if (encoding == null) {
558                                b = s.getBytes();
559                        } else {
560                                b = s.getBytes(encoding);
561
562                                if (!parserKnowsUnicode && (encoding.equalsIgnoreCase("SJIS") //$NON-NLS-1$
563                                                || encoding.equalsIgnoreCase("BIG5") //$NON-NLS-1$
564                                || encoding.equalsIgnoreCase("GBK"))) { //$NON-NLS-1$
565
566                                        if (!encoding.equalsIgnoreCase(serverEncoding)) {
567                                                b = escapeEasternUnicodeByteStream(b, s, 0, s.length());
568                                        }
569                                }
570                        }
571
572                        return b;
573                } catch (UnsupportedEncodingException uee) {
574                        throw SQLError.createSQLException(Messages.getString("StringUtils.5") //$NON-NLS-1$
575                                        + encoding + Messages.getString("StringUtils.6"),
576                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT, exceptionInterceptor); //$NON-NLS-1$
577                }
578        }
579
580        public static final byte[] getBytesWrapped(String s, char beginWrap, char endWrap,
581                        SingleByteCharsetConverter converter, String encoding,
582                        String serverEncoding, boolean parserKnowsUnicode, ExceptionInterceptor exceptionInterceptor)
583                        throws SQLException {
584                try {
585                        byte[] b = null;
586
587                        if (converter != null) {
588                                b = converter.toBytesWrapped(s, beginWrap, endWrap);
589                        } else if (encoding == null) {
590                                StringBuffer buf = new StringBuffer(s.length() + 2);
591                                buf.append(beginWrap);
592                                buf.append(s);
593                                buf.append(endWrap);
594                               
595                                b = buf.toString().getBytes();
596                        } else {
597                                StringBuffer buf = new StringBuffer(s.length() + 2);
598                                buf.append(beginWrap);
599                                buf.append(s);
600                                buf.append(endWrap);
601                               
602                                s = buf.toString();
603                                b = s.getBytes(encoding);
604
605                                if (!parserKnowsUnicode && (encoding.equalsIgnoreCase("SJIS") //$NON-NLS-1$
606                                                || encoding.equalsIgnoreCase("BIG5") //$NON-NLS-1$
607                                || encoding.equalsIgnoreCase("GBK"))) { //$NON-NLS-1$
608
609                                        if (!encoding.equalsIgnoreCase(serverEncoding)) {
610                                                b = escapeEasternUnicodeByteStream(b, s, 0, s.length());
611                                        }
612                                }
613                        }
614
615                        return b;
616                } catch (UnsupportedEncodingException uee) {
617                        throw SQLError.createSQLException(Messages.getString("StringUtils.5") //$NON-NLS-1$
618                                        + encoding + Messages.getString("StringUtils.6"),
619                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT, exceptionInterceptor); //$NON-NLS-1$
620                }
621        }
622       
623        /**
624         * DOCUMENT ME!
625         *
626         * @param s
627         *            DOCUMENT ME!
628         * @param converter
629         *            DOCUMENT ME!
630         * @param encoding
631         *            DOCUMENT ME!
632         * @param serverEncoding
633         *            DOCUMENT ME!
634         * @param offset
635         *            DOCUMENT ME!
636         * @param length
637         *            DOCUMENT ME!
638         * @param parserKnowsUnicode
639         *            DOCUMENT ME!
640         *
641         * @return DOCUMENT ME!
642         *
643         * @throws SQLException
644         *             DOCUMENT ME!
645         */
646        public static final byte[] getBytes(String s,
647                        SingleByteCharsetConverter converter, String encoding,
648                        String serverEncoding, int offset, int length,
649                        boolean parserKnowsUnicode, ExceptionInterceptor exceptionInterceptor) throws SQLException {
650                try {
651                        byte[] b = null;
652
653                        if (converter != null) {
654                                b = converter.toBytes(s, offset, length);
655                        } else if (encoding == null) {
656                                byte[] temp = s.substring(offset, offset + length).getBytes();
657
658                                length = temp.length;
659                               
660                                b = new byte[length];
661                                System.arraycopy(temp, 0, b, 0, length);
662                        } else {
663
664                                byte[] temp = s.substring(offset, offset + length)
665                                        .getBytes(encoding);
666
667                                length = temp.length;
668                               
669                                b = new byte[length];
670                                System.arraycopy(temp, 0, b, 0, length);
671
672                                if (!parserKnowsUnicode && (encoding.equalsIgnoreCase("SJIS") //$NON-NLS-1$
673                                                || encoding.equalsIgnoreCase("BIG5") //$NON-NLS-1$
674                                || encoding.equalsIgnoreCase("GBK"))) { //$NON-NLS-1$
675
676                                        if (!encoding.equalsIgnoreCase(serverEncoding)) {
677                                                b = escapeEasternUnicodeByteStream(b, s, offset, length);
678                                        }
679                                }
680                        }
681
682                        return b;
683                } catch (UnsupportedEncodingException uee) {
684                        throw SQLError.createSQLException(Messages.getString("StringUtils.10") //$NON-NLS-1$
685                                        + encoding + Messages.getString("StringUtils.11"),
686                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT, exceptionInterceptor); //$NON-NLS-1$
687                }
688        }
689
690        /**
691         * Returns the byte[] representation of the given string using given
692         * encoding.
693         *
694         * @param s
695         *            the string to convert
696         * @param encoding
697         *            the character encoding to use
698         * @param parserKnowsUnicode
699         *            DOCUMENT ME!
700         *
701         * @return byte[] representation of the string
702         *
703         * @throws SQLException
704         *             if an encoding unsupported by the JVM is supplied.
705         */
706        public static final byte[] getBytes(String s, String encoding,
707                        String serverEncoding, boolean parserKnowsUnicode, 
708                        MySQLConnection conn, ExceptionInterceptor exceptionInterceptor)
709                        throws SQLException {
710                try {
711                        SingleByteCharsetConverter converter = null;
712                       
713                        if (conn != null) {
714                                converter = conn.getCharsetConverter(encoding);
715                        } else {
716                                converter = SingleByteCharsetConverter.getInstance(encoding, null);
717                        }
718
719                        return getBytes(s, converter, encoding, serverEncoding,
720                                        parserKnowsUnicode, exceptionInterceptor);
721                } catch (UnsupportedEncodingException uee) {
722                        throw SQLError.createSQLException(Messages.getString("StringUtils.0") //$NON-NLS-1$
723                                        + encoding + Messages.getString("StringUtils.1"),
724                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT, exceptionInterceptor); //$NON-NLS-1$
725                }
726        }
727
728        public static int getInt(byte[] buf, int offset, int endPos) throws NumberFormatException {
729                int base = 10;
730
731                int s = offset;
732
733                /* Skip white space. */
734                while (Character.isWhitespace((char) buf[s]) && (s < endPos)) {
735                        ++s;
736                }
737
738                if (s == endPos) {
739                        throw new NumberFormatException(StringUtils.toString(buf));
740                }
741
742                /* Check for a sign. */
743                boolean negative = false;
744
745                if ((char) buf[s] == '-') {
746                        negative = true;
747                        ++s;
748                } else if ((char) buf[s] == '+') {
749                        ++s;
750                }
751
752                /* Save the pointer so we can check later if anything happened. */
753                int save = s;
754
755                int cutoff = Integer.MAX_VALUE / base;
756                int cutlim = (Integer.MAX_VALUE % base);
757
758                if (negative) {
759                        cutlim++;
760                }
761
762                boolean overflow = false;
763
764                int i = 0;
765
766                for (; s < endPos; s++) {
767                        char c = (char) buf[s];
768
769                        if (Character.isDigit(c)) {
770                                c -= '0';
771                        } else if (Character.isLetter(c)) {
772                                c = (char) (Character.toUpperCase(c) - 'A' + 10);
773                        } else {
774                                break;
775                        }
776
777                        if (c >= base) {
778                                break;
779                        }
780
781                        /* Check for overflow. */
782                        if ((i > cutoff) || ((i == cutoff) && (c > cutlim))) {
783                                overflow = true;
784                        } else {
785                                i *= base;
786                                i += c;
787                        }
788                }
789
790                if (s == save) {
791                        throw new NumberFormatException(StringUtils.toString(buf));
792                }
793
794                if (overflow) {
795                        throw new NumberFormatException(StringUtils.toString(buf));
796                }
797
798                /* Return the result of the appropriate sign. */
799                return (negative ? (-i) : i);
800        }
801       
802        public static int getInt(byte[] buf) throws NumberFormatException {
803                return getInt(buf, 0, buf.length);
804        }
805
806        public static long getLong(byte[] buf) throws NumberFormatException {
807                return getLong(buf, 0, buf.length);
808        }
809       
810        public static long getLong(byte[] buf, int offset, int endpos) throws NumberFormatException {
811                int base = 10;
812
813                int s = offset;
814
815                /* Skip white space. */
816                while (Character.isWhitespace((char) buf[s]) && (s < endpos)) {
817                        ++s;
818                }
819
820                if (s == endpos) {
821                        throw new NumberFormatException(StringUtils.toString(buf));
822                }
823
824                /* Check for a sign. */
825                boolean negative = false;
826
827                if ((char) buf[s] == '-') {
828                        negative = true;
829                        ++s;
830                } else if ((char) buf[s] == '+') {
831                        ++s;
832                }
833
834                /* Save the pointer so we can check later if anything happened. */
835                int save = s;
836
837                long cutoff = Long.MAX_VALUE / base;
838                long cutlim = (int) (Long.MAX_VALUE % base);
839
840                if (negative) {
841                        cutlim++;
842                }
843
844                boolean overflow = false;
845                long i = 0;
846
847                for (; s < endpos; s++) {
848                        char c = (char) buf[s];
849
850                        if (Character.isDigit(c)) {
851                                c -= '0';
852                        } else if (Character.isLetter(c)) {
853                                c = (char) (Character.toUpperCase(c) - 'A' + 10);
854                        } else {
855                                break;
856                        }
857
858                        if (c >= base) {
859                                break;
860                        }
861
862                        /* Check for overflow. */
863                        if ((i > cutoff) || ((i == cutoff) && (c > cutlim))) {
864                                overflow = true;
865                        } else {
866                                i *= base;
867                                i += c;
868                        }
869                }
870
871                if (s == save) {
872                        throw new NumberFormatException(StringUtils.toString(buf));
873                }
874
875                if (overflow) {
876                        throw new NumberFormatException(StringUtils.toString(buf));
877                }
878
879                /* Return the result of the appropriate sign. */
880                return (negative ? (-i) : i);
881        }
882
883        public static short getShort(byte[] buf) throws NumberFormatException {
884                short base = 10;
885
886                int s = 0;
887
888                /* Skip white space. */
889                while (Character.isWhitespace((char) buf[s]) && (s < buf.length)) {
890                        ++s;
891                }
892
893                if (s == buf.length) {
894                        throw new NumberFormatException(StringUtils.toString(buf));
895                }
896
897                /* Check for a sign. */
898                boolean negative = false;
899
900                if ((char) buf[s] == '-') {
901                        negative = true;
902                        ++s;
903                } else if ((char) buf[s] == '+') {
904                        ++s;
905                }
906
907                /* Save the pointer so we can check later if anything happened. */
908                int save = s;
909
910                short cutoff = (short) (Short.MAX_VALUE / base);
911                short cutlim = (short) (Short.MAX_VALUE % base);
912
913                if (negative) {
914                        cutlim++;
915                }
916
917                boolean overflow = false;
918                short i = 0;
919
920                for (; s < buf.length; s++) {
921                        char c = (char) buf[s];
922
923                        if (Character.isDigit(c)) {
924                                c -= '0';
925                        } else if (Character.isLetter(c)) {
926                                c = (char) (Character.toUpperCase(c) - 'A' + 10);
927                        } else {
928                                break;
929                        }
930
931                        if (c >= base) {
932                                break;
933                        }
934
935                        /* Check for overflow. */
936                        if ((i > cutoff) || ((i == cutoff) && (c > cutlim))) {
937                                overflow = true;
938                        } else {
939                                i *= base;
940                                i += c;
941                        }
942                }
943
944                if (s == save) {
945                        throw new NumberFormatException(StringUtils.toString(buf));
946                }
947
948                if (overflow) {
949                        throw new NumberFormatException(StringUtils.toString(buf));
950                }
951
952                /* Return the result of the appropriate sign. */
953                return (negative ? (short) -i : (short) i);
954        }
955
956        public final static int indexOfIgnoreCase(int startingPosition,
957                        String searchIn, String searchFor) {
958                if ((searchIn == null) || (searchFor == null)
959                                || startingPosition > searchIn.length()) {
960                        return -1;
961                }
962
963                int patternLength = searchFor.length();
964                int stringLength = searchIn.length();
965                int stopSearchingAt = stringLength - patternLength;
966
967                if (patternLength == 0) {
968                        return -1;
969                }
970
971                // Brute force string pattern matching
972                // Some locales don't follow upper-case rule, so need to check both
973                char firstCharOfPatternUc = Character.toUpperCase(searchFor.charAt(0));
974                char firstCharOfPatternLc = Character.toLowerCase(searchFor.charAt(0));
975
976                // note, this also catches the case where patternLength > stringLength
977        for (int i = startingPosition; i <= stopSearchingAt; i++) {
978            if (isNotEqualIgnoreCharCase(searchIn, firstCharOfPatternUc,
979                                        firstCharOfPatternLc, i)) {
980                // find the first occurrence of the first character of searchFor in searchIn
981                while (++i <= stopSearchingAt && (isNotEqualIgnoreCharCase(searchIn, firstCharOfPatternUc,
982                                                firstCharOfPatternLc, i)));
983            }
984
985            if (i <= stopSearchingAt /* searchFor might be one character long! */) {
986                // walk searchIn and searchFor in lock-step starting just past the first match,bail out if not
987                // a match, or we've hit the end of searchFor...
988                int j = i + 1;
989                int end = j + patternLength - 1;
990                for (int k = 1; j < end && (Character.toLowerCase(searchIn.charAt(j)) == 
991                        Character.toLowerCase(searchFor.charAt(k)) || Character.toUpperCase(searchIn.charAt(j)) == 
992                        Character.toUpperCase(searchFor.charAt(k))); j++, k++);
993
994                if (j == end) {
995                    return i;
996                }
997            }
998        }
999       
1000        return -1;
1001        }
1002
1003        private final static boolean isNotEqualIgnoreCharCase(String searchIn,
1004                        char firstCharOfPatternUc, char firstCharOfPatternLc, int i) {
1005                return Character.toLowerCase(searchIn.charAt(i)) != firstCharOfPatternLc && Character.toUpperCase(searchIn.charAt(i)) != firstCharOfPatternUc;
1006        }
1007       
1008
1009        /**
1010         * DOCUMENT ME!
1011         *
1012         * @param searchIn
1013         *            DOCUMENT ME!
1014         * @param searchFor
1015         *            DOCUMENT ME!
1016         *
1017         * @return DOCUMENT ME!
1018         */
1019        public final static int indexOfIgnoreCase(String searchIn, String searchFor) {
1020                return indexOfIgnoreCase(0, searchIn, searchFor);
1021        }
1022
1023        public static int indexOfIgnoreCaseRespectMarker(int startAt, String src,
1024                        String target, String marker, String markerCloses,
1025                        boolean allowBackslashEscapes) {
1026                char contextMarker = Character.MIN_VALUE;
1027                boolean escaped = false;
1028                int markerTypeFound = 0;
1029                int srcLength = src.length();
1030                int ind = 0;
1031
1032                for (int i = startAt; i < srcLength; i++) {
1033                        char c = src.charAt(i);
1034
1035                        if (allowBackslashEscapes && c == '\\') {
1036                                escaped = !escaped;
1037                        } else if (contextMarker != Character.MIN_VALUE && c == markerCloses.charAt(markerTypeFound) && !escaped) {
1038                                contextMarker = Character.MIN_VALUE;
1039                        } else if ((ind = marker.indexOf(c)) != -1 && !escaped
1040                                        && contextMarker == Character.MIN_VALUE) {
1041                                markerTypeFound = ind;
1042                                contextMarker = c;
1043                        } else if ((Character.toUpperCase(c) == Character.toUpperCase(target.charAt(0)) ||
1044                                        Character.toLowerCase(c) == Character.toLowerCase(target.charAt(0))) && !escaped
1045                                        && contextMarker == Character.MIN_VALUE) {
1046                                if (startsWithIgnoreCase(src, i, target))
1047                                        return i;
1048                        }
1049                }
1050
1051                return -1;
1052
1053        }
1054
1055        public static int indexOfIgnoreCaseRespectQuotes(int startAt, String src,
1056                        String target, char quoteChar, boolean allowBackslashEscapes) {
1057                char contextMarker = Character.MIN_VALUE;
1058                boolean escaped = false;
1059
1060                int srcLength = src.length();
1061
1062                for (int i = startAt; i < srcLength; i++) {
1063                        char c = src.charAt(i);
1064
1065                        if (allowBackslashEscapes && c == '\\') {
1066                                escaped = !escaped;
1067                        } else if (c == contextMarker && !escaped) {
1068                                contextMarker = Character.MIN_VALUE;
1069                        } else if (c == quoteChar && !escaped
1070                                        && contextMarker == Character.MIN_VALUE) {
1071                                contextMarker = c;
1072                        // This test looks complex, but remember that in certain locales, upper case
1073                        // of two different codepoints coverts to same codepoint, and vice-versa.
1074                        } else if ((Character.toUpperCase(c) == Character.toUpperCase(target.charAt(0)) ||
1075                                        Character.toLowerCase(c) == Character.toLowerCase(target.charAt(0))) && !escaped
1076                                        && contextMarker == Character.MIN_VALUE) {
1077                                if (startsWithIgnoreCase(src, i, target))
1078                                        return i;
1079                        }
1080                }
1081
1082                return -1;
1083
1084        }
1085
1086        /**
1087         * Splits stringToSplit into a list, using the given delimitter
1088         *
1089         * @param stringToSplit
1090         *            the string to split
1091         * @param delimitter
1092         *            the string to split on
1093         * @param trim
1094         *            should the split strings be whitespace trimmed?
1095         *
1096         * @return the list of strings, split by delimitter
1097         *
1098         * @throws IllegalArgumentException
1099         *             DOCUMENT ME!
1100         */
1101        public static final List<String> split(String stringToSplit, String delimitter,
1102                        boolean trim) {
1103                if (stringToSplit == null) {
1104                        return new ArrayList<String>();
1105                }
1106
1107                if (delimitter == null) {
1108                        throw new IllegalArgumentException();
1109                }
1110
1111                StringTokenizer tokenizer = new StringTokenizer(stringToSplit,
1112                                delimitter, false);
1113
1114                List<String> splitTokens = new ArrayList<String>(tokenizer.countTokens());
1115
1116                while (tokenizer.hasMoreTokens()) {
1117                        String token = tokenizer.nextToken();
1118
1119                        if (trim) {
1120                                token = token.trim();
1121                        }
1122
1123                        splitTokens.add(token);
1124                }
1125
1126                return splitTokens;
1127        }
1128
1129        /**
1130         * Splits stringToSplit into a list, using the given delimitter
1131         *
1132         * @param stringToSplit
1133         *            the string to split
1134         * @param delimitter
1135         *            the string to split on
1136         * @param trim
1137         *            should the split strings be whitespace trimmed?
1138         *
1139         * @return the list of strings, split by delimiter
1140         *
1141         * @throws IllegalArgumentException
1142         *             DOCUMENT ME!
1143         */
1144        public static final List<String> split(String stringToSplit, String delimiter,
1145                        String markers, String markerCloses, boolean trim) {
1146                if (stringToSplit == null) {
1147                        return new ArrayList<String>();
1148                }
1149
1150                if (delimiter == null) {
1151                        throw new IllegalArgumentException();
1152                }
1153
1154                int delimPos = 0;
1155                int currentPos = 0;
1156
1157                List<String> splitTokens = new ArrayList<String>();
1158
1159                while ((delimPos = indexOfIgnoreCaseRespectMarker(currentPos,
1160                                stringToSplit, delimiter, markers, markerCloses, false)) != -1) {
1161                        String token = stringToSplit.substring(currentPos, delimPos);
1162
1163                        if (trim) {
1164                                token = token.trim();
1165                        }
1166
1167                        splitTokens.add(token);
1168                        currentPos = delimPos + 1;
1169                }
1170
1171                if (currentPos < stringToSplit.length()) {
1172                        String token = stringToSplit.substring(currentPos);
1173
1174                        if (trim) {
1175                                token = token.trim();
1176                        }
1177
1178                        splitTokens.add(token);
1179                }
1180
1181                return splitTokens;
1182        }
1183
1184        private static boolean startsWith(byte[] dataFrom, String chars) {
1185                for (int i = 0; i < chars.length(); i++) {
1186                        if (dataFrom[i] != chars.charAt(i)) {
1187                                return false;
1188                        }
1189                }
1190                return true;
1191        }
1192
1193        /**
1194         * Determines whether or not the string 'searchIn' contains the string
1195         * 'searchFor', dis-regarding case starting at 'startAt' Shorthand for a
1196         * String.regionMatch(...)
1197         *
1198         * @param searchIn
1199         *            the string to search in
1200         * @param startAt
1201         *            the position to start at
1202         * @param searchFor
1203         *            the string to search for
1204         *
1205         * @return whether searchIn starts with searchFor, ignoring case
1206         */
1207        public static boolean startsWithIgnoreCase(String searchIn, int startAt,
1208                        String searchFor) {
1209                return searchIn.regionMatches(true, startAt, searchFor, 0, searchFor
1210                                .length());
1211        }
1212
1213        /**
1214         * Determines whether or not the string 'searchIn' contains the string
1215         * 'searchFor', dis-regarding case. Shorthand for a String.regionMatch(...)
1216         *
1217         * @param searchIn
1218         *            the string to search in
1219         * @param searchFor
1220         *            the string to search for
1221         *
1222         * @return whether searchIn starts with searchFor, ignoring case
1223         */
1224        public static boolean startsWithIgnoreCase(String searchIn, String searchFor) {
1225                return startsWithIgnoreCase(searchIn, 0, searchFor);
1226        }
1227
1228        /**
1229         * Determines whether or not the sting 'searchIn' contains the string
1230         * 'searchFor', disregarding case,leading whitespace and non-alphanumeric
1231         * characters.
1232         *
1233         * @param searchIn
1234         *            the string to search in
1235         * @param searchFor
1236         *            the string to search for
1237         *
1238         * @return true if the string starts with 'searchFor' ignoring whitespace
1239         */
1240        public static boolean startsWithIgnoreCaseAndNonAlphaNumeric(
1241                        String searchIn, String searchFor) {
1242                if (searchIn == null) {
1243                        return searchFor == null;
1244                }
1245
1246                int beginPos = 0;
1247
1248                int inLength = searchIn.length();
1249
1250                for (beginPos = 0; beginPos < inLength; beginPos++) {
1251                        char c = searchIn.charAt(beginPos);
1252
1253                        if (Character.isLetterOrDigit(c)) {
1254                                break;
1255                        }
1256                }
1257
1258                return startsWithIgnoreCase(searchIn, beginPos, searchFor);
1259        }
1260
1261        /**
1262         * Determines whether or not the sting 'searchIn' contains the string
1263         * 'searchFor', disregarding case and leading whitespace
1264         *
1265         * @param searchIn
1266         *            the string to search in
1267         * @param searchFor
1268         *            the string to search for
1269         *
1270         * @return true if the string starts with 'searchFor' ignoring whitespace
1271         */
1272        public static boolean startsWithIgnoreCaseAndWs(String searchIn,
1273                        String searchFor) {
1274                return startsWithIgnoreCaseAndWs(searchIn, searchFor, 0);
1275        }
1276       
1277        /**
1278         * Determines whether or not the sting 'searchIn' contains the string
1279         * 'searchFor', disregarding case and leading whitespace
1280         *
1281         * @param searchIn
1282         *            the string to search in
1283         * @param searchFor
1284         *            the string to search for
1285         * @param beginPos
1286         *            where to start searching
1287         *
1288         * @return true if the string starts with 'searchFor' ignoring whitespace
1289         */
1290       
1291        public static boolean startsWithIgnoreCaseAndWs(String searchIn,
1292                        String searchFor, int beginPos) {
1293                if (searchIn == null) {
1294                        return searchFor == null;
1295                }
1296
1297                int inLength = searchIn.length();
1298
1299                for (; beginPos < inLength; beginPos++) {
1300                        if (!Character.isWhitespace(searchIn.charAt(beginPos))) {
1301                                break;
1302                        }
1303                }
1304
1305                return startsWithIgnoreCase(searchIn, beginPos, searchFor);
1306        }
1307
1308        /**
1309         * @param bytesToStrip
1310         * @param prefix
1311         * @param suffix
1312         * @return
1313         */
1314        public static byte[] stripEnclosure(byte[] source, String prefix,
1315                        String suffix) {
1316                if (source.length >= prefix.length() + suffix.length()
1317                                && startsWith(source, prefix) && endsWith(source, suffix)) {
1318
1319                        int totalToStrip = prefix.length() + suffix.length();
1320                        int enclosedLength = source.length - totalToStrip;
1321                        byte[] enclosed = new byte[enclosedLength];
1322
1323                        int startPos = prefix.length();
1324                        int numToCopy = enclosed.length;
1325                        System.arraycopy(source, startPos, enclosed, 0, numToCopy);
1326
1327                        return enclosed;
1328                }
1329                return source;
1330        }
1331
1332        /**
1333         * Returns the bytes as an ASCII String.
1334         *
1335         * @param buffer
1336         *            the bytes representing the string
1337         *
1338         * @return The ASCII String.
1339         */
1340        public static final String toAsciiString(byte[] buffer) {
1341                return toAsciiString(buffer, 0, buffer.length);
1342        }
1343
1344        /**
1345         * Returns the bytes as an ASCII String.
1346         *
1347         * @param buffer
1348         *            the bytes to convert
1349         * @param startPos
1350         *            the position to start converting
1351         * @param length
1352         *            the length of the string to convert
1353         *
1354         * @return the ASCII string
1355         */
1356        public static final String toAsciiString(byte[] buffer, int startPos,
1357                        int length) {
1358                char[] charArray = new char[length];
1359                int readpoint = startPos;
1360
1361                for (int i = 0; i < length; i++) {
1362                        charArray[i] = (char) buffer[readpoint];
1363                        readpoint++;
1364                }
1365
1366                return new String(charArray);
1367        }
1368
1369        /**
1370         * Compares searchIn against searchForWildcard with wildcards (heavily
1371         * borrowed from strings/ctype-simple.c in the server sources)
1372         *
1373         * @param searchIn
1374         *            the string to search in
1375         * @param searchForWildcard
1376         *            the string to search for, using the 'standard' SQL wildcard
1377         *            chars of '%' and '_'
1378         *
1379         * @return WILD_COMPARE_MATCH_NO_WILD if matched, WILD_COMPARE_NO_MATCH if
1380         *         not matched with wildcard, WILD_COMPARE_MATCH_WITH_WILD if
1381         *         matched with wildcard
1382         */
1383        public static int wildCompare(String searchIn, String searchForWildcard) {
1384                if ((searchIn == null) || (searchForWildcard == null)) {
1385                        return WILD_COMPARE_NO_MATCH;
1386                }
1387
1388                if (searchForWildcard.equals("%")) { //$NON-NLS-1$
1389
1390                        return WILD_COMPARE_MATCH_WITH_WILD;
1391                }
1392
1393                int result = WILD_COMPARE_NO_MATCH; /* Not found, using wildcards */
1394
1395                char wildcardMany = '%';
1396                char wildcardOne = '_';
1397                char wildcardEscape = '\\';
1398
1399                int searchForPos = 0;
1400                int searchForEnd = searchForWildcard.length();
1401
1402                int searchInPos = 0;
1403                int searchInEnd = searchIn.length();
1404
1405                while (searchForPos != searchForEnd) {
1406                        char wildstrChar = searchForWildcard.charAt(searchForPos);
1407
1408                        while ((searchForWildcard.charAt(searchForPos) != wildcardMany)
1409                                        && (wildstrChar != wildcardOne)) {
1410                                if ((searchForWildcard.charAt(searchForPos) == wildcardEscape)
1411                                                && ((searchForPos + 1) != searchForEnd)) {
1412                                        searchForPos++;
1413                                }
1414
1415                                if ((searchInPos == searchInEnd)
1416                                                || (Character.toUpperCase(searchForWildcard
1417                                                                .charAt(searchForPos++)) != Character
1418                                                                .toUpperCase(searchIn.charAt(searchInPos++)))) {
1419                                        return WILD_COMPARE_MATCH_WITH_WILD; /* No match */
1420                                }
1421
1422                                if (searchForPos == searchForEnd) {
1423                                        return ((searchInPos != searchInEnd) ? WILD_COMPARE_MATCH_WITH_WILD
1424                                                        : WILD_COMPARE_MATCH_NO_WILD); /*
1425                                                                                                                         * Match if both are
1426                                                                                                                         * at end
1427                                                                                                                         */
1428                                }
1429
1430                                result = WILD_COMPARE_MATCH_WITH_WILD; /* Found an anchor char */
1431                        }
1432
1433                        if (searchForWildcard.charAt(searchForPos) == wildcardOne) {
1434                                do {
1435                                        if (searchInPos == searchInEnd) { /*
1436                                                                                                                 * Skip one char if
1437                                                                                                                 * possible
1438                                                                                                                 */
1439
1440                                                return (result);
1441                                        }
1442
1443                                        searchInPos++;
1444                                } while ((++searchForPos < searchForEnd)
1445                                                && (searchForWildcard.charAt(searchForPos) == wildcardOne));
1446
1447                                if (searchForPos == searchForEnd) {
1448                                        break;
1449                                }
1450                        }
1451
1452                        if (searchForWildcard.charAt(searchForPos) == wildcardMany) { /*
1453                                                                                                                                                         * Found
1454                                                                                                                                                         * w_many
1455                                                                                                                                                         */
1456
1457                                char cmp;
1458
1459                                searchForPos++;
1460
1461                                /* Remove any '%' and '_' from the wild search string */
1462                                for (; searchForPos != searchForEnd; searchForPos++) {
1463                                        if (searchForWildcard.charAt(searchForPos) == wildcardMany) {
1464                                                continue;
1465                                        }
1466
1467                                        if (searchForWildcard.charAt(searchForPos) == wildcardOne) {
1468                                                if (searchInPos == searchInEnd) {
1469                                                        return (WILD_COMPARE_NO_MATCH);
1470                                                }
1471
1472                                                searchInPos++;
1473
1474                                                continue;
1475                                        }
1476
1477                                        break; /* Not a wild character */
1478                                }
1479
1480                                if (searchForPos == searchForEnd) {
1481                                        return WILD_COMPARE_MATCH_NO_WILD; /* Ok if w_many is last */
1482                                }
1483
1484                                if (searchInPos == searchInEnd) {
1485                                        return WILD_COMPARE_NO_MATCH;
1486                                }
1487
1488                                if (((cmp = searchForWildcard.charAt(searchForPos)) == wildcardEscape)
1489                                                && ((searchForPos + 1) != searchForEnd)) {
1490                                        cmp = searchForWildcard.charAt(++searchForPos);
1491                                }
1492
1493                                searchForPos++;
1494
1495                                do {
1496                                        while ((searchInPos != searchInEnd)
1497                                                        && (Character.toUpperCase(searchIn
1498                                                                        .charAt(searchInPos)) != Character
1499                                                                        .toUpperCase(cmp)))
1500                                                searchInPos++;
1501
1502                                        if (searchInPos++ == searchInEnd) {
1503                                                return WILD_COMPARE_NO_MATCH;
1504                                        }
1505
1506                                        {
1507                                                int tmp = wildCompare(searchIn, searchForWildcard);
1508
1509                                                if (tmp <= 0) {
1510                                                        return (tmp);
1511                                                }
1512                                        }
1513                                } while ((searchInPos != searchInEnd)
1514                                                && (searchForWildcard.charAt(0) != wildcardMany));
1515
1516                                return WILD_COMPARE_NO_MATCH;
1517                        }
1518                }
1519
1520                return ((searchInPos != searchInEnd) ? WILD_COMPARE_MATCH_WITH_WILD
1521                                : WILD_COMPARE_MATCH_NO_WILD);
1522        }
1523       
1524        static byte[] s2b(String s, MySQLConnection conn) throws SQLException {
1525                if (s == null) {
1526                        return null;
1527                }
1528               
1529                if ((conn != null) && conn.getUseUnicode()) {
1530                        try {
1531                                String encoding = conn.getEncoding();
1532
1533                                if (encoding == null) {
1534                                        return s.getBytes();
1535                                }
1536
1537                                SingleByteCharsetConverter converter = conn
1538                                                .getCharsetConverter(encoding);
1539
1540                                if (converter != null) {
1541                                        return converter.toBytes(s);
1542                                }
1543
1544                                return s.getBytes(encoding);
1545                        } catch (java.io.UnsupportedEncodingException E) {
1546                                return s.getBytes();
1547                        }
1548                }
1549
1550                return s.getBytes();
1551        }
1552       
1553        public static int lastIndexOf(byte[] s, char c) {
1554                if (s == null) {
1555                        return -1;
1556                }
1557               
1558                for (int i = s.length - 1; i >= 0; i--) {
1559                        if (s[i] == c) {
1560                                return i;
1561                        }
1562                }
1563               
1564                return -1;
1565        }
1566
1567        public static int indexOf(byte[] s, char c) {
1568                if (s == null) {
1569                        return -1;
1570                }
1571               
1572                int length = s.length;
1573               
1574                for (int i = 0; i < length; i++) {
1575                        if (s[i] == c) {
1576                                return i;
1577                        }
1578                }
1579               
1580                return -1;
1581        }
1582       
1583        public static boolean isNullOrEmpty(String toTest) {
1584                return (toTest == null || toTest.length() == 0);
1585        }
1586       
1587        /**
1588         * Returns the given string, with comments removed
1589         *
1590         * @param src
1591         *            the source string
1592         * @param stringOpens
1593         *            characters which delimit the "open" of a string
1594         * @param stringCloses
1595         *            characters which delimit the "close" of a string, in
1596         *            counterpart order to <code>stringOpens</code>
1597         * @param slashStarComments
1598         *            strip slash-star type "C" style comments
1599         * @param slashSlashComments
1600         *            strip slash-slash C++ style comments to end-of-line
1601         * @param hashComments
1602         *            strip #-style comments to end-of-line
1603         * @param dashDashComments
1604         *            strip "--" style comments to end-of-line
1605         * @return the input string with all comment-delimited data removed
1606         */
1607        public static String stripComments(String src, String stringOpens,
1608                        String stringCloses, boolean slashStarComments,
1609                        boolean slashSlashComments, boolean hashComments,
1610                        boolean dashDashComments) {
1611                if (src == null) {
1612                        return null;
1613                }
1614
1615                StringBuffer buf = new StringBuffer(src.length());
1616
1617                // It's just more natural to deal with this as a stream
1618                // when parsing..This code is currently only called when
1619                // parsing the kind of metadata that developers are strongly
1620                // recommended to cache anyways, so we're not worried
1621                // about the _1_ extra object allocation if it cleans
1622                // up the code
1623
1624                StringReader sourceReader = new StringReader(src);
1625
1626                int contextMarker = Character.MIN_VALUE;
1627                boolean escaped = false;
1628                int markerTypeFound = -1;
1629
1630                int ind = 0;
1631
1632                int currentChar = 0;
1633
1634                try {
1635                        while ((currentChar = sourceReader.read()) != -1) {
1636
1637                                if (false && currentChar == '\\') {
1638                                        escaped = !escaped;
1639                                } else if (markerTypeFound != -1 && currentChar == stringCloses.charAt(markerTypeFound)
1640                                                && !escaped) {
1641                                        contextMarker = Character.MIN_VALUE;
1642                                        markerTypeFound = -1;
1643                                } else if ((ind = stringOpens.indexOf(currentChar)) != -1
1644                                                && !escaped && contextMarker == Character.MIN_VALUE) {
1645                                        markerTypeFound = ind;
1646                                        contextMarker = currentChar;
1647                                }
1648
1649                                if (contextMarker == Character.MIN_VALUE && currentChar == '/'
1650                                                && (slashSlashComments || slashStarComments)) {
1651                                        currentChar = sourceReader.read();
1652                                        if (currentChar == '*' && slashStarComments) {
1653                                                int prevChar = 0;
1654                                                while ((currentChar = sourceReader.read()) != '/'
1655                                                                || prevChar != '*') {
1656                                                        if (currentChar == '\r') {
1657
1658                                                                currentChar = sourceReader.read();
1659                                                                if (currentChar == '\n') {
1660                                                                        currentChar = sourceReader.read();
1661                                                                }
1662                                                        } else {
1663                                                                if (currentChar == '\n') {
1664
1665                                                                        currentChar = sourceReader.read();
1666                                                                }
1667                                                        }
1668                                                        if (currentChar < 0)
1669                                                                break;
1670                                                        prevChar = currentChar;
1671                                                }
1672                                                continue;
1673                                        } else if (currentChar == '/' && slashSlashComments) {
1674                                                while ((currentChar = sourceReader.read()) != '\n'
1675                                                                && currentChar != '\r' && currentChar >= 0)
1676                                                        ;
1677                                        }
1678                                } else if (contextMarker == Character.MIN_VALUE
1679                                                && currentChar == '#' && hashComments) {
1680                                        // Slurp up everything until the newline
1681                                        while ((currentChar = sourceReader.read()) != '\n'
1682                                                        && currentChar != '\r' && currentChar >= 0)
1683                                                ;
1684                                } else if (contextMarker == Character.MIN_VALUE
1685                                                && currentChar == '-' && dashDashComments) {
1686                                        currentChar = sourceReader.read();
1687
1688                                        if (currentChar == -1 || currentChar != '-') {
1689                                                buf.append('-');
1690
1691                                                if (currentChar != -1) {
1692                                                        buf.append(currentChar);
1693                                                }
1694
1695                                                continue;
1696                                        }
1697
1698                                        // Slurp up everything until the newline
1699
1700                                        while ((currentChar = sourceReader.read()) != '\n'
1701                                                        && currentChar != '\r' && currentChar >= 0)
1702                                                ;
1703                                }
1704
1705                                if (currentChar != -1) {
1706                                        buf.append((char) currentChar);
1707                                }
1708                        }
1709                } catch (IOException ioEx) {
1710                        // we'll never see this from a StringReader
1711                }
1712
1713                return buf.toString();
1714        }
1715       
1716        /**
1717         * Next two functions are to help DBMD check if
1718         * the given string is in form of database.name and return it
1719         * as "database";"name" with comments removed.
1720         * If string is NULL or wildcard (%), returns null and exits.
1721         *
1722         * First, we sanitize...
1723         *
1724         * @param src
1725         *            the source string
1726         * @return the input string with all comment-delimited data removed
1727         */
1728        public static String sanitizeProcOrFuncName(String src) {
1729                if ((src == null) || (src.equals("%"))) {
1730                        return null;
1731                }
1732                       
1733                return src;
1734        }
1735
1736        /**
1737         * Next we check if there is anything to split. If so
1738         * we return result in form of "database";"name"
1739         * If string is NULL or wildcard (%), returns null and exits.
1740         *
1741         * @param src
1742         *            the source string
1743         * @param cat
1744         *            Catalog, if available
1745         * @param quotId
1746         *            quoteId as defined on server
1747         * @param isNoBslashEscSet
1748         *            Is our connection in BackSlashEscape mode
1749         * @return the input string with all comment-delimited data removed
1750         */
1751        public static List<String> splitDBdotName(String src, String cat, String quotId,
1752                        boolean isNoBslashEscSet) {
1753                if ((src == null) || (src.equals("%"))) {
1754                        return new ArrayList<String>();
1755                }
1756               
1757                boolean isQuoted = StringUtils.indexOfIgnoreCase(0,src, quotId) > -1;
1758               
1759               
1760                String retval = src;
1761                String tmpCat = cat;
1762                //I.e., what if database is named `MyDatabase 1.0.0`... thus trueDotIndex
1763                int trueDotIndex = -1;
1764                if (!" ".equals(quotId)) {
1765                        //Presumably, if there is a database name attached and it contains dots, then it should
1766                        //be quoted so we first check for that
1767                        if (isQuoted) {
1768                                trueDotIndex = StringUtils.indexOfIgnoreCase(0,
1769                                        retval, quotId + "." + quotId);
1770                        } else {
1771                                //NOT quoted, fetch first DOT
1772                                // ex: cStmt = this.conn.prepareCall("{call bug57022.procbug57022(?, ?)}");
1773                                trueDotIndex = StringUtils.indexOfIgnoreCase(0,
1774                                                retval, ".");
1775                        }
1776                } else {
1777                        trueDotIndex = retval.indexOf(".");
1778                }
1779
1780                List<String> retTokens = new ArrayList<String>(2);
1781
1782                if (trueDotIndex != -1) {
1783                        //There is a catalog attached
1784                        if (isQuoted) {
1785                                tmpCat = StringUtils.toString(StringUtils.stripEnclosure(retval.substring(0, trueDotIndex+1)
1786                                                .getBytes(), quotId, quotId));
1787                                if (StringUtils.startsWithIgnoreCaseAndWs(tmpCat, quotId)) {
1788                                        tmpCat = tmpCat.substring(1, tmpCat.length() - 1);
1789                                }
1790
1791                                retval = retval.substring(trueDotIndex + 2);
1792                                retval = StringUtils.toString(StringUtils.stripEnclosure(retval
1793                                                .getBytes(), quotId, quotId));
1794                        } else {
1795                                //NOT quoted, adjust indexOf
1796                                tmpCat = retval.substring(0, trueDotIndex);
1797                                retval = retval.substring(trueDotIndex + 1);
1798                        }
1799                } else {
1800                        //No catalog attached, strip retval and return
1801                        retval = StringUtils.toString(StringUtils.stripEnclosure(retval
1802                                .getBytes(), quotId, quotId));
1803                }
1804               
1805                retTokens.add(tmpCat);
1806                retTokens.add(retval);
1807                return retTokens;
1808        }
1809       
1810        public static final boolean isEmptyOrWhitespaceOnly(String str) {
1811                if (str == null || str.length() == 0) {
1812                        return true;
1813                }
1814               
1815                int length = str.length();
1816               
1817                for (int i = 0; i < length; i++) {
1818                        if (!Character.isWhitespace(str.charAt(i))) {
1819                                return false;
1820                        }
1821                }
1822               
1823                return true;
1824        }
1825       
1826        public static String escapeQuote(String src, String quotChar) {
1827                if (src == null) {
1828                        return null;
1829                }
1830
1831                src = StringUtils.toString(stripEnclosure(src.getBytes(), quotChar, quotChar));
1832
1833                int lastNdx = src.indexOf(quotChar);
1834                String tmpSrc;
1835                String tmpRest;
1836
1837                tmpSrc = src.substring(0, lastNdx);
1838                tmpSrc = tmpSrc + quotChar + quotChar;
1839               
1840                tmpRest = src.substring(lastNdx+1, src.length());
1841               
1842                lastNdx = tmpRest.indexOf(quotChar);
1843                while (lastNdx > -1) {
1844                       
1845                        tmpSrc = tmpSrc + tmpRest.substring(0, lastNdx);
1846                        tmpSrc = tmpSrc + quotChar + quotChar;
1847                        tmpRest = tmpRest.substring(lastNdx+1, tmpRest.length());
1848                       
1849                        lastNdx = tmpRest.indexOf(quotChar);
1850                }
1851               
1852                tmpSrc = tmpSrc + tmpRest;
1853                src = tmpSrc;
1854
1855                return src;
1856        }
1857       
1858        // The following methods all exist because of the Java bug
1859        //
1860        // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6790402
1861        //
1862        // which has been observed by users and reported as MySQL Bug#61105
1863        //
1864        // We can turn around and replace them with their java.lang.String
1865        // equivalents if/when that bug is ever fixed.
1866       
1867        public static String toString(byte[] value, int offset, int length,
1868                        String encoding) throws UnsupportedEncodingException {
1869                Charset cs = findCharset(encoding);
1870
1871                return cs.decode(ByteBuffer.wrap(value, offset, length)).toString();
1872        }
1873
1874        public static String toString(byte[] value, String encoding)
1875                        throws UnsupportedEncodingException {
1876                Charset cs = findCharset(encoding);
1877
1878                return cs.decode(ByteBuffer.wrap(value)).toString();
1879        }
1880
1881        public static String toString(byte[] value, int offset, int length) {
1882                try {
1883                        Charset cs = findCharset(platformEncoding);
1884                       
1885                        return cs.decode(ByteBuffer.wrap(value, offset, length)).toString();
1886                } catch (UnsupportedEncodingException e) {
1887                        // can't happen, emulating new String(byte[])
1888                }
1889               
1890                return null;
1891        }
1892
1893        public static String toString(byte[] value) {
1894                try {
1895                        Charset cs = findCharset(platformEncoding);
1896                       
1897                        return cs.decode(ByteBuffer.wrap(value)).toString();
1898                } catch (UnsupportedEncodingException e) {
1899                        // can't happen, emulating new String(byte[])
1900                }
1901               
1902                return null;
1903        }
1904
1905        public static byte[] getBytes(String value, String encoding)
1906                        throws UnsupportedEncodingException {
1907                Charset cs = findCharset(encoding);
1908
1909                // can't simply .array() this to get the bytes
1910                // especially with variable-length charsets the
1911                // buffer is sometimes larger than the actual encoded data
1912                ByteBuffer buf = cs.encode(value);
1913               
1914                int encodedLen = buf.limit();
1915                byte[] asBytes = new byte[encodedLen];
1916                buf.get(asBytes, 0, encodedLen);
1917               
1918                return asBytes;
1919        }
1920       
1921        public static byte[] getBytes(String value) {
1922                try {
1923                        Charset cs = findCharset(platformEncoding);
1924                       
1925                        ByteBuffer buf = cs.encode(value);
1926                       
1927                        int encodedLen = buf.limit();
1928                        byte[] asBytes = new byte[encodedLen];
1929                        buf.get(asBytes, 0, encodedLen);
1930                       
1931                        return asBytes;
1932                } catch (UnsupportedEncodingException e) {
1933                        // can't happen, emulating new String(byte[])
1934                }
1935               
1936                return null;
1937        }
1938
1939        public static final boolean isValidIdChar(char c) {
1940                return VALID_ID_CHARS.indexOf(c) != -1;
1941        }
1942}
Note: See TracBrowser for help on using the repository browser.