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