/** * Adds a record to the table and the ID index. * * @param i index in the table where the record should be inserted * @param pre pre value * @param fid first ID value * @param nid last ID value * @param inc increment value * @param oid original ID value */ private void add( final int i, final int pre, final int fid, final int nid, final int inc, final int oid) { if (rows == pres.length) { final int s = Array.newSize(rows); pres = Arrays.copyOf(pres, s); fids = Arrays.copyOf(fids, s); nids = Arrays.copyOf(nids, s); incs = Arrays.copyOf(incs, s); oids = Arrays.copyOf(oids, s); } if (i < rows) { final int destPos = i + 1; final int length = rows - i; System.arraycopy(pres, i, pres, destPos, length); System.arraycopy(fids, i, fids, destPos, length); System.arraycopy(nids, i, nids, destPos, length); System.arraycopy(incs, i, incs, destPos, length); System.arraycopy(oids, i, oids, destPos, length); } pres[i] = pre; fids[i] = fid; nids[i] = nid; incs[i] = inc; oids[i] = oid; ++rows; }
/** * Sets the output text. * * @param t output text * @param s text size */ public final void setText(final byte[] t, final int s) { // remove invalid characters and compare old with new string int ns = 0; final int ts = text.size(); final byte[] tt = text.text(); boolean eq = true; for (int r = 0; r < s; ++r) { final byte b = t[r]; // support characters, highlighting codes, tabs and newlines if (b >= ' ' || b <= TokenBuilder.MARK || b == 0x09 || b == 0x0A) { t[ns++] = t[r]; } eq &= ns < ts && ns < s && t[ns] == tt[ns]; } eq &= ns == ts; // new text is different... if (!eq) { text = new BaseXTextTokens(Arrays.copyOf(t, ns)); rend.setText(text); scroll.pos(0); } if (undo != null) undo.store(t.length != ns ? Arrays.copyOf(t, ns) : t, 0); SwingUtilities.invokeLater(calc); }
/** * Binary search of a key in a list. If there are several hits the last one is returned. * * @param a array to search into * @param e key to search for * @return index of the found hit or where the key ought to be inserted */ private int sortedLastIndexOf(final int[] a, final int e) { int i = Arrays.binarySearch(a, 0, rows, e); if (i >= 0) { while (++i < rows && a[i] == e) ; return i - 1; } return i; }
/** * 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 the output text. * * @param text output text * @param size text size */ public final void setText(final byte[] text, final int size) { byte[] txt = text; if (Token.contains(text, '\r')) { // remove carriage returns int ns = 0; for (int r = 0; r < size; ++r) { final byte b = text[r]; if (b != '\r') text[ns++] = b; } // new text is different... txt = Arrays.copyOf(text, ns); } else if (text.length != size) { txt = Arrays.copyOf(text, size); } if (editor.text(txt)) { if (hist != null) hist.store(txt, editor.pos(), 0); } if (isShowing()) resizeCode.invokeLater(); }
/** * Inserts a new record. * * @param pre record PRE * @param id record ID * @param c number of inserted records */ public void insert(final int pre, final int id, final int c) { if (rows == 0 && pre == id && id == baseid + 1) { // no mapping and we append at the end => nothing to do baseid += c; return; } int pos = 0; int inc = c; int oid = pre; if (rows > 0) { pos = Arrays.binarySearch(pres, 0, rows, pre); if (pos < 0) { pos = -pos - 1; if (pos != 0) { // check if inserting into an existing id interval final int prev = pos - 1; final int prevcnt = nids[prev] - fids[prev] + 1; final int prevpre = pres[prev]; if (pre < prevpre + prevcnt) { // split the id interval final int split = pre - prevpre; final int fid = fids[prev] + split; // add a new next interval add(pos, pre, fid, nids[prev], incs[prev], oids[prev]); // shrink the previous interval nids[prev] = fid - 1; incs[prev] -= prevcnt - split; oid = oids[prev]; inc += incs[prev]; } else { oid = pre - incs[prev]; inc += incs[prev]; } } } else if (pos > 0) { oid = oids[pos]; inc += incs[pos - 1]; } increment(pos, c); } // add the new interval add(pos, pre, id, id + c - 1, inc, oid); }
/** * Returns the byte buffer. * * @return byte buffer */ private byte[] buffer() { final byte[] bb = bp == b.length ? b : Arrays.copyOf(b, bp); bp = 0; return bb; }
@Override public void insert(final int pre, final byte[] entries) { final int nnew = entries.length; if (nnew == 0) return; dirty(); // number of records to be inserted final int nr = nnew >>> IO.NODEPOWER; int split = 0; if (used == 0) { // special case: insert new data into first block if database is empty readPage(0); usedPages.set(0); ++used; } else if (pre > 0) { // find the offset within the block where the new records will be inserted split = cursor(pre - 1) + IO.NODESIZE; } else { // all insert operations will add data after first node. // i.e., there is no "insert before first document" statement throw Util.notExpected("Insertion at beginning of populated table."); } // number of bytes occupied by old records in the current block final int nold = npre - fpre << IO.NODEPOWER; // number of bytes occupied by old records which will be moved at the end final int moved = nold - split; // special case: all entries fit in the current block Buffer bf = bm.current(); if (nold + nnew <= IO.BLOCKSIZE) { Array.move(bf.data, split, nnew, moved); System.arraycopy(entries, 0, bf.data, split, nnew); bf.dirty = true; // increment first pre-values of blocks after the last modified block for (int i = page + 1; i < used; ++i) fpres[i] += nr; // update cached variables (fpre is not changed) npre += nr; meta.size += nr; return; } // append old entries at the end of the new entries final byte[] all = new byte[nnew + moved]; System.arraycopy(entries, 0, all, 0, nnew); System.arraycopy(bf.data, split, all, nnew, moved); // fill in the current block with new entries // number of bytes which fit in the first block int nrem = IO.BLOCKSIZE - split; if (nrem > 0) { System.arraycopy(all, 0, bf.data, split, nrem); bf.dirty = true; } // number of new required blocks and remaining bytes final int req = all.length - nrem; int needed = req / IO.BLOCKSIZE; final int remain = req % IO.BLOCKSIZE; if (remain > 0) { // check if the last entries can fit in the block after the current one if (page + 1 < used) { final int o = occSpace(page + 1) << IO.NODEPOWER; if (remain <= IO.BLOCKSIZE - o) { // copy the last records readPage(page + 1); bf = bm.current(); System.arraycopy(bf.data, 0, bf.data, remain, o); System.arraycopy(all, all.length - remain, bf.data, 0, remain); bf.dirty = true; // reduce the pre value, since it will be later incremented with nr fpres[page] -= remain >>> IO.NODEPOWER; // go back to the previous block readPage(page - 1); } else { // there is not enough space in the block - allocate a new one ++needed; } } else { // this is the last block - allocate a new one ++needed; } } // number of expected blocks: existing blocks + needed block - empty blocks final int exp = blocks + needed - (blocks - used); if (exp > fpres.length) { // resize directory arrays if existing ones are too small final int ns = Math.max(fpres.length << 1, exp); fpres = Arrays.copyOf(fpres, ns); pages = Arrays.copyOf(pages, ns); } // make place for the blocks where the new entries will be written Array.move(fpres, page + 1, needed, used - page - 1); Array.move(pages, page + 1, needed, used - page - 1); // write the all remaining entries while (needed-- > 0) { freeBlock(); nrem += write(all, nrem); fpres[page] = fpres[page - 1] + IO.ENTRIES; pages[page] = (int) bm.current().pos; } // increment all fpre values after the last modified block for (int i = page + 1; i < used; ++i) fpres[i] += nr; meta.size += nr; // update cached variables fpre = fpres[page]; npre = page + 1 < used && fpres[page + 1] < meta.size ? fpres[page + 1] : meta.size; }