1. /*
  2. * @(#)URLEncoder.java 1.16 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.net;
  8. import java.io.ByteArrayOutputStream;
  9. import java.io.OutputStreamWriter;
  10. import java.io.IOException;
  11. import java.util.BitSet;
  12. /**
  13. * The class contains a utility method for converting a
  14. * <code>String</code> into a MIME format called
  15. * "<code>x-www-form-urlencoded</code>" format.
  16. * <p>
  17. * To convert a <code>String</code>, each character is examined in turn:
  18. * <ul>
  19. * <li>The ASCII characters '<code>a</code>' through '<code>z</code>',
  20. * '<code>A</code>' through '<code>Z</code>', and '<code>0</code>'
  21. * through '<code>9</code>' remain the same.
  22. * <li>The space character '<code> </code>' is converted into a
  23. * plus sign '<code>+</code>'.
  24. * <li>All other characters are converted into the 3-character string
  25. * "<code>%<i>xy</i></code>", where <i>xy</i> is the two-digit
  26. * hexadecimal representation of the lower 8-bits of the character.
  27. * </ul>
  28. *
  29. * @author Herb Jellinek
  30. * @version 1.16, 11/29/01
  31. * @since JDK1.0
  32. */
  33. public class URLEncoder {
  34. static BitSet dontNeedEncoding;
  35. static final int caseDiff = ('a' - 'A');
  36. /* The list of characters that are not encoded have been determined by
  37. referencing O'Reilly's "HTML: The Definitive Guide" (page 164). */
  38. static {
  39. dontNeedEncoding = new BitSet(256);
  40. int i;
  41. for (i = 'a'; i <= 'z'; i++) {
  42. dontNeedEncoding.set(i);
  43. }
  44. for (i = 'A'; i <= 'Z'; i++) {
  45. dontNeedEncoding.set(i);
  46. }
  47. for (i = '0'; i <= '9'; i++) {
  48. dontNeedEncoding.set(i);
  49. }
  50. dontNeedEncoding.set(' '); /* encoding a space to a + is done in the encode() method */
  51. dontNeedEncoding.set('-');
  52. dontNeedEncoding.set('_');
  53. dontNeedEncoding.set('.');
  54. dontNeedEncoding.set('*');
  55. }
  56. /**
  57. * You can't call the constructor.
  58. */
  59. private URLEncoder() { }
  60. /**
  61. * Translates a string into <code>x-www-form-urlencoded</code> format.
  62. *
  63. * @param s <code>String</code> to be translated.
  64. * @return the translated <code>String</code>.
  65. */
  66. public static String encode(String s) {
  67. int maxBytesPerChar = 10;
  68. StringBuffer out = new StringBuffer(s.length());
  69. ByteArrayOutputStream buf = new ByteArrayOutputStream(maxBytesPerChar);
  70. OutputStreamWriter writer = new OutputStreamWriter(buf);
  71. for (int i = 0; i < s.length(); i++) {
  72. int c = (int)s.charAt(i);
  73. if (dontNeedEncoding.get(c)) {
  74. if (c == ' ') {
  75. c = '+';
  76. }
  77. out.append((char)c);
  78. } else {
  79. // convert to external encoding before hex conversion
  80. try {
  81. writer.write(c);
  82. writer.flush();
  83. } catch(IOException e) {
  84. buf.reset();
  85. continue;
  86. }
  87. byte[] ba = buf.toByteArray();
  88. for (int j = 0; j < ba.length; j++) {
  89. out.append('%');
  90. char ch = Character.forDigit((ba[j] >> 4) & 0xF, 16);
  91. // converting to use uppercase letter as part of
  92. // the hex value if ch is a letter.
  93. if (Character.isLetter(ch)) {
  94. ch -= caseDiff;
  95. }
  96. out.append(ch);
  97. ch = Character.forDigit(ba[j] & 0xF, 16);
  98. if (Character.isLetter(ch)) {
  99. ch -= caseDiff;
  100. }
  101. out.append(ch);
  102. }
  103. buf.reset();
  104. }
  105. }
  106. return out.toString();
  107. }
  108. }