1 /** 2 * Upgraded 3 * !!Do not modify the above line!! 4 */ 5 /** 6 * SafeFN is a Javascript implementation of Christopher Smith's php 7 * SafeFN class which was written for Dokuwiki 8 * 9 * @author Myron Turner <turnermm@shaw.ca> 10 * @copyright Myron Turner (C) GPL 2 or greater 11 */ 12 13var SafeFN = { 14 plain: '-./[_0123456789abcdefghijklmnopqrstuvwxyz', // these characters aren't converted 15 pre_indicator: '%', 16 post_indicator:']', 17 18 /** 19 * convert numbers from base 10 to base 36 and base 36 to base 10 20 * 21 * @param string representing an integer or integer num number to be converted 22 * @param integer from base from which to convert 23 * @param integer to base to which to convert 24 * 25 * @return array int an array of unicode codepoints 26 * 27 * @author Myron Turner <turnermm02@shaw.ca> 28 */ 29 30 changeSafeBase: function(num, from, to) { 31 if(isNaN(from) || from < 2 || from > 36 || isNaN(to) || to < 2 || to > 36) { 32 throw (new RangeError("Illegal radix. Radices must be integers between 2 and 36, inclusive.")); 33 } 34 num = parseInt(num, from); 35 if(from == 36) return num; 36 return num.toString(to); 37 }, 38 39 40 /** 41 * convert a UTF8 string into an array of unicode code points 42 * 43 * @param UTF8 string 44 * @return array int an array of unicode codepoints 45 * 46 * @author Myron Turner <turnermm02@shaw.ca> 47 */ 48 49 get_u_array: function(utf8str) { 50 var unicode_array = new Array(); 51 for (var i=0; i<utf8str.length; i++) { 52 unicode_array[i] = utf8str.charCodeAt(i);; 53 } 54 return unicode_array; 55 }, 56 57 58 /** 59 * convert a 'safe_filename' string into an array of unicode codepoints 60 * 61 * @param string safe a filename in 'safe_filename' format 62 * @return array int an array of unicode codepoints 63 * @author Christopher Smith <chris@jalakai.co.uk> 64 * @author Myron Turner<turnermm02@shaw.ca> 65 */ 66 safe_to_unicode: function(safe) { 67 var unicode = new Array(); 68 var regex = new RegExp('(?=[' + this.pre_indicator + '\\' + this.post_indicator + '])'); 69 var split_array = safe.split(regex); 70 var converted = false; 71 72 for (var i = 0; i<split_array.length; i++ ) { 73 var sub = split_array[i]; 74 if (sub.charAt(0) != this.pre_indicator) { // i.e. sub.charAt(0) != '%' 75 var start = converted?1:0; 76 for (j=start; j < sub.length; j++) { 77 unicode.push(sub.charCodeAt(j)); 78 } 79 converted = false; 80 } else if (sub.length==1) { 81 unicode.push(sub.charCodeAt(0)); 82 converted = true; 83 } else { 84 85 unicode.push(32 + this.changeSafeBase(sub.slice(1),36,10)); 86 converted = true; 87 } 88 } 89 90 return unicode; 91 }, 92 93 /** 94 * convert an array of unicode codepoints into 'safe_filename' format 95 * 96 * @param array int $unicode an array of unicode codepoints 97 * @return string the unicode represented in 'safe_filename' format 98 * 99 * @author Christopher Smith <chris@jalakai.co.uk> 100 * @author Myron Turner <turnermm02@shaw.ca> 101 */ 102 unicode_to_safe: function (unicode) { 103 var safe = ''; 104 var converted = false; 105 var plain_str = this.plain + this.post_indicator; 106 107 for (var i=0; i< unicode.length; i++) { 108 codepoint = unicode[i]; 109 var match = ''; 110 if(String.fromCharCode(codepoint) != '\\') { 111 var regex = new RegExp(String.fromCharCode(codepoint)); 112 var match = plain_str.match(regex); 113 } 114 115 if (codepoint < 127 && match) { 116 if (converted) { 117 safe += this.post_indicator; 118 converted = false; 119 } 120 safe += String.fromCharCode(codepoint); 121 122 } else if (codepoint == this.pre_indicator.charCodeAt(0)) { 123 safe += this.pre_indicator; 124 converted = true; 125 } else { 126 safe += this.pre_indicator + this.changeSafeBase((codepoint-32), 10, 36); 127 converted = true; 128 } 129 } 130 if(converted) safe += this.post_indicator; 131 132 return safe; 133 }, 134 135 /** 136 * Convert an UTF-8 string to a safe ASCII String 137 * 138 * 139 * @param string filename a utf8 string, should only include printable characters - not 0x00-0x1f 140 * @return string an encoded representation of filename using only 'safe' ASCII characters 141 * 142 * @author Myron Turner <turnermm02@shaw.ca> 143 */ 144 encode: function(filename) { 145 return this.unicode_to_safe(this.get_u_array(filename)); 146 }, 147 148 /** 149 * decode a 'safe' encoded file name and return a UTF8 string 150 * 151 * @param string filename a 'safe' encoded ASCII string, 152 * @return string decoded utf8 string 153 * 154 * @author Myron Turner <turnermm02@shaw.ca> 155 */ 156 157 decode: function (filename) { 158 var unic = this.safe_to_unicode(filename); 159 160 // convert unicode code points to utf8 161 var str = new Array(); 162 for (var i=0; i < unic.length; i++) { 163 str[i] = this.code2utf(unic[i]); 164 } 165 // return the decoded string 166 return this.utf8Decode(str.join('')); 167 }, 168 169/* UTF8 encoding/decoding functions 170 * Copyright (c) 2006 by Ali Farhadi. 171 * released under the terms of the Gnu Public License. 172 * see the GPL for details. 173 * 174 * Email: ali[at]farhadi[dot]ir 175 * Website: http://farhadi.ir/ 176 */ 177 178//an alias of String.fromCharCode 179chr: function (code) 180{ 181 return String.fromCharCode(code); 182}, 183 184//returns utf8 encoded charachter of a unicode value. 185//code must be a number indicating the Unicode value. 186//returned value is a string between 1 and 4 charachters. 187code2utf: function (code) 188{ 189 if (code < 128) return this.chr(code); 190 if (code < 2048) return this.chr(192+(code>>6)) + this.chr(128+(code&63)); 191 if (code < 65536) return this.chr(224+(code>>12)) + this.chr(128+((code>>6)&63)) + this.chr(128+(code&63)); 192 if (code < 2097152) return this.chr(240+(code>>18)) + this.chr(128+((code>>12)&63)) + this.chr(128+((code>>6)&63)) + this.chr(128+(code&63)); 193}, 194 195//it is a private function for internal use in utf8Decode function 196_utf8Decode: function (utf8str) 197{ 198 199 var str = new Array(); 200 var code,code2,code3,code4,j = 0; 201 for (var i=0; i<utf8str.length; ) { 202 code = utf8str.charCodeAt(i++); 203 204 205 if (code > 127) code2 = utf8str.charCodeAt(i++); 206 if (code > 223) code3 = utf8str.charCodeAt(i++); 207 if (code > 239) code4 = utf8str.charCodeAt(i++); 208 209 if (code < 128) str[j++]= this.chr(code); 210 else if (code < 224) str[j++] = this.chr(((code-192)<<6) + (code2-128)); 211 else if (code < 240) str[j++] = this.chr(((code-224)<<12) + ((code2-128)<<6) + (code3-128)); 212 else str[j++] = this.chr(((code-240)<<18) + ((code2-128)<<12) + ((code3-128)<<6) + (code4-128)); 213 214 } 215 return str.join(''); 216}, 217 218//Decodes a UTF8 formated string 219utf8Decode: function (utf8str) 220{ 221 var str = new Array(); 222 var pos = 0; 223 var tmpStr = ''; 224 var j=0; 225 while ((pos = utf8str.search(/[^\x00-\x7F]/)) != -1) { 226 tmpStr = utf8str.match(/([^\x00-\x7F]+[\x00-\x7F]{0,10})+/)[0]; 227 str[j++]= utf8str.substr(0, pos) + this._utf8Decode(tmpStr); 228 utf8str = utf8str.substr(pos + tmpStr.length); 229 } 230 231 str[j++] = utf8str; 232 return str.join(''); 233} 234 235}; 236 237function SafeFN_encode(filename) { 238 return SafeFN.encode(filename); 239} 240 241function SafeFN_decode(filename) { 242 return SafeFN.decode(filename); 243} 244 245 246function dwikiUTF8_encodeFN(file, encoding){ 247 248 if(encoding == 'utf-8') return file; 249 250 if(file.match(/^[a-zA-Z0-9\/_\-\.%\]]+$/)){ 251 return file; 252 } 253 254 if(encoding == 'safe'){ 255 return SafeFN_encode(file); 256 } 257 258 file = encodeURIComponent(file); 259 file = file.replace(/%2F/g,'/'); 260 return file; 261} 262 263 264function dwikiUTF8_decodeFN(file, encoding){ 265 266 if(encoding == 'utf-8') return file; 267 268 if(encoding == 'safe'){ 269 return SafeFN_decode(file); 270 } 271 272 return decodeURIComponent(file); 273} 274