1 /* 2 Copyright 2008, 3 Matthias Ehmann, 4 Michael Gerhaeuser, 5 Carsten Miller, 6 Bianca Valentin, 7 Alfred Wassermann, 8 Peter Wilfahrt 9 10 This file is part of JSXGraph. 11 12 JSXGraph is free software: you can redistribute it and/or modify 13 it under the terms of the GNU Lesser General Public License as published by 14 the Free Software Foundation, either version 3 of the License, or 15 (at your option) any later version. 16 17 JSXGraph is distributed in the hope that it will be useful, 18 but WITHOUT ANY WARRANTY; without even the implied warranty of 19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 GNU Lesser General Public License for more details. 21 22 You should have received a copy of the GNU Lesser General Public License 23 along with JSXGraph. If not, see <http://www.gnu.org/licenses/>. 24 */ 25 26 /** 27 * The FileReader object bundles the file input capabilities of JSXGraph. 28 */ 29 JXG.FileReader = { 30 31 /** 32 * Opens a file using the given URL and passes the contents to {@link JXG.FileReader#parseString} 33 * @param {String} url 34 * @param {JXG.Board|function} board Either a board or in case <tt>format</tt> equals 'raw' this has to be a callback function. 35 * @param {String} format The expected file format. Possible values are <dl> 36 * <dt>raw</dt><dd>Raw text file. In this case <tt>board</tt> has to be a callback function.</dd> 37 * <dt>geonext</dt><dd>Geonext File <a href="http://www.geonext.de">http://www.geonext.de</a></dd> 38 * <dt>intergeo</dt><dd>Intergeo file format <a href="http://www.i2geo.net">http://www.i2geo.net</a></dd> 39 * <dt>tracenpoche</dt><dd>Tracenpoche construction <a href="http://www.tracenpoche.net">http://www.tracenpoche.net</a></dd> 40 * <dt>graph</dt><dd>Graph file</dd> 41 * <dt>digraph</dt><dd>DiGraph file</dd> 42 * <dt>geogebra</dt><dd>Geogebra File <a href="http://www.geogebra.org">http://www.geogebra.org</a></dd> 43 * <dl><dt>cdy or cinderella</dt><dd>Cinderella (<a href="http://www.cinderella.de/">http://www.cinderella.de</a></dd> 44 * </dl> 45 * @param {Boolean} async Call ajax asynchonously. 46 */ 47 parseFileContent: function (url, board, format, async) { 48 var request = false; 49 50 if(!JXG.exists(async)) { 51 async = true; 52 } 53 54 //this.request = false; 55 56 try { 57 request = new XMLHttpRequest(); 58 if(format.toLowerCase()=='raw') { 59 request.overrideMimeType('text/plain; charset=iso-8859-1'); 60 } else { 61 request.overrideMimeType('text/xml; charset=iso-8859-1'); 62 } 63 } catch (e) { 64 try { 65 request = new ActiveXObject("Msxml2.XMLHTTP"); 66 } catch (e) { 67 try { 68 request = new ActiveXObject("Microsoft.XMLHTTP"); 69 } catch (e) { 70 request = false; 71 } 72 } 73 } 74 75 if (!request) { 76 alert("AJAX not activated!"); 77 return; 78 } 79 80 request.open("GET", url, async); 81 82 if(format.toLowerCase() === 'raw') { 83 this.cbp = function() { 84 var req = request; 85 if (req.readyState == 4) { 86 board(req.responseText); 87 } 88 }; 89 } else { 90 this.cbp = function() { 91 var req = request; 92 if (req.readyState == 4) { 93 var text = ''; 94 95 if (typeof req.responseStream!='undefined' && 96 (req.responseText.slice(0,2) == "PK" // ZIP -> Geogebra 97 || JXG.Util.asciiCharCodeAt(req.responseText.slice(0,1),0)==31) // gzip -> Cinderella 98 ) { 99 text = JXG.Util.Base64.decode(BinFileReader(req)); // After this, text contains the base64 encoded, zip-compressed string 100 } else { 101 text = req.responseText; 102 } 103 this.parseString(text, board, format, false); 104 } 105 }; 106 } 107 108 this.cb = JXG.bind(this.cbp, this); 109 request.onreadystatechange = this.cb; 110 111 try { 112 request.send(null); 113 } catch (e) { 114 throw new Error("JSXGraph: A problem occurred while trying to read '" + url + "'."); 115 } 116 }, 117 118 /** 119 * Cleans out unneccessary whitespaces in a chunk of xml. 120 * @param {XMLElement} el 121 */ 122 cleanWhitespace: function (el) { 123 var cur = el.firstChild; 124 125 while (cur != null) { 126 if (cur.nodeType == 3 && !/\S/.test(cur.nodeValue)) { 127 el.removeChild( cur ); 128 } else if ( cur.nodeType == 1 ) { 129 this.cleanWhitespace( cur ); 130 } 131 cur = cur.nextSibling; 132 } 133 }, 134 135 /** 136 * Converts a given string into a XML tree. 137 * @param {String} str 138 * @returns {XMLElement} The xml tree represented by the root node. 139 */ 140 stringToXMLTree: function (str) { 141 // The string "str" is converted into a XML tree. 142 if(typeof DOMParser === 'undefined') { 143 // IE workaround, since there is no DOMParser 144 DOMParser = function () {}; 145 DOMParser.prototype.parseFromString = function (str, contentType) { 146 if (typeof ActiveXObject !== 'undefined') { 147 var d = new ActiveXObject('MSXML.DomDocument'); 148 d.loadXML(str); 149 return d; 150 } 151 }; 152 } 153 var parser = new DOMParser(), 154 tree = parser.parseFromString(str, 'text/xml'); 155 156 this.cleanWhitespace(tree); 157 return tree; 158 }, 159 160 /** 161 * Parses a given string according to the file format given in format. 162 * @param {String} str Contents of the file. 163 * @param {JXG.Board} board The board the construction in the file should be loaded in. 164 * @param {String} format Possible values are <dl> 165 * <dt>raw</dt><dd>Raw text file. In this case <tt>board</tt> has to be a callback function.</dd> 166 * <dt>geonext</dt><dd>Geonext File <a href="http://www.geonext.de">http://www.geonext.de</a></dd> 167 * <dt>intergeo</dt><dd>Intergeo file format <a href="http://www.i2geo.net">http://www.i2geo.net</a></dd> 168 * <dt>tracenpoche</dt><dd>Tracenpoche construction <a href="http://www.tracenpoche.net">http://www.tracenpoche.net</a></dd> 169 * <dt>graph</dt><dd>Graph file</dd> 170 * <dt>digraph</dt><dd>DiGraph file</dd> 171 * <dt>geogebra</dt><dd>Geogebra File <a href="http://www.geogebra.org">http://www.geogebra.org</a></dd> 172 * <dl><dt>cdy or cinderella</dt><dd>Cinderella (<a href="http://www.cinderella.de/">http://www.cinderella.de</a></dd> 173 * </dl> 174 * @param {Boolean} isString Some file formats can be given as Base64 encoded strings or as plain xml, in both cases 175 * they are given as strings. This flag is used to distinguish those cases: <tt>true</tt> means, it is given as a string, 176 * no need to un-Base64 and unzip the file. 177 */ 178 parseString: function (str, board, format, isString) { 179 var tree, graph, xml; 180 181 format = format.toLowerCase(); 182 183 switch (format) { 184 case 'cdy': 185 case 'cinderella': 186 // if isString is true, str is the base64 encoded zip file, otherwise it's just the zip file 187 if(isString) { 188 str = JXG.Util.Base64.decode(str); 189 } 190 191 str = JXG.CinderellaReader.readCinderella(str, board); 192 board.xmlString = str; 193 194 break; 195 case 'tracenpoche': 196 board.xmlString = JXG.TracenpocheReader.readTracenpoche(str, board); 197 198 break; 199 case 'graph': 200 str = JXG.GraphReader.readGraph(str, board, false); 201 break; 202 case 'digraph': 203 str = JXG.GraphReader.readGraph(str, updateboard, true); 204 break; 205 case 'geonext': 206 // str is a string containing the XML code of the construction 207 str = JXG.GeonextReader.prepareString(str); 208 xml = true; 209 break; 210 case 'geogebra': 211 isString = str.slice(0, 2) !== "PK"; 212 213 // if isString is true, str is a base64 encoded string, otherwise it's the zipped file 214 str = JXG.GeogebraReader.prepareString(str, isString); 215 xml = true; 216 break; 217 case 'intergeo': 218 if(isString) { 219 str = JXG.Util.Base64.decode(str); 220 } 221 222 str = JXG.IntergeoReader.prepareString(str); 223 xml = true; 224 break; 225 } 226 227 if (xml) { 228 board.xmlString = str; 229 tree = this.stringToXMLTree(str); 230 // Now, we can walk through the tree 231 this.readElements(tree, board, format); 232 } 233 }, 234 235 /** 236 * Reading the elements of a geonext or geogebra file 237 * @param {} tree expects the content of the parsed geonext file returned by function parseFromString 238 * @param {Object} board board object 239 */ 240 readElements: function (tree, board, format) { 241 if (format.toLowerCase()=='geonext') { 242 board.suspendUpdate(); 243 if(tree.getElementsByTagName('GEONEXT').length != 0) { 244 JXG.GeonextReader.readGeonext(tree, board); 245 } 246 board.unsuspendUpdate(); 247 } 248 else if(tree.getElementsByTagName('geogebra').length != 0) { 249 JXG.GeogebraReader.readGeogebra(tree, board); 250 } 251 else if(format.toLowerCase()=='intergeo') { 252 JXG.IntergeoReader.readIntergeo(tree, board); 253 } 254 } 255 }; 256 257 // The following code is vbscript. This is a workaround to enable binary data downloads via AJAX in 258 // Microsoft Internet Explorer. 259 260 if(/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent && document && document.write)) { 261 document.write('<script type="text/vbscript">\n\ 262 Function Base64Encode(inData)\n\ 263 Const Base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"\n\ 264 Dim cOut, sOut, I\n\ 265 For I = 1 To LenB(inData) Step 3\n\ 266 Dim nGroup, pOut, sGroup\n\ 267 nGroup = &H10000 * AscB(MidB(inData, I, 1)) + _\n\ 268 &H100 * MyASC(MidB(inData, I + 1, 1)) + MyASC(MidB(inData, I + 2, 1))\n\ 269 nGroup = Oct(nGroup)\n\ 270 nGroup = String(8 - Len(nGroup), "0") & nGroup\n\ 271 pOut = Mid(Base64, CLng("&o" & Mid(nGroup, 1, 2)) + 1, 1) + _\n\ 272 Mid(Base64, CLng("&o" & Mid(nGroup, 3, 2)) + 1, 1) + _\n\ 273 Mid(Base64, CLng("&o" & Mid(nGroup, 5, 2)) + 1, 1) + _\n\ 274 Mid(Base64, CLng("&o" & Mid(nGroup, 7, 2)) + 1, 1)\n\ 275 sOut = sOut + pOut\n\ 276 Next\n\ 277 Select Case LenB(inData) Mod 3\n\ 278 Case 1: \'8 bit final\n\ 279 sOut = Left(sOut, Len(sOut) - 2) + "=="\n\ 280 Case 2: \'16 bit final\n\ 281 sOut = Left(sOut, Len(sOut) - 1) + "="\n\ 282 End Select\n\ 283 Base64Encode = sOut\n\ 284 End Function\n\ 285 \n\ 286 Function MyASC(OneChar)\n\ 287 If OneChar = "" Then MyASC = 0 Else MyASC = AscB(OneChar)\n\ 288 End Function\n\ 289 \n\ 290 Function BinFileReader(xhr)\n\ 291 Dim byteString\n\ 292 Dim b64String\n\ 293 Dim i\n\ 294 byteString = xhr.responseBody\n\ 295 ReDim byteArray(LenB(byteString))\n\ 296 For i = 1 To LenB(byteString)\n\ 297 byteArray(i-1) = AscB(MidB(byteString, i, 1))\n\ 298 Next\n\ 299 b64String = Base64Encode(byteString)\n\ 300 BinFileReader = b64String\n\ 301 End Function\n\ 302 </script>\n'); 303 } 304