/** * Format a number supplied as a decimal * * @param dval the decimal value * @param fsb the FastStringBuffer to contain the result */ private void formatDecimal(BigDecimal dval, FastStringBuffer fsb) { dval = dval.setScale(maxFractionPartSize, BigDecimal.ROUND_HALF_EVEN); DecimalValue.decimalToString(dval, fsb); int point = fsb.indexOf('.'); int intDigits; if (point >= 0) { int zz = maxFractionPartSize - minFractionPartSize; while (zz > 0) { if (fsb.charAt(fsb.length() - 1) == '0') { fsb.setLength(fsb.length() - 1); zz--; } else { break; } } intDigits = point; if (fsb.charAt(fsb.length() - 1) == '.') { fsb.setLength(fsb.length() - 1); } } else { intDigits = fsb.length(); if (minFractionPartSize > 0) { fsb.append('.'); for (int i = 0; i < minFractionPartSize; i++) { fsb.append('0'); } } } if (minWholePartSize == 0 && intDigits == 1 && fsb.charAt(0) == '0') { fsb.removeCharAt(0); } else { fsb.prependRepeated('0', minWholePartSize - intDigits); } }
private static String byteArrayToHex(byte[] bytes) { // final StringBuilder sb = new StringBuilder(bytes.length * 2); final FastStringBuffer sb = new FastStringBuffer(bytes.length * 2); for (int i = 0; i < bytes.length; i++) { sb.append(HEXADECIMAL_DIGITS[(bytes[i] >> 4) & 0xf]); sb.append(HEXADECIMAL_DIGITS[bytes[i] & 0xf]); } return sb.toString(); }
/** * Format a number supplied as a integer * * @param value the integer value * @param fsb the FastStringBuffer to contain the result */ private void formatInteger(NumericValue value, FastStringBuffer fsb) { fsb.append(value.getStringValueCS()); int leadingZeroes = minWholePartSize - fsb.length(); fsb.prependRepeated('0', leadingZeroes); if (minFractionPartSize != 0) { fsb.append('.'); for (int i = 0; i < minFractionPartSize; i++) { fsb.append('0'); } } }
/** * Format a number using this sub-picture * * @param value the absolute value of the number to be formatted * @param dfs the decimal format symbols to be used * @param minusSign the representation of a minus sign to be used * @return the formatted number */ public CharSequence format(NumericValue value, DecimalSymbols dfs, String minusSign) { // System.err.println("Formatting " + value); if (value.isNaN()) { return dfs.NaN; // changed by W3C Bugzilla 2712 } if ((value instanceof DoubleValue || value instanceof FloatValue) && Double.isInfinite(value.getDoubleValue())) { return minusSign + prefix + dfs.infinity + suffix; } int multiplier = 1; if (isPercent) { multiplier = 100; } else if (isPerMille) { multiplier = 1000; } if (multiplier != 1) { try { // value = value.arithmetic(Token.MULT, new Int64Value(multiplier), null); value = (NumericValue) ArithmeticExpression.compute( value, Calculator.TIMES, new Int64Value(multiplier), null); } catch (XPathException e) { value = new DoubleValue(value.getDoubleValue() * multiplier); } } FastStringBuffer sb = new FastStringBuffer(20); if (value instanceof DoubleValue || value instanceof FloatValue) { BigDecimal dec = adjustToDecimal(value.getDoubleValue(), 2); formatDecimal(dec, sb); // formatDouble(value.getDoubleValue(), sb); } else if (value instanceof Int64Value || value instanceof BigIntegerValue) { formatInteger(value, sb); } else if (value instanceof DecimalValue) { //noinspection RedundantCast formatDecimal(((DecimalValue) value).getDecimalValue(), sb); } // System.err.println("Justified number: " + sb.toString()); // Map the digits and decimal point to use the selected characters int[] ib = StringValue.expand(sb); int ibused = ib.length; int point = sb.indexOf('.'); if (point == -1) { point = sb.length(); } else { ib[point] = dfs.decimalSeparator; // If there is no fractional part, delete the decimal point if (maxFractionPartSize == 0) { ibused--; } } // Map the digits if (dfs.zeroDigit != '0') { int newZero = dfs.zeroDigit; for (int i = 0; i < ibused; i++) { int c = ib[i]; if (c >= '0' && c <= '9') { ib[i] = (c - '0' + newZero); } } } // Add the whole-part grouping separators if (wholePartGroupingPositions != null) { if (wholePartGroupingPositions.length == 1) { // grouping separators are at regular positions int g = wholePartGroupingPositions[0]; int p = point - g; while (p > 0) { ib = insert(ib, ibused++, dfs.groupingSeparator, p); // sb.insert(p, unicodeChar(dfs.groupingSeparator)); p -= g; } } else { // grouping separators are at irregular positions for (int i = 0; i < wholePartGroupingPositions.length; i++) { int p = point - wholePartGroupingPositions[i]; if (p > 0) { ib = insert(ib, ibused++, dfs.groupingSeparator, p); // sb.insert(p, unicodeChar(dfs.groupingSeparator)); } } } } // Add the fractional-part grouping separators if (fractionalPartGroupingPositions != null) { // grouping separators are at irregular positions. for (int i = 0; i < fractionalPartGroupingPositions.length; i++) { int p = point + 1 + fractionalPartGroupingPositions[i] + i; if (p < ibused - 1) { ib = insert(ib, ibused++, dfs.groupingSeparator, p); // sb.insert(p, dfs.groupingSeparator); } else { break; } } } // System.err.println("Grouped number: " + sb.toString()); // sb.insert(0, prefix); // sb.insert(0, minusSign); // sb.append(suffix); FastStringBuffer res = new FastStringBuffer(prefix.length() + minusSign.length() + suffix.length() + ibused); res.append(minusSign); res.append(prefix); res.append(StringValue.contract(ib, ibused)); res.append(suffix); return res; }
/** * Convert a double to a BigDecimal. In general there will be several BigDecimal values that are * equal to the supplied value, and the one we want to choose is the one with fewest non-zero * digits. The algorithm used is rather pragmatic: look for a string of zeroes or nines, try * rounding the number down or up as approriate, then convert the adjusted value to a double to * see if it's equal to the original: if not, use the original value unchanged. * * @param value the double to be converted * @param precision 2 for a double, 1 for a float * @return the result of conversion to a double */ public static BigDecimal adjustToDecimal(double value, int precision) { final String zeros = (precision == 1 ? "00000" : "000000000"); final String nines = (precision == 1 ? "99999" : "999999999"); BigDecimal initial = new BigDecimal(value); BigDecimal trial = null; FastStringBuffer fsb = new FastStringBuffer(20); DecimalValue.decimalToString(initial, fsb); String s = fsb.toString(); int start = (s.charAt(0) == '-' ? 1 : 0); int p = s.indexOf("."); int i = s.lastIndexOf(zeros); if (i > 0) { if (p < 0 || i < p) { // we're in the integer part // try replacing all following digits with zeros and seeing if we get the same double back FastStringBuffer sb = new FastStringBuffer(s.length()); sb.append(s.substring(0, i)); for (int n = i; n < s.length(); n++) { sb.append(s.charAt(n) == '.' ? '.' : '0'); } trial = new BigDecimal(sb.toString()); } else { // we're in the fractional part // try truncating the number before the zeros and seeing if we get the same double back trial = new BigDecimal(s.substring(0, i)); } } else { i = s.indexOf(nines); if (i >= 0) { if (i == start) { // number starts with 99999... or -99999. Try rounding up to 100000.. or -100000... FastStringBuffer sb = new FastStringBuffer(s.length() + 1); if (start == 1) { sb.append('-'); } sb.append('1'); for (int n = start; n < s.length(); n++) { sb.append(s.charAt(n) == '.' ? '.' : '0'); } trial = new BigDecimal(sb.toString()); } else { // try rounding up while (i >= 0 && (s.charAt(i) == '9' || s.charAt(i) == '.')) { i--; } if (i < 0 || s.charAt(i) == '-') { return initial; // can't happen: we've already handled numbers starting 99999.. } else if (p < 0 || i < p) { // we're in the integer part FastStringBuffer sb = new FastStringBuffer(s.length()); sb.append(s.substring(0, i)); sb.append((char) ((int) s.charAt(i) + 1)); for (int n = i; n < s.length(); n++) { sb.append(s.charAt(n) == '.' ? '.' : '0'); } trial = new BigDecimal(sb.toString()); } else { // we're in the fractional part - can ignore following digits String s2 = s.substring(0, i) + (char) ((int) s.charAt(i) + 1); trial = new BigDecimal(s2); } } } } if (trial != null && (precision == 1 ? trial.floatValue() == value : trial.doubleValue() == value)) { return trial; } else { return initial; } }
public static PooledXPathExpression getXPathExpression( PropertyContext propertyContext, List<Item> contextItems, int contextPosition, String xpathString, Map<String, String> prefixToURIMap, Map<String, ValueRepresentation> variableToValueMap, FunctionLibrary functionLibrary, String baseURI, boolean isAvt, boolean testNoCache, LocationData locationData) { try { // Find pool from cache final Long validity = (long) 0; final Cache cache = ObjectCache.instance(XPATH_CACHE_NAME, XPATH_CACHE_DEFAULT_SIZE); final FastStringBuffer cacheKeyString = new FastStringBuffer(xpathString); { if (functionLibrary != null) { // This is ok cacheKeyString.append('|'); cacheKeyString.append(Integer.toString(functionLibrary.hashCode())); } } { // NOTE: Mike Kay confirms on 2007-07-04 that compilation depends on the namespace context, // so we need // to use it as part of the cache key. // TODO: PERF: It turns out that this takes a lot of time. Now that the namespace // information is computed statically, we can do better. if (DEBUG_TEST_KEY_OPTIMIZATION) { // PERF TEST ONLY cacheKeyString.append("|DUMMYNSVAR|"); } else { if (prefixToURIMap != null) { final Map<String, String> sortedMap = (prefixToURIMap instanceof TreeMap) ? prefixToURIMap : new TreeMap<String, String>( prefixToURIMap); // this should make sure we always get the keys in the same // order for (Map.Entry<String, String> currentEntry : sortedMap.entrySet()) { cacheKeyString.append('|'); cacheKeyString.append(currentEntry.getKey()); cacheKeyString.append('='); cacheKeyString.append(currentEntry.getValue()); } } } } if (DEBUG_TEST_KEY_OPTIMIZATION) { // PERF TEST ONLY // NOP } else { if (variableToValueMap != null && variableToValueMap.size() > 0) { // There are some variables in scope. They must be part of the key // TODO: Put this in static state as this can be determined statically once and for all for (final String variableName : variableToValueMap.keySet()) { cacheKeyString.append('|'); cacheKeyString.append(variableName); } } } { // Add this to the key as evaluating "name" as XPath or as AVT is very different! cacheKeyString.append('|'); cacheKeyString.append(Boolean.toString(isAvt)); } // TODO: Add baseURI to cache key (currently, baseURI is pretty much unused) final Set<String> variableNames = (variableToValueMap != null) ? variableToValueMap.keySet() : null; final PooledXPathExpression expr; if (testNoCache) { // For testing only: don't get expression from cache final Object o = new XFormsCachePoolableObjetFactory( null, xpathString, prefixToURIMap, variableNames, functionLibrary, baseURI, isAvt, false, locationData) .makeObject(); expr = (PooledXPathExpression) o; } else { // Get or create pool final InternalCacheKey cacheKey = new InternalCacheKey("XPath Expression2", cacheKeyString.toString()); ObjectPool pool = (ObjectPool) cache.findValid(propertyContext, cacheKey, validity); if (pool == null) { pool = createXPathPool( xpathString, prefixToURIMap, variableNames, functionLibrary, baseURI, isAvt, locationData); cache.add(propertyContext, cacheKey, validity, pool); } // Get object from pool final Object o = pool.borrowObject(); expr = (PooledXPathExpression) o; } // Set context items and position expr.setContextItems(contextItems, contextPosition); // Set variables expr.setVariables(variableToValueMap); return expr; } catch (Exception e) { throw handleXPathException(e, xpathString, "preparing XPath expression", locationData); } }
/** Evaluate as an expression. */ public Item evaluateItem(XPathContext context) throws XPathException { if (isLazyConstruction() && (context.getConfiguration().areAllNodesUntyped() || (validation == Validation.PRESERVE && getSchemaType() == null))) { return new UnconstructedDocument(this, context); } else { Controller controller = context.getController(); DocumentInfo root; if (textOnly) { CharSequence textValue; if (constantText != null) { textValue = constantText; } else { FastStringBuffer sb = new FastStringBuffer(100); SequenceIterator iter = content.iterate(context); while (true) { Item item = iter.next(); if (item == null) break; sb.append(item.getStringValueCS()); } textValue = sb.condense(); } root = new TextFragmentValue(textValue, getBaseURI()); ((TextFragmentValue) root).setConfiguration(controller.getConfiguration()); } else { try { XPathContext c2 = context.newMinorContext(); c2.setOrigin(this); Builder builder = controller.makeBuilder(); // builder.setSizeParameters(treeSizeParameters); builder.setLineNumbering(controller.getConfiguration().isLineNumbering()); // receiver.setSystemId(getBaseURI()); builder.setBaseURI(getBaseURI()); builder.setTiming(false); PipelineConfiguration pipe = controller.makePipelineConfiguration(); pipe.setHostLanguage(getHostLanguage()); // pipe.setBaseURI(baseURI); builder.setPipelineConfiguration(pipe); c2.changeOutputDestination( null, builder, false, getHostLanguage(), validation, getSchemaType()); Receiver out = c2.getReceiver(); out.open(); out.startDocument(0); content.process(c2); out.endDocument(); out.close(); root = (DocumentInfo) builder.getCurrentRoot(); } catch (XPathException e) { e.maybeSetLocation(this); e.maybeSetContext(context); throw e; } } return root; } }