diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ecma/EcmaFloatingDecimal.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ecma/EcmaFloatingDecimal.java
new file mode 100644
index 000000000..28d6336a9
--- /dev/null
+++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ecma/EcmaFloatingDecimal.java
@@ -0,0 +1,1674 @@
+/*
+ * Copyright (C) 2010-2015 JPEXS, All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3.0 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.
+ */
+/*
+ * Copyright 1996-2004 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.jpexs.decompiler.flash.ecma;
+
+import java.util.regex.Pattern;
+
+public class EcmaFloatingDecimal {
+
+ boolean isExceptional;
+
+ boolean isNegative;
+
+ int decExponent;
+
+ char digits[];
+
+ int nDigits;
+
+ int bigIntExp;
+
+ int bigIntNBits;
+
+ boolean mustSetRoundDir = false;
+
+ boolean fromHex = false;
+
+ int roundDir = 0; // set by doubleValue
+
+ private EcmaFloatingDecimal(boolean negSign, int decExponent, char[] digits, int n, boolean e) {
+ isNegative = negSign;
+ isExceptional = e;
+ this.decExponent = decExponent;
+ this.digits = digits;
+ this.nDigits = n;
+ }
+
+ /*
+ * Constants of the implementation
+ * Most are IEEE-754 related.
+ * (There are more really boring constants at the end.)
+ */
+ static final long signMask = 0x8000000000000000L;
+
+ static final long expMask = 0x7ff0000000000000L;
+
+ static final long fractMask = ~(signMask | expMask);
+
+ static final int expShift = 52;
+
+ static final int expBias = 1023;
+
+ static final long fractHOB = (1L << expShift); // assumed High-Order bit
+
+ static final long expOne = ((long) expBias) << expShift; // exponent of 1.0
+
+ static final int maxSmallBinExp = 62;
+
+ static final int minSmallBinExp = -(63 / 3);
+
+ static final int maxDecimalDigits = 15;
+
+ static final int maxDecimalExponent = 308;
+
+ static final int minDecimalExponent = -324;
+
+ static final int bigDecimalExponent = 324; // i.e. abs(minDecimalExponent)
+
+ static final long highbyte = 0xff00000000000000L;
+
+ static final long highbit = 0x8000000000000000L;
+
+ static final long lowbytes = ~highbyte;
+
+ static final int singleSignMask = 0x80000000;
+
+ static final int singleExpMask = 0x7f800000;
+
+ static final int singleFractMask = ~(singleSignMask | singleExpMask);
+
+ static final int singleExpShift = 23;
+
+ static final int singleFractHOB = 1 << singleExpShift;
+
+ static final int singleExpBias = 127;
+
+ static final int singleMaxDecimalDigits = 7;
+
+ static final int singleMaxDecimalExponent = 38;
+
+ static final int singleMinDecimalExponent = -45;
+
+ static final int intDecimalDigits = 9;
+
+
+ /*
+ * count number of bits from high-order 1 bit to low-order 1 bit,
+ * inclusive.
+ */
+ private static int
+ countBits(long v) {
+ //
+ // the strategy is to shift until we get a non-zero sign bit
+ // then shift until we have no bits left, counting the difference.
+ // we do byte shifting as a hack. Hope it helps.
+ //
+ if (v == 0L) {
+ return 0;
+ }
+
+ while ((v & highbyte) == 0L) {
+ v <<= 8;
+ }
+ while (v > 0L) { // i.e. while ((v&highbit) == 0L )
+ v <<= 1;
+ }
+
+ int n = 0;
+ while ((v & lowbytes) != 0L) {
+ v <<= 8;
+ n += 8;
+ }
+ while (v != 0L) {
+ v <<= 1;
+ n += 1;
+ }
+ return n;
+ }
+
+ /*
+ * Keep big powers of 5 handy for future reference.
+ */
+ private static FDBigInt b5p[];
+
+ private static synchronized FDBigInt big5pow(int p) {
+ assert p >= 0 : p; // negative power of 5
+ if (b5p == null) {
+ b5p = new FDBigInt[p + 1];
+ } else if (b5p.length <= p) {
+ FDBigInt t[] = new FDBigInt[p + 1];
+ System.arraycopy(b5p, 0, t, 0, b5p.length);
+ b5p = t;
+ }
+ if (b5p[p] != null) {
+ return b5p[p];
+ } else if (p < small5pow.length) {
+ return b5p[p] = new FDBigInt(small5pow[p]);
+ } else if (p < long5pow.length) {
+ return b5p[p] = new FDBigInt(long5pow[p]);
+ } else {
+ // construct the value.
+ // recursively.
+ int q, r;
+ // in order to compute 5^p,
+ // compute its square root, 5^(p/2) and square.
+ // or, let q = p / 2, r = p -q, then
+ // 5^p = 5^(q+r) = 5^q * 5^r
+ q = p >> 1;
+ r = p - q;
+ FDBigInt bigq = b5p[q];
+ if (bigq == null) {
+ bigq = big5pow(q);
+ }
+ if (r < small5pow.length) {
+ return (b5p[p] = bigq.mult(small5pow[r]));
+ } else {
+ FDBigInt bigr = b5p[r];
+ if (bigr == null) {
+ bigr = big5pow(r);
+ }
+ return (b5p[p] = bigq.mult(bigr));
+ }
+ }
+ }
+
+ //
+ // a common operation
+ //
+ private static FDBigInt
+ multPow52(FDBigInt v, int p5, int p2) {
+ if (p5 != 0) {
+ if (p5 < small5pow.length) {
+ v = v.mult(small5pow[p5]);
+ } else {
+ v = v.mult(big5pow(p5));
+ }
+ }
+ if (p2 != 0) {
+ v.lshiftMe(p2);
+ }
+ return v;
+ }
+
+ //
+ // another common operation
+ //
+ private static FDBigInt constructPow52(int p5, int p2) {
+ FDBigInt v = new FDBigInt(big5pow(p5));
+ if (p2 != 0) {
+ v.lshiftMe(p2);
+ }
+ return v;
+ }
+
+ /*
+ * Make a floating double into a FDBigInt.
+ * This could also be structured as a FDBigInt
+ * constructor, but we'd have to build a lot of knowledge
+ * about floating-point representation into it, and we don't want to.
+ *
+ * AS A SIDE EFFECT, THIS METHOD WILL SET THE INSTANCE VARIABLES
+ * bigIntExp and bigIntNBits
+ *
+ */
+ private FDBigInt
+ doubleToBigInt(double dval) {
+ long lbits = Double.doubleToLongBits(dval) & ~signMask;
+ int binexp = (int) (lbits >>> expShift);
+ lbits &= fractMask;
+ if (binexp > 0) {
+ lbits |= fractHOB;
+ } else {
+ assert lbits != 0L : lbits; // doubleToBigInt(0.0)
+ binexp += 1;
+ while ((lbits & fractHOB) == 0L) {
+ lbits <<= 1;
+ binexp -= 1;
+ }
+ }
+ binexp -= expBias;
+ int nbits = countBits(lbits);
+ /*
+ * We now know where the high-order 1 bit is,
+ * and we know how many there are.
+ */
+ int lowOrderZeros = expShift + 1 - nbits;
+ lbits >>>= lowOrderZeros;
+
+ bigIntExp = binexp + 1 - nbits;
+ bigIntNBits = nbits;
+ return new FDBigInt(lbits);
+ }
+
+ /*
+ * Compute a number that is the ULP of the given value,
+ * for purposes of addition/subtraction. Generally easy.
+ * More difficult if subtracting and the argument
+ * is a normalized a power of 2, as the ULP changes at these points.
+ */
+ private static double ulp(double dval, boolean subtracting) {
+ long lbits = Double.doubleToLongBits(dval) & ~signMask;
+ int binexp = (int) (lbits >>> expShift);
+ double ulpval;
+ if (subtracting && (binexp >= expShift) && ((lbits & fractMask) == 0L)) {
+ // for subtraction from normalized, powers of 2,
+ // use next-smaller exponent
+ binexp -= 1;
+ }
+ if (binexp > expShift) {
+ ulpval = Double.longBitsToDouble(((long) (binexp - expShift)) << expShift);
+ } else if (binexp == 0) {
+ ulpval = Double.MIN_VALUE;
+ } else {
+ ulpval = Double.longBitsToDouble(1L << (binexp - 1));
+ }
+ if (subtracting) {
+ ulpval = -ulpval;
+ }
+
+ return ulpval;
+ }
+
+ /*
+ * Round a double to a float.
+ * In addition to the fraction bits of the double,
+ * look at the class instance variable roundDir,
+ * which should help us avoid double-rounding error.
+ * roundDir was set in hardValueOf if the estimate was
+ * close enough, but not exact. It tells us which direction
+ * of rounding is preferred.
+ */
+ float stickyRound(double dval) {
+ long lbits = Double.doubleToLongBits(dval);
+ long binexp = lbits & expMask;
+ if (binexp == 0L || binexp == expMask) {
+ // what we have here is special.
+ // don't worry, the right thing will happen.
+ return (float) dval;
+ }
+ lbits += (long) roundDir; // hack-o-matic.
+ return (float) Double.longBitsToDouble(lbits);
+ }
+
+
+ /*
+ * This is the easy subcase --
+ * all the significant bits, after scaling, are held in lvalue.
+ * negSign and decExponent tell us what processing and scaling
+ * has already been done. Exceptional cases have already been
+ * stripped out.
+ * In particular:
+ * lvalue is a finite number (not Inf, nor NaN)
+ * lvalue > 0L (not zero, nor negative).
+ *
+ * The only reason that we develop the digits here, rather than
+ * calling on Long.toString() is that we can do it a little faster,
+ * and besides want to treat trailing 0s specially. If Long.toString
+ * changes, we should re-evaluate this strategy!
+ */
+ private void developLongDigits(int decExponent, long lvalue, long insignificant) {
+ char digits[];
+ int ndigits;
+ int digitno;
+ int c;
+ //
+ // Discard non-significant low-order bits, while rounding,
+ // up to insignificant value.
+ int i;
+ for (i = 0; insignificant >= 10L; i++) {
+ insignificant /= 10L;
+ }
+ if (i != 0) {
+ long pow10 = long5pow[i] << i; // 10^i == 5^i * 2^i;
+ long residue = lvalue % pow10;
+ lvalue /= pow10;
+ decExponent += i;
+ if (residue >= (pow10 >> 1)) {
+ // round up based on the low-order bits we're discarding
+ lvalue++;
+ }
+ }
+ if (lvalue <= Integer.MAX_VALUE) {
+ assert lvalue > 0L : lvalue; // lvalue <= 0
+ // even easier subcase!
+ // can do int arithmetic rather than long!
+ int ivalue = (int) lvalue;
+ ndigits = 10;
+ digits = (char[]) (perThreadBuffer.get());
+ digitno = ndigits - 1;
+ c = ivalue % 10;
+ ivalue /= 10;
+ while (c == 0) {
+ decExponent++;
+ c = ivalue % 10;
+ ivalue /= 10;
+ }
+ while (ivalue != 0) {
+ digits[digitno--] = (char) (c + '0');
+ decExponent++;
+ c = ivalue % 10;
+ ivalue /= 10;
+ }
+ digits[digitno] = (char) (c + '0');
+ } else {
+ // same algorithm as above (same bugs, too )
+ // but using long arithmetic.
+ ndigits = 20;
+ digits = (char[]) (perThreadBuffer.get());
+ digitno = ndigits - 1;
+ c = (int) (lvalue % 10L);
+ lvalue /= 10L;
+ while (c == 0) {
+ decExponent++;
+ c = (int) (lvalue % 10L);
+ lvalue /= 10L;
+ }
+ while (lvalue != 0L) {
+ digits[digitno--] = (char) (c + '0');
+ decExponent++;
+ c = (int) (lvalue % 10L);
+ lvalue /= 10;
+ }
+ digits[digitno] = (char) (c + '0');
+ }
+ char result[];
+ ndigits -= digitno;
+ result = new char[ndigits];
+ System.arraycopy(digits, digitno, result, 0, ndigits);
+ this.digits = result;
+ this.decExponent = decExponent + 1;
+ this.nDigits = ndigits;
+ }
+
+ //
+ // add one to the least significant digit.
+ // in the unlikely event there is a carry out,
+ // deal with it.
+ // assert that this will only happen where there
+ // is only one digit, e.g. (float)1e-44 seems to do it.
+ //
+ private void roundup() {
+ int i;
+ int q = digits[i = (nDigits - 1)];
+ if (q == '9') {
+ while (q == '9' && i > 0) {
+ digits[i] = '0';
+ q = digits[--i];
+ }
+ if (q == '9') {
+ // carryout! High-order 1, rest 0s, larger exp.
+ decExponent += 1;
+ digits[0] = '1';
+ return;
+ }
+ // else fall through.
+ }
+ digits[i] = (char) (q + 1);
+ }
+
+ /*
+ * FIRST IMPORTANT CONSTRUCTOR: DOUBLE
+ */
+ public EcmaFloatingDecimal(double d) {
+ long dBits = Double.doubleToLongBits(d);
+ long fractBits;
+ int binExp;
+ int nSignificantBits;
+
+ // discover and delete sign
+ if ((dBits & signMask) != 0) {
+ isNegative = true;
+ dBits ^= signMask;
+ } else {
+ isNegative = false;
+ }
+ // Begin to unpack
+ // Discover obvious special cases of NaN and Infinity.
+ binExp = (int) ((dBits & expMask) >> expShift);
+ fractBits = dBits & fractMask;
+ if (binExp == (int) (expMask >> expShift)) {
+ isExceptional = true;
+ if (fractBits == 0L) {
+ digits = infinity;
+ } else {
+ digits = notANumber;
+ isNegative = false; // NaN has no sign!
+ }
+ nDigits = digits.length;
+ return;
+ }
+ isExceptional = false;
+ // Finish unpacking
+ // Normalize denormalized numbers.
+ // Insert assumed high-order bit for normalized numbers.
+ // Subtract exponent bias.
+ if (binExp == 0) {
+ if (fractBits == 0L) {
+ // not a denorm, just a 0!
+ decExponent = 0;
+ digits = zero;
+ nDigits = 1;
+ return;
+ }
+ while ((fractBits & fractHOB) == 0L) {
+ fractBits <<= 1;
+ binExp -= 1;
+ }
+ nSignificantBits = expShift + binExp + 1; // recall binExp is - shift count.
+ binExp += 1;
+ } else {
+ fractBits |= fractHOB;
+ nSignificantBits = expShift + 1;
+ }
+ binExp -= expBias;
+ // call the routine that actually does all the hard work.
+ dtoa(binExp, fractBits, nSignificantBits);
+ }
+
+ /*
+ * SECOND IMPORTANT CONSTRUCTOR: SINGLE
+ */
+ public EcmaFloatingDecimal(float f) {
+ int fBits = Float.floatToIntBits(f);
+ int fractBits;
+ int binExp;
+ int nSignificantBits;
+
+ // discover and delete sign
+ if ((fBits & singleSignMask) != 0) {
+ isNegative = true;
+ fBits ^= singleSignMask;
+ } else {
+ isNegative = false;
+ }
+ // Begin to unpack
+ // Discover obvious special cases of NaN and Infinity.
+ binExp = (int) ((fBits & singleExpMask) >> singleExpShift);
+ fractBits = fBits & singleFractMask;
+ if (binExp == (int) (singleExpMask >> singleExpShift)) {
+ isExceptional = true;
+ if (fractBits == 0L) {
+ digits = infinity;
+ } else {
+ digits = notANumber;
+ isNegative = false; // NaN has no sign!
+ }
+ nDigits = digits.length;
+ return;
+ }
+ isExceptional = false;
+ // Finish unpacking
+ // Normalize denormalized numbers.
+ // Insert assumed high-order bit for normalized numbers.
+ // Subtract exponent bias.
+ if (binExp == 0) {
+ if (fractBits == 0) {
+ // not a denorm, just a 0!
+ decExponent = 0;
+ digits = zero;
+ nDigits = 1;
+ return;
+ }
+ while ((fractBits & singleFractHOB) == 0) {
+ fractBits <<= 1;
+ binExp -= 1;
+ }
+ nSignificantBits = singleExpShift + binExp + 1; // recall binExp is - shift count.
+ binExp += 1;
+ } else {
+ fractBits |= singleFractHOB;
+ nSignificantBits = singleExpShift + 1;
+ }
+ binExp -= singleExpBias;
+ // call the routine that actually does all the hard work.
+ dtoa(binExp, ((long) fractBits) << (expShift - singleExpShift), nSignificantBits);
+ }
+
+ private void dtoa(int binExp, long fractBits, int nSignificantBits) {
+ int nFractBits; // number of significant bits of fractBits;
+ int nTinyBits; // number of these to the right of the point.
+ int decExp;
+
+ // Examine number. Determine if it is an easy case,
+ // which we can do pretty trivially using float/long conversion,
+ // or whether we must do real work.
+ nFractBits = countBits(fractBits);
+ nTinyBits = Math.max(0, nFractBits - binExp - 1);
+ if (binExp <= maxSmallBinExp && binExp >= minSmallBinExp) {
+ // Look more closely at the number to decide if,
+ // with scaling by 10^nTinyBits, the result will fit in
+ // a long.
+ if ((nTinyBits < long5pow.length) && ((nFractBits + n5bits[nTinyBits]) < 64)) {
+ /*
+ * We can do this:
+ * take the fraction bits, which are normalized.
+ * (a) nTinyBits == 0: Shift left or right appropriately
+ * to align the binary point at the extreme right, i.e.
+ * where a long int point is expected to be. The integer
+ * result is easily converted to a string.
+ * (b) nTinyBits > 0: Shift right by expShift-nFractBits,
+ * which effectively converts to long and scales by
+ * 2^nTinyBits. Then multiply by 5^nTinyBits to
+ * complete the scaling. We know this won't overflow
+ * because we just counted the number of bits necessary
+ * in the result. The integer you get from this can
+ * then be converted to a string pretty easily.
+ */
+ long halfULP;
+ if (nTinyBits == 0) {
+ if (binExp > nSignificantBits) {
+ halfULP = 1L << (binExp - nSignificantBits - 1);
+ } else {
+ halfULP = 0L;
+ }
+ if (binExp >= expShift) {
+ fractBits <<= (binExp - expShift);
+ } else {
+ fractBits >>>= (expShift - binExp);
+ }
+ developLongDigits(0, fractBits, halfULP);
+ return;
+ }
+ /*
+ * The following causes excess digits to be printed
+ * out in the single-float case. Our manipulation of
+ * halfULP here is apparently not correct. If we
+ * better understand how this works, perhaps we can
+ * use this special case again. But for the time being,
+ * we do not.
+ * else {
+ * fractBits >>>= expShift+1-nFractBits;
+ * fractBits *= long5pow[ nTinyBits ];
+ * halfULP = long5pow[ nTinyBits ] >> (1+nSignificantBits-nFractBits);
+ * developLongDigits( -nTinyBits, fractBits, halfULP );
+ * return;
+ * }
+ */
+ }
+ }
+ /*
+ * This is the hard case. We are going to compute large positive
+ * integers B and S and integer decExp, s.t.
+ * d = ( B / S ) * 10^decExp
+ * 1 <= B / S < 10
+ * Obvious choices are:
+ * decExp = floor( log10(d) )
+ * B = d * 2^nTinyBits * 10^max( 0, -decExp )
+ * S = 10^max( 0, decExp) * 2^nTinyBits
+ * (noting that nTinyBits has already been forced to non-negative)
+ * I am also going to compute a large positive integer
+ * M = (1/2^nSignificantBits) * 2^nTinyBits * 10^max( 0, -decExp )
+ * i.e. M is (1/2) of the ULP of d, scaled like B.
+ * When we iterate through dividing B/S and picking off the
+ * quotient bits, we will know when to stop when the remainder
+ * is <= M.
+ *
+ * We keep track of powers of 2 and powers of 5.
+ */
+
+ /*
+ * Estimate decimal exponent. (If it is small-ish,
+ * we could double-check.)
+ *
+ * First, scale the mantissa bits such that 1 <= d2 < 2.
+ * We are then going to estimate
+ * log10(d2) ~=~ (d2-1.5)/1.5 + log(1.5)
+ * and so we can estimate
+ * log10(d) ~=~ log10(d2) + binExp * log10(2)
+ * take the floor and call it decExp.
+ * FIXME -- use more precise constants here. It costs no more.
+ */
+ double d2 = Double.longBitsToDouble(
+ expOne | (fractBits & ~fractHOB));
+ decExp = (int) Math.floor(
+ (d2 - 1.5D) * 0.289529654D + 0.176091259 + (double) binExp * 0.301029995663981);
+ int B2, B5; // powers of 2 and powers of 5, respectively, in B
+ int S2, S5; // powers of 2 and powers of 5, respectively, in S
+ int M2, M5; // powers of 2 and powers of 5, respectively, in M
+ int Bbits; // binary digits needed to represent B, approx.
+ int tenSbits; // binary digits needed to represent 10*S, approx.
+ FDBigInt Sval, Bval, Mval;
+
+ B5 = Math.max(0, -decExp);
+ B2 = B5 + nTinyBits + binExp;
+
+ S5 = Math.max(0, decExp);
+ S2 = S5 + nTinyBits;
+
+ M5 = B5;
+ M2 = B2 - nSignificantBits;
+
+ /*
+ * the long integer fractBits contains the (nFractBits) interesting
+ * bits from the mantissa of d ( hidden 1 added if necessary) followed
+ * by (expShift+1-nFractBits) zeros. In the interest of compactness,
+ * I will shift out those zeros before turning fractBits into a
+ * FDBigInt. The resulting whole number will be
+ * d * 2^(nFractBits-1-binExp).
+ */
+ fractBits >>>= (expShift + 1 - nFractBits);
+ B2 -= nFractBits - 1;
+ int common2factor = Math.min(B2, S2);
+ B2 -= common2factor;
+ S2 -= common2factor;
+ M2 -= common2factor;
+
+ /*
+ * HACK!! For exact powers of two, the next smallest number
+ * is only half as far away as we think (because the meaning of
+ * ULP changes at power-of-two bounds) for this reason, we
+ * hack M2. Hope this works.
+ */
+ if (nFractBits == 1) {
+ M2 -= 1;
+ }
+
+ if (M2 < 0) {
+ // oops.
+ // since we cannot scale M down far enough,
+ // we must scale the other values up.
+ B2 -= M2;
+ S2 -= M2;
+ M2 = 0;
+ }
+ /*
+ * Construct, Scale, iterate.
+ * Some day, we'll write a stopping test that takes
+ * account of the asymmetry of the spacing of floating-point
+ * numbers below perfect powers of 2
+ * 26 Sept 96 is not that day.
+ * So we use a symmetric test.
+ */
+ char digits[] = this.digits = new char[18];
+ int ndigit = 0;
+ boolean low, high;
+ long lowDigitDifference;
+ int q;
+
+ /*
+ * Detect the special cases where all the numbers we are about
+ * to compute will fit in int or long integers.
+ * In these cases, we will avoid doing FDBigInt arithmetic.
+ * We use the same algorithms, except that we "normalize"
+ * our FDBigInts before iterating. This is to make division easier,
+ * as it makes our fist guess (quotient of high-order words)
+ * more accurate!
+ *
+ * Some day, we'll write a stopping test that takes
+ * account of the asymmetry of the spacing of floating-point
+ * numbers below perfect powers of 2
+ * 26 Sept 96 is not that day.
+ * So we use a symmetric test.
+ */
+ Bbits = nFractBits + B2 + ((B5 < n5bits.length) ? n5bits[B5] : (B5 * 3));
+ tenSbits = S2 + 1 + (((S5 + 1) < n5bits.length) ? n5bits[(S5 + 1)] : ((S5 + 1) * 3));
+ if (Bbits < 64 && tenSbits < 64) {
+ if (Bbits < 32 && tenSbits < 32) {
+ // wa-hoo! They're all ints!
+ int b = ((int) fractBits * small5pow[B5]) << B2;
+ int s = small5pow[S5] << S2;
+ int m = small5pow[M5] << M2;
+ int tens = s * 10;
+ /*
+ * Unroll the first iteration. If our decExp estimate
+ * was too high, our first quotient will be zero. In this
+ * case, we discard it and decrement decExp.
+ */
+ ndigit = 0;
+ q = b / s;
+ b = 10 * (b % s);
+ m *= 10;
+ low = (b < m);
+ high = (b + m > tens);
+ assert q < 10 : q; // excessively large digit
+ if ((q == 0) && !high) {
+ // oops. Usually ignore leading zero.
+ decExp--;
+ } else {
+ digits[ndigit++] = (char) ('0' + q);
+ }
+ /*
+ * HACK! Java spec sez that we always have at least
+ * one digit after the . in either F- or E-form output.
+ * Thus we will need more than one digit if we're using
+ * E-form
+ */
+ if (decExp <= -3 || decExp >= 8) {
+ high = low = false;
+ }
+ while (!low && !high) {
+ q = b / s;
+ b = 10 * (b % s);
+ m *= 10;
+ assert q < 10 : q; // excessively large digit
+ if (m > 0L) {
+ low = (b < m);
+ high = (b + m > tens);
+ } else {
+ // hack -- m might overflow!
+ // in this case, it is certainly > b,
+ // which won't
+ // and b+m > tens, too, since that has overflowed
+ // either!
+ low = true;
+ high = true;
+ }
+ digits[ndigit++] = (char) ('0' + q);
+ }
+ lowDigitDifference = (b << 1) - tens;
+ } else {
+ // still good! they're all longs!
+ long b = (fractBits * long5pow[B5]) << B2;
+ long s = long5pow[S5] << S2;
+ long m = long5pow[M5] << M2;
+ long tens = s * 10L;
+ /*
+ * Unroll the first iteration. If our decExp estimate
+ * was too high, our first quotient will be zero. In this
+ * case, we discard it and decrement decExp.
+ */
+ ndigit = 0;
+ q = (int) (b / s);
+ b = 10L * (b % s);
+ m *= 10L;
+ low = (b < m);
+ high = (b + m > tens);
+ assert q < 10 : q; // excessively large digit
+ if ((q == 0) && !high) {
+ // oops. Usually ignore leading zero.
+ decExp--;
+ } else {
+ digits[ndigit++] = (char) ('0' + q);
+ }
+ /*
+ * HACK! Java spec sez that we always have at least
+ * one digit after the . in either F- or E-form output.
+ * Thus we will need more than one digit if we're using
+ * E-form
+ */
+ if (decExp <= -3 || decExp >= 8) {
+ high = low = false;
+ }
+ while (!low && !high) {
+ q = (int) (b / s);
+ b = 10 * (b % s);
+ m *= 10;
+ assert q < 10 : q; // excessively large digit
+ if (m > 0L) {
+ low = (b < m);
+ high = (b + m > tens);
+ } else {
+ // hack -- m might overflow!
+ // in this case, it is certainly > b,
+ // which won't
+ // and b+m > tens, too, since that has overflowed
+ // either!
+ low = true;
+ high = true;
+ }
+ digits[ndigit++] = (char) ('0' + q);
+ }
+ lowDigitDifference = (b << 1) - tens;
+ }
+ } else {
+ FDBigInt tenSval;
+ int shiftBias;
+
+ /*
+ * We really must do FDBigInt arithmetic.
+ * Fist, construct our FDBigInt initial values.
+ */
+ Bval = multPow52(new FDBigInt(fractBits), B5, B2);
+ Sval = constructPow52(S5, S2);
+ Mval = constructPow52(M5, M2);
+
+ // normalize so that division works better
+ Bval.lshiftMe(shiftBias = Sval.normalizeMe());
+ Mval.lshiftMe(shiftBias);
+ tenSval = Sval.mult(10);
+ /*
+ * Unroll the first iteration. If our decExp estimate
+ * was too high, our first quotient will be zero. In this
+ * case, we discard it and decrement decExp.
+ */
+ ndigit = 0;
+ q = Bval.quoRemIteration(Sval);
+ Mval = Mval.mult(10);
+ low = (Bval.cmp(Mval) < 0);
+ high = (Bval.add(Mval).cmp(tenSval) > 0);
+ assert q < 10 : q; // excessively large digit
+ if ((q == 0) && !high) {
+ // oops. Usually ignore leading zero.
+ decExp--;
+ } else {
+ digits[ndigit++] = (char) ('0' + q);
+ }
+ /*
+ * HACK! Java spec sez that we always have at least
+ * one digit after the . in either F- or E-form output.
+ * Thus we will need more than one digit if we're using
+ * E-form
+ */
+ if (decExp <= -3 || decExp >= 8) {
+ high = low = false;
+ }
+ while (!low && !high) {
+ q = Bval.quoRemIteration(Sval);
+ Mval = Mval.mult(10);
+ assert q < 10 : q; // excessively large digit
+ low = (Bval.cmp(Mval) < 0);
+ high = (Bval.add(Mval).cmp(tenSval) > 0);
+ digits[ndigit++] = (char) ('0' + q);
+ }
+ if (high && low) {
+ Bval.lshiftMe(1);
+ lowDigitDifference = Bval.cmp(tenSval);
+ } else {
+ lowDigitDifference = 0L; // this here only for flow analysis!
+ }
+ }
+ this.decExponent = decExp + 1;
+ this.digits = digits;
+ this.nDigits = ndigit;
+ /*
+ * Last digit gets rounded based on stopping condition.
+ */
+ if (high) {
+ if (low) {
+ if (lowDigitDifference == 0L) {
+ // it's a tie!
+ // choose based on which digits we like.
+ if ((digits[nDigits - 1] & 1) != 0) {
+ roundup();
+ }
+ } else if (lowDigitDifference > 0) {
+ roundup();
+ }
+ } else {
+ roundup();
+ }
+ }
+ }
+
+ public String toString() {
+ // most brain-dead version
+ StringBuffer result = new StringBuffer(nDigits + 8);
+ if (isNegative) {
+ result.append('-');
+ }
+ if (isExceptional) {
+ result.append(digits, 0, nDigits);
+ } else {
+ result.append("0.");
+ result.append(digits, 0, nDigits);
+ result.append('e');
+ result.append(decExponent);
+ }
+ return new String(result);
+ }
+
+ public String toJavaFormatString() {
+ char result[] = (char[]) (perThreadBuffer.get());
+ int i = getChars(result);
+ return new String(result, 0, i);
+ }
+
+ private int getChars(char[] result) {
+ assert nDigits <= 19 : nDigits; // generous bound on size of nDigits
+ int i = 0;
+ if (isNegative) {
+ result[0] = '-';
+ i = 1;
+ }
+ if (isExceptional) {
+ System.arraycopy(digits, 0, result, i, nDigits);
+ i += nDigits;
+ } else {
+ if (decExponent > 0 && decExponent < 22) {
+ // print digits.digits.
+ int charLength = Math.min(nDigits, decExponent);
+ System.arraycopy(digits, 0, result, i, charLength);
+ i += charLength;
+ if (charLength < decExponent) {
+ charLength = decExponent - charLength;
+ System.arraycopy(zero, 0, result, i, charLength);
+ i += charLength;
+ } else {
+ if (charLength < nDigits) {
+ result[i++] = '.';
+ int t = nDigits - charLength;
+ System.arraycopy(digits, charLength, result, i, t);
+ i += t;
+ }
+ }
+ } else if (decExponent <= 0 && decExponent > -5) {
+ result[i++] = '0';
+ if (digits != zero) {
+ result[i++] = '.';
+ if (decExponent != 0) {
+ System.arraycopy(zero, 0, result, i, -decExponent);
+ i -= decExponent;
+ }
+ System.arraycopy(digits, 0, result, i, nDigits);
+ i += nDigits;
+ }
+ } else {
+ result[i++] = digits[0];
+ result[i++] = '.';
+ if (nDigits > 1) {
+ System.arraycopy(digits, 1, result, i, nDigits - 1);
+ i += nDigits - 1;
+ } else {
+ result[i++] = '0';
+ }
+ result[i++] = 'e';
+ int e;
+ if (decExponent <= 0) {
+ result[i++] = '-';
+ e = -decExponent + 1;
+ } else {
+ e = decExponent - 1;
+ }
+ // decExponent has 1, 2, or 3, digits
+ if (e <= 9) {
+ result[i++] = (char) (e + '0');
+ } else if (e <= 99) {
+ result[i++] = (char) (e / 10 + '0');
+ result[i++] = (char) (e % 10 + '0');
+ } else {
+ result[i++] = (char) (e / 100 + '0');
+ e %= 100;
+ result[i++] = (char) (e / 10 + '0');
+ result[i++] = (char) (e % 10 + '0');
+ }
+ }
+ }
+ return i;
+ }
+
+ // Per-thread buffer for string/stringbuffer conversion
+ private static ThreadLocal perThreadBuffer = new ThreadLocal() {
+ protected synchronized Object initialValue() {
+ return new char[26];
+ }
+ };
+
+ public void appendTo(Appendable buf) {
+ char result[] = (char[]) (perThreadBuffer.get());
+ int i = getChars(result);
+ if (buf instanceof StringBuilder) {
+ ((StringBuilder) buf).append(result, 0, i);
+ } else if (buf instanceof StringBuffer) {
+ ((StringBuffer) buf).append(result, 0, i);
+ } else {
+ assert false;
+ }
+ }
+
+ /*
+ * All the positive powers of 10 that can be
+ * represented exactly in double/float.
+ */
+ private static final double small10pow[] = {
+ 1.0e0,
+ 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5,
+ 1.0e6, 1.0e7, 1.0e8, 1.0e9, 1.0e10,
+ 1.0e11, 1.0e12, 1.0e13, 1.0e14, 1.0e15,
+ 1.0e16, 1.0e17, 1.0e18, 1.0e19, 1.0e20,
+ 1.0e21, 1.0e22
+ };
+
+ private static final float singleSmall10pow[] = {
+ 1.0e0f,
+ 1.0e1f, 1.0e2f, 1.0e3f, 1.0e4f, 1.0e5f,
+ 1.0e6f, 1.0e7f, 1.0e8f, 1.0e9f, 1.0e10f
+ };
+
+ private static final double big10pow[] = {
+ 1e16, 1e32, 1e64, 1e128, 1e256};
+
+ private static final double tiny10pow[] = {
+ 1e-16, 1e-32, 1e-64, 1e-128, 1e-256};
+
+ private static final int maxSmallTen = small10pow.length - 1;
+
+ private static final int singleMaxSmallTen = singleSmall10pow.length - 1;
+
+ private static final int small5pow[] = {
+ 1,
+ 5,
+ 5 * 5,
+ 5 * 5 * 5,
+ 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5
+ };
+
+ private static final long long5pow[] = {
+ 1L,
+ 5L,
+ 5L * 5,
+ 5L * 5 * 5,
+ 5L * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,};
+
+ // approximately ceil( log2( long5pow[i] ) )
+ private static final int n5bits[] = {
+ 0,
+ 3,
+ 5,
+ 7,
+ 10,
+ 12,
+ 14,
+ 17,
+ 19,
+ 21,
+ 24,
+ 26,
+ 28,
+ 31,
+ 33,
+ 35,
+ 38,
+ 40,
+ 42,
+ 45,
+ 47,
+ 49,
+ 52,
+ 54,
+ 56,
+ 59,
+ 61,};
+
+ private static final char infinity[] = {'I', 'n', 'f', 'i', 'n', 'i', 't', 'y'};
+
+ private static final char notANumber[] = {'N', 'a', 'N'};
+
+ private static final char zero[] = {'0', '0', '0', '0', '0', '0', '0', '0'};
+
+
+ /*
+ * Grammar is compatible with hexadecimal floating-point constants
+ * described in section 6.4.4.2 of the C99 specification.
+ */
+ private static Pattern hexFloatPattern = Pattern.compile(
+ //1 234 56 7 8 9
+ "([-+])?0[xX](((\\p{XDigit}+)\\.?)|((\\p{XDigit}*)\\.(\\p{XDigit}+)))[pP]([-+])?(\\p{Digit}+)[fFdD]?"
+ );
+
+ /**
+ * Return s with any leading zeros removed.
+ */
+ static String stripLeadingZeros(String s) {
+ return s.replaceFirst("^0+", "");
+ }
+
+ /**
+ * Extract a hexadecimal digit from position position
+ * of string s.
+ */
+ static int getHexDigit(String s, int position) {
+ int value = Character.digit(s.charAt(position), 16);
+ if (value <= -1 || value >= 16) {
+ throw new AssertionError("Unexpected failure of digit conversion of "
+ + s.charAt(position));
+ }
+ return value;
+ }
+}
+
+/*
+ * A really, really simple bigint package
+ * tailored to the needs of floating base conversion.
+ */
+class FDBigInt {
+
+ int nWords; // number of words used
+
+ int data[]; // value: data[0] is least significant
+
+ public FDBigInt(int v) {
+ nWords = 1;
+ data = new int[1];
+ data[0] = v;
+ }
+
+ public FDBigInt(long v) {
+ data = new int[2];
+ data[0] = (int) v;
+ data[1] = (int) (v >>> 32);
+ nWords = (data[1] == 0) ? 1 : 2;
+ }
+
+ public FDBigInt(FDBigInt other) {
+ data = new int[nWords = other.nWords];
+ System.arraycopy(other.data, 0, data, 0, nWords);
+ }
+
+ private FDBigInt(int[] d, int n) {
+ data = d;
+ nWords = n;
+ }
+
+ public FDBigInt(long seed, char digit[], int nd0, int nd) {
+ int n = (nd + 8) / 9; // estimate size needed.
+ if (n < 2) {
+ n = 2;
+ }
+ data = new int[n]; // allocate enough space
+ data[0] = (int) seed; // starting value
+ data[1] = (int) (seed >>> 32);
+ nWords = (data[1] == 0) ? 1 : 2;
+ int i = nd0;
+ int limit = nd - 5; // slurp digits 5 at a time.
+ int v;
+ while (i < limit) {
+ int ilim = i + 5;
+ v = (int) digit[i++] - (int) '0';
+ while (i < ilim) {
+ v = 10 * v + (int) digit[i++] - (int) '0';
+ }
+ multaddMe(100000, v); // ... where 100000 is 10^5.
+ }
+ int factor = 1;
+ v = 0;
+ while (i < nd) {
+ v = 10 * v + (int) digit[i++] - (int) '0';
+ factor *= 10;
+ }
+ if (factor != 1) {
+ multaddMe(factor, v);
+ }
+ }
+
+ /*
+ * Left shift by c bits.
+ * Shifts this in place.
+ */
+ public void
+ lshiftMe(int c) throws IllegalArgumentException {
+ if (c <= 0) {
+ if (c == 0) {
+ return; // silly.
+ } else {
+ throw new IllegalArgumentException("negative shift count");
+ }
+ }
+ int wordcount = c >> 5;
+ int bitcount = c & 0x1f;
+ int anticount = 32 - bitcount;
+ int t[] = data;
+ int s[] = data;
+ if (nWords + wordcount + 1 > t.length) {
+ // reallocate.
+ t = new int[nWords + wordcount + 1];
+ }
+ int target = nWords + wordcount;
+ int src = nWords - 1;
+ if (bitcount == 0) {
+ // special hack, since an anticount of 32 won't go!
+ System.arraycopy(s, 0, t, wordcount, nWords);
+ target = wordcount - 1;
+ } else {
+ t[target--] = s[src] >>> anticount;
+ while (src >= 1) {
+ t[target--] = (s[src] << bitcount) | (s[--src] >>> anticount);
+ }
+ t[target--] = s[src] << bitcount;
+ }
+ while (target >= 0) {
+ t[target--] = 0;
+ }
+ data = t;
+ nWords += wordcount + 1;
+ // may have constructed high-order word of 0.
+ // if so, trim it
+ while (nWords > 1 && data[nWords - 1] == 0) {
+ nWords--;
+ }
+ }
+
+ /*
+ * normalize this number by shifting until
+ * the MSB of the number is at 0x08000000.
+ * This is in preparation for quoRemIteration, below.
+ * The idea is that, to make division easier, we want the
+ * divisor to be "normalized" -- usually this means shifting
+ * the MSB into the high words sign bit. But because we know that
+ * the quotient will be 0 < q < 10, we would like to arrange that
+ * the dividend not span up into another word of precision.
+ * (This needs to be explained more clearly!)
+ */
+ public int
+ normalizeMe() throws IllegalArgumentException {
+ int src;
+ int wordcount = 0;
+ int bitcount = 0;
+ int v = 0;
+ for (src = nWords - 1; src >= 0 && (v = data[src]) == 0; src--) {
+ wordcount += 1;
+ }
+ if (src < 0) {
+ // oops. Value is zero. Cannot normalize it!
+ throw new IllegalArgumentException("zero value");
+ }
+ /*
+ * In most cases, we assume that wordcount is zero. This only
+ * makes sense, as we try not to maintain any high-order
+ * words full of zeros. In fact, if there are zeros, we will
+ * simply SHORTEN our number at this point. Watch closely...
+ */
+ nWords -= wordcount;
+ /*
+ * Compute how far left we have to shift v s.t. its highest-
+ * order bit is in the right place. Then call lshiftMe to
+ * do the work.
+ */
+ if ((v & 0xf0000000) != 0) {
+ // will have to shift up into the next word.
+ // too bad.
+ for (bitcount = 32; (v & 0xf0000000) != 0; bitcount--) {
+ v >>>= 1;
+ }
+ } else {
+ while (v <= 0x000fffff) {
+ // hack: byte-at-a-time shifting
+ v <<= 8;
+ bitcount += 8;
+ }
+ while (v <= 0x07ffffff) {
+ v <<= 1;
+ bitcount += 1;
+ }
+ }
+ if (bitcount != 0) {
+ lshiftMe(bitcount);
+ }
+ return bitcount;
+ }
+
+ /*
+ * Multiply a FDBigInt by an int.
+ * Result is a new FDBigInt.
+ */
+ public FDBigInt
+ mult(int iv) {
+ long v = iv;
+ int r[];
+ long p;
+
+ // guess adequate size of r.
+ r = new int[(v * ((long) data[nWords - 1] & 0xffffffffL) > 0xfffffffL) ? nWords + 1 : nWords];
+ p = 0L;
+ for (int i = 0; i < nWords; i++) {
+ p += v * ((long) data[i] & 0xffffffffL);
+ r[i] = (int) p;
+ p >>>= 32;
+ }
+ if (p == 0L) {
+ return new FDBigInt(r, nWords);
+ } else {
+ r[nWords] = (int) p;
+ return new FDBigInt(r, nWords + 1);
+ }
+ }
+
+ /*
+ * Multiply a FDBigInt by an int and add another int.
+ * Result is computed in place.
+ * Hope it fits!
+ */
+ public void
+ multaddMe(int iv, int addend) {
+ long v = iv;
+ long p;
+
+ // unroll 0th iteration, doing addition.
+ p = v * ((long) data[0] & 0xffffffffL) + ((long) addend & 0xffffffffL);
+ data[0] = (int) p;
+ p >>>= 32;
+ for (int i = 1; i < nWords; i++) {
+ p += v * ((long) data[i] & 0xffffffffL);
+ data[i] = (int) p;
+ p >>>= 32;
+ }
+ if (p != 0L) {
+ data[nWords] = (int) p; // will fail noisily if illegal!
+ nWords++;
+ }
+ }
+
+ /*
+ * Multiply a FDBigInt by another FDBigInt.
+ * Result is a new FDBigInt.
+ */
+ public FDBigInt
+ mult(FDBigInt other) {
+ // crudely guess adequate size for r
+ int r[] = new int[nWords + other.nWords];
+ int i;
+ // I think I am promised zeros...
+
+ for (i = 0; i < this.nWords; i++) {
+ long v = (long) this.data[i] & 0xffffffffL; // UNSIGNED CONVERSION
+ long p = 0L;
+ int j;
+ for (j = 0; j < other.nWords; j++) {
+ p += ((long) r[i + j] & 0xffffffffL) + v * ((long) other.data[j] & 0xffffffffL); // UNSIGNED CONVERSIONS ALL 'ROUND.
+ r[i + j] = (int) p;
+ p >>>= 32;
+ }
+ r[i + j] = (int) p;
+ }
+ // compute how much of r we actually needed for all that.
+ for (i = r.length - 1; i > 0; i--) {
+ if (r[i] != 0) {
+ break;
+ }
+ }
+ return new FDBigInt(r, i + 1);
+ }
+
+ /*
+ * Add one FDBigInt to another. Return a FDBigInt
+ */
+ public FDBigInt
+ add(FDBigInt other) {
+ int i;
+ int a[], b[];
+ int n, m;
+ long c = 0L;
+ // arrange such that a.nWords >= b.nWords;
+ // n = a.nWords, m = b.nWords
+ if (this.nWords >= other.nWords) {
+ a = this.data;
+ n = this.nWords;
+ b = other.data;
+ m = other.nWords;
+ } else {
+ a = other.data;
+ n = other.nWords;
+ b = this.data;
+ m = this.nWords;
+ }
+ int r[] = new int[n];
+ for (i = 0; i < n; i++) {
+ c += (long) a[i] & 0xffffffffL;
+ if (i < m) {
+ c += (long) b[i] & 0xffffffffL;
+ }
+ r[i] = (int) c;
+ c >>= 32; // signed shift.
+ }
+ if (c != 0L) {
+ // oops -- carry out -- need longer result.
+ int s[] = new int[r.length + 1];
+ System.arraycopy(r, 0, s, 0, r.length);
+ s[i++] = (int) c;
+ return new FDBigInt(s, i);
+ }
+ return new FDBigInt(r, i);
+ }
+
+ /*
+ * Subtract one FDBigInt from another. Return a FDBigInt
+ * Assert that the result is positive.
+ */
+ public FDBigInt
+ sub(FDBigInt other) {
+ int r[] = new int[this.nWords];
+ int i;
+ int n = this.nWords;
+ int m = other.nWords;
+ int nzeros = 0;
+ long c = 0L;
+ for (i = 0; i < n; i++) {
+ c += (long) this.data[i] & 0xffffffffL;
+ if (i < m) {
+ c -= (long) other.data[i] & 0xffffffffL;
+ }
+ if ((r[i] = (int) c) == 0) {
+ nzeros++;
+ } else {
+ nzeros = 0;
+ }
+ c >>= 32; // signed shift
+ }
+ assert c == 0L : c; // borrow out of subtract
+ assert dataInRangeIsZero(i, m, other); // negative result of subtract
+ return new FDBigInt(r, n - nzeros);
+ }
+
+ private static boolean dataInRangeIsZero(int i, int m, FDBigInt other) {
+ while (i < m) {
+ if (other.data[i++] != 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /*
+ * Compare FDBigInt with another FDBigInt. Return an integer
+ * >0: this > other
+ * 0: this == other
+ * <0: this < other
+ */
+ public int
+ cmp(FDBigInt other) {
+ int i;
+ if (this.nWords > other.nWords) {
+ // if any of my high-order words is non-zero,
+ // then the answer is evident
+ int j = other.nWords - 1;
+ for (i = this.nWords - 1; i > j; i--) {
+ if (this.data[i] != 0) {
+ return 1;
+ }
+ }
+ } else if (this.nWords < other.nWords) {
+ // if any of other's high-order words is non-zero,
+ // then the answer is evident
+ int j = this.nWords - 1;
+ for (i = other.nWords - 1; i > j; i--) {
+ if (other.data[i] != 0) {
+ return -1;
+ }
+ }
+ } else {
+ i = this.nWords - 1;
+ }
+ for (; i > 0; i--) {
+ if (this.data[i] != other.data[i]) {
+ break;
+ }
+ }
+ // careful! want unsigned compare!
+ // use brute force here.
+ int a = this.data[i];
+ int b = other.data[i];
+ if (a < 0) {
+ // a is really big, unsigned
+ if (b < 0) {
+ return a - b; // both big, negative
+ } else {
+ return 1; // b not big, answer is obvious;
+ }
+ } else {
+ // a is not really big
+ if (b < 0) {
+ // but b is really big
+ return -1;
+ } else {
+ return a - b;
+ }
+ }
+ }
+
+ /*
+ * Compute
+ * q = (int)( this / S )
+ * this = 10 * ( this mod S )
+ * Return q.
+ * This is the iteration step of digit development for output.
+ * We assume that S has been normalized, as above, and that
+ * "this" has been lshift'ed accordingly.
+ * Also assume, of course, that the result, q, can be expressed
+ * as an integer, 0 <= q < 10.
+ */
+ public int
+ quoRemIteration(FDBigInt S) throws IllegalArgumentException {
+ // ensure that this and S have the same number of
+ // digits. If S is properly normalized and q < 10 then
+ // this must be so.
+ if (nWords != S.nWords) {
+ throw new IllegalArgumentException("disparate values");
+ }
+ // estimate q the obvious way. We will usually be
+ // right. If not, then we're only off by a little and
+ // will re-add.
+ int n = nWords - 1;
+ long q = ((long) data[n] & 0xffffffffL) / (long) S.data[n];
+ long diff = 0L;
+ for (int i = 0; i <= n; i++) {
+ diff += ((long) data[i] & 0xffffffffL) - q * ((long) S.data[i] & 0xffffffffL);
+ data[i] = (int) diff;
+ diff >>= 32; // N.B. SIGNED shift.
+ }
+ if (diff != 0L) {
+ // damn, damn, damn. q is too big.
+ // add S back in until this turns +. This should
+ // not be very many times!
+ long sum = 0L;
+ while (sum == 0L) {
+ sum = 0L;
+ for (int i = 0; i <= n; i++) {
+ sum += ((long) data[i] & 0xffffffffL) + ((long) S.data[i] & 0xffffffffL);
+ data[i] = (int) sum;
+ sum >>= 32; // Signed or unsigned, answer is 0 or 1
+ }
+ /*
+ * Originally the following line read
+ * "if ( sum !=0 && sum != -1 )"
+ * but that would be wrong, because of the
+ * treatment of the two values as entirely unsigned,
+ * it would be impossible for a carry-out to be interpreted
+ * as -1 -- it would have to be a single-bit carry-out, or
+ * +1.
+ */
+ assert sum == 0 || sum == 1 : sum; // carry out of division correction
+ q -= 1;
+ }
+ }
+ // finally, we can multiply this by 10.
+ // it cannot overflow, right, as the high-order word has
+ // at least 4 high-order zeros!
+ long p = 0L;
+ for (int i = 0; i <= n; i++) {
+ p += 10 * ((long) data[i] & 0xffffffffL);
+ data[i] = (int) p;
+ p >>= 32; // SIGNED shift.
+ }
+ assert p == 0L : p; // Carry out of *10
+ return (int) q;
+ }
+
+ public long
+ longValue() {
+ // if this can be represented as a long, return the value
+ assert this.nWords > 0 : this.nWords; // longValue confused
+
+ if (this.nWords == 1) {
+ return ((long) data[0] & 0xffffffffL);
+ }
+
+ assert dataInRangeIsZero(2, this.nWords, this); // value too big
+ assert data[1] >= 0; // value too big
+ return ((long) (data[1]) << 32) | ((long) data[0] & 0xffffffffL);
+ }
+
+ public String
+ toString() {
+ StringBuffer r = new StringBuffer(30);
+ r.append('[');
+ int i = Math.min(nWords - 1, data.length - 1);
+ if (nWords > data.length) {
+ r.append("(" + data.length + "<" + nWords + "!)");
+ }
+ for (; i > 0; i--) {
+ r.append(Integer.toHexString(data[i]));
+ r.append(' ');
+ }
+ r.append(Integer.toHexString(data[0]));
+ r.append(']');
+ return new String(r);
+ }
+}
diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ecma/EcmaScript.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ecma/EcmaScript.java
index a3abfd024..71bfc8c70 100644
--- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ecma/EcmaScript.java
+++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ecma/EcmaScript.java
@@ -71,7 +71,9 @@ public class EcmaScript {
if (o.getClass() == Long.class) {
return EcmaType.NUMBER;
}
-
+ if (o.getClass() == Boolean.class) {
+ return EcmaType.BOOLEAN;
+ }
if (o.getClass() == Null.class) {
return EcmaType.NULL;
}
@@ -289,4 +291,18 @@ public class EcmaScript {
posInt %= (1 << 32);
return posInt;
}
+
+ public static String toString(Object o) {
+ if (o == null) {
+ return "null";
+ }
+
+ if (o instanceof Number) {
+ // http://www.ecma-international.org/ecma-262/5.1/#sec-9.8.1
+ Number n = (Number) o;
+ return new EcmaFloatingDecimal(n.doubleValue()).toJavaFormatString();
+ }
+
+ return o.toString();
+ }
}