1 /* 2 Copyright 2008-2024 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 dual licensed under the GNU LGPL or MIT License. 13 14 You can redistribute it and/or modify it under the terms of the 15 16 * GNU Lesser General Public License as published by 17 the Free Software Foundation, either version 3 of the License, or 18 (at your option) any later version 19 OR 20 * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT 21 22 JSXGraph is distributed in the hope that it will be useful, 23 but WITHOUT ANY WARRANTY; without even the implied warranty of 24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 GNU Lesser General Public License for more details. 26 27 You should have received a copy of the GNU Lesser General Public License and 28 the MIT License along with JSXGraph. If not, see <https://www.gnu.org/licenses/> 29 and <https://opensource.org/licenses/MIT/>. 30 */ 31 32 /*global JXG:true, define: true, ActiveXObject:true, jxgBinFileReader:true, DOMParser:true, XMLHttpRequest:true, document:true, navigator:true*/ 33 /*jslint nomen: true, plusplus: true*/ 34 35 import JXG from "../jxg.js"; 36 import Env from "../utils/env.js"; 37 import Type from "../utils/type.js"; 38 import Encoding from "../utils/encoding.js"; 39 import Base64 from "../utils/base64.js"; 40 41 /** 42 * The FileReader object bundles the file input capabilities of JSXGraph. 43 */ 44 JXG.FileReader = { 45 /** 46 * 47 * @param {String} url 48 * @param {JXG.Board} board 49 * @param {String} format 50 * @param {Boolean} async 51 * @param {Function} callback 52 * 53 * @private 54 */ 55 handleRemoteFile: function (url, board, format, async, encoding, callback) { 56 var request = false; 57 58 try { 59 request = new XMLHttpRequest(); 60 if (format.toLowerCase() === "raw") { 61 request.overrideMimeType("text/plain; charset=" + encoding); 62 } else { 63 request.overrideMimeType("text/xml; charset=" + encoding); 64 } 65 } catch (e) { 66 try { 67 request = new ActiveXObject("Msxml2.XMLHTTP"); 68 } catch (ex) { 69 try { 70 request = new ActiveXObject("Microsoft.XMLHTTP"); 71 } catch (exc) { 72 request = false; 73 } 74 } 75 } 76 if (!request) { 77 JXG.debug("AJAX not activated!"); 78 return; 79 } 80 81 request.open("GET", url, async); 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 text = ""; 93 94 if (req.readyState === 4) { 95 // Hack for ancient IEs: 96 // We use the Visual Basic stuff from below. 97 if ( 98 Type.exists(req.responseStream) && 99 // PK: zip, geogebra 100 // 31: gzip, cinderella 101 (req.responseText.slice(0, 2) === "PK" || 102 Encoding.asciiCharCodeAt(req.responseText.slice(0, 1), 0) === 31) 103 ) { 104 // After this, text contains the binary? zip-compressed string 105 text = Base64.decode(jxgBinFileReader(req)); 106 } else { 107 // This is for all browsers except ancient IEs. 108 text = req.responseText; 109 // console.log(text); 110 } 111 this.parseString(text, board, format, callback); 112 } 113 }; 114 } 115 116 this.cb = Type.bind(this.cbp, this); 117 // Old style 118 request.onreadystatechange = this.cb; 119 120 try { 121 request.send(null); 122 } catch (ex2) { 123 throw new Error( 124 "JSXGraph: A problem occurred while trying to read remote file '" + url + "'." 125 ); 126 } 127 }, 128 129 /** 130 * 131 * @param {Blob} url The Blob or File from which to read 132 * @param {JXG.Board} board 133 * @param {String} format 134 * @param {Boolean} async 135 * @param {Function} callback 136 * 137 * @private 138 */ 139 handleLocalFile: function (url, board, format, async, encoding, callback) { 140 if (!Type.exists(async)) { 141 async = true; 142 } 143 144 if (format.toLowerCase() === "raw") { 145 this.cbp = function (e) { 146 board(e.target.result); 147 }; 148 } else { 149 this.cbp = function (e) { 150 var text = e.target.result; 151 //console.log(text); 152 this.parseString(text, board, format, callback); 153 }; 154 } 155 156 this.cb = Type.bind(this.cbp, this); 157 158 var reader = new FileReader(); 159 reader.onload = this.cb; 160 if (format.toLowerCase() === "raw") { 161 reader.readAsText(url); 162 } else { 163 reader.readAsText(url, encoding); 164 } 165 }, 166 167 /** 168 * Opens a file using the given URL and passes the contents to {@link JXG.FileReader#parseString} 169 * @param {String} url 170 * @param {JXG.Board|function} board Either a board or in case <tt>format</tt> equals 'raw' this has to be a callback function. 171 * @param {String} format The expected file format. Possible values are <dl> 172 * <dt>raw</dt><dd>Raw text file. In this case <tt>board</tt> has to be a callback function.</dd> 173 * <dt>geonext</dt><dd>Geonext File <a href="https://www.geonext.de">https://www.geonext.de</a></dd> 174 * <dt>intergeo</dt><dd>Intergeo file format <a href="https://www.i2geo.net">https://www.i2geo.net</a></dd> 175 * <dt>tracenpoche</dt><dd>Tracenpoche construction <a href="https://tracenpoche.sesamath.net/">https://tracenpoche.sesamath.net/</a></dd> 176 * <dt>graph</dt><dd>Graph file</dd> 177 * <dt>digraph</dt><dd>DiGraph file</dd> 178 * <dt>geogebra</dt><dd>Geogebra File <a href="https://www.geogebra.org">https://www.geogebra.org</a></dd> 179 * <dl><dt>cdy or cinderella</dt><dd>Cinderella (<a href="https://www.cinderella.de/">https://www.cinderella.de</a></dd> 180 * </dl> 181 * @param {Boolean} async Call ajax asynchonously. 182 * @param {function} callback A function that is run when the board is ready. 183 */ 184 parseFileContent: function (url, board, format, async, encoding, callback) { 185 if (Type.isString(url) || FileReader === undefined) { 186 this.handleRemoteFile(url, board, format, async, encoding, callback); 187 } else { 188 this.handleLocalFile(url, board, format, async, encoding, callback); 189 } 190 }, 191 192 /** 193 * Parses a given string according to the file format given in format. 194 * @param {String} str Contents of the file. 195 * @param {JXG.Board} board The board the construction in the file should be loaded in. 196 * @param {String} format Possible values are <dl> 197 * <dt>raw</dt><dd>Raw text file. In this case <tt>board</tt> has to be a callback function.</dd> 198 * <dt>geonext</dt><dd>Geonext File <a href="https://www.geonext.de">https://www.geonext.de</a></dd> 199 * <dt>intergeo</dt><dd>Intergeo file format <a href="https://www.i2geo.net">https://www.i2geo.net</a></dd> 200 * <dt>tracenpoche</dt><dd>Tracenpoche construction <a href="https://tracenpoche.sesamath.net/">https://tracenpoche.sesamath.net/</a></dd> 201 * <dt>graph</dt><dd>Graph file</dd> 202 * <dt>digraph</dt><dd>DiGraph file</dd> 203 * <dt>geogebra</dt><dd>Geogebra File <a href="https://www.geogebra.org">https://www.geogebra.org</a></dd> 204 * <dl><dt>cdy or cinderella</dt><dd>Cinderella (<a href="https://www.cinderella.de/">https://www.cinderella.de</a></dd> 205 * </dl> 206 * @param {function} callback 207 */ 208 parseString: function (str, board, format, callback) { 209 var Reader, read; 210 211 format = format.toLowerCase(); 212 Reader = JXG.readers[format]; 213 214 if (Type.exists(Reader)) { 215 read = new Reader(board, str); 216 read.read(); 217 } else if (format === "jessiecode") { 218 } else { 219 throw new Error("JSXGraph: There is no reader available for '" + format + "'."); 220 } 221 222 if (Type.isFunction(callback)) { 223 callback(board); 224 } 225 } 226 }; 227 228 // The following code is vbscript. This is a workaround to enable binary data downloads via AJAX in 229 // Microsoft Internet Explorer. 230 231 /*jslint evil:true, es5:true, white:true*/ 232 /*jshint multistr:true*/ 233 if ( 234 !Env.isMetroApp() && 235 Env.isBrowser && 236 typeof navigator === "object" && 237 /msie/i.test(navigator.userAgent) && 238 !/opera/i.test(navigator.userAgent) && 239 document && 240 document.write 241 ) { 242 document.write( 243 '<script type="text/vbscript">\n\ 244 Function Base64Encode(inData)\n\ 245 Const Base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"\n\ 246 Dim cOut, sOut, I\n\ 247 For I = 1 To LenB(inData) Step 3\n\ 248 Dim nGroup, pOut, sGroup\n\ 249 nGroup = &H10000 * AscB(MidB(inData, I, 1)) + _\n\ 250 &H100 * MyASC(MidB(inData, I + 1, 1)) + MyASC(MidB(inData, I + 2, 1))\n\ 251 nGroup = Oct(nGroup)\n\ 252 nGroup = String(8 - Len(nGroup), "0") & nGroup\n\ 253 pOut = Mid(Base64, CLng("&o" & Mid(nGroup, 1, 2)) + 1, 1) + _\n\ 254 Mid(Base64, CLng("&o" & Mid(nGroup, 3, 2)) + 1, 1) + _\n\ 255 Mid(Base64, CLng("&o" & Mid(nGroup, 5, 2)) + 1, 1) + _\n\ 256 Mid(Base64, CLng("&o" & Mid(nGroup, 7, 2)) + 1, 1)\n\ 257 sOut = sOut + pOut\n\ 258 Next\n\ 259 Select Case LenB(inData) Mod 3\n\ 260 Case 1: \'8 bit final\n\ 261 sOut = Left(sOut, Len(sOut) - 2) + "=="\n\ 262 Case 2: \'16 bit final\n\ 263 sOut = Left(sOut, Len(sOut) - 1) + "="\n\ 264 End Select\n\ 265 Base64Encode = sOut\n\ 266 End Function\n\ 267 \n\ 268 Function MyASC(OneChar)\n\ 269 If OneChar = "" Then MyASC = 0 Else MyASC = AscB(OneChar)\n\ 270 End Function\n\ 271 \n\ 272 Function jxgBinFileReader(xhr)\n\ 273 Dim byteString\n\ 274 Dim b64String\n\ 275 Dim i\n\ 276 byteString = xhr.responseBody\n\ 277 ReDim byteArray(LenB(byteString))\n\ 278 For i = 1 To LenB(byteString)\n\ 279 byteArray(i-1) = AscB(MidB(byteString, i, 1))\n\ 280 Next\n\ 281 b64String = Base64Encode(byteString)\n\ 282 jxgBinFileReader = b64String\n\ 283 End Function\n\ 284 </script>\n' 285 ); 286 } 287 288 export default JXG.FileReader; 289