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