/** * 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()); }
/** * Encrypts or decrypts the given input. * * @param in input * @param s encryption type * @param k secret key * @param a encryption algorithm * @param ec encrypt or decrypt * @return encrypted or decrypted input * @throws QueryException query exception */ Str encryption(final byte[] in, final byte[] s, final byte[] k, final byte[] a, final boolean ec) throws QueryException { final boolean symmetric = eq(lc(s), SYM) || s.length == 0; final byte[] aa = a.length == 0 ? DES : a; final byte[] tivl = ALGE.get(lc(aa)); if (!symmetric) throw CX_ENCTYP.get(info, ec); if (tivl == null) throw CX_INVALGO.get(info, s); // initialization vector length final int ivl = toInt(tivl); try { return Str.get(ec ? encrypt(in, k, aa, ivl) : decrypt(in, k, aa, ivl)); } catch (final NoSuchPaddingException e) { throw CX_NOPAD.get(info, e); } catch (final BadPaddingException e) { throw CX_BADPAD.get(info, e); } catch (final InvalidKeyException e) { throw CX_KEYINV.get(info, e); } catch (final IllegalBlockSizeException e) { throw CX_ILLBLO.get(info, e); } catch (final GeneralSecurityException e) { throw CX_INVALGO.get(info, e); } }
/** * Scans a PEReference. [69] * * @return entity * @throws IOException I/O exception */ private byte[] peRef() throws IOException { // scans predefined entities final byte[] name = name(true); consume(';'); final byte[] en = pents.get(name); if (en != null) return en; return name; }
/** * Decrypts the given input data. * * @param in data to decrypt * @param k secret key * @param a encryption algorithm * @param ivl initialization vector length * @return decrypted data * @throws NoSuchAlgorithmException ex * @throws NoSuchPaddingException ex * @throws InvalidKeyException ex * @throws InvalidAlgorithmParameterException ex * @throws IllegalBlockSizeException ex * @throws BadPaddingException ex */ private static byte[] decrypt(final byte[] in, final byte[] k, final byte[] a, final int ivl) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { final SecretKeySpec keySpec = new SecretKeySpec(k, string(a)); final Cipher cipher = Cipher.getInstance(string(ALGN.get(lc(a)))); // extract iv from message beginning final byte[] iv = substring(in, 0, ivl); final IvParameterSpec ivspec = new IvParameterSpec(iv); cipher.init(Cipher.DECRYPT_MODE, keySpec, ivspec); return cipher.doFinal(substring(in, ivl, in.length)); }
/** * Scans a reference. [67] * * @param f dissolve entities * @return entity * @throws IOException I/O exception */ private byte[] ref(final boolean f) throws IOException { // scans numeric entities if (consume('#')) { // [66] final TokenBuilder ent = new TokenBuilder(); int b = 10; int ch = nextChar(); ent.add(ch); if (ch == 'x') { b = 16; ent.add(ch = nextChar()); } int n = 0; do { final boolean m = ch >= '0' && ch <= '9'; final boolean h = b == 16 && (ch >= 'a' && ch <= 'f' || ch >= 'A' && ch <= 'F'); if (!m && !h) { completeRef(ent); return QUESTION; } n *= b; n += ch & 15; if (!m) n += 9; ent.add(ch = nextChar()); } while (ch != ';'); if (!valid(n)) return QUESTION; ent.reset(); ent.add(n); return ent.finish(); } // scans predefined entities [68] final byte[] name = name(false); if (!consume(';')) return QUESTION; if (!f) return concat(AMPER, name, SEMI); byte[] en = ents.get(name); if (en == null) { // unknown entity: try HTML entities (lazy initialization) if (HTMLENTS.size() == 0) { for (int s = 0; s < HTMLENTITIES.length; s += 2) { HTMLENTS.add(token(HTMLENTITIES[s]), token(HTMLENTITIES[s + 1])); } } en = HTMLENTS.get(name); } return en == null ? QUESTION : en; }
/** * Reads next character or throws an exception if all bytes have been read. * * @return next character * @throws IOException I/O exception */ private int consume() throws IOException { while (true) { final int ch = input.read(); if (ch == -1) return 0; if (ch == '%' && pe) { // [69] final byte[] key = name(true); final byte[] val = pents.get(key); if (val == null) error(UNKNOWNPE, key); check(';'); input.add(val, true); } else { return ch; } } }
/** * Builds the thesaurus. * * @param value input nodes * @throws QueryException query exception */ private void build(final Value value) throws QueryException { final Value synonyms = nodes("*:synonym", value); if (synonyms.isEmpty()) return; final ThesNode term = node(text("*:term", value)); for (final Item synonym : synonyms) { final ThesNode sterm = node(text("*:term", synonym)); final byte[] rs = text("*:relationship", synonym); term.add(sterm, rs); final byte[] srs = RSHIPS.get(rs); if (srs != null) sterm.add(term, srs); build(synonyms); } }
/** * Encrypts the given input data. * * @param in input data to encrypt * @param k key * @param a encryption algorithm * @param ivl initialization vector length * @return encrypted input data * @throws InvalidKeyException ex * @throws InvalidAlgorithmParameterException ex * @throws NoSuchAlgorithmException ex * @throws NoSuchPaddingException ex * @throws IllegalBlockSizeException ex * @throws BadPaddingException ex */ private static byte[] encrypt(final byte[] in, final byte[] k, final byte[] a, final int ivl) throws InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException { final Cipher cipher = Cipher.getInstance(string(ALGN.get(lc(a)))); final SecretKeySpec kspec = new SecretKeySpec(k, string(a)); // generate random iv. random iv is necessary to make the encryption of a // string look different every time it is encrypted. final byte[] iv = new byte[ivl]; // create new random iv if encrypting final SecureRandom rand = SecureRandom.getInstance("SHA1PRNG"); rand.nextBytes(iv); final IvParameterSpec ivspec = new IvParameterSpec(iv); // encrypt/decrypt cipher.init(Cipher.ENCRYPT_MODE, kspec, ivspec); final byte[] t = cipher.doFinal(in); // initialization vector is appended to the message for later decryption return concat(iv, t); }
/** * Creates a message authentication code (MAC) for the given input. * * @param msg input * @param k secret key * @param a encryption algorithm * @param enc encoding * @return MAC * @throws QueryException query exception */ Item hmac(final byte[] msg, final byte[] k, final byte[] a, final byte[] enc) throws QueryException { // create hash value from input message final Key key = new SecretKeySpec(k, string(a)); final byte[] aa = a.length == 0 ? DEFA : a; if (!ALGHMAC.contains(lc(aa))) throw CX_INVHASH.get(info, aa); final boolean b64 = eq(lc(enc), BASE64) || enc.length == 0; if (!b64 && !eq(lc(enc), HEX)) throw CX_ENC.get(info, enc); try { final Mac mac = Mac.getInstance(string(ALGHMAC.get(lc(aa)))); mac.init(key); final byte[] hash = mac.doFinal(msg); // convert to specified encoding, base64 as a standard, else use hex return Str.get(b64 ? org.basex.util.Base64.encode(hash) : hex(hash, true)); } catch (final NoSuchAlgorithmException e) { throw CX_INVHASH.get(info, e); } catch (final InvalidKeyException e) { throw CX_KEYINV.get(info, e); } }
/** * Inserts a data instance at the specified pre value. Note that the specified data instance must * differ from this instance. * * @param ipre value at which to insert new data * @param ipar parent pre value of node * @param clip data clip */ public final void insert(final int ipre, final int ipar, final DataClip clip) { meta.update(); // update value and document indexes if (meta.updindex) indexBegin(); resources.insert(ipre, clip); final int dsize = clip.size(); final int buf = Math.min(dsize, IO.BLOCKSIZE >> IO.NODEPOWER); // resize buffer to cache more entries buffer(buf); // find all namespaces in scope to avoid duplicate declarations final TokenMap nsScope = nspaces.scope(ipar, this); // loop through all entries final IntList preStack = new IntList(); final NSNode nsRoot = nspaces.current(); final HashSet<NSNode> newNodes = new HashSet<NSNode>(); final IntList flagPres = new IntList(); // indicates if database only contains a dummy node final Data data = clip.data; int c = 0; for (int dpre = clip.start; dpre < clip.end; ++dpre, ++c) { if (c != 0 && c % buf == 0) insert(ipre + c - buf); final int pre = ipre + c; final int dkind = data.kind(dpre); final int dpar = data.parent(dpre, dkind); // ipar < 0 if document nodes on top level are added final int dis = dpar >= 0 ? dpre - dpar : ipar >= 0 ? pre - ipar : 0; final int par = dis == 0 ? -1 : pre - dis; if (c == 0) nspaces.root(par, this); while (!preStack.isEmpty() && preStack.peek() > par) nspaces.close(preStack.pop()); switch (dkind) { case DOC: // add document nspaces.prepare(); final int s = data.size(dpre, dkind); doc(pre, s, data.text(dpre, true)); meta.ndocs++; preStack.push(pre); break; case ELEM: // add element nspaces.prepare(); boolean ne = false; if (data.nsFlag(dpre)) { final Atts at = data.ns(dpre); for (int a = 0; a < at.size(); ++a) { // see if prefix has been declared/ is part of current ns scope final byte[] old = nsScope.get(at.name(a)); if (old == null || !eq(old, at.value(a))) { // we have to keep track of all new NSNodes that are added // to the Namespace structure, as their pre values must not // be updated. I.e. if an NSNode N with pre value 3 existed // prior to inserting and two new nodes are inserted at // location pre == 3 we have to make sure N and only N gets // updated. newNodes.add(nspaces.add(at.name(a), at.value(a), pre)); ne = true; } } } byte[] nm = data.name(dpre, dkind); elem( dis, tagindex.index(nm, null, false), data.attSize(dpre, dkind), data.size(dpre, dkind), nspaces.uri(nm, true), ne); preStack.push(pre); break; case TEXT: case COMM: case PI: // add text text(pre, dis, data.text(dpre, true), dkind); break; case ATTR: // add attribute nm = data.name(dpre, dkind); // check if prefix already in nsScope or not final byte[] attPref = prefix(nm); // check if prefix of attribute has already been declared, otherwise // add declaration to parent node if (data.nsFlag(dpre) && nsScope.get(attPref) == null) { nspaces.add( par, preStack.isEmpty() ? -1 : preStack.peek(), attPref, data.nspaces.uri(data.uri(dpre, dkind)), this); // save pre value to set ns flag later for this node. can't be done // here as direct table access would interfere with the buffer flagPres.add(par); } attr( pre, dis, atnindex.index(nm, null, false), data.text(dpre, false), nspaces.uri(nm, false), false); break; } } // finalize and update namespace structure while (!preStack.isEmpty()) nspaces.close(preStack.pop()); nspaces.root(nsRoot); if (bp != 0) insert(ipre + c - 1 - (c - 1) % buf); // reset buffer to old size buffer(1); // set ns flags for (int f = 0; f < flagPres.size(); f++) { final int fl = flagPres.get(f); table.write2(fl, 1, name(fl) | 1 << 15); } // increase size of ancestors int p = ipar; while (p >= 0) { final int k = kind(p); size(p, k, size(p, k) + dsize); p = parent(p, k); } if (meta.updindex) { // add the entries to the ID -> PRE mapping: idmap.insert(ipre, id(ipre), dsize); indexEnd(); } if (!cache) updateDist(ipre + dsize, dsize); // propagate PRE value shifts to namespaces if (ipar != -1) nspaces.insert(ipre, dsize, newNodes); }
/** * Constructor. * * @param info input info * @param map decimal format * @throws QueryException query exception */ public DecFormatter(final InputInfo info, final TokenMap map) throws QueryException { // assign map values int z = '0'; if (map != null) { for (final byte[] key : map) { final String k = string(key); final byte[] v = map.get(key); if (k.equals(DF_INF)) { inf = v; } else if (k.equals(DF_NAN)) { nan = v; } else if (v.length != 0 && cl(v, 0) == v.length) { final int cp = cp(v, 0); switch (k) { case DF_DEC: decimal = cp; break; case DF_GRP: grouping = cp; break; case DF_EXP: exponent = cp; break; case DF_PAT: pattern = cp; break; case DF_MIN: minus = cp; break; case DF_DIG: optional = cp; break; case DF_PC: percent = cp; break; case DF_PM: permille = cp; break; case DF_ZD: z = zeroes(cp); if (z == -1) throw INVDECFORM_X_X.get(info, k, v); if (z != cp) throw INVDECZERO_X.get(info, (char) cp); break; } } else { // signs must have single character throw INVDECSINGLE_X_X.get(info, k, v); } } } // check for duplicate characters zero = z; final IntSet is = new IntSet(); for (int i = 0; i < 10; i++) is.add(zero + i); final int[] ss = {decimal, grouping, exponent, percent, permille, optional, pattern}; for (final int s : ss) if (!is.add(s)) throw DUPLDECFORM_X.get(info, (char) s); // create auxiliary strings final TokenBuilder tb = new TokenBuilder(); for (int i = 0; i < 10; i++) tb.add(zero + i); digits = tb.toArray(); // "decimal-separator-sign, exponent-separator-sign, grouping-sign, decimal-digit-family, // optional-digit-sign and pattern-separator-sign are classified as active characters" // -> decimal-digit-family: added above. pattern-separator-sign: will never occur at this stage actives = tb.add(decimal).add(exponent).add(grouping).add(optional).finish(); // "all other characters (including the percent-sign and per-mille-sign) are classified // as passive characters." }