/** * Constructor. * @param picture variable marker (info picture) * @param def default presentation modifier * @param info input info * @throws QueryException query exception */ DateFormat(final byte[] picture, final byte[] def, final InputInfo info) throws QueryException { super(info); // split variable marker final int comma = lastIndexOf(picture, ','); byte[] pres = comma == -1 ? picture : substring(picture, 0, comma); // extract second presentation modifier final int pl = pres.length; if(pl > 1) { final int p = pres[pl - 1]; if(p == 'a' || p == 'c' || p == 'o' || p == 't') { pres = substring(pres, 0, pl - 1); if(p == 'o') ordinal = EMPTY; if(p == 't') trad = true; } } // choose first character and case finish(pres.length == 0 ? def : presentation(pres, def, true)); // check width modifier final byte[] width = comma == -1 ? null : substring(picture, comma + 1); if(width != null) { final Matcher m = WIDTH.matcher(string(width)); if(!m.find()) throw PICDATE_X.get(info, width); int i = Strings.toInt(m.group(1)); if(i != Integer.MIN_VALUE) min = i; final String mc = m.group(3); i = mc != null ? Strings.toInt(mc) : Integer.MIN_VALUE; if(i != Integer.MIN_VALUE) max = i; } }
/** * Constructor. * * @param value value * @param type item type * @param ii input info * @throws QueryException query exception */ private Dur(final byte[] value, final Type type, final InputInfo ii) throws QueryException { this(type); final String val = Token.string(value).trim(); final Matcher mt = DUR.matcher(val); if (!mt.matches() || val.endsWith("P") || val.endsWith("T")) throw dateError(value, XDURR, ii); yearMonth(value, mt, ii); dayTime(value, mt, 6, ii); }
/** * Initializes the yearMonth component. * * @param vl value * @param mt matcher * @param ii input info * @throws QueryException query exception */ void yearMonth(final byte[] vl, final Matcher mt, final InputInfo ii) throws QueryException { final long y = mt.group(2) != null ? toLong(mt.group(3), true, ii) : 0; final long m = mt.group(4) != null ? toLong(mt.group(5), true, ii) : 0; mon = y * 12 + m; double v = y * 12d + m; if (!mt.group(1).isEmpty()) { mon = -mon; v = -v; } if (v <= Long.MIN_VALUE || v >= Long.MAX_VALUE) throw DURRANGE_X_X.get(ii, type, vl); }
/** * Initializes the date format. * * @param d input * @param e example format * @param ii input info * @throws QueryException query exception */ final void date(final byte[] d, final String e, final InputInfo ii) throws QueryException { final Matcher mt = DATE.matcher(Token.string(d).trim()); if (!mt.matches()) throw dateError(d, e, ii); yea = toLong(mt.group(1), false, ii); // +1 is added to BC values to simplify computations if (yea < 0) yea++; mon = (byte) (Strings.toInt(mt.group(3)) - 1); day = (byte) (Strings.toInt(mt.group(4)) - 1); if (mon < 0 || mon >= 12 || day < 0 || day >= dpm(yea, mon)) throw dateError(d, e, ii); if (yea <= MIN_YEAR || yea > MAX_YEAR) throw DATERANGE_X_X.get(ii, type, chop(d, ii)); zone(mt, 5, d, ii); }
/** * Initializes the timezone. * * @param matcher matcher * @param pos first matching position * @param value value * @param ii input info * @throws QueryException query exception */ final void zone(final Matcher matcher, final int pos, final byte[] value, final InputInfo ii) throws QueryException { final String z = matcher.group(pos); if (z == null) return; if ("Z".equals(z)) { tz = 0; } else { final int th = Strings.toInt(matcher.group(pos + 2)); final int tm = Strings.toInt(matcher.group(pos + 3)); if (th > 14 || tm > 59 || th == 14 && tm != 0) throw INVALIDZONE_X.get(ii, value); final int mn = th * 60 + tm; tz = (short) ("-".equals(matcher.group(pos + 1)) ? -mn : mn); } }
/** * Initializes the time format. * * @param d input format * @param e expected format * @param ii input info * @throws QueryException query exception */ final void time(final byte[] d, final String e, final InputInfo ii) throws QueryException { final Matcher mt = TIME.matcher(Token.string(d).trim()); if (!mt.matches()) throw dateError(d, e, ii); hou = (byte) Strings.toInt(mt.group(1)); min = (byte) Strings.toInt(mt.group(2)); sec = toDecimal(mt.group(3), false, ii); if (min >= 60 || sec.compareTo(BD60) >= 0 || hou > 24 || hou == 24 && (min > 0 || sec.compareTo(BigDecimal.ZERO) > 0)) throw dateError(d, e, ii); zone(mt, 5, d, ii); if (hou == 24) { hou = 0; add(DAYSECONDS); } }
/** * Evaluates the analyze-string function. * * @param val input value * @param ctx query context * @return function result * @throws QueryException query exception */ private Item analyzeString(final byte[] val, final QueryContext ctx) throws QueryException { final Pattern p = pattern(expr[1], expr.length == 3 ? expr[2] : null, ctx); if (p.matcher("").matches()) REGROUP.thrw(info); final String str = string(val); final Matcher m = p.matcher(str); final FElem root = new FElem(Q_ANALYZE, new Atts(FN, FNURI)); int s = 0; while (m.find()) { if (s != m.start()) nonmatch(str.substring(s, m.start()), root); match(m, str, root, 0); s = m.end(); } if (s != str.length()) nonmatch(str.substring(s), root); return root; }
/** * Checks the specified template and adds a variable. * * @param tmp template string * @param type allowed type * @param declared variable declaration flags * @return resulting variable * @throws QueryException query exception */ private QNm checkVariable(final String tmp, final Type type, final boolean[] declared) throws QueryException { final Var[] args = function.args; final Matcher m = TEMPLATE.matcher(tmp); if (!m.find()) error(INV_TEMPLATE, tmp); final byte[] vn = token(m.group(1)); if (!XMLToken.isQName(vn)) error(INV_VARNAME, vn); final QNm qnm = new QNm(vn, context); int r = -1; while (++r < args.length && !args[r].name.eq(qnm)) ; if (r == args.length) error(UNKNOWN_VAR, vn); if (declared[r]) error(VAR_ASSIGNED, vn); final SeqType st = args[r].declaredType(); if (args[r].checksType() && !st.type.instanceOf(type)) error(INV_VARTYPE, vn, type); declared[r] = true; return qnm; }
/** * Evaluates the tokenize function. * * @param ctx query context * @return function result * @throws QueryException query exception */ private Value tokenize(final QueryContext ctx) throws QueryException { final byte[] val = checkEStr(expr[0], ctx); final Pattern p = pattern(expr[1], expr.length == 3 ? expr[2] : null, ctx); if (p.matcher("").matches()) REGROUP.thrw(info); final TokenList tl = new TokenList(); final String str = string(val); if (!str.isEmpty()) { final Matcher m = p.matcher(str); int s = 0; while (m.find()) { tl.add(str.substring(s, m.start())); s = m.end(); } tl.add(str.substring(s, str.length())); } return StrSeq.get(tl); }
/** * Processes a match. * * @param m matcher * @param str string * @param par parent * @param g group number * @return next group number and position in string */ private static int[] match(final Matcher m, final String str, final FElem par, final int g) { final FElem nd = new FElem(g == 0 ? Q_MATCH : Q_MGROUP, new Atts(FN, FNURI)); if (g > 0) nd.add(Q_NR, token(g)); final int start = m.start(g), end = m.end(g), gc = m.groupCount(); int[] pos = {g + 1, start}; // group and position in string while (pos[0] <= gc && m.end(pos[0]) <= end) { final int st = m.start(pos[0]); if (st >= 0) { // group matched if (pos[1] < st) nd.add(str.substring(pos[1], st)); pos = match(m, str, nd, pos[0]); } else pos[0]++; // skip it } if (pos[1] < end) { nd.add(str.substring(pos[1], end)); pos[1] = end; } par.add(nd); return pos; }
/** * Initializes the dayTime component. * * @param vl value * @param mt matcher * @param p first matching position * @param ii input info * @throws QueryException query exception */ void dayTime(final byte[] vl, final Matcher mt, final int p, final InputInfo ii) throws QueryException { final long d = mt.group(p) != null ? toLong(mt.group(p + 1), true, ii) : 0; final long h = mt.group(p + 3) != null ? toLong(mt.group(p + 4), true, ii) : 0; final long m = mt.group(p + 5) != null ? toLong(mt.group(p + 6), true, ii) : 0; final BigDecimal s = mt.group(p + 7) != null ? toDecimal(mt.group(p + 8), true, ii) : BigDecimal.ZERO; sec = s.add(BigDecimal.valueOf(d).multiply(DAYSECONDS)) .add(BigDecimal.valueOf(h).multiply(BD3600)) .add(BigDecimal.valueOf(m).multiply(BD60)); if (!mt.group(1).isEmpty()) sec = sec.negate(); final double v = sec.doubleValue(); if (v <= Long.MIN_VALUE || v >= Long.MAX_VALUE) throw DURRANGE_X_X.get(ii, type, vl); }
/** * 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; }
/** * Binds the annotated variables. * * @param http http context * @param arg argument array * @throws QueryException query exception * @throws IOException I/O exception */ void bind(final HTTPContext http, final Expr[] arg) throws QueryException, IOException { // bind variables from segments for (int s = 0; s < path.size; s++) { final Matcher m = TEMPLATE.matcher(path.segment[s]); if (!m.find()) continue; final QNm qnm = new QNm(token(m.group(1)), context); bind(qnm, arg, new Atm(http.segment(s))); } // cache request body final String ct = http.contentType(); IOContent body = null; if (requestBody != null) { body = cache(http, null); try { // bind request body in the correct format body.name(http.method + IO.XMLSUFFIX); bind(requestBody, arg, Parser.item(body, context.context.prop, ct)); } catch (final IOException ex) { error(INPUT_CONV, ex); } } // bind query parameters final Map<String, String[]> params = http.params(); for (final RestXqParam rxp : queryParams) bind(rxp, arg, params.get(rxp.key)); // bind form parameters if (!formParams.isEmpty()) { if (MimeTypes.APP_FORM.equals(ct)) { // convert parameters encoded in a form body = cache(http, body); addParams(body.toString(), params); } for (final RestXqParam rxp : formParams) bind(rxp, arg, params.get(rxp.key)); } // bind header parameters for (final RestXqParam rxp : headerParams) { final StringList sl = new StringList(); final Enumeration<?> en = http.req.getHeaders(rxp.key); while (en.hasMoreElements()) { for (final String s : en.nextElement().toString().split(", *")) sl.add(s); } bind(rxp, arg, sl.toArray()); } // bind cookie parameters final Cookie[] ck = http.req.getCookies(); for (final RestXqParam rxp : cookieParams) { String v = null; if (ck != null) { for (final Cookie c : ck) { if (rxp.key.equals(c.getName())) v = c.getValue(); } } if (v == null) bind(rxp, arg); else bind(rxp, arg, v); } }