[runtime] Replace %to_string_fun with %_ToString.
[platform/upstream/v8.git] / src / uri.js
1 // Copyright 2006-2008 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // This file contains support for URI manipulations written in
6 // JavaScript.
7
8 (function(global, utils) {
9
10 "use strict";
11
12 %CheckIsBootstrapping();
13
14 //- ------------------------------------------------------------------
15 // Imports
16
17 var GlobalObject = global.Object;
18 var GlobalArray = global.Array;
19 var InternalArray = utils.InternalArray;
20
21 // -------------------------------------------------------------------
22 // Define internal helper functions.
23
24 function HexValueOf(code) {
25   // 0-9
26   if (code >= 48 && code <= 57) return code - 48;
27   // A-F
28   if (code >= 65 && code <= 70) return code - 55;
29   // a-f
30   if (code >= 97 && code <= 102) return code - 87;
31
32   return -1;
33 }
34
35 // Does the char code correspond to an alpha-numeric char.
36 function isAlphaNumeric(cc) {
37   // a - z
38   if (97 <= cc && cc <= 122) return true;
39   // A - Z
40   if (65 <= cc && cc <= 90) return true;
41   // 0 - 9
42   if (48 <= cc && cc <= 57) return true;
43
44   return false;
45 }
46
47 // Lazily initialized.
48 var hexCharCodeArray = 0;
49
50 function URIAddEncodedOctetToBuffer(octet, result, index) {
51   result[index++] = 37; // Char code of '%'.
52   result[index++] = hexCharCodeArray[octet >> 4];
53   result[index++] = hexCharCodeArray[octet & 0x0F];
54   return index;
55 }
56
57 function URIEncodeOctets(octets, result, index) {
58   if (hexCharCodeArray === 0) {
59     hexCharCodeArray = [48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
60                         65, 66, 67, 68, 69, 70];
61   }
62   index = URIAddEncodedOctetToBuffer(octets[0], result, index);
63   if (octets[1]) index = URIAddEncodedOctetToBuffer(octets[1], result, index);
64   if (octets[2]) index = URIAddEncodedOctetToBuffer(octets[2], result, index);
65   if (octets[3]) index = URIAddEncodedOctetToBuffer(octets[3], result, index);
66   return index;
67 }
68
69 function URIEncodeSingle(cc, result, index) {
70   var x = (cc >> 12) & 0xF;
71   var y = (cc >> 6) & 63;
72   var z = cc & 63;
73   var octets = new GlobalArray(3);
74   if (cc <= 0x007F) {
75     octets[0] = cc;
76   } else if (cc <= 0x07FF) {
77     octets[0] = y + 192;
78     octets[1] = z + 128;
79   } else {
80     octets[0] = x + 224;
81     octets[1] = y + 128;
82     octets[2] = z + 128;
83   }
84   return URIEncodeOctets(octets, result, index);
85 }
86
87 function URIEncodePair(cc1 , cc2, result, index) {
88   var u = ((cc1 >> 6) & 0xF) + 1;
89   var w = (cc1 >> 2) & 0xF;
90   var x = cc1 & 3;
91   var y = (cc2 >> 6) & 0xF;
92   var z = cc2 & 63;
93   var octets = new GlobalArray(4);
94   octets[0] = (u >> 2) + 240;
95   octets[1] = (((u & 3) << 4) | w) + 128;
96   octets[2] = ((x << 4) | y) + 128;
97   octets[3] = z + 128;
98   return URIEncodeOctets(octets, result, index);
99 }
100
101 function URIHexCharsToCharCode(highChar, lowChar) {
102   var highCode = HexValueOf(highChar);
103   var lowCode = HexValueOf(lowChar);
104   if (highCode == -1 || lowCode == -1) throw MakeURIError();
105   return (highCode << 4) | lowCode;
106 }
107
108 // Callers must ensure that |result| is a sufficiently long sequential
109 // two-byte string!
110 function URIDecodeOctets(octets, result, index) {
111   var value;
112   var o0 = octets[0];
113   if (o0 < 0x80) {
114     value = o0;
115   } else if (o0 < 0xc2) {
116     throw MakeURIError();
117   } else {
118     var o1 = octets[1];
119     if (o0 < 0xe0) {
120       var a = o0 & 0x1f;
121       if ((o1 < 0x80) || (o1 > 0xbf)) throw MakeURIError();
122       var b = o1 & 0x3f;
123       value = (a << 6) + b;
124       if (value < 0x80 || value > 0x7ff) throw MakeURIError();
125     } else {
126       var o2 = octets[2];
127       if (o0 < 0xf0) {
128         var a = o0 & 0x0f;
129         if ((o1 < 0x80) || (o1 > 0xbf)) throw MakeURIError();
130         var b = o1 & 0x3f;
131         if ((o2 < 0x80) || (o2 > 0xbf)) throw MakeURIError();
132         var c = o2 & 0x3f;
133         value = (a << 12) + (b << 6) + c;
134         if ((value < 0x800) || (value > 0xffff)) throw MakeURIError();
135       } else {
136         var o3 = octets[3];
137         if (o0 < 0xf8) {
138           var a = (o0 & 0x07);
139           if ((o1 < 0x80) || (o1 > 0xbf)) throw MakeURIError();
140           var b = (o1 & 0x3f);
141           if ((o2 < 0x80) || (o2 > 0xbf)) {
142             throw MakeURIError();
143           }
144           var c = (o2 & 0x3f);
145           if ((o3 < 0x80) || (o3 > 0xbf)) throw MakeURIError();
146           var d = (o3 & 0x3f);
147           value = (a << 18) + (b << 12) + (c << 6) + d;
148           if ((value < 0x10000) || (value > 0x10ffff)) throw MakeURIError();
149         } else {
150           throw MakeURIError();
151         }
152       }
153     }
154   }
155   if (0xD800 <= value && value <= 0xDFFF) throw MakeURIError();
156   if (value < 0x10000) {
157     %_TwoByteSeqStringSetChar(index++, value, result);
158   } else {
159     %_TwoByteSeqStringSetChar(index++, (value >> 10) + 0xd7c0, result);
160     %_TwoByteSeqStringSetChar(index++, (value & 0x3ff) + 0xdc00, result);
161   }
162   return index;
163 }
164
165 // ECMA-262, section 15.1.3
166 function Encode(uri, unescape) {
167   uri = TO_STRING(uri);
168   var uriLength = uri.length;
169   var array = new InternalArray(uriLength);
170   var index = 0;
171   for (var k = 0; k < uriLength; k++) {
172     var cc1 = %_StringCharCodeAt(uri, k);
173     if (unescape(cc1)) {
174       array[index++] = cc1;
175     } else {
176       if (cc1 >= 0xDC00 && cc1 <= 0xDFFF) throw MakeURIError();
177       if (cc1 < 0xD800 || cc1 > 0xDBFF) {
178         index = URIEncodeSingle(cc1, array, index);
179       } else {
180         k++;
181         if (k == uriLength) throw MakeURIError();
182         var cc2 = %_StringCharCodeAt(uri, k);
183         if (cc2 < 0xDC00 || cc2 > 0xDFFF) throw MakeURIError();
184         index = URIEncodePair(cc1, cc2, array, index);
185       }
186     }
187   }
188
189   var result = %NewString(array.length, NEW_ONE_BYTE_STRING);
190   for (var i = 0; i < array.length; i++) {
191     %_OneByteSeqStringSetChar(i, array[i], result);
192   }
193   return result;
194 }
195
196 // ECMA-262, section 15.1.3
197 function Decode(uri, reserved) {
198   uri = TO_STRING(uri);
199   var uriLength = uri.length;
200   var one_byte = %NewString(uriLength, NEW_ONE_BYTE_STRING);
201   var index = 0;
202   var k = 0;
203
204   // Optimistically assume one-byte string.
205   for ( ; k < uriLength; k++) {
206     var code = %_StringCharCodeAt(uri, k);
207     if (code == 37) {  // '%'
208       if (k + 2 >= uriLength) throw MakeURIError();
209       var cc = URIHexCharsToCharCode(%_StringCharCodeAt(uri, k+1),
210                                      %_StringCharCodeAt(uri, k+2));
211       if (cc >> 7) break;  // Assumption wrong, two-byte string.
212       if (reserved(cc)) {
213         %_OneByteSeqStringSetChar(index++, 37, one_byte);  // '%'.
214         %_OneByteSeqStringSetChar(index++, %_StringCharCodeAt(uri, k+1),
215                                   one_byte);
216         %_OneByteSeqStringSetChar(index++, %_StringCharCodeAt(uri, k+2),
217                                   one_byte);
218       } else {
219         %_OneByteSeqStringSetChar(index++, cc, one_byte);
220       }
221       k += 2;
222     } else {
223       if (code > 0x7f) break;  // Assumption wrong, two-byte string.
224       %_OneByteSeqStringSetChar(index++, code, one_byte);
225     }
226   }
227
228   one_byte = %TruncateString(one_byte, index);
229   if (k == uriLength) return one_byte;
230
231   // Write into two byte string.
232   var two_byte = %NewString(uriLength - k, NEW_TWO_BYTE_STRING);
233   index = 0;
234
235   for ( ; k < uriLength; k++) {
236     var code = %_StringCharCodeAt(uri, k);
237     if (code == 37) {  // '%'
238       if (k + 2 >= uriLength) throw MakeURIError();
239       var cc = URIHexCharsToCharCode(%_StringCharCodeAt(uri, ++k),
240                                      %_StringCharCodeAt(uri, ++k));
241       if (cc >> 7) {
242         var n = 0;
243         while (((cc << ++n) & 0x80) != 0) { }
244         if (n == 1 || n > 4) throw MakeURIError();
245         var octets = new GlobalArray(n);
246         octets[0] = cc;
247         if (k + 3 * (n - 1) >= uriLength) throw MakeURIError();
248         for (var i = 1; i < n; i++) {
249           if (uri[++k] != '%') throw MakeURIError();
250           octets[i] = URIHexCharsToCharCode(%_StringCharCodeAt(uri, ++k),
251                                             %_StringCharCodeAt(uri, ++k));
252         }
253         index = URIDecodeOctets(octets, two_byte, index);
254       } else  if (reserved(cc)) {
255         %_TwoByteSeqStringSetChar(index++, 37, two_byte);  // '%'.
256         %_TwoByteSeqStringSetChar(index++, %_StringCharCodeAt(uri, k - 1),
257                                   two_byte);
258         %_TwoByteSeqStringSetChar(index++, %_StringCharCodeAt(uri, k),
259                                   two_byte);
260       } else {
261         %_TwoByteSeqStringSetChar(index++, cc, two_byte);
262       }
263     } else {
264       %_TwoByteSeqStringSetChar(index++, code, two_byte);
265     }
266   }
267
268   two_byte = %TruncateString(two_byte, index);
269   return one_byte + two_byte;
270 }
271
272 // -------------------------------------------------------------------
273 // Define exported functions.
274
275 // ECMA-262 - B.2.1.
276 function URIEscapeJS(s) {
277   return %URIEscape(s);
278 }
279
280 // ECMA-262 - B.2.2.
281 function URIUnescapeJS(s) {
282   return %URIUnescape(s);
283 }
284
285 // ECMA-262 - 15.1.3.1.
286 function URIDecode(uri) {
287   var reservedPredicate = function(cc) {
288     // #$
289     if (35 <= cc && cc <= 36) return true;
290     // &
291     if (cc == 38) return true;
292     // +,
293     if (43 <= cc && cc <= 44) return true;
294     // /
295     if (cc == 47) return true;
296     // :;
297     if (58 <= cc && cc <= 59) return true;
298     // =
299     if (cc == 61) return true;
300     // ?@
301     if (63 <= cc && cc <= 64) return true;
302
303     return false;
304   };
305   return Decode(uri, reservedPredicate);
306 }
307
308 // ECMA-262 - 15.1.3.2.
309 function URIDecodeComponent(component) {
310   var reservedPredicate = function(cc) { return false; };
311   return Decode(component, reservedPredicate);
312 }
313
314 // ECMA-262 - 15.1.3.3.
315 function URIEncode(uri) {
316   var unescapePredicate = function(cc) {
317     if (isAlphaNumeric(cc)) return true;
318     // !
319     if (cc == 33) return true;
320     // #$
321     if (35 <= cc && cc <= 36) return true;
322     // &'()*+,-./
323     if (38 <= cc && cc <= 47) return true;
324     // :;
325     if (58 <= cc && cc <= 59) return true;
326     // =
327     if (cc == 61) return true;
328     // ?@
329     if (63 <= cc && cc <= 64) return true;
330     // _
331     if (cc == 95) return true;
332     // ~
333     if (cc == 126) return true;
334
335     return false;
336   };
337   return Encode(uri, unescapePredicate);
338 }
339
340 // ECMA-262 - 15.1.3.4
341 function URIEncodeComponent(component) {
342   var unescapePredicate = function(cc) {
343     if (isAlphaNumeric(cc)) return true;
344     // !
345     if (cc == 33) return true;
346     // '()*
347     if (39 <= cc && cc <= 42) return true;
348     // -.
349     if (45 <= cc && cc <= 46) return true;
350     // _
351     if (cc == 95) return true;
352     // ~
353     if (cc == 126) return true;
354
355     return false;
356   };
357   return Encode(component, unescapePredicate);
358 }
359
360 // -------------------------------------------------------------------
361 // Install exported functions.
362
363 // Set up non-enumerable URI functions on the global object and set
364 // their names.
365 utils.InstallFunctions(global, DONT_ENUM, [
366   "escape", URIEscapeJS,
367   "unescape", URIUnescapeJS,
368   "decodeURI", URIDecode,
369   "decodeURIComponent", URIDecodeComponent,
370   "encodeURI", URIEncode,
371   "encodeURIComponent", URIEncodeComponent
372 ]);
373
374 })