Skip to content

Commit

Permalink
[FIX] QT3TS: CDATA-SECTION-ELEMENTS, map/array instance checks
Browse files Browse the repository at this point in the history
  • Loading branch information
ChristianGruen committed Nov 6, 2015
1 parent 4cfed81 commit fafe24d
Show file tree
Hide file tree
Showing 11 changed files with 76 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public void parse() throws IOException {
builder.text(tb.next());
builder.closeElem();
} else {
tb.add(XMLToken.valid(ch) ? ch : '?');
tb.add(XMLToken.valid(ch) ? ch : Token.INVALID);
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions basex-core/src/main/java/org/basex/io/in/TextDecoder.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@ static TextDecoder get(final String enc) throws IOException {

/**
* Processes an invalid character. Throws an exception if input must be valid,
* or returns a question mark as replacement.
* or returns a replacement character as replacement.
* @return question mark
* @throws IOException I/O exception
*/
int invalid() throws IOException {
if(valid) throw new InputException();
return '?';
return Token.INVALID;
}

/** UTF8 Decoder. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ private int bs() throws IOException {
* @param ch character
*/
private static void add(final TokenBuilder entry, final int ch) {
entry.add(XMLToken.valid(ch) ? ch : '?');
entry.add(XMLToken.valid(ch) ? ch : Token.INVALID);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@
* @author Leo Woerteler
*/
final class JsonParser extends InputParser {
/** Invalid Unicode character. */
private static final int INVALID = '\uFFFD';
/** Names of control characters not allowed in string literals. */
private static final String[] CTRL = {
// U+0000 -- U+001F
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,8 @@ public SerializerOptions(final SerializerOptions opts) {
* @param info input info
* @throws QueryException query exception
*/
public void parse(final String name,
final byte[] val, final StaticContext sc, final InputInfo info) throws QueryException {
public void parse(final String name, final byte[] val, final StaticContext sc,
final InputInfo info) throws QueryException {

try {
if(name.equals(USE_CHARACTER_MAPS.name()) && !eq(val, token(WEBDAV)))
Expand Down
1 change: 0 additions & 1 deletion basex-core/src/main/java/org/basex/query/QueryError.java
Original file line number Diff line number Diff line change
Expand Up @@ -1389,7 +1389,6 @@ public enum ErrType {
/** FOFD Error type. */ FOFD,
/** FOER Error type. */ FOER,
/** FOJS Error type. */ FOJS,
/** FOMP Error type. */ FOMP,
/** FONS Error type. */ FONS,
/** FORG Error type. */ FORG,
/** FORX Error type. */ FORX,
Expand Down
35 changes: 34 additions & 1 deletion basex-core/src/main/java/org/basex/query/func/FuncOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -131,24 +131,57 @@ private String optString(final ANode node, final QueryError error) throws QueryE
}
// retrieve key from element name and value from "value" attribute or text node
byte[] v = null;
final String name = string(qn.local());
if(hasElements(child)) {
v = token(optString(child, error));
} else {
for(final ANode attr : child.attributes()) {
if(eq(attr.name(), VALUE)) {
v = attr.string();
if(name.equals(SerializerOptions.CDATA_SECTION_ELEMENTS.name())) {
v = resolve(child, v);
}
} else {
// Conflicts with QT3TS, Serialization-json-34 etc.
//throw error.get(info, Util.info("Invalid attribute: '%'", attr.name()));
}
}
if(v == null) v = child.string();
}
tb.add(string(qn.local())).add('=').add(string(v).trim().replace(",", ",,")).add(',');
tb.add(name).add('=').add(string(v).trim().replace(",", ",,")).add(',');
}
return tb.toString();
}

/**
* Resolve QName in options.
* @param elem root element
* @param v value
* @return name with resolved QNames
*/
private static byte[] resolve(final ANode elem, final byte[] v) {
if(!Token.contains(v, ':')) return v;

final TokenBuilder tmp = new TokenBuilder();
for(final byte[] t : split(normalize(v), ' ')) {
if(t.length == 0) continue;

final int i = indexOf(t, ':');
if(i == -1) {
tmp.add(t);
} else {
final byte[] vl = elem.nsScope(null).value(substring(t, 0, i));
if(vl != null) {
tmp.add("Q{").add(vl).add('}').add(substring(t, i + 1));
} else {
tmp.add(t);
}
}
tmp.add(' ');
}
return tmp.finish();
}

/**
* Checks if the specified node has elements as children.
* @param node node
Expand Down
23 changes: 12 additions & 11 deletions basex-core/src/main/java/org/basex/query/value/array/Array.java
Original file line number Diff line number Diff line change
Expand Up @@ -424,26 +424,27 @@ public FItem coerceTo(final FuncType ft, final QueryContext qc, final InputInfo
/**
* Checks if this is an instance of the specified type.
* @param tp type
* @param one tolerate one-or-more results
* @param coerce coerce value
* @return result of check
*/
private boolean instOf(final FuncType tp, final boolean one) {
private boolean instOf(final FuncType tp, final boolean coerce) {
if(tp instanceof MapType) return false;

final SeqType[] at = tp.argTypes;
if(at != null && (at.length != 1 || !at[0].instanceOf(SeqType.ITR))) return false;

final boolean array = tp instanceof ArrayType;
SeqType ret = tp.retType;

// no argument and return type: no check required
if(ret == null || ret.eq(SeqType.ITEM_ZM)) return true;
// check types of members
for(final Value val : members()) {
if(!ret.instance(val)) return false;
if(tp instanceof ArrayType) {
// no argument and return type: no check required
if(ret == null || ret.eq(SeqType.ITEM_ZM)) return true;
// check types of members
for(final Value val : members()) {
if(!ret.instance(val)) return false;
}
return true;
}
// array { ... } instance of function(...) as item() -> false (result may be empty sequence)
return one || array || ret.mayBeZero();
// allow coercion
return coerce || ret == null || ret.eq(SeqType.ITEM_ZM);
}

@Override
Expand Down
25 changes: 11 additions & 14 deletions basex-core/src/main/java/org/basex/query/value/map/Map.java
Original file line number Diff line number Diff line change
Expand Up @@ -148,28 +148,25 @@ public Map coerceTo(final FuncType ft, final QueryContext qc, final InputInfo ii
/**
* Checks if this is an instance of the specified type.
* @param tp type
* @param one tolerate one-or-more results
* @param coerce coerce value
* @return result of check
*/
private boolean instOf(final FuncType tp, final boolean one) {
private boolean instOf(final FuncType tp, final boolean coerce) {
if(tp instanceof ArrayType) return false;

final SeqType[] at = tp.argTypes;
if(at != null && (at.length != 1 || !at[0].one())) return false;

// only check key for map types:
// map { 'a': ... } instance of function(xs:integer, ...) -> true
// map { 'a': ... } instance of map(xs:integer, ...) -> false
final boolean map = tp instanceof MapType;
AtomType arg = map ? ((MapType) tp).keyType() : null;
if(arg == AtomType.AAT) arg = null;
SeqType ret = tp.retType;
if(ret == null || ret.eq(SeqType.ITEM_ZM)) ret = null;

// no argument and return type: no check required
if(arg == null && ret == null) return true;
// map { ... } instance of function(...) as item() -> false (result may be empty sequence)
return root.instanceOf(arg, ret) && (one || map || ret == null || ret.mayBeZero());
if(tp instanceof MapType) {
AtomType arg = ((MapType) tp).keyType();
if(arg == AtomType.AAT) arg = null;
if(ret == null || ret.eq(SeqType.ITEM_ZM)) ret = null;
// map { ... } instance of function(...) as item() -> false (result may be empty sequence)
return (arg == null && ret == null) || root.instanceOf(arg, ret);
}
// allow coercion
return coerce || ret == null || ret.eq(SeqType.ITEM_ZM);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ public Atts namespaces() {

/**
* Returns a copy of the namespace hierarchy.
* @param sc static context
* @param sc static context (can be {@code null})
* @return namespaces
*/
public final Atts nsScope(final StaticContext sc) {
Expand Down
23 changes: 12 additions & 11 deletions basex-core/src/main/java/org/basex/util/Token.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,6 @@
* @author Christian Gruen
*/
public final class Token {
/** Maximum length for hash calculation. */
private static final byte MAXLENGTH = 96;

/** Maximum values for converting tokens to integer values. */
private static final int MAXINT = Integer.MAX_VALUE / 10;
/** Maximum values for converting tokens to long values. */
private static final long MAXLONG = Long.MAX_VALUE / 10;

/** Empty token. */
public static final byte[] EMPTY = {};
/** XML token. */
Expand Down Expand Up @@ -57,6 +49,16 @@ public final class Token {
/** Colon. */
public static final byte[] COLON = { ':' };

/** Invalid Unicode character. */
public static final char INVALID = '\uFFFD';

/** Maximum length for hash calculation. */
private static final byte MAXLENGTH = 96;
/** Maximum values for converting tokens to integer values. */
private static final int MAXINT = Integer.MAX_VALUE / 10;
/** Maximum values for converting tokens to long values. */
private static final long MAXLONG = Long.MAX_VALUE / 10;

/** Hex codes. */
public static final byte[] HEX = token("0123456789ABCDEF");
/** Reserved characters. */
Expand Down Expand Up @@ -215,8 +217,7 @@ public static byte[] utf8(final byte[] token, final String encoding) {

/**
* Returns the codepoint (unicode value) of the specified token, starting at
* the specified position. Returns a unicode replacement character for invalid
* values.
* the specified position. Returns a unicode replacement character for invalid values.
* @param token token
* @param pos character position
* @return current character
Expand All @@ -227,7 +228,7 @@ public static int cp(final byte[] token, final int pos) {
if((v & 0xFF) < 192) return v & 0xFF;
// number of bytes to be read
final int vl = cl(v);
if(pos + vl > token.length) return 0xFFFD;
if(pos + vl > token.length) return INVALID;
// 110xxxxx 10xxxxxx
if(vl == 2) return (v & 0x1F) << 6 | token[pos + 1] & 0x3F;
// 1110xxxx 10xxxxxx 10xxxxxx
Expand Down

0 comments on commit fafe24d

Please sign in to comment.