@Override public void execute(final GUI gui) { final DialogExport dialog = new DialogExport(gui); if (!dialog.ok()) return; final IOFile root = new IOFile(dialog.path()); // check if existing files will be overwritten if (root.exists()) { IO file = null; boolean overwrite = false; final Data d = gui.context.data(); final IntList il = d.resources.docs(); final int is = il.size(); for (int i = 0; i < is; i++) { file = root.merge(Token.string(d.text(il.get(i), true))); if (file.exists()) { if (overwrite) { // more than one file will be overwritten; check remaining tests file = null; break; } overwrite = true; } } if (overwrite) { // show message for overwriting files or directories final String msg = file == null ? FILES_REPLACE_X : FILE_EXISTS_X; if (file == null) file = root; if (!BaseXDialog.confirm(gui, Util.info(msg, file))) return; } } DialogProgress.execute(gui, new Export(root.path())); }
/** Saves the displayed text. */ private void save() { final BaseXFileChooser fc = new BaseXFileChooser(SAVE_AS, gui.gopts.get(GUIOptions.WORKPATH), gui).suffix(IO.XMLSUFFIX); final IO file = fc.select(Mode.FSAVE); if (file == null) return; gui.gopts.set(GUIOptions.WORKPATH, file.path()); gui.cursor(CURSORWAIT, true); final MainOptions opts = gui.context.options; final int mh = opts.get(MainOptions.MAXHITS); opts.set(MainOptions.MAXHITS, -1); opts.set(MainOptions.CACHEQUERY, false); try (final PrintOutput out = new PrintOutput(file.toString())) { if (cmd != null) { cmd.execute(gui.context, out); } else if (ns != null) { ns.serialize(Serializer.get(out)); } else { final byte[] txt = text.getText(); for (final byte t : txt) if (t < 0 || t > ' ' || ws(t)) out.write(t); } } catch (final IOException ex) { BaseXDialog.error(gui, Util.info(FILE_NOT_SAVED_X, file)); } finally { opts.set(MainOptions.MAXHITS, mh); opts.set(MainOptions.CACHEQUERY, true); gui.cursor(CURSORARROW, true); } }
/** * Scans an external ID. * * @param f full flag * @param r root flag * @return id * @throws IOException I/O exception */ private byte[] externalID(final boolean f, final boolean r) throws IOException { byte[] cont = null; final boolean pub = consume(PUBLIC); if (pub || consume(SYSTEM)) { checkS(); if (pub) { pubidLit(); if (f) checkS(); } final int qu = consume(); // [11] if (qu == '\'' || qu == '"') { int ch; final TokenBuilder tok = new TokenBuilder(); while ((ch = nextChar()) != qu) tok.add(ch); if (!f) return null; final String name = string(tok.finish()); if (!dtd && r) return cont; final XMLInput tin = input; try { final IO file = input.io().merge(name); cont = file.read(); } catch (final IOException ex) { Util.debug(ex); // skip unknown DTDs/entities cont = new byte[] {'?'}; } input = new XMLInput(new IOContent(cont, name)); if (consume(XDECL)) { check(XML); s(); if (version()) checkS(); s(); if (encoding() == null) error(TEXTENC); ch = nextChar(); if (s(ch)) ch = nextChar(); if (ch != '?') error(WRONGCHAR, '?', ch); ch = nextChar(); if (ch != '>') error(WRONGCHAR, '>', ch); cont = Arrays.copyOfRange(cont, input.pos(), cont.length); } s(); if (r) { extSubsetDecl(); if (!consume((char) 0)) error(INVEND); } input = tin; } else { if (f) error(SCANQUOTE, (char) qu); prev(1); } } return cont; }
/** * Sets a syntax highlighter, based on the file format. * * @param file file reference * @param opened indicates if file was opened from disk */ protected final void setSyntax(final IO file, final boolean opened) { setSyntax( !opened || file.hasSuffix(IO.XQSUFFIXES) ? new XQuerySyntax() : file.hasSuffix(IO.JSONSUFFIX) ? new JSONSyntax() : file.hasSuffix(IO.XMLSUFFIXES) || file.hasSuffix(IO.HTMLSUFFIXES) ? new XMLSyntax() : BaseXSyntax.SIMPLE); }
/** * Parses a module. * * @param io input reference * @return query parser * @throws QueryException query exception */ final QueryParser parseQuery(final IO io) throws QueryException { try (final QueryContext qctx = new QueryContext(qc)) { final String input = string(io.read()); // parse query final QueryParser qp = new QueryParser(input, io.path(), qctx, null); module = QueryProcessor.isLibrary(input) ? qp.parseLibrary(true) : qp.parseMain(); return qp; } catch (final IOException | QueryException ex) { throw IOERR_X.get(info, ex); } }
/** * Stores the specified source to the specified file. * * @param in input source * @param file target file * @throws IOException I/O exception */ public static void store(final InputSource in, final IOFile file) throws IOException { // add directory if it does not exist anyway file.dir().md(); final PrintOutput po = new PrintOutput(file.path()); try { final Reader r = in.getCharacterStream(); final InputStream is = in.getByteStream(); final String id = in.getSystemId(); if (r != null) { for (int c; (c = r.read()) != -1; ) po.utf8(c); } else if (is != null) { for (int b; (b = is.read()) != -1; ) po.write(b); } else if (id != null) { final BufferInput bi = new BufferInput(IO.get(id)); try { for (int b; (b = bi.read()) != -1; ) po.write(b); } finally { bi.close(); } } } finally { po.close(); } }
/** * Constructor. * * @param ex exception * @param level type * @param schema schema url */ ErrorInfo(final SAXException ex, final String level, final IO schema) { this.level = level; String m = ex.getMessage(); Throwable e = ex; if (m.contains("Exception:")) { // may be recursively called if external validator (e.g. Saxon) is used e = Util.rootException(e); if (e instanceof SAXException) m = e.getLocalizedMessage(); } if (ex instanceof SAXParseException) { final SAXParseException se = (SAXParseException) ex; final String id = se.getSystemId(); if (id != null) { final IO io = IO.get(id); if (schema == null || !io.isDir() && !schema.equals(io)) url = id; } line = se.getLineNumber(); column = se.getColumnNumber(); } message = m; }
@Override protected boolean run() { final boolean create = context.user.has(Perm.CREATE); String path = MetaData.normPath(args[0]); if (path == null || path.endsWith(".")) return error(NAME_INVALID_X, args[0]); if (in == null) { final IO io = IO.get(args[1]); if (!io.exists() || io.isDir()) return error(RES_NOT_FOUND_X, create ? io : args[1]); in = io.inputSource(); // set/add name of document if ((path.isEmpty() || path.endsWith("/")) && !(io instanceof IOContent)) path += io.name(); } // ensure that the final name is not empty if (path.isEmpty()) return error(NAME_INVALID_X, path); // ensure that the name is not empty and contains no trailing dots final Data data = context.data(); if (data.inMemory()) return error(NO_MAINMEM); final IOFile file = data.meta.binary(path); if (path.isEmpty() || path.endsWith(".") || file == null || file.isDir()) return error(NAME_INVALID_X, create ? path : args[0]); // start update if (!data.startUpdate()) return error(DB_PINNED_X, data.meta.name); try { store(in, file); return info(QUERY_EXECUTED_X_X, "", perf); } catch (final IOException ex) { return error(FILE_NOT_STORED_X, Util.message(ex)); } finally { data.finishUpdate(); } }
/** * Sets a syntax highlighter, based on the file format. * * @param file file reference * @param opened indicates if file was opened from disk */ protected final void setSyntax(final IO file, final boolean opened) { setSyntax( !opened || file.hasSuffix(IO.XQSUFFIXES) ? new SyntaxXQuery() : file.hasSuffix(IO.JSONSUFFIX) ? new SyntaxJSON() : file.hasSuffix(IO.JSSUFFIX) ? new SyntaxJS() : file.hasSuffix(IO.XMLSUFFIXES) || file.hasSuffix(IO.HTMLSUFFIXES) || file.hasSuffix(IO.XSLSUFFIXES) || file.hasSuffix(IO.BXSSUFFIX) ? new SyntaxXML() : Syntax.SIMPLE); }
/** * Refreshes the list of recent query files and updates the query path. * * @param file new file */ void refreshHistory(final IOFile file) { final StringList sl = new StringList(); String path = null; if (file != null) { path = file.path(); gui.gprop.set(GUIProp.WORKPATH, file.dirPath()); sl.add(path); tabs.setToolTipTextAt(tabs.getSelectedIndex(), path); } final String[] qu = gui.gprop.strings(GUIProp.EDITOR); for (int q = 0; q < qu.length && q < 19; q++) { final String f = qu[q]; if (!f.equalsIgnoreCase(path) && IO.get(f).exists()) sl.add(f); } // store sorted history gui.gprop.set(GUIProp.EDITOR, sl.toArray()); hist.setEnabled(!sl.isEmpty()); }
/** * Handles info messages resulting from a query execution. * * @param msg info message * @return true if error was found */ private boolean error(final String msg) { final String line = msg.replaceAll("[\\r\\n].*", ""); Matcher m = XQERROR.matcher(line); int el, ec = 2; if (!m.matches()) { m = XMLERROR.matcher(line); if (!m.matches()) return true; el = Integer.parseInt(m.group(1)); errFile = getEditor().file.path(); } else { el = Integer.parseInt(m.group(1)); ec = Integer.parseInt(m.group(2)); errFile = m.group(3); } final EditorArea edit = find(IO.get(errFile), false); if (edit == null) return true; // find approximate error position final int ll = edit.last.length; int ep = ll; for (int e = 1, l = 1, c = 1; e < ll; ++c, e += cl(edit.last, e)) { if (l > el || l == el && c == ec) { ep = e; break; } if (edit.last[e] == '\n') { ++l; c = 0; } } if (ep < ll && Character.isLetterOrDigit(cp(edit.last, ep))) { while (ep > 0 && Character.isLetterOrDigit(cp(edit.last, ep - 1))) ep--; } edit.error(ep); errPos = ep; return true; }
/** * Converts an HTML document to XML. * * @param io io reference * @param opts html options * @return parser * @throws IOException I/O exception */ private static IO toXML(final IO io, final HtmlOptions opts) throws IOException { // reader could not be initialized; fall back to XML if (READER == null) return io; try { // tries to extract the encoding from the input final TextInput ti = new TextInput(io); String enc = ti.encoding(); final byte[] content = ti.content(); // looks for a charset definition final byte[] encoding = token("charset="); int cs = indexOf(content, encoding); if (cs > 0) { // extracts the encoding string cs += encoding.length; int ce = cs; final int cl = content.length; while (++ce < cl && content[ce] > 0x28) ; enc = string(substring(content, cs, ce)); } // define input final InputSource is = new InputSource(new ArrayInput(content)); is.setEncoding(supported(enc) ? normEncoding(enc) : UTF8); // define output final StringWriter sw = new StringWriter(); final XMLReader reader = (XMLReader) Reflect.get(READER); final Object writer = Reflect.get(WRITER, sw); // set TagSoup options if (opts.get(HtmlOptions.HTML)) { reader.setFeature("http://xml.org/sax/features/namespaces", false); opt("method", "html"); opt("omit-xml-declaration", "yes"); } if (opts.get(HtmlOptions.NONS)) reader.setFeature("http://xml.org/sax/features/namespaces", false); if (opts.get(HtmlOptions.OMITXML)) opt("omit-xml-declaration", "yes"); if (opts.get(HtmlOptions.NOBOGONS)) reader.setFeature(FEATURES + "ignore-bogons", true); if (opts.get(HtmlOptions.NODEFAULTS)) reader.setFeature(FEATURES + "default-attributes", false); if (opts.get(HtmlOptions.NOCOLONS)) reader.setFeature(FEATURES + "translate-colons", true); if (opts.get(HtmlOptions.NORESTART)) reader.setFeature(FEATURES + "restart-elements", false); if (opts.get(HtmlOptions.IGNORABLE)) reader.setFeature(FEATURES + "ignorable-whitespace", true); if (opts.get(HtmlOptions.EMPTYBOGONS)) reader.setFeature(FEATURES + "bogons-empty", true); if (opts.get(HtmlOptions.ANY)) reader.setFeature(FEATURES + "bogons-empty", false); if (opts.get(HtmlOptions.NOROOTBOGONS)) reader.setFeature(FEATURES + "root-bogons", false); if (opts.get(HtmlOptions.NOCDATA)) reader.setFeature(FEATURES + "cdata-elements", false); if (opts.get(HtmlOptions.LEXICAL)) reader.setProperty("http://xml.org/sax/properties/lexical-handler", writer); if (opts.contains(HtmlOptions.METHOD)) opt("method", opts.get(HtmlOptions.METHOD)); if (opts.contains(HtmlOptions.DOCTYPESYS)) opt("doctype-system", opts.get(HtmlOptions.DOCTYPESYS)); if (opts.contains(HtmlOptions.DOCTYPEPUB)) opt("doctype-public", opts.get(HtmlOptions.DOCTYPEPUB)); if (opts.contains(HtmlOptions.ENCODING)) is.setEncoding(opts.get(HtmlOptions.ENCODING)); // end TagSoup options reader.setContentHandler((ContentHandler) writer); reader.parse(is); return new IOContent(token(sw.toString()), io.name()); } catch (final SAXException ex) { Util.errln(ex); return io; } }
/** * Compares two thesaurus instances. * * @param th instance to be compared * @return result of check */ boolean sameAs(final Thesaurus th) { return file.eq(th.file) && min == th.min && max == th.max && eq(rel, th.rel); }
/** * Constructor. * * @param args command-line arguments * @throws IOException I/O exception */ public BaseX(final String... args) throws IOException { super(args); // create session to show optional login request session(); console = true; try { // loop through all commands final StringBuilder bind = new StringBuilder(); SerializerOptions sopts = null; boolean v = false, qi = false, qp = false; final int os = ops.size(); for (int o = 0; o < os; o++) { final int c = ops.get(o); String val = vals.get(o); if (c == 'b') { // set/add variable binding if (bind.length() != 0) bind.append(','); // commas are escaped by a second comma val = bind.append(val.replaceAll(",", ",,")).toString(); execute(new Set(MainOptions.BINDINGS, val), false); } else if (c == 'c') { // evaluate commands final IO io = IO.get(val); String base = "."; if (io.exists() && !io.isDir()) { val = io.string(); base = io.path(); } execute(new Set(MainOptions.QUERYPATH, base), false); execute(val); execute(new Set(MainOptions.QUERYPATH, ""), false); console = false; } else if (c == 'D') { // hidden option: show/hide dot query graph execute(new Set(MainOptions.DOTPLAN, null), false); } else if (c == 'i') { // open database or create main memory representation execute(new Set(MainOptions.MAINMEM, true), false); execute(new Check(val), verbose); execute(new Set(MainOptions.MAINMEM, false), false); } else if (c == 'I') { // set/add variable binding if (bind.length() != 0) bind.append(','); // commas are escaped by a second comma val = bind.append("=").append(val.replaceAll(",", ",,")).toString(); execute(new Set(MainOptions.BINDINGS, val), false); } else if (c == 'o') { // change output stream if (out != System.out) out.close(); out = new PrintOutput(val); session().setOutputStream(out); } else if (c == 'q') { // evaluate query execute(new XQuery(val), verbose); console = false; } else if (c == 'Q') { // evaluate file contents or string as query final IO io = IO.get(val); String base = "."; if (io.exists() && !io.isDir()) { val = io.string(); base = io.path(); } execute(new Set(MainOptions.QUERYPATH, base), false); execute(new XQuery(val), verbose); execute(new Set(MainOptions.QUERYPATH, ""), false); console = false; } else if (c == 'r') { // parse number of runs execute(new Set(MainOptions.RUNS, Strings.toInt(val)), false); } else if (c == 'R') { // toggle query evaluation execute(new Set(MainOptions.RUNQUERY, null), false); } else if (c == 's') { // set/add serialization parameter if (sopts == null) sopts = new SerializerOptions(); final String[] kv = val.split("=", 2); sopts.assign(kv[0], kv.length > 1 ? kv[1] : ""); execute(new Set(MainOptions.SERIALIZER, sopts), false); } else if (c == 't') { // evaluate query execute(new Test(val), verbose); console = false; } else if (c == 'u') { // (de)activate write-back for updates execute(new Set(MainOptions.WRITEBACK, null), false); } else if (c == 'v') { // show/hide verbose mode v ^= true; } else if (c == 'V') { // show/hide query info qi ^= true; execute(new Set(MainOptions.QUERYINFO, null), false); } else if (c == 'w') { // toggle chopping of whitespaces execute(new Set(MainOptions.CHOP, null), false); } else if (c == 'x') { // show/hide xml query plan execute(new Set(MainOptions.XMLPLAN, null), false); qp ^= true; } else if (c == 'X') { // show query plan before/after query compilation execute(new Set(MainOptions.COMPPLAN, null), false); } else if (c == 'z') { // toggle result serialization execute(new Set(MainOptions.SERIALIZE, null), false); } verbose = qi || qp || v; } if (console) console(); } finally { quit(); } }