/** * Extracts entries from the archive. * * @param ctx query context * @return text entries * @throws QueryException query exception */ private TokenList extract(final QueryContext ctx) throws QueryException { final B64 archive = (B64) checkType(checkItem(expr[0], ctx), AtomType.B64); TokenSet hs = null; if (expr.length > 1) { // filter result to specified entries hs = new TokenSet(); final Iter names = ctx.iter(expr[1]); for (Item en; (en = names.next()) != null; ) { hs.add(checkElmStr(en).string(info)); } } final TokenList tl = new TokenList(); final ArchiveIn in = ArchiveIn.get(archive.input(info), info); try { while (in.more()) { final ZipEntry ze = in.entry(); if (ze.isDirectory()) continue; if (hs == null || hs.delete(token(ze.getName())) != 0) tl.add(in.read()); } } catch (final IOException ex) { Util.debug(ex); ARCH_FAIL.thrw(info, ex); } finally { in.close(); } return tl; }
/** * Runs the command without permission, data and concurrency checks. * * @param ctx database context * @param os output stream * @return result of check */ public boolean run(final Context ctx, final OutputStream os) { perf = new Performance(); context = ctx; prop = ctx.prop; mprop = ctx.mprop; out = PrintOutput.get(os); try { return run(); } catch (final ProgressException ex) { // process was interrupted by the user or server abort(); return error(INTERRUPTED); } catch (final Throwable ex) { // unexpected error Performance.gc(2); abort(); if (ex instanceof OutOfMemoryError) { Util.debug(ex); return error(OUT_OF_MEM + (createWrite() ? H_OUT_OF_MEM : "")); } return error(Util.bug(ex) + NL + info.toString()); } finally { // flushes the output try { if (out != null) out.flush(); } catch (final IOException ignored) { } } }
/** * Returns the options of an archive. * * @param ctx query context * @return entries * @throws QueryException query exception */ private FElem options(final QueryContext ctx) throws QueryException { final B64 archive = (B64) checkType(checkItem(expr[0], ctx), AtomType.B64); String format = null; int level = -1; final ArchiveIn arch = ArchiveIn.get(archive.input(info), info); try { format = arch.format(); while (arch.more()) { final ZipEntry ze = arch.entry(); if (ze.isDirectory()) continue; level = ze.getMethod(); break; } } catch (final IOException ex) { Util.debug(ex); ARCH_FAIL.thrw(info, ex); } finally { arch.close(); } // create result element final FElem e = new FElem(Q_OPTIONS, NS); if (format != null) e.add(new FElem(Q_FORMAT).add(Q_VALUE, format)); if (level >= 0) { final byte[] lvl = level == 8 ? DEFLATE : level == 0 ? STORED : UNKNOWN; e.add(new FElem(Q_ALGORITHM).add(Q_VALUE, lvl)); } return e; }
/** * Returns the entries of an archive. * * @param ctx query context * @return entries * @throws QueryException query exception */ private Iter entries(final QueryContext ctx) throws QueryException { final B64 archive = (B64) checkType(checkItem(expr[0], ctx), AtomType.B64); final ValueBuilder vb = new ValueBuilder(); final ArchiveIn in = ArchiveIn.get(archive.input(info), info); try { while (in.more()) { final ZipEntry ze = in.entry(); if (ze.isDirectory()) continue; final FElem e = new FElem(Q_ENTRY, NS); long s = ze.getSize(); if (s != -1) e.add(Q_SIZE, token(s)); s = ze.getTime(); if (s != -1) e.add(Q_LAST_MOD, new Dtm(s, info).string(info)); s = ze.getCompressedSize(); if (s != -1) e.add(Q_COMP_SIZE, token(s)); e.add(ze.getName()); vb.add(e); } return vb; } catch (final IOException ex) { Util.debug(ex); throw ARCH_FAIL.thrw(info, ex); } finally { in.close(); } }
/** * Draws the specified string. * * @param g graphics reference * @param s text * @param x x coordinate * @param y y coordinate * @param w width * @param fs font size */ public static void chopString( final Graphics g, final byte[] s, final int x, final int y, final int w, final int fs) { if (w < 12) return; final int[] cw = fontWidths(g.getFont()); int j = s.length; try { int l = 0; int fw = 0; for (int k = 0; k < j; k += l) { final int ww = width(g, cw, cp(s, k)); if (fw + ww >= w - 4) { j = Math.max(1, k - l); if (k > 1) fw -= width(g, cw, cp(s, k - 1)); g.drawString("..", x + fw, y + fs); break; } fw += ww; l = cl(s, k); } } catch (final Exception ex) { Util.debug(ex); } g.drawString(string(s, 0, j), x, y + fs); }
/** * Searches a string in a file. * * @param path file path * @param search codepoints of search string * @return success flag */ private static boolean filterContent(final String path, final int[] search) { final int cl = search.length; if (cl == 0) return true; try (final TextInput ti = new TextInput(new IOFile(path))) { final IntList il = new IntList(cl - 1); int c = 0; while (true) { if (!il.isEmpty()) { if (il.remove(0) == search[c++]) continue; c = 0; } while (true) { final int cp = ti.read(); if (cp == -1 || !XMLToken.valid(cp)) return false; final int lc = Token.lc(cp); if (c > 0) il.add(lc); if (lc == search[c]) { if (++c == cl) return true; } else { c = 0; break; } } } } catch (final IOException ex) { // file may not be accessible Util.debug(ex); return false; } }
/** * 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; }
/** * Returns the width of the specified text. Cached font widths are used to speed up calculation. * * @param g graphics reference * @param s string to be evaluated * @return string width */ public static int width(final Graphics g, final byte[] s) { final int[] cw = fontWidths(g.getFont()); final int l = s.length; int fw = 0; try { // ignore faulty character sets for (int k = 0; k < l; k += cl(s, k)) fw += width(g, cw, cp(s, k)); } catch (final Exception ex) { Util.debug(ex); } return fw; }
/** * Converts a token from the input encoding to UTF8. * * @param token token to be converted * @return byte array * @param encoding input encoding */ public static byte[] utf8(final byte[] token, final String encoding) { // UTF8 (comparison by ref.) or no special characters: return input if (encoding == UTF8 || ascii(token)) return token; // convert to utf8. if errors occur while converting, an empty is returned. try { return token(new String(token, encoding)); } catch (final Exception ex) { Util.debug(ex); return EMPTY; } }
/** * Returns the clipboard text. * * @return text */ private static String clip() { // copy selection to clipboard final Clipboard clip = Toolkit.getDefaultToolkit().getSystemClipboard(); final Transferable tr = clip.getContents(null); if (tr != null) { final ArrayList<Object> contents = BaseXLayout.contents(tr); if (!contents.isEmpty()) return contents.get(0).toString(); } else { Util.debug("Clipboard has no contents."); } return null; }
/** * Checks if the query possibly performs updates. * * @param ctx database context * @param query query string * @return result of check */ final boolean updates(final Context ctx, final String query) { try { final Performance p = new Performance(); qp(query, ctx); parse(p); return qp.updating; } catch (final QueryException ex) { Util.debug(ex); exception = ex; qp.close(); return false; } }
static { IOFile dic = null; if (Reflect.available(PATTERN)) { dic = new IOFile(LANG); if (!dic.exists()) { dic = new IOFile(Prop.HOME, "etc/" + LANG); if (!dic.exists()) { available = false; } } } else { available = false; } if (available) { Class<?> clz = Reflect.find(PATTERN); if (clz == null) { Util.debug("Could not initialize Igo Japanese lexer."); } else { /* Igo constructor. */ final Constructor<?> tgr = Reflect.find(clz, String.class); tagger = Reflect.get(tgr, dic.path()); if (tagger == null) { available = false; Util.debug("Could not initialize Igo Japanese lexer."); } else { parse = Reflect.method(clz, "parse", CharSequence.class); if (parse == null) { Util.debug("Could not initialize Igo lexer method."); } clz = Reflect.find("net.reduls.igo.Morpheme"); surface = Reflect.field(clz, "surface"); feature = Reflect.field(clz, "feature"); start = Reflect.field(clz, "start"); } } } }
/** * Creates a new archive. * * @param ctx query context * @return archive * @throws QueryException query exception */ private B64 create(final QueryContext ctx) throws QueryException { final Iter entr = ctx.iter(expr[0]); final Iter cont = ctx.iter(expr[1]); final Item opt = expr.length > 2 ? expr[2].item(ctx, info) : null; final TokenMap map = new FuncParams(Q_OPTIONS, info).parse(opt); final byte[] f = map.get(FORMAT); final String format = f != null ? string(lc(f)) : "zip"; final ArchiveOut out = ArchiveOut.get(format, info); // check algorithm final byte[] alg = map.get(ALGORITHM); int level = ZipEntry.DEFLATED; if (alg != null) { if (format.equals("zip") && !eq(alg, STORED, DEFLATE) || format.equals("gzip") && !eq(alg, DEFLATE)) { ARCH_SUPP.thrw(info, ALGORITHM, alg); } if (eq(alg, STORED)) level = ZipEntry.STORED; else if (eq(alg, DEFLATE)) level = ZipEntry.DEFLATED; } out.level(level); try { int e = 0; int c = 0; Item en, cn; while (true) { en = entr.next(); cn = cont.next(); if (en == null || cn == null) break; if (out instanceof GZIPOut && c > 0) ARCH_ONE.thrw(info, format.toUpperCase(Locale.ENGLISH)); add(checkElmStr(en), cn, out, level); e++; c++; } // count remaining entries if (cn != null) do c++; while (cont.next() != null); if (en != null) do e++; while (entr.next() != null); if (e != c) throw ARCH_DIFF.thrw(info, e, c); } catch (final IOException ex) { Util.debug(ex); throw ARCH_FAIL.thrw(info, ex); } finally { out.close(); } return new B64(out.toArray()); }
/** * Updates an archive. * * @param ctx query context * @return updated archive * @throws QueryException query exception */ private B64 update(final QueryContext ctx) throws QueryException { final B64 archive = (B64) checkType(checkItem(expr[0], ctx), AtomType.B64); // entries to be updated final TokenObjMap<Item[]> hm = new TokenObjMap<Item[]>(); final Iter entr = ctx.iter(expr[1]); final Iter cont = ctx.iter(expr[2]); int e = 0; int c = 0; Item en, cn; while (true) { en = entr.next(); cn = cont.next(); if (en == null || cn == null) break; hm.add(checkElmStr(en).string(info), new Item[] {en, cn}); e++; c++; } // count remaining entries if (cn != null) do c++; while (cont.next() != null); if (en != null) do e++; while (entr.next() != null); if (e != c) ARCH_DIFF.thrw(info, e, c); final ArchiveIn in = ArchiveIn.get(archive.input(info), info); final ArchiveOut out = ArchiveOut.get(in.format(), info); try { if (in instanceof GZIPIn) ARCH_MODIFY.thrw(info, in.format().toUpperCase(Locale.ENGLISH)); // delete entries to be updated while (in.more()) if (!hm.contains(token(in.entry().getName()))) out.write(in); // add new and updated entries for (final byte[] h : hm) { if (h == null) continue; final Item[] it = hm.get(h); add(it[0], it[1], out, ZipEntry.DEFLATED); } } catch (final IOException ex) { Util.debug(ex); ARCH_FAIL.thrw(info, ex); } finally { in.close(); out.close(); } return new B64(out.toArray()); }
/** * Refreshes the view after a file has been saved. * * @param root root directory * @param ctx database context * @throws InterruptedException interruption */ void parse(final IOFile root, final Context ctx) throws InterruptedException { final long id = ++parseId; final HashSet<String> parsed = new HashSet<>(); final TreeMap<String, InputInfo> errs = new TreeMap<>(); // collect files to be parsed final ProjectCache pc = cache(root); final StringList mods = new StringList(), lmods = new StringList(); for (final String path : pc) { final IOFile file = new IOFile(path); if (file.hasSuffix(IO.XQSUFFIXES)) (file.hasSuffix(IO.XQMSUFFIX) ? lmods : mods).add(path); } mods.add(lmods); // parse modules for (final String path : mods) { if (id != parseId) throw new InterruptedException(); if (parsed.contains(path)) continue; final IOFile file = new IOFile(path); try (final TextInput ti = new TextInput(file)) { // parse query try (final QueryContext qc = new QueryContext(ctx)) { final String input = ti.cache().toString(); final boolean lib = QueryProcessor.isLibrary(input); qc.parse(input, lib, path, null); // parsing was successful: remember path parsed.add(path); for (final byte[] mod : qc.modParsed) parsed.add(Token.string(mod)); } catch (final QueryException ex) { // parsing failed: remember path final InputInfo ii = ex.info(); errs.put(path, ii); parsed.add(ii.path()); } } catch (final IOException ex) { // file may not be accessible Util.debug(ex); } } errors = errs; }
/** * Deletes files from an archive. * * @param ctx query context * @return updated archive * @throws QueryException query exception */ private B64 delete(final QueryContext ctx) throws QueryException { final B64 archive = (B64) checkType(checkItem(expr[0], ctx), AtomType.B64); // entries to be deleted final TokenObjMap<Item[]> hm = new TokenObjMap<Item[]>(); final Iter names = ctx.iter(expr[1]); for (Item en; (en = names.next()) != null; ) { hm.add(checkElmStr(en).string(info), null); } final ArchiveIn in = ArchiveIn.get(archive.input(info), info); final ArchiveOut out = ArchiveOut.get(in.format(), info); try { if (in instanceof GZIPIn) ARCH_MODIFY.thrw(info, in.format().toUpperCase(Locale.ENGLISH)); while (in.more()) if (!hm.contains(token(in.entry().getName()))) out.write(in); } catch (final IOException ex) { Util.debug(ex); ARCH_FAIL.thrw(info, ex); } finally { in.close(); out.close(); } return new B64(out.toArray()); }
/** * Initializes the database context, based on the initial servlet context. Parses all context * parameters and passes them on to the database context. * * @param sc servlet context * @throws IOException I/O exception */ public static synchronized void init(final ServletContext sc) throws IOException { // check if HTTP context has already been initialized if (init) return; init = true; // set web application path as home directory and HTTPPATH final String webapp = sc.getRealPath("/"); Options.setSystem(Prop.PATH, webapp); Options.setSystem(GlobalOptions.WEBPATH, webapp); // bind all parameters that start with "org.basex." to system properties final Enumeration<String> en = sc.getInitParameterNames(); while (en.hasMoreElements()) { final String key = en.nextElement(); if (!key.startsWith(Prop.DBPREFIX)) continue; String val = sc.getInitParameter(key); if (key.endsWith("path") && !new File(val).isAbsolute()) { // prefix relative path with absolute servlet path Util.debug(key.toUpperCase(Locale.ENGLISH) + ": " + val); val = new IOFile(webapp, val).path(); } Options.setSystem(key, val); } // create context, update options if (context == null) { context = new Context(false); } else { context.globalopts.setSystem(); context.options.setSystem(); } // start server instance if (!context.globalopts.get(GlobalOptions.HTTPLOCAL)) new BaseXServer(context); }
/** * Evaluates the specified query. * * @param query query * @return success flag */ final boolean query(final String query) { final Performance p = new Performance(); String error; if (exception != null) { error = Util.message(exception); } else { try { long hits = 0; final boolean run = options.get(MainOptions.RUNQUERY); final boolean serial = options.get(MainOptions.SERIALIZE); final int runs = Math.max(1, options.get(MainOptions.RUNS)); for (int r = 0; r < runs; ++r) { // reuse existing processor instance if (r != 0) qp = null; qp(query, context); parse(p); if (r == 0) plan(false); qp.compile(); info.compiling += p.time(); if (r == 0) plan(true); if (!run) continue; final PrintOutput po = r == 0 && serial ? out : new NullOutput(); try (final Serializer ser = qp.getSerializer(po)) { if (maxResults >= 0) { result = qp.cache(maxResults); info.evaluating += p.time(); result.serialize(ser); hits = result.size(); } else { hits = 0; final Iter ir = qp.iter(); info.evaluating += p.time(); for (Item it; (it = ir.next()) != null; ) { ser.serialize(it); ++hits; checkStop(); } } } qp.close(); info.serializing += p.time(); } // dump some query info // out.flush(); // remove string list if global locking is used and if query is updating if (soptions.get(StaticOptions.GLOBALLOCK) && qp.updating) { info.readLocked = null; info.writeLocked = null; } return info(info.toString(qp, out.size(), hits, options.get(MainOptions.QUERYINFO))); } catch (final QueryException | IOException ex) { exception = ex; error = Util.message(ex); } catch (final ProcException ex) { error = INTERRUPTED; } catch (final StackOverflowError ex) { Util.debug(ex); error = BASX_STACKOVERFLOW.desc; } catch (final RuntimeException ex) { extError(""); Util.debug(info()); throw ex; } finally { // close processor after exceptions if (qp != null) qp.close(); } } return extError(error); }
/** Writes the properties to disk. */ public final synchronized void write() { final StringBuilder user = new StringBuilder(); BufferedReader br = null; try { // caches options specified by the user if (file.exists()) { br = new BufferedReader(new FileReader(file.file())); for (String line; (line = br.readLine()) != null; ) { if (line.equals(PROPUSER)) break; } for (String line; (line = br.readLine()) != null; ) { user.append(line).append(NL); } } } catch (final Exception ex) { Util.debug(ex); } finally { if (br != null) try { br.close(); } catch (final IOException e) { } } BufferedWriter bw = null; try { bw = new BufferedWriter(new FileWriter(file.file())); bw.write(PROPHEADER + NL); for (final Field f : getClass().getFields()) { final Object obj = f.get(null); if (!(obj instanceof Object[])) continue; final String key = ((Object[]) obj)[0].toString(); final Object val = props.get(key); if (val instanceof String[]) { final String[] str = (String[]) val; bw.write(key + " = " + str.length + NL); final int is = str.length; for (int i = 0; i < is; ++i) { if (str[i] != null) bw.write(key + (i + 1) + " = " + str[i] + NL); } } else if (val instanceof int[]) { final int[] num = (int[]) val; final int ns = num.length; for (int i = 0; i < ns; ++i) { bw.write(key + i + " = " + num[i] + NL); } } else { bw.write(key + " = " + val + NL); } } bw.write(NL + PROPUSER + NL); bw.write(user.toString()); } catch (final Exception ex) { Util.errln("% could not be written.", file); Util.debug(ex); } finally { if (bw != null) try { bw.close(); } catch (final IOException e) { } } }
/** * Reads the configuration file and initializes the project properties. The file is located in the * project home directory. * * @param prop property file extension */ protected synchronized void read(final String prop) { file = new IOFile(HOME + IO.BASEXSUFFIX + prop); final StringList read = new StringList(); final TokenBuilder err = new TokenBuilder(); if (!file.exists()) { err.addExt("Saving properties in \"%\"..." + NL, file); } else { BufferedReader br = null; try { br = new BufferedReader(new FileReader(file.file())); for (String line; (line = br.readLine()) != null; ) { line = line.trim(); if (line.isEmpty() || line.charAt(0) == '#') continue; final int d = line.indexOf('='); if (d < 0) { err.addExt("%: \"%\" ignored. " + NL, file, line); continue; } final String val = line.substring(d + 1).trim(); String key = line.substring(0, d).trim(); // extract numeric value in key int num = 0; final int ss = key.length(); for (int s = 0; s < ss; ++s) { if (Character.isDigit(key.charAt(s))) { num = Integer.parseInt(key.substring(s)); key = key.substring(0, s); break; } } read.add(key); final Object entry = props.get(key); if (entry == null) { err.addExt("%: \"%\" not found. " + NL, file, key); } else if (entry instanceof String) { props.put(key, val); } else if (entry instanceof Integer) { props.put(key, Integer.parseInt(val)); } else if (entry instanceof Boolean) { props.put(key, Boolean.parseBoolean(val)); } else if (entry instanceof String[]) { if (num == 0) { props.put(key, new String[Integer.parseInt(val)]); } else { ((String[]) entry)[num - 1] = val; } } else if (entry instanceof int[]) { ((int[]) entry)[num] = Integer.parseInt(val); } } } catch (final Exception ex) { err.addExt("% could not be parsed." + NL, file); Util.debug(ex); } finally { if (br != null) try { br.close(); } catch (final IOException ex) { } } } // check if all mandatory files have been read try { if (err.isEmpty()) { boolean ok = true; for (final Field f : getClass().getFields()) { final Object obj = f.get(null); if (!(obj instanceof Object[])) continue; final String key = ((Object[]) obj)[0].toString(); ok &= read.contains(key); } if (!ok) err.addExt("Saving properties in \"%\"..." + NL, file); } } catch (final IllegalAccessException ex) { Util.notexpected(ex); } if (!err.isEmpty()) { Util.err(err.toString()); write(); } }